]> jspc29.x-matter.uni-frankfurt.de Git - mvdsensorcontrol.git/commitdiff
Latest changes in lab in FFM
authorMaps <maps@ikf>
Thu, 9 Jun 2016 13:44:07 +0000 (15:44 +0200)
committerMaps <maps@ikf>
Thu, 9 Jun 2016 13:44:07 +0000 (15:44 +0200)
35 files changed:
Environment.pm
HldRec/.gitignore [new file with mode: 0644]
HldRec/.htaccess [new file with mode: 0644]
HldRec/CGI_dispatch.pm [new file with mode: 0644]
HldRec/HldRec.pl [new file with mode: 0755]
HldRec/HldRec.pm [new file with mode: 0644]
HldRec/HldRec.settings [new file with mode: 0644]
HldRec/css/HldRec.css [new file with mode: 0644]
HldRec/css/jquery-ui.css [new file with mode: 0644]
HldRec/css/styles.css [new file with mode: 0644]
HldRec/has_settings.pm [new file with mode: 0644]
HldRec/htdocs [new symlink]
HldRec/httpi [new file with mode: 0755]
HldRec/js/HldRec.js [new file with mode: 0644]
HldRec/js/cookies.js [new file with mode: 0644]
HldRec/js/has_settings.js [new file with mode: 0644]
HldRec/js/jquery-ui.js [new file with mode: 0644]
HldRec/js/jquery.flot.js [new file with mode: 0644]
HldRec/js/jquery.flot.selection.js [new file with mode: 0644]
HldRec/js/jquery.min.js [new file with mode: 0644]
HldRec/js/jquery.mwiebusch.js [new file with mode: 0644]
HldRec/js/jquery.timer.js [new file with mode: 0644]
HldRec/js/jquery.unfold.js [new file with mode: 0644]
HldRec/main_controls.html [new file with mode: 0644]
HldRec/misc_subs.pm [new file with mode: 0644]
HldRec/shm [new symlink]
HldRec/shm_manager.pm [new file with mode: 0644]
tools/init_setup.pl
tools/init_system.pl
tools/preview/exec_evtbuild_t.pl
tools/run.pl
tools/scurve_control.sh
tools/test.txt [deleted file]
tools/testgui.pl
tools/unpacker/unpacker.cxx

index 6b3d9777260eb4bbdf59252450351918cea2ff81..8f0f1c260135c055157f65ae6ef7df0e29117107 100644 (file)
@@ -19,8 +19,8 @@ use constant CONFDIR          => JTAGROOTPATH."../mvdconfig/config/";
 use constant SPECDIR          => JTAGROOTPATH."specs/";
 use constant PICTUREPATH      => TEMPDIR."prevImgs/";                #path for images on webserver (absolute path)
 use constant PICTUREPATHREL   => "../temp/prevImgs/";                #path for images on webserver relative to tools/
-use constant DUMPPATH         => "/tmp/MAPS_PREV/";                  #path for small hld dumps
-use constant SHAREPATH        => JTAGROOTPATH."share/";             #path for icons and misc stuff
+use constant DUMPPATH         => "/local.1/tmp/MAPS_PREV/";          #path for small hld dumps
+use constant SHAREPATH        => JTAGROOTPATH."share/";              #path for icons and misc stuff
 
 use constant SETUPFILE        => SETUPDIR."testsetup.xml";
 use constant SHMSYMLINK       => JTAGROOTPATH."shm/";
diff --git a/HldRec/.gitignore b/HldRec/.gitignore
new file mode 100644 (file)
index 0000000..d15d807
--- /dev/null
@@ -0,0 +1,2 @@
+*~
+access.log
diff --git a/HldRec/.htaccess b/HldRec/.htaccess
new file mode 100644 (file)
index 0000000..837105b
--- /dev/null
@@ -0,0 +1,2 @@
+AddType text/plain .txt
+AddType text/plain .log
diff --git a/HldRec/CGI_dispatch.pm b/HldRec/CGI_dispatch.pm
new file mode 100644 (file)
index 0000000..5d12df6
--- /dev/null
@@ -0,0 +1,82 @@
+package CGI_dispatch;
+
+use strict;
+use warnings;
+use Data::Dumper;
+use CGI ':standard';
+use CGI::Carp qw(fatalsToBrowser);
+use misc_subs;
+
+my $query;
+
+
+sub dispatch_sub {
+
+  my %options= @_;
+  my $self = $options{"package"};
+  my $dispatch_table = $options{"dispatch_table"};
+  my $default_sub = $options{"default_sub"} || "help";
+  
+  $query = CGI->new();
+
+  my $sub = $query->param('sub') || $default_sub;
+
+  # if method exists in dispatch table, execute it, if not complain and show help message
+  # if there is no dispatch table, allow execution of every sub
+  printHeader('text/html');
+  if ( not(defined ($dispatch_table)) or $dispatch_table->{$sub}) {
+    my $args = CGI_parameters();
+    
+    # do not pass the "sub=..." parameters to the called sub
+    delete $args->{"sub"};
+    # do not pass the "_=(some random number)" parameters to the called sub
+    delete $args->{"_"};
+    
+    # here the corresponding method is called
+    my $return = $self->$sub(%$args);
+    # does it return anything?
+    if(defined($return)){ # we get a return value
+      if(ref(\$return) eq "SCALAR"){ # just print it if it is a scalar
+        print "$return\n";
+      } else { # use Data::Dumper to display a hash
+        print "sub returns a hash:\n";
+        print Dumper $return;
+      }
+    }
+  } else {
+    print "$sub is not a valid sub!\n\n";
+    $self->help(1);
+  }
+
+}
+
+sub CGI_parameters {
+  # for each item on the list, get the
+  # designated parameter from the CGI query and
+  # store it in the target hash IF the parameter is
+  # defined in the query!
+  
+  my %options = @_;
+  my $items   = $options{items};
+  # target can be left undefined, then a new hash is created
+  # and returned
+  my $target;
+  $target = $options{target} if defined($options{target});
+  
+  
+  if(defined($items)){ # if there is a list of parameters
+    for my $item (@{$items}){
+      if(defined($query->param($item))){
+        $target->{$item} = $query->param($item);
+      } 
+    }
+  } else { # if there is no list of parameters
+    # extract all parameters
+    for my $item($query->param) {
+      $target->{$item} = $query->param($item);
+    }
+  }
+  return $target;
+}
+
+1;
diff --git a/HldRec/HldRec.pl b/HldRec/HldRec.pl
new file mode 100755 (executable)
index 0000000..d596f3c
--- /dev/null
@@ -0,0 +1,23 @@
+#!/usr/bin/perl
+
+####################################################################################
+##  This is a simple script to dispatch a perl module's subs from a CGI request   ##
+####################################################################################
+
+use strict;
+use warnings;
+use CGI_dispatch;
+
+use HldRec;
+my $self = HldRec->new();
+
+# go only to methods that are in the following dispatch table:
+# if associated value is one, sub can be called via CGI
+my $dispatch_table = {
+  #table is empty ... all subs are allowed
+};
+
+CGI_dispatch::dispatch_sub(package => $self,
+  #dispatch_table => $dispatch_table,
+  default_sub => "main_html"
+  );
diff --git a/HldRec/HldRec.pm b/HldRec/HldRec.pm
new file mode 100644 (file)
index 0000000..03bc76c
--- /dev/null
@@ -0,0 +1,426 @@
+package HldRec;
+
+
+use strict;
+use warnings;
+use Time::HiRes qw/alarm setitimer ITIMER_REAL/;
+use POSIX;
+use Data::Dumper;
+use File::Path qw(make_path remove_tree);
+
+use CGI ':standard';
+use JSON;
+
+use has_settings;
+our @ISA = qw/has_settings/; # assimilate the methods of the has_settings class
+
+$ENV{'PATH'} = $ENV{'PATH'}.":/home/maps/bin/";
+
+use misc_subs;
+use shm_manager;
+
+my $shm_path = "/dev/shm/HldRec/";
+
+## methods
+
+sub new {
+  my $class = shift;
+  my %options = @_;
+  
+  my $self = {}; # put tons of default values here (if you wish);
+
+  $self->{constants} = {
+  };
+  
+  $self->{settings_file} = "./".__PACKAGE__.".settings";
+  
+  $self->{default_settings} = { # hard default settings
+#     pid_file           => "./".__PACKAGE__.".pid",
+#     log_file           => "./".__PACKAGE__.".log",
+#     evtb_log           => "./shm/evtb.log",
+#     netm_log           => "./shm/netm.log",
+#     status_file        => "./shm/".__PACKAGE__.".state.json",
+    dump_dir           => "/tmp/",
+#     dump_fn            => "rec000.hld",
+    shm_id             => "HldRec",
+    acquisition_time   => 1,
+    backend_timeout    => 4,
+    ports              => 50888,
+  };
+  
+  $self->{settings_desc} = {
+  };
+
+  $self->{has_run} = {}; # remember which subs already have run
+  
+  $self->{settings} = {%{$self->{default_settings}}};
+  
+  $self  = {
+    %$self,
+    %options
+  };
+  bless($self, $class);
+  
+  $self->load_settings();
+  
+#   $self->{status_shm} = shm_manager->new( shmName => __PACKAGE__.".status" );
+#   $self->{status_shm}->initShm(); 
+  
+  return $self;
+}
+
+sub main_html {
+
+  my $self = shift;
+  my %options = @_;
+  
+#   printHeader('text/html'); #is already in the cgi dispatch module
+
+  $self->{settings} = {%{$self->{settings}} , %options};
+  
+  print start_html(
+    -title => 'HldRec',
+        
+    -style => [
+      {'src' => './css/styles.css'},
+      {'src' => './css/HldRec.css'},
+      {'src' => './css/jquery-ui.css'}
+    ],
+    
+    -script => [
+      {-src => './js/cookies.js'},
+      {-src => './js/jquery.min.js'},
+      {-src => './js/jquery.timer.js'},
+      {-src => './js/jquery-ui.js'},
+      {-src => './js/jquery.flot.js'},
+      {-src => './js/jquery.flot.selection.js'},
+      {-src => './js/jquery.mwiebusch.js'},
+      {-src => './js/jquery.unfold.js'},
+      {-src => './js/has_settings.js'},
+      {-src => './js/HldRec.js'},
+    ]
+  );
+  
+  # give the settings to the JavaScript
+  print "<script>";
+  print "var settings=";
+  print encode_json $self->{settings};
+  print ";";
+  print "</script>";
+
+  print h2 "HldRec v0.1";
+  
+  print "<div id='main_body'>";
+  
+  print "<p class='unfoldBtn' data-ContainerId='main_controls_container' >main controls</p>";
+  print "<div id='main_controls_container' class='stylishBox padded'>";
+  
+  open(FILE, "./main_controls.html");
+  print $_ while <FILE>;
+  close(FILE);
+#   print "<a href='".$self->{settings}->{log_file}."'>log file</a>";
+#   print "<a href='".$self->{settings}->{evtb_log}."'>evtb log</a>";
+#   print "<a href='".$self->{settings}->{netm_log}."'>netm log</a>";
+  
+  print "</div>";
+
+  
+  print "<p class='unfoldBtn' data-ContainerId='settings_container' >settings</p>";
+  print "<div align=right id='settings_container' class='stylishBox settings_form hidden_by_default'>";
+  $self->settings_form();
+  print "</div>";
+  
+  print "<p class='unfoldBtn' data-ContainerId='debug_output_container' >debug output</p>";
+  print "<div id='debug_output_container' class='stylishBox hidden_by_default padded'>";
+  print "<pre>";
+  print "<div align='bottom' id='debug_output' class='padded' >";
+  print "</div>";
+  print "</pre>";
+  print "<div align='right'><input type='button' id='btn_clear_debug' value='clear'></div>";
+  print "</div>";
+  
+  
+  print "</div>";
+  
+  print end_html();
+  
+  
+  return " ";
+}
+
+sub write_frontEnd {
+  my $status_file = shift;
+  my $status = shift;
+  
+  my $data = { timestamp => time(), data => $status };
+  open(FILE, "> ".$status_file);
+  print FILE encode_json $data;
+  close(FILE);
+}
+
+sub record {
+  my $self = shift;
+  my %options = @_;
+  
+  my $time   = $options{time} || "12h";
+  my $path   = $options{path} || "/tmp/";
+  my $ports  = $options{ports};
+  my $shm_id = $options{shm_id} || $self->{settings}->{shm_id};
+  
+#   my $evtb_log = $self->{settings}->{evtb_log};
+#   my $netm_log = $self->{settings}->{netm_log};
+  
+  unless(-e $path or make_path($path)){
+    print "could not create path $path!\n";
+    exit;
+  }
+  unless(-e $shm_path or make_path($shm_path)){
+    print "could not create shm path $shm_path!\n";
+    exit;
+  }
+  
+#   my $thr1 = threads->new(\&start_evtb, $self, time => $time, path => $path, shm_id => $shm_id, ports => $ports);
+  $self->start_evtb(time => $time, path => $path, shm_id => $shm_id, ports => $ports);
+  sleep 1;
+  $self->start_netm(time => $time, path => $path, shm_id => $shm_id, ports => $ports);
+  
+  $self->monitor(time => $time, shm_id => $shm_id);
+#   sleep 1;
+#   my $thr2 = threads->new(\&start_netm, $self, time => $time, path => $path, shm_id => $shm_id, ports => $ports);
+#   my $thr3 = threads->new(\&monitor, $self,time => $time, shm_id => $shm_id );
+#   $thr3->join();
+#   $thr1->join();
+#   $thr2->join();
+  
+}
+
+sub start_evtb {
+  my $self    = shift;
+  my %options = @_;
+  my $shm_id  = $options{shm_id};
+  my $path    = $options{path}||"/tmp/";
+  my $pf      = $shm_path."daq_evtbuild$shm_id.pid";
+  my $log     = $shm_path."daq_evtbuild$shm_id.log";
+  
+  my $ports = $options{ports};
+#   my $time  = $options{time} || "12h";
+  
+  my $c;
+  my $portoption = "";
+  if (defined($ports)) {
+    $portoption = $ports;
+    $c = ($portoption =~ tr/-//) + 1;
+    $ports =~ s/-/ -i /g;
+    $portoption = "-i ".$ports;
+    }
+  else {
+    die "No ports specified";
+    }
+  
+  
+  
+  # create semaphores, somehow evenbuilder/netmem needs these files to be there
+  system("cd $path && >netqueue".$shm_id."_0SC.sem && >netqueue".$shm_id."_0SR.sem");
+  
+  my $daemon = Proc::Daemon->new(
+    pid_file => $pf,
+    work_dir => $path,
+    child_STDOUT => $log,
+    child_STDERR => $log
+    );
+    
+  my $kid1_pid = $daemon->Init( { 
+#                     exec_command => ">netqueue".$shm_id."_0SC.sem; >netqueue".$shm_id."_0SR.sem; daq_evtbuild -m $c -q 32 -d file -x te -Se -S $shm_id"
+                    exec_command => "daq_evtbuild -m $c -q 32 -d file -x te -Se -S $shm_id"
+                 } ); 
+}
+
+sub start_netm {
+  my $self    = shift;
+  my %options = @_;
+  my $shm_id  = $options{shm_id};
+  my $path    = $options{path}||"/tmp/";
+  my $pf      = $shm_path."daq_netmem$shm_id.pid";
+  my $log     = $shm_path."daq_netmem$shm_id.log";
+  
+  my $ports = $options{ports};
+#   my $time  = $options{time} || "12h";
+  
+  my $c;
+  my $portoption = "";
+  if (defined($ports)) {
+    $portoption = $ports;
+    $c = ($portoption =~ tr/-//) + 1;
+    $ports =~ s/-/ -i /g;
+    $portoption = "-i ".$ports;
+    }
+  else {
+    die "No ports specified";
+    }
+  
+#   my $time_s     = time_to_s($time);
+  
+  my $daemon = Proc::Daemon->new(
+    pid_file => $pf,
+    work_dir => $path,
+    child_STDOUT => $log,
+    child_STDERR => $log
+    );
+    
+  my $kid2_pid = $daemon->Init( { 
+                    exec_command => "daq_netmem -m $c -q 32 $portoption -S $shm_id"
+                 } ); 
+}
+
+sub monitor {
+  my $self = shift;
+  my %options = @_;
+  my $shm_id  = $options{shm_id};
+  my $time    = $options{time} || "12h";
+  my $time_s  = time_to_s($time);
+  
+  my $pf     = $shm_path."HldRec$shm_id.pid";
+  my $log    = $shm_path."HldRec$shm_id.log";
+  
+  my $eb_shm = "/dev/shm/daq_evtbuild$shm_id.shm";
+  my $nm_shm = "/dev/shm/daq_netmem$shm_id.shm";
+  my $evtb_pf      = $shm_path."daq_evtbuild$shm_id.pid";
+  my $netm_pf      = $shm_path."daq_netmem$shm_id.pid";
+  
+  my $status_file  = $shm_path."HldRec$shm_id.state.json";
+
+  
+  my $start_time = time();
+  
+  $self->daemon_start( pf => $pf, log => $log );
+
+# signal handler is empty
+  $SIG{ALRM} = sub { };
+  setitimer(ITIMER_REAL, 1, 1);
+  
+  
+#   eval{
+#   
+#     local $SIG{ALRM} = sub {
+#       $self->stop(shm_id => $shm_id);
+#       alarm 0;
+#     };
+#     
+#     alarm $time_s;
+#     
+#     setitimer(ITIMER_VIRTUAL, 1, 1);
+    
+    my $last_eb_data;
+    my $last_nm_data;
+    while(1) {
+      my $eb_data = slurp_daq_shm($eb_shm);
+      my $nm_data = slurp_daq_shm($nm_shm);
+      
+      my $remaining_time = $time_s - (time() - $start_time);
+      $self->stop(shm_id => $shm_id) if ($remaining_time <= 0);
+      
+      
+      print "bytes written:  ".$eb_data->{bytesWritten}."\n";
+      print "bytes received: ".$nm_data->{bytesReceived0}."\n";
+      my $status = {
+        '#bytesWritten'   => $eb_data->{bytesWritten}." (".kilomega($eb_data->{bytesWritten}).")",
+        '#bytesReceived0' => $nm_data->{bytesReceived0}." (".kilomega($nm_data->{bytesReceived0}).")",
+        '#bytesReceived0_s' => $nm_data->{bytesReceived0}-$last_nm_data->{bytesReceived0}
+        ." (".kilomega($nm_data->{bytesReceived0}-$last_nm_data->{bytesReceived0}).")",
+        '#remainingTime' => hms_string($remaining_time-1),
+      };      
+      write_frontEnd($status_file,$status);
+      $last_nm_data = $nm_data;
+      $last_eb_data = $eb_data;
+      pause;
+    
+    }
+    
+#     eval {
+#       while(1){
+#       
+#         my $eb_data = slurp_daq_shm($eb_shm);
+#         my $nm_data = slurp_daq_shm($nm_shm);
+#         
+#         my $remaining_time = $time_s - (time() - $start_time);
+#         
+#         print "bytes written:  ".$eb_data->{bytesWritten}."\n";
+#         print "bytes received: ".$nm_data->{bytesReceived0}."\n";
+#         my $status = {
+#           '#bytesWritten'   => $eb_data->{bytesWritten}." (".kilomega($eb_data->{bytesWritten}).")",
+#           '#bytesReceived0' => $nm_data->{bytesReceived0}." (".kilomega($nm_data->{bytesReceived0}).")",
+#           '#remainingTime' => hms_string($remaining_time-1),
+#         };
+#         
+#         write_frontEnd($status_file,$status);
+#         sleep 1;
+#       }
+#     };
+#     
+#     alarm 0;
+# #     die if $@ && $@ !~ /alarm clock restart/;
+#   };
+  
+}
+
+sub dump_json {
+  my $self = shift;
+  my %options = @_;
+  my $data = $options{data};
+  print Dumper decode_json $data;
+
+}
+
+sub stop {
+  my $self = shift;
+  my %options = @_;
+  
+  my $shm_id = $options{shm_id};
+  
+  my $evtb_pf      = $shm_path."daq_evtbuild$shm_id.pid";
+  my $netm_pf      = $shm_path."daq_netmem$shm_id.pid";
+  my $HldRec_pf    = $shm_path."HldRec$shm_id.pid";
+  
+  $self->daemon_stop(pf => $netm_pf);
+  $self->daemon_stop(pf => $evtb_pf);
+  $self->daemon_stop(pf => $HldRec_pf);
+
+}
+
+sub execute {
+        my $s = shift;
+        print "$s\n";
+        system($s);
+}
+
+
+sub slurp_daq_shm {
+#  #evtbuid keys: 
+#  #PID bytesWritten coreNr dataMover diskNum diskNumEB errBit0 errBit1 errBit10 errBit11 errBit12 errBit2 errBit3 errBit4 errBit5 errBit6 errBit7 errBit8 errBit9 errBitPtrn0 errBitPtrn1 errBitPtrn2 errBitPtrn3 errBitPtrn4 errBitStat0_0 errBitStat0_1 errBitStat0_10 errBitStat0_11 errBitStat0_12 errBitStat0_2 errBitStat0_3 errBitStat0_4 errBitStat0_5 errBitStat0_6 errBitStat0_7 errBitStat0_8 errBitStat0_9 errBitStat1_0 errBitStat1_1 errBitStat1_10 errBitStat1_11 errBitStat1_12 errBitStat1_2 errBitStat1_3 errBitStat1_4 errBitStat1_5 errBitStat1_6 errBitStat1_7 errBitStat1_8 errBitStat1_9 errBitStat2_0 errBitStat2_1 errBitStat2_10 errBitStat2_11 errBitStat2_12 errBitStat2_2 errBitStat2_3 errBitStat2_4 errBitStat2_5 errBitStat2_6 errBitStat2_7 errBitStat2_8 errBitStat2_9 errBitStat3_0 errBitStat3_1 errBitStat3_10 errBitStat3_11 errBitStat3_12 errBitStat3_2 errBitStat3_3 errBitStat3_4 errBitStat3_5 errBitStat3_6 errBitStat3_7 errBitStat3_8 errBitStat3_9 errBitStat4_0 errBitStat4_1 errBitStat4_10 errBitStat4_11 errBitStat4_12 errBitStat4_2 errBitStat4_3 errBitStat4_4 errBitStat4_5 errBitStat4_6 errBitStat4_7 errBitStat4_8 errBitStat4_9 evtId0 evtId1 evtId10 evtId11 evtId12 evtId13 evtId14 evtId15 evtId16 evtId17 evtId18 evtId19 evtId2 evtId20 evtId21 evtId22 evtId23 evtId24 evtId25 evtId26 evtId27 evtId28 evtId29 evtId3 evtId30 evtId31 evtId32 evtId33 evtId34 evtId35 evtId36 evtId37 evtId38 evtId39 evtId4 evtId40 evtId41 evtId42 evtId43 evtId44 evtId45 evtId46 evtId47 evtId48 evtId49 evtId5 evtId50 evtId51 evtId52 evtId53 evtId54 evtId55 evtId56 evtId57 evtId58 evtId59 evtId6 evtId60 evtId61 evtId62 evtId63 evtId7 evtId8 evtId9 evtbuildBuff0 evtbuildBuff1 evtbuildBuff10 evtbuildBuff11 evtbuildBuff12 evtbuildBuff2 evtbuildBuff3 evtbuildBuff4 evtbuildBuff5 evtbuildBuff6 evtbuildBuff7 evtbuildBuff8 evtbuildBuff9 evtsComplete evtsDataError evtsDiscarded evtsTagError nrOfMsgs pid prefix runId trigNr0 trigNr1 trigNr10 trigNr11 trigNr12 trigNr2 trigNr3 trigNr4 trigNr5 trigNr6 trigNr7 trigNr8 trigNr9
+
+#  #netmem  keys: 
+#  #PID bytesReceived0 bytesReceived1 bytesReceived10 bytesReceived11 bytesReceived12 bytesReceived2 bytesReceived3 bytesReceived4 bytesReceived5 bytesReceived6 bytesReceived7 bytesReceived8 bytesReceived9 bytesReceivedRate0 bytesReceivedRate1 bytesReceivedRate10 bytesReceivedRate11 bytesReceivedRate12 bytesReceivedRate2 bytesReceivedRate3 bytesReceivedRate4 bytesReceivedRate5 bytesReceivedRate6 bytesReceivedRate7 bytesReceivedRate8 bytesReceivedRate9 coreNr msgsDiscarded0 msgsDiscarded1 msgsDiscarded10 msgsDiscarded11 msgsDiscarded12 msgsDiscarded2 msgsDiscarded3 msgsDiscarded4 msgsDiscarded5 msgsDiscarded6 msgsDiscarded7 msgsDiscarded8 msgsDiscarded9 msgsReceived0 msgsReceived1 msgsReceived10 msgsReceived11 msgsReceived12 msgsReceived2 msgsReceived3 msgsReceived4 msgsReceived5 msgsReceived6 msgsReceived7 msgsReceived8 msgsReceived9 netmemBuff0 netmemBuff1 netmemBuff10 netmemBuff11 netmemBuff12 netmemBuff2 netmemBuff3 netmemBuff4 netmemBuff5 netmemBuff6 netmemBuff7 netmemBuff8 netmemBuff9 nrOfMsgs pid pktsDiscarded0 pktsDiscarded1 pktsDiscarded10 pktsDiscarded11 pktsDiscarded12 pktsDiscarded2 pktsDiscarded3 pktsDiscarded4 pktsDiscarded5 pktsDiscarded6 pktsDiscarded7 pktsDiscarded8 pktsDiscarded9 pktsReceived0 pktsReceived1 pktsReceived10 pktsReceived11 pktsReceived12 pktsReceived2 pktsReceived3 pktsReceived4 pktsReceived5 pktsReceived6 pktsReceived7 pktsReceived8 pktsReceived9 portNr0 portNr1 portNr10 portNr11 portNr12 portNr2 portNr3 portNr4 portNr5 portNr6 portNr7 portNr8 portNr9
+
+  my $infile = shift;
+  open (INFILE, "<", $infile) or return;
+  binmode (INFILE);
+  
+  my $data = {};
+  while (1) {
+    my $string;
+    my $rawval;
+    read (INFILE, $string, 32) or last;
+    ($string) = $string =~ m/^([\w]+)/;
+    last unless ($string);
+    read (INFILE, $rawval   ,  8) or last;
+    my $number = unpack("L",pack("a8",$rawval));
+#     printf("%20s : %16d (0x%016X) \n",$string,$number,$number);
+    $data->{$string}=$number;
+  }
+  close(INFILE);
+  return $data;
+}
+
+
+
+1;
diff --git a/HldRec/HldRec.settings b/HldRec/HldRec.settings
new file mode 100644 (file)
index 0000000..0ec3407
Binary files /dev/null and b/HldRec/HldRec.settings differ
diff --git a/HldRec/css/HldRec.css b/HldRec/css/HldRec.css
new file mode 100644 (file)
index 0000000..7e6e261
--- /dev/null
@@ -0,0 +1,70 @@
+
+   
+.plotArea {
+   position:absolute;
+   left:0px;
+   top:50px;
+   min-width: 640px;
+   min-height: 480px;
+   padding:10px;
+   margin-top:30px;
+   margin-left:30px;
+}
+   
+
+#debug_output {
+  height: 400px;
+  overflow-y: scroll;
+  overflow-x: scroll;
+}
+   
+div.padded {
+     padding:10px;
+  
+}
+
+div.settings_form{
+  padding:10px;
+  padding-right:250px;
+}
+
+div.header {
+    font-size:13pt;
+    position:absolute;
+    top:-22px;
+    color:#444;
+    z-index:-2;
+
+   }
+
+   
+.unfoldBtn {
+  background:#dde;
+  cursor:pointer;
+  color:#228;
+  transition:background .4s;
+}
+  
+.unfoldBtn:hover{
+    background:#eed;
+}
+
+.hidden_by_default {
+  display:none;
+}
+
+
+.quickEditArea {
+   float:left;
+   position:relative;
+   width:320px;
+   padding:10px;
+   margin:50px 10px 0 30px;
+   }
+   
+#main_body {
+  float:left;
+  position:relative;
+  width:800px;
+
+}
\ No newline at end of file
diff --git a/HldRec/css/jquery-ui.css b/HldRec/css/jquery-ui.css
new file mode 100644 (file)
index 0000000..62578c5
--- /dev/null
@@ -0,0 +1,1225 @@
+/*! jQuery UI - v1.11.2 - 2014-10-16
+* http://jqueryui.com
+* Includes: core.css, accordion.css, autocomplete.css, button.css, datepicker.css, dialog.css, draggable.css, menu.css, progressbar.css, resizable.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
+* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2CArial%2Csans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=cccccc&bgTextureHeader=highlight_soft&bgImgOpacityHeader=75&borderColorHeader=aaaaaa&fcHeader=222222&iconColorHeader=222222&bgColorContent=ffffff&bgTextureContent=flat&bgImgOpacityContent=75&borderColorContent=aaaaaa&fcContent=222222&iconColorContent=222222&bgColorDefault=e6e6e6&bgTextureDefault=glass&bgImgOpacityDefault=75&borderColorDefault=d3d3d3&fcDefault=555555&iconColorDefault=888888&bgColorHover=dadada&bgTextureHover=glass&bgImgOpacityHover=75&borderColorHover=999999&fcHover=212121&iconColorHover=454545&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=aaaaaa&fcActive=212121&iconColorActive=454545&bgColorHighlight=fbf9ee&bgTextureHighlight=glass&bgImgOpacityHighlight=55&borderColorHighlight=fcefa1&fcHighlight=363636&iconColorHighlight=2e83ff&bgColorError=fef1ec&bgTextureError=glass&bgImgOpacityError=95&borderColorError=cd0a0a&fcError=cd0a0a&iconColorError=cd0a0a&bgColorOverlay=aaaaaa&bgTextureOverlay=flat&bgImgOpacityOverlay=0&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=flat&bgImgOpacityShadow=0&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+/* Layout helpers
+----------------------------------*/
+.ui-helper-hidden {
+       display: none;
+}
+.ui-helper-hidden-accessible {
+       border: 0;
+       clip: rect(0 0 0 0);
+       height: 1px;
+       margin: -1px;
+       overflow: hidden;
+       padding: 0;
+       position: absolute;
+       width: 1px;
+}
+.ui-helper-reset {
+       margin: 0;
+       padding: 0;
+       border: 0;
+       outline: 0;
+       line-height: 1.3;
+       text-decoration: none;
+       font-size: 100%;
+       list-style: none;
+}
+.ui-helper-clearfix:before,
+.ui-helper-clearfix:after {
+       content: "";
+       display: table;
+       border-collapse: collapse;
+}
+.ui-helper-clearfix:after {
+       clear: both;
+}
+.ui-helper-clearfix {
+       min-height: 0; /* support: IE7 */
+}
+.ui-helper-zfix {
+       width: 100%;
+       height: 100%;
+       top: 0;
+       left: 0;
+       position: absolute;
+       opacity: 0;
+       filter:Alpha(Opacity=0); /* support: IE8 */
+}
+
+.ui-front {
+       z-index: 100;
+}
+
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-disabled {
+       cursor: default !important;
+}
+
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+       display: block;
+       text-indent: -99999px;
+       overflow: hidden;
+       background-repeat: no-repeat;
+}
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Overlays */
+.ui-widget-overlay {
+       position: fixed;
+       top: 0;
+       left: 0;
+       width: 100%;
+       height: 100%;
+}
+.ui-accordion .ui-accordion-header {
+       display: block;
+       cursor: pointer;
+       position: relative;
+       margin: 2px 0 0 0;
+       padding: .5em .5em .5em .7em;
+       min-height: 0; /* support: IE7 */
+       font-size: 100%;
+}
+.ui-accordion .ui-accordion-icons {
+       padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-icons .ui-accordion-icons {
+       padding-left: 2.2em;
+}
+.ui-accordion .ui-accordion-header .ui-accordion-header-icon {
+       position: absolute;
+       left: .5em;
+       top: 50%;
+       margin-top: -8px;
+}
+.ui-accordion .ui-accordion-content {
+       padding: 1em 2.2em;
+       border-top: 0;
+       overflow: auto;
+}
+.ui-autocomplete {
+       position: absolute;
+       top: 0;
+       left: 0;
+       cursor: default;
+}
+.ui-button {
+       display: inline-block;
+       position: relative;
+       padding: 0;
+       line-height: normal;
+       margin-right: .1em;
+       cursor: pointer;
+       vertical-align: middle;
+       text-align: center;
+       overflow: visible; /* removes extra width in IE */
+}
+.ui-button,
+.ui-button:link,
+.ui-button:visited,
+.ui-button:hover,
+.ui-button:active {
+       text-decoration: none;
+}
+/* to make room for the icon, a width needs to be set here */
+.ui-button-icon-only {
+       width: 2.2em;
+}
+/* button elements seem to need a little more width */
+button.ui-button-icon-only {
+       width: 2.4em;
+}
+.ui-button-icons-only {
+       width: 3.4em;
+}
+button.ui-button-icons-only {
+       width: 3.7em;
+}
+
+/* button text element */
+.ui-button .ui-button-text {
+       display: block;
+       line-height: normal;
+}
+.ui-button-text-only .ui-button-text {
+       padding: .4em 1em;
+}
+.ui-button-icon-only .ui-button-text,
+.ui-button-icons-only .ui-button-text {
+       padding: .4em;
+       text-indent: -9999999px;
+}
+.ui-button-text-icon-primary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+       padding: .4em 1em .4em 2.1em;
+}
+.ui-button-text-icon-secondary .ui-button-text,
+.ui-button-text-icons .ui-button-text {
+       padding: .4em 2.1em .4em 1em;
+}
+.ui-button-text-icons .ui-button-text {
+       padding-left: 2.1em;
+       padding-right: 2.1em;
+}
+/* no icon support for input elements, provide padding by default */
+input.ui-button {
+       padding: .4em 1em;
+}
+
+/* button icon element(s) */
+.ui-button-icon-only .ui-icon,
+.ui-button-text-icon-primary .ui-icon,
+.ui-button-text-icon-secondary .ui-icon,
+.ui-button-text-icons .ui-icon,
+.ui-button-icons-only .ui-icon {
+       position: absolute;
+       top: 50%;
+       margin-top: -8px;
+}
+.ui-button-icon-only .ui-icon {
+       left: 50%;
+       margin-left: -8px;
+}
+.ui-button-text-icon-primary .ui-button-icon-primary,
+.ui-button-text-icons .ui-button-icon-primary,
+.ui-button-icons-only .ui-button-icon-primary {
+       left: .5em;
+}
+.ui-button-text-icon-secondary .ui-button-icon-secondary,
+.ui-button-text-icons .ui-button-icon-secondary,
+.ui-button-icons-only .ui-button-icon-secondary {
+       right: .5em;
+}
+
+/* button sets */
+.ui-buttonset {
+       margin-right: 7px;
+}
+.ui-buttonset .ui-button {
+       margin-left: 0;
+       margin-right: -.3em;
+}
+
+/* workarounds */
+/* reset extra padding in Firefox, see h5bp.com/l */
+input.ui-button::-moz-focus-inner,
+button.ui-button::-moz-focus-inner {
+       border: 0;
+       padding: 0;
+}
+.ui-datepicker {
+       width: 17em;
+       padding: .2em .2em 0;
+       display: none;
+}
+.ui-datepicker .ui-datepicker-header {
+       position: relative;
+       padding: .2em 0;
+}
+.ui-datepicker .ui-datepicker-prev,
+.ui-datepicker .ui-datepicker-next {
+       position: absolute;
+       top: 2px;
+       width: 1.8em;
+       height: 1.8em;
+}
+.ui-datepicker .ui-datepicker-prev-hover,
+.ui-datepicker .ui-datepicker-next-hover {
+       top: 1px;
+}
+.ui-datepicker .ui-datepicker-prev {
+       left: 2px;
+}
+.ui-datepicker .ui-datepicker-next {
+       right: 2px;
+}
+.ui-datepicker .ui-datepicker-prev-hover {
+       left: 1px;
+}
+.ui-datepicker .ui-datepicker-next-hover {
+       right: 1px;
+}
+.ui-datepicker .ui-datepicker-prev span,
+.ui-datepicker .ui-datepicker-next span {
+       display: block;
+       position: absolute;
+       left: 50%;
+       margin-left: -8px;
+       top: 50%;
+       margin-top: -8px;
+}
+.ui-datepicker .ui-datepicker-title {
+       margin: 0 2.3em;
+       line-height: 1.8em;
+       text-align: center;
+}
+.ui-datepicker .ui-datepicker-title select {
+       font-size: 1em;
+       margin: 1px 0;
+}
+.ui-datepicker select.ui-datepicker-month,
+.ui-datepicker select.ui-datepicker-year {
+       width: 45%;
+}
+.ui-datepicker table {
+       width: 100%;
+       font-size: .9em;
+       border-collapse: collapse;
+       margin: 0 0 .4em;
+}
+.ui-datepicker th {
+       padding: .7em .3em;
+       text-align: center;
+       font-weight: bold;
+       border: 0;
+}
+.ui-datepicker td {
+       border: 0;
+       padding: 1px;
+}
+.ui-datepicker td span,
+.ui-datepicker td a {
+       display: block;
+       padding: .2em;
+       text-align: right;
+       text-decoration: none;
+}
+.ui-datepicker .ui-datepicker-buttonpane {
+       background-image: none;
+       margin: .7em 0 0 0;
+       padding: 0 .2em;
+       border-left: 0;
+       border-right: 0;
+       border-bottom: 0;
+}
+.ui-datepicker .ui-datepicker-buttonpane button {
+       float: right;
+       margin: .5em .2em .4em;
+       cursor: pointer;
+       padding: .2em .6em .3em .6em;
+       width: auto;
+       overflow: visible;
+}
+.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current {
+       float: left;
+}
+
+/* with multiple calendars */
+.ui-datepicker.ui-datepicker-multi {
+       width: auto;
+}
+.ui-datepicker-multi .ui-datepicker-group {
+       float: left;
+}
+.ui-datepicker-multi .ui-datepicker-group table {
+       width: 95%;
+       margin: 0 auto .4em;
+}
+.ui-datepicker-multi-2 .ui-datepicker-group {
+       width: 50%;
+}
+.ui-datepicker-multi-3 .ui-datepicker-group {
+       width: 33.3%;
+}
+.ui-datepicker-multi-4 .ui-datepicker-group {
+       width: 25%;
+}
+.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header {
+       border-left-width: 0;
+}
+.ui-datepicker-multi .ui-datepicker-buttonpane {
+       clear: left;
+}
+.ui-datepicker-row-break {
+       clear: both;
+       width: 100%;
+       font-size: 0;
+}
+
+/* RTL support */
+.ui-datepicker-rtl {
+       direction: rtl;
+}
+.ui-datepicker-rtl .ui-datepicker-prev {
+       right: 2px;
+       left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next {
+       left: 2px;
+       right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-prev:hover {
+       right: 1px;
+       left: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-next:hover {
+       left: 1px;
+       right: auto;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane {
+       clear: right;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button {
+       float: left;
+}
+.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,
+.ui-datepicker-rtl .ui-datepicker-group {
+       float: right;
+}
+.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,
+.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header {
+       border-right-width: 0;
+       border-left-width: 1px;
+}
+.ui-dialog {
+       overflow: hidden;
+       position: absolute;
+       top: 0;
+       left: 0;
+       padding: .2em;
+       outline: 0;
+}
+.ui-dialog .ui-dialog-titlebar {
+       padding: .4em 1em;
+       position: relative;
+}
+.ui-dialog .ui-dialog-title {
+       float: left;
+       margin: .1em 0;
+       white-space: nowrap;
+       width: 90%;
+       overflow: hidden;
+       text-overflow: ellipsis;
+}
+.ui-dialog .ui-dialog-titlebar-close {
+       position: absolute;
+       right: .3em;
+       top: 50%;
+       width: 20px;
+       margin: -10px 0 0 0;
+       padding: 1px;
+       height: 20px;
+}
+.ui-dialog .ui-dialog-content {
+       position: relative;
+       border: 0;
+       padding: .5em 1em;
+       background: none;
+       overflow: auto;
+}
+.ui-dialog .ui-dialog-buttonpane {
+       text-align: left;
+       border-width: 1px 0 0 0;
+       background-image: none;
+       margin-top: .5em;
+       padding: .3em 1em .5em .4em;
+}
+.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset {
+       float: right;
+}
+.ui-dialog .ui-dialog-buttonpane button {
+       margin: .5em .4em .5em 0;
+       cursor: pointer;
+}
+.ui-dialog .ui-resizable-se {
+       width: 12px;
+       height: 12px;
+       right: -5px;
+       bottom: -5px;
+       background-position: 16px 16px;
+}
+.ui-draggable .ui-dialog-titlebar {
+       cursor: move;
+}
+.ui-draggable-handle {
+       -ms-touch-action: none;
+       touch-action: none;
+}
+.ui-menu {
+       list-style: none;
+       padding: 0;
+       margin: 0;
+       display: block;
+       outline: none;
+}
+.ui-menu .ui-menu {
+       position: absolute;
+}
+.ui-menu .ui-menu-item {
+       position: relative;
+       margin: 0;
+       padding: 3px 1em 3px .4em;
+       cursor: pointer;
+       min-height: 0; /* support: IE7 */
+       /* support: IE10, see #8844 */
+       list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7");
+}
+.ui-menu .ui-menu-divider {
+       margin: 5px 0;
+       height: 0;
+       font-size: 0;
+       line-height: 0;
+       border-width: 1px 0 0 0;
+}
+.ui-menu .ui-state-focus,
+.ui-menu .ui-state-active {
+       margin: -1px;
+}
+
+/* icon support */
+.ui-menu-icons {
+       position: relative;
+}
+.ui-menu-icons .ui-menu-item {
+       padding-left: 2em;
+}
+
+/* left-aligned */
+.ui-menu .ui-icon {
+       position: absolute;
+       top: 0;
+       bottom: 0;
+       left: .2em;
+       margin: auto 0;
+}
+
+/* right-aligned */
+.ui-menu .ui-menu-icon {
+       left: auto;
+       right: 0;
+}
+.ui-progressbar {
+       height: 2em;
+       text-align: left;
+       overflow: hidden;
+}
+.ui-progressbar .ui-progressbar-value {
+       margin: -1px;
+       height: 100%;
+}
+.ui-progressbar .ui-progressbar-overlay {
+       background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");
+       height: 100%;
+       filter: alpha(opacity=25); /* support: IE8 */
+       opacity: 0.25;
+}
+.ui-progressbar-indeterminate .ui-progressbar-value {
+       background-image: none;
+}
+.ui-resizable {
+       position: relative;
+}
+.ui-resizable-handle {
+       position: absolute;
+       font-size: 0.1px;
+       display: block;
+       -ms-touch-action: none;
+       touch-action: none;
+}
+.ui-resizable-disabled .ui-resizable-handle,
+.ui-resizable-autohide .ui-resizable-handle {
+       display: none;
+}
+.ui-resizable-n {
+       cursor: n-resize;
+       height: 7px;
+       width: 100%;
+       top: -5px;
+       left: 0;
+}
+.ui-resizable-s {
+       cursor: s-resize;
+       height: 7px;
+       width: 100%;
+       bottom: -5px;
+       left: 0;
+}
+.ui-resizable-e {
+       cursor: e-resize;
+       width: 7px;
+       right: -5px;
+       top: 0;
+       height: 100%;
+}
+.ui-resizable-w {
+       cursor: w-resize;
+       width: 7px;
+       left: -5px;
+       top: 0;
+       height: 100%;
+}
+.ui-resizable-se {
+       cursor: se-resize;
+       width: 12px;
+       height: 12px;
+       right: 1px;
+       bottom: 1px;
+}
+.ui-resizable-sw {
+       cursor: sw-resize;
+       width: 9px;
+       height: 9px;
+       left: -5px;
+       bottom: -5px;
+}
+.ui-resizable-nw {
+       cursor: nw-resize;
+       width: 9px;
+       height: 9px;
+       left: -5px;
+       top: -5px;
+}
+.ui-resizable-ne {
+       cursor: ne-resize;
+       width: 9px;
+       height: 9px;
+       right: -5px;
+       top: -5px;
+}
+.ui-selectable {
+       -ms-touch-action: none;
+       touch-action: none;
+}
+.ui-selectable-helper {
+       position: absolute;
+       z-index: 100;
+       border: 1px dotted black;
+}
+.ui-selectmenu-menu {
+       padding: 0;
+       margin: 0;
+       position: absolute;
+       top: 0;
+       left: 0;
+       display: none;
+}
+.ui-selectmenu-menu .ui-menu {
+       overflow: auto;
+       /* Support: IE7 */
+       overflow-x: hidden;
+       padding-bottom: 1px;
+}
+.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup {
+       font-size: 1em;
+       font-weight: bold;
+       line-height: 1.5;
+       padding: 2px 0.4em;
+       margin: 0.5em 0 0 0;
+       height: auto;
+       border: 0;
+}
+.ui-selectmenu-open {
+       display: block;
+}
+.ui-selectmenu-button {
+       display: inline-block;
+       overflow: hidden;
+       position: relative;
+       text-decoration: none;
+       cursor: pointer;
+}
+.ui-selectmenu-button span.ui-icon {
+       right: 0.5em;
+       left: auto;
+       margin-top: -8px;
+       position: absolute;
+       top: 50%;
+}
+.ui-selectmenu-button span.ui-selectmenu-text {
+       text-align: left;
+       padding: 0.4em 2.1em 0.4em 1em;
+       display: block;
+       line-height: 1.4;
+       overflow: hidden;
+       text-overflow: ellipsis;
+       white-space: nowrap;
+}
+.ui-slider {
+       position: relative;
+       text-align: left;
+}
+.ui-slider .ui-slider-handle {
+       position: absolute;
+       z-index: 2;
+       width: 1.2em;
+       height: 1.2em;
+       cursor: default;
+       -ms-touch-action: none;
+       touch-action: none;
+}
+.ui-slider .ui-slider-range {
+       position: absolute;
+       z-index: 1;
+       font-size: .7em;
+       display: block;
+       border: 0;
+       background-position: 0 0;
+}
+
+/* support: IE8 - See #6727 */
+.ui-slider.ui-state-disabled .ui-slider-handle,
+.ui-slider.ui-state-disabled .ui-slider-range {
+       filter: inherit;
+}
+
+.ui-slider-horizontal {
+       height: .8em;
+}
+.ui-slider-horizontal .ui-slider-handle {
+       top: -.3em;
+       margin-left: -.6em;
+}
+.ui-slider-horizontal .ui-slider-range {
+       top: 0;
+       height: 100%;
+}
+.ui-slider-horizontal .ui-slider-range-min {
+       left: 0;
+}
+.ui-slider-horizontal .ui-slider-range-max {
+       right: 0;
+}
+
+.ui-slider-vertical {
+       width: .8em;
+       height: 100px;
+}
+.ui-slider-vertical .ui-slider-handle {
+       left: -.3em;
+       margin-left: 0;
+       margin-bottom: -.6em;
+}
+.ui-slider-vertical .ui-slider-range {
+       left: 0;
+       width: 100%;
+}
+.ui-slider-vertical .ui-slider-range-min {
+       bottom: 0;
+}
+.ui-slider-vertical .ui-slider-range-max {
+       top: 0;
+}
+.ui-sortable-handle {
+       -ms-touch-action: none;
+       touch-action: none;
+}
+.ui-spinner {
+       position: relative;
+       display: inline-block;
+       overflow: hidden;
+       padding: 0;
+       vertical-align: middle;
+}
+.ui-spinner-input {
+       border: none;
+       background: none;
+       color: inherit;
+       padding: 0;
+       margin: .2em 0;
+       vertical-align: middle;
+       margin-left: .4em;
+       margin-right: 22px;
+}
+.ui-spinner-button {
+       width: 16px;
+       height: 50%;
+       font-size: .5em;
+       padding: 0;
+       margin: 0;
+       text-align: center;
+       position: absolute;
+       cursor: default;
+       display: block;
+       overflow: hidden;
+       right: 0;
+}
+/* more specificity required here to override default borders */
+.ui-spinner a.ui-spinner-button {
+       border-top: none;
+       border-bottom: none;
+       border-right: none;
+}
+/* vertically center icon */
+.ui-spinner .ui-icon {
+       position: absolute;
+       margin-top: -8px;
+       top: 50%;
+       left: 0;
+}
+.ui-spinner-up {
+       top: 0;
+}
+.ui-spinner-down {
+       bottom: 0;
+}
+
+/* TR overrides */
+.ui-spinner .ui-icon-triangle-1-s {
+       /* need to fix icons sprite */
+       background-position: -65px -16px;
+}
+.ui-tabs {
+       position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
+       padding: .2em;
+}
+.ui-tabs .ui-tabs-nav {
+       margin: 0;
+       padding: .2em .2em 0;
+}
+.ui-tabs .ui-tabs-nav li {
+       list-style: none;
+       float: left;
+       position: relative;
+       top: 0;
+       margin: 1px .2em 0 0;
+       border-bottom-width: 0;
+       padding: 0;
+       white-space: nowrap;
+}
+.ui-tabs .ui-tabs-nav .ui-tabs-anchor {
+       float: left;
+       padding: .5em 1em;
+       text-decoration: none;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active {
+       margin-bottom: -1px;
+       padding-bottom: 1px;
+}
+.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,
+.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor {
+       cursor: text;
+}
+.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor {
+       cursor: pointer;
+}
+.ui-tabs .ui-tabs-panel {
+       display: block;
+       border-width: 0;
+       padding: 1em 1.4em;
+       background: none;
+}
+.ui-tooltip {
+       padding: 8px;
+       position: absolute;
+       z-index: 9999;
+       max-width: 300px;
+       -webkit-box-shadow: 0 0 5px #aaa;
+       box-shadow: 0 0 5px #aaa;
+}
+body .ui-tooltip {
+       border-width: 2px;
+}
+
+/* Component containers
+----------------------------------*/
+.ui-widget {
+       font-family: Verdana,Arial,sans-serif;
+       font-size: 1.1em;
+}
+.ui-widget .ui-widget {
+       font-size: 1em;
+}
+.ui-widget input,
+.ui-widget select,
+.ui-widget textarea,
+.ui-widget button {
+       font-family: Verdana,Arial,sans-serif;
+       font-size: 1em;
+}
+.ui-widget-content {
+       border: 1px solid #aaaaaa;
+       background: #ffffff url("images/ui-bg_flat_75_ffffff_40x100.png") 50% 50% repeat-x;
+       color: #222222;
+}
+.ui-widget-content a {
+       color: #222222;
+}
+.ui-widget-header {
+       border: 1px solid #aaaaaa;
+       background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x;
+       color: #222222;
+       font-weight: bold;
+}
+.ui-widget-header a {
+       color: #222222;
+}
+
+/* Interaction states
+----------------------------------*/
+.ui-state-default,
+.ui-widget-content .ui-state-default,
+.ui-widget-header .ui-state-default {
+       border: 1px solid #d3d3d3;
+       background: #e6e6e6 url("images/ui-bg_glass_75_e6e6e6_1x400.png") 50% 50% repeat-x;
+       font-weight: normal;
+       color: #555555;
+}
+.ui-state-default a,
+.ui-state-default a:link,
+.ui-state-default a:visited {
+       color: #555555;
+       text-decoration: none;
+}
+.ui-state-hover,
+.ui-widget-content .ui-state-hover,
+.ui-widget-header .ui-state-hover,
+.ui-state-focus,
+.ui-widget-content .ui-state-focus,
+.ui-widget-header .ui-state-focus {
+       border: 1px solid #999999;
+       background: #dadada url("images/ui-bg_glass_75_dadada_1x400.png") 50% 50% repeat-x;
+       font-weight: normal;
+       color: #212121;
+}
+.ui-state-hover a,
+.ui-state-hover a:hover,
+.ui-state-hover a:link,
+.ui-state-hover a:visited,
+.ui-state-focus a,
+.ui-state-focus a:hover,
+.ui-state-focus a:link,
+.ui-state-focus a:visited {
+       color: #212121;
+       text-decoration: none;
+}
+.ui-state-active,
+.ui-widget-content .ui-state-active,
+.ui-widget-header .ui-state-active {
+       border: 1px solid #aaaaaa;
+       background: #ffffff url("images/ui-bg_glass_65_ffffff_1x400.png") 50% 50% repeat-x;
+       font-weight: normal;
+       color: #212121;
+}
+.ui-state-active a,
+.ui-state-active a:link,
+.ui-state-active a:visited {
+       color: #212121;
+       text-decoration: none;
+}
+
+/* Interaction Cues
+----------------------------------*/
+.ui-state-highlight,
+.ui-widget-content .ui-state-highlight,
+.ui-widget-header .ui-state-highlight {
+       border: 1px solid #fcefa1;
+       background: #fbf9ee url("images/ui-bg_glass_55_fbf9ee_1x400.png") 50% 50% repeat-x;
+       color: #363636;
+}
+.ui-state-highlight a,
+.ui-widget-content .ui-state-highlight a,
+.ui-widget-header .ui-state-highlight a {
+       color: #363636;
+}
+.ui-state-error,
+.ui-widget-content .ui-state-error,
+.ui-widget-header .ui-state-error {
+       border: 1px solid #cd0a0a;
+       background: #fef1ec url("images/ui-bg_glass_95_fef1ec_1x400.png") 50% 50% repeat-x;
+       color: #cd0a0a;
+}
+.ui-state-error a,
+.ui-widget-content .ui-state-error a,
+.ui-widget-header .ui-state-error a {
+       color: #cd0a0a;
+}
+.ui-state-error-text,
+.ui-widget-content .ui-state-error-text,
+.ui-widget-header .ui-state-error-text {
+       color: #cd0a0a;
+}
+.ui-priority-primary,
+.ui-widget-content .ui-priority-primary,
+.ui-widget-header .ui-priority-primary {
+       font-weight: bold;
+}
+.ui-priority-secondary,
+.ui-widget-content .ui-priority-secondary,
+.ui-widget-header .ui-priority-secondary {
+       opacity: .7;
+       filter:Alpha(Opacity=70); /* support: IE8 */
+       font-weight: normal;
+}
+.ui-state-disabled,
+.ui-widget-content .ui-state-disabled,
+.ui-widget-header .ui-state-disabled {
+       opacity: .35;
+       filter:Alpha(Opacity=35); /* support: IE8 */
+       background-image: none;
+}
+.ui-state-disabled .ui-icon {
+       filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */
+}
+
+/* Icons
+----------------------------------*/
+
+/* states and images */
+.ui-icon {
+       width: 16px;
+       height: 16px;
+}
+.ui-icon,
+.ui-widget-content .ui-icon {
+       background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-widget-header .ui-icon {
+       background-image: url("images/ui-icons_222222_256x240.png");
+}
+.ui-state-default .ui-icon {
+       background-image: url("images/ui-icons_888888_256x240.png");
+}
+.ui-state-hover .ui-icon,
+.ui-state-focus .ui-icon {
+       background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-active .ui-icon {
+       background-image: url("images/ui-icons_454545_256x240.png");
+}
+.ui-state-highlight .ui-icon {
+       background-image: url("images/ui-icons_2e83ff_256x240.png");
+}
+.ui-state-error .ui-icon,
+.ui-state-error-text .ui-icon {
+       background-image: url("images/ui-icons_cd0a0a_256x240.png");
+}
+
+/* positioning */
+.ui-icon-blank { background-position: 16px 16px; }
+.ui-icon-carat-1-n { background-position: 0 0; }
+.ui-icon-carat-1-ne { background-position: -16px 0; }
+.ui-icon-carat-1-e { background-position: -32px 0; }
+.ui-icon-carat-1-se { background-position: -48px 0; }
+.ui-icon-carat-1-s { background-position: -64px 0; }
+.ui-icon-carat-1-sw { background-position: -80px 0; }
+.ui-icon-carat-1-w { background-position: -96px 0; }
+.ui-icon-carat-1-nw { background-position: -112px 0; }
+.ui-icon-carat-2-n-s { background-position: -128px 0; }
+.ui-icon-carat-2-e-w { background-position: -144px 0; }
+.ui-icon-triangle-1-n { background-position: 0 -16px; }
+.ui-icon-triangle-1-ne { background-position: -16px -16px; }
+.ui-icon-triangle-1-e { background-position: -32px -16px; }
+.ui-icon-triangle-1-se { background-position: -48px -16px; }
+.ui-icon-triangle-1-s { background-position: -64px -16px; }
+.ui-icon-triangle-1-sw { background-position: -80px -16px; }
+.ui-icon-triangle-1-w { background-position: -96px -16px; }
+.ui-icon-triangle-1-nw { background-position: -112px -16px; }
+.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
+.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
+.ui-icon-arrow-1-n { background-position: 0 -32px; }
+.ui-icon-arrow-1-ne { background-position: -16px -32px; }
+.ui-icon-arrow-1-e { background-position: -32px -32px; }
+.ui-icon-arrow-1-se { background-position: -48px -32px; }
+.ui-icon-arrow-1-s { background-position: -64px -32px; }
+.ui-icon-arrow-1-sw { background-position: -80px -32px; }
+.ui-icon-arrow-1-w { background-position: -96px -32px; }
+.ui-icon-arrow-1-nw { background-position: -112px -32px; }
+.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
+.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
+.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
+.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
+.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
+.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
+.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
+.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
+.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
+.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
+.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
+.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
+.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
+.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
+.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
+.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
+.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
+.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
+.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
+.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
+.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
+.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
+.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
+.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
+.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
+.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
+.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
+.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
+.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
+.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
+.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
+.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
+.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
+.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
+.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
+.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
+.ui-icon-arrow-4 { background-position: 0 -80px; }
+.ui-icon-arrow-4-diag { background-position: -16px -80px; }
+.ui-icon-extlink { background-position: -32px -80px; }
+.ui-icon-newwin { background-position: -48px -80px; }
+.ui-icon-refresh { background-position: -64px -80px; }
+.ui-icon-shuffle { background-position: -80px -80px; }
+.ui-icon-transfer-e-w { background-position: -96px -80px; }
+.ui-icon-transferthick-e-w { background-position: -112px -80px; }
+.ui-icon-folder-collapsed { background-position: 0 -96px; }
+.ui-icon-folder-open { background-position: -16px -96px; }
+.ui-icon-document { background-position: -32px -96px; }
+.ui-icon-document-b { background-position: -48px -96px; }
+.ui-icon-note { background-position: -64px -96px; }
+.ui-icon-mail-closed { background-position: -80px -96px; }
+.ui-icon-mail-open { background-position: -96px -96px; }
+.ui-icon-suitcase { background-position: -112px -96px; }
+.ui-icon-comment { background-position: -128px -96px; }
+.ui-icon-person { background-position: -144px -96px; }
+.ui-icon-print { background-position: -160px -96px; }
+.ui-icon-trash { background-position: -176px -96px; }
+.ui-icon-locked { background-position: -192px -96px; }
+.ui-icon-unlocked { background-position: -208px -96px; }
+.ui-icon-bookmark { background-position: -224px -96px; }
+.ui-icon-tag { background-position: -240px -96px; }
+.ui-icon-home { background-position: 0 -112px; }
+.ui-icon-flag { background-position: -16px -112px; }
+.ui-icon-calendar { background-position: -32px -112px; }
+.ui-icon-cart { background-position: -48px -112px; }
+.ui-icon-pencil { background-position: -64px -112px; }
+.ui-icon-clock { background-position: -80px -112px; }
+.ui-icon-disk { background-position: -96px -112px; }
+.ui-icon-calculator { background-position: -112px -112px; }
+.ui-icon-zoomin { background-position: -128px -112px; }
+.ui-icon-zoomout { background-position: -144px -112px; }
+.ui-icon-search { background-position: -160px -112px; }
+.ui-icon-wrench { background-position: -176px -112px; }
+.ui-icon-gear { background-position: -192px -112px; }
+.ui-icon-heart { background-position: -208px -112px; }
+.ui-icon-star { background-position: -224px -112px; }
+.ui-icon-link { background-position: -240px -112px; }
+.ui-icon-cancel { background-position: 0 -128px; }
+.ui-icon-plus { background-position: -16px -128px; }
+.ui-icon-plusthick { background-position: -32px -128px; }
+.ui-icon-minus { background-position: -48px -128px; }
+.ui-icon-minusthick { background-position: -64px -128px; }
+.ui-icon-close { background-position: -80px -128px; }
+.ui-icon-closethick { background-position: -96px -128px; }
+.ui-icon-key { background-position: -112px -128px; }
+.ui-icon-lightbulb { background-position: -128px -128px; }
+.ui-icon-scissors { background-position: -144px -128px; }
+.ui-icon-clipboard { background-position: -160px -128px; }
+.ui-icon-copy { background-position: -176px -128px; }
+.ui-icon-contact { background-position: -192px -128px; }
+.ui-icon-image { background-position: -208px -128px; }
+.ui-icon-video { background-position: -224px -128px; }
+.ui-icon-script { background-position: -240px -128px; }
+.ui-icon-alert { background-position: 0 -144px; }
+.ui-icon-info { background-position: -16px -144px; }
+.ui-icon-notice { background-position: -32px -144px; }
+.ui-icon-help { background-position: -48px -144px; }
+.ui-icon-check { background-position: -64px -144px; }
+.ui-icon-bullet { background-position: -80px -144px; }
+.ui-icon-radio-on { background-position: -96px -144px; }
+.ui-icon-radio-off { background-position: -112px -144px; }
+.ui-icon-pin-w { background-position: -128px -144px; }
+.ui-icon-pin-s { background-position: -144px -144px; }
+.ui-icon-play { background-position: 0 -160px; }
+.ui-icon-pause { background-position: -16px -160px; }
+.ui-icon-seek-next { background-position: -32px -160px; }
+.ui-icon-seek-prev { background-position: -48px -160px; }
+.ui-icon-seek-end { background-position: -64px -160px; }
+.ui-icon-seek-start { background-position: -80px -160px; }
+/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
+.ui-icon-seek-first { background-position: -80px -160px; }
+.ui-icon-stop { background-position: -96px -160px; }
+.ui-icon-eject { background-position: -112px -160px; }
+.ui-icon-volume-off { background-position: -128px -160px; }
+.ui-icon-volume-on { background-position: -144px -160px; }
+.ui-icon-power { background-position: 0 -176px; }
+.ui-icon-signal-diag { background-position: -16px -176px; }
+.ui-icon-signal { background-position: -32px -176px; }
+.ui-icon-battery-0 { background-position: -48px -176px; }
+.ui-icon-battery-1 { background-position: -64px -176px; }
+.ui-icon-battery-2 { background-position: -80px -176px; }
+.ui-icon-battery-3 { background-position: -96px -176px; }
+.ui-icon-circle-plus { background-position: 0 -192px; }
+.ui-icon-circle-minus { background-position: -16px -192px; }
+.ui-icon-circle-close { background-position: -32px -192px; }
+.ui-icon-circle-triangle-e { background-position: -48px -192px; }
+.ui-icon-circle-triangle-s { background-position: -64px -192px; }
+.ui-icon-circle-triangle-w { background-position: -80px -192px; }
+.ui-icon-circle-triangle-n { background-position: -96px -192px; }
+.ui-icon-circle-arrow-e { background-position: -112px -192px; }
+.ui-icon-circle-arrow-s { background-position: -128px -192px; }
+.ui-icon-circle-arrow-w { background-position: -144px -192px; }
+.ui-icon-circle-arrow-n { background-position: -160px -192px; }
+.ui-icon-circle-zoomin { background-position: -176px -192px; }
+.ui-icon-circle-zoomout { background-position: -192px -192px; }
+.ui-icon-circle-check { background-position: -208px -192px; }
+.ui-icon-circlesmall-plus { background-position: 0 -208px; }
+.ui-icon-circlesmall-minus { background-position: -16px -208px; }
+.ui-icon-circlesmall-close { background-position: -32px -208px; }
+.ui-icon-squaresmall-plus { background-position: -48px -208px; }
+.ui-icon-squaresmall-minus { background-position: -64px -208px; }
+.ui-icon-squaresmall-close { background-position: -80px -208px; }
+.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
+.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
+.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
+.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
+.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
+.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
+
+
+/* Misc visuals
+----------------------------------*/
+
+/* Corner radius */
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-left,
+.ui-corner-tl {
+       border-top-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-top,
+.ui-corner-right,
+.ui-corner-tr {
+       border-top-right-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-left,
+.ui-corner-bl {
+       border-bottom-left-radius: 4px;
+}
+.ui-corner-all,
+.ui-corner-bottom,
+.ui-corner-right,
+.ui-corner-br {
+       border-bottom-right-radius: 4px;
+}
+
+/* Overlays */
+.ui-widget-overlay {
+       background: #aaaaaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;
+       opacity: .3;
+       filter: Alpha(Opacity=30); /* support: IE8 */
+}
+.ui-widget-shadow {
+       margin: -8px 0 0 -8px;
+       padding: 8px;
+       background: #aaaaaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x;
+       opacity: .3;
+       filter: Alpha(Opacity=30); /* support: IE8 */
+       border-radius: 8px;
+}
diff --git a/HldRec/css/styles.css b/HldRec/css/styles.css
new file mode 100644 (file)
index 0000000..1b6a564
--- /dev/null
@@ -0,0 +1,269 @@
+body {
+/*     background:#f5f5f5; */
+    font-size:10pt;
+    margin:0px 0 0 25px;
+    padding:0;
+    font-family:sans-serif;
+
+}
+
+table {
+  font-size: 10pt;
+  
+}
+
+body.index {
+      background:#f5f5f5 url("/layout/background.png") fixed no-repeat;
+}
+
+h2 {
+/*   position:absolute; */
+  width:100%;
+/*   top:-15px; */
+/*   left:0px; */
+/*   float:left; */
+  background:#f9f9f9;
+  border-bottom:1px solid #ccc;
+  padding:10px 15px 5px 10px;
+  margin: 0px 0 10px  -25px;
+}
+
+h3 {
+  border-bottom: 1px solid #dddddd;
+  font-size: 120%;
+  font-weight: bold;
+  color: #6B7B95;
+  margin:10px 30px 0 0;
+}
+
+
+div.index {
+  margin: 0 30px 0 15px;
+  background: rgba(255,255,255,.5);
+  overflow: hidden;
+  padding: 5px;
+}
+
+div.index ul a{
+  text-decoration:none; 
+  color:#6B7B95;
+}
+
+div.index ul li{
+  color:#6B7B95;
+}
+   
+   
+table.form {
+  border:1px solid #ccc;
+  padding:0;
+  background:#f0f0f8;
+  margin-bottom:20px;
+  border-collapse:collapse;
+}
+
+table.form td {
+  padding:2px 10px;
+}
+
+table.content {
+ border:solid #ccc; 
+ border-width:1px 0 0 1px;
+ margin:0 20px 20px 0;
+ border-spacing:0;
+}
+
+table.content td:first-child, table.content th:first-child{
+  width:40px;
+  
+  padding-right:0px;
+  text-align:center;
+}
+
+
+
+table.content td, table.content th {
+ border:solid #ccc; 
+ border-width:0 1px 1px 0;
+ width:90px;
+ min-width:90px;
+ text-align:right;
+ padding-right:15px;
+}
+
+table.content {
+ border:1px solid #ccc; 
+}
+
+
+div#bar1 {
+  width:900px;
+  overflow-x:scroll;
+  }
+  
+div#bar1 div {
+  width:66500px;
+  height:0px;
+}
+
+div#bar2 {
+  width:900px;
+  overflow-x:scroll;
+  }
+  
+div#bar2 div {
+  width:65536px;
+  height:0px;
+}
+
+
+#total {
+  text-align:center;
+  font-weight:bold;
+  }
+
+.content tr:nth-child(odd), .odd {
+  background:#f0f0f8;
+}
+
+.content tr:nth-child(even), .even {
+  background:#e0e0e8;
+}
+
+.odd {
+  background:#f0f0f8;
+}
+
+.content tr:hover, .content tr:hover {
+  background:#ffe;
+}
+
+.even {
+  background:#e0e0e8;
+}
+
+tr.head th {
+  background:#333;
+  color:#eef;
+}
+
+table.content td.over {
+  width:50px;
+  margin:0 10px;
+  padding-right:10px;
+  border-left: 5px solid #fcc;
+  border-right:5px solid #fcc;
+  border-radius:20px 20px;
+  background:#fcc;
+}
+
+table.content td.under {
+  width:50px;
+  margin:0 10px;
+  padding-right:10px;
+  border-left: 5px solid #cfc;
+  border-right:5px solid #cfc;
+  border-radius:20px 20px;
+  background:#cfc;
+}
+
+
+table.content  tr:hover td.over {
+  background:#fdd;
+  border-color:#fdd;
+}
+
+table.content  tr:hover td.under {
+  background:#dfd;
+  border-color:#dfd;
+}
+/*
+input[type="text"]{
+  width:182px;
+}*/
+
+input.small {
+  width:90px;
+  text-align:right;
+  margin-right:-6px;
+}
+
+#form_rate, #form_rate2, #form_min, #form_max {
+width: 89px;
+}
+
+.fixed {
+  font-family:monospace;
+  font-size:85%;
+}
+
+
+.content .checkbox {
+  display: block;
+  float:left;
+  margin:0px -15px 2px 0px;
+  padding:0px 0px 0px 0px;
+}
+
+
+.onoffbutton {
+  width:22px;
+}
+
+.triggerbutton {
+  width:100px;
+}
+
+table#content.map td {border-bottom:none; margin-left:10px; text-align:right}
+table#content.map td:first-child {text-align:left;padding-left:10px; width:100px;}
+table#content.map td + td + td + td {width:200px;}
+table#content.map td + td + td + td + td{width:120px;}
+
+#content .level1 {background:#f5f5f5;}
+#content .level2 {background:#eaeaea;}
+#content .level3 {background:#dedede;}
+#content .level4 {background:#d0d0d0;}
+#content .level5 {background:#f5f5f5;}
+#content .level6 {background:#eaeaea;}
+#content .level7 {background:#dedede;}
+#content .level8 {background:#d0d0d0;}
+#content .level9 {background:#d0d0d0;}
+
+#content .level1 > td:first-child { border-left:10px solid #333;}
+#content .level2 > td:first-child { border-left:30px solid #333;}
+#content .level3 > td:first-child { border-left:50px solid #333;}
+#content .level4 > td:first-child { border-left:70px solid #333; }
+#content .level5 > td:first-child { border-left:90px solid #333; }
+#content .level6 > td:first-child { border-left:110px solid #333; }
+#content .level7 > td:first-child { border-left:130px solid #333; }
+#content .level8 > td:first-child { border-left:150px solid #333;  }
+#content .level9 > td:first-child { border-left:170px solid #333;  }
+#content .newlevel td {border-top:1px solid #aaa;}
+
+
+
+
+#content .level > td:first-child div {
+  position:relative;
+  left:-30px;
+  width:20px;
+  text-align:right;
+  color:white;
+  float:left;
+  font-size:80%;
+  margin-top:3px;
+}
+
+table#server-details td.label {
+   padding-right: 10px;
+}
+
+table#server-details pre {
+   display: inline;
+}
+   
+.stylishBox {
+   border-radius:5px;
+   background:#eef;
+   box-shadow: 0 0 10px 5px #fff,  0 0 4px 1px #78b inset;
+}
\ No newline at end of file
diff --git a/HldRec/has_settings.pm b/HldRec/has_settings.pm
new file mode 100644 (file)
index 0000000..2cf299a
--- /dev/null
@@ -0,0 +1,107 @@
+package has_settings;
+use Storable qw(lock_store lock_retrieve);
+use misc_subs;
+use JSON;
+
+
+
+
+sub load_settings {
+  my $self=shift;
+  my %options = @_;
+  my $json = $options{json};
+  
+  my $settings_file = $self->{settings_file};
+  
+  if ( -e $settings_file ) {
+    $self->{settings} = {%{$self->{settings}}, %{lock_retrieve($settings_file)}};
+  }
+  
+  if($json){
+    print encode_json $self->{settings};
+    return " ";
+  }
+  
+  return $self->{settings};
+}
+
+sub save_settings {
+# make sure load settings is executed first, or you will lose your data!
+  my $self=shift;
+  my %options = @_;
+  
+  my $settings_file = $self->{settings_file};
+  
+  $self->{settings} = { %{$self->{settings}}, %options};
+  lock_store($self->{settings},$settings_file);
+  print "settings were saved!\n";
+  return $self->{settings};
+}
+
+sub reset_settings {
+  my $self=shift;
+  my $settings_file = $self->{settings_file};
+  lock_store({},$settings_file);
+  $self->{settings} = {%{$self->{default_settings}}};
+  return $self->{settings}
+}
+
+
+sub settings_form {
+  my $self=shift;
+  my %options=@_;
+  my $settings = $self->load_settings();
+  my $settings_desc = $self->{settings_desc};
+  
+  my $header=$options{header};
+
+  printHeader('text/html') if $header;
+  
+  print '
+<style>
+.hidden {
+  display:none;
+}
+
+span.dropt {border-bottom: thin dotted; background: #ffeedd;}
+span.dropt:hover {text-decoration: none; background: #ffffff; z-index: 6; }
+span.dropt span {position: absolute; left: -9999px;
+  margin: 20px 0 0 0px; padding: 3px 3px 3px 3px;
+  border-style:solid; border-color:black; border-width:1px; z-index: 6;}
+span.dropt:hover span {left: 2%; background: #ffffff;} 
+span.dropt span {position: absolute; left: -9999px;
+  margin: 4px 0 0 0px; padding: 3px 3px 3px 3px; 
+  border-style:solid; border-color:black; border-width:1px;}
+span.dropt:hover span {margin: 20px 0 0 170px; background: #ffffff; z-index:6;} 
+
+</style>
+
+  
+<form class="has_settings_form" action="'.ref($self).'.pl" method="get" target="_blank">
+  <input type="text" name="sub" value="save_settings" class="hidden"><br>
+  <table>
+  ';
+  
+  for my $key ( sort(keys %$settings) ) {
+    my $value = $settings->{$key};
+    print "<tr><td align=right><span class=dropt>$key :";
+    
+    print "<span style=\"width:300px;\" >".$settings_desc->{$key}."</span></span></td>";
+    print "<td><input type='text' name='$key' value='$value'></td></tr>";
+  }
+
+print '
+  <tr><td></td><td>
+  <input type="submit" value="save">
+  <input type="button" value="reset"></td>
+  </table>
+</form>
+
+
+';
+  return " ";
+
+}
+
+
+1;
\ No newline at end of file
diff --git a/HldRec/htdocs b/HldRec/htdocs
new file mode 120000 (symlink)
index 0000000..945c9b4
--- /dev/null
@@ -0,0 +1 @@
+.
\ No newline at end of file
diff --git a/HldRec/httpi b/HldRec/httpi
new file mode 100755 (executable)
index 0000000..727c1f1
--- /dev/null
@@ -0,0 +1,541 @@
+#!/usr/bin/perl
+use POSIX qw(SIGALRM SIGTERM sigaction);
+
+use lib "./include";
+use Digest::SHA::PurePerl qw(sha1_base64);
+use File::Basename;
+
+$VERSION = "1.7 (Demonic/Linux)";
+
+# HTTPi Hypertext Tiny Truncated Process Implementation
+# Copyright 1999-2010 Cameron Kaiser and Contributors # All rights reserved
+# Please read LICENSE # Do not strip this copyright message.
+
+###############################################################
+# WHITE HATS ONLY BELOW THIS POINT -- SEE DOCUMENTATION FIRST #
+###############################################################
+
+%system_content_types =
+       ("html" => "text/html",
+        "htm" => "text/html",
+        "txt" => "text/plain",
+        "xml" => "text/xml",
+        "xsl" => "text/xml",
+        "xhtml" => "application/xhtml+xml",
+        "css" => "text/css",
+        "gif" => "image/gif",
+        "jpeg" => "image/jpeg",
+        "jpg" => "image/jpeg",
+        "bmp" => "image/bmp",
+        "png" => "image/png",
+        "tif" => "image/tiff",
+        "tiff" => "image/tiff",
+        "ico" => "image/x-icon",
+        "svg" => "image/svg+xml",
+        "svgz" => "image/svg+xml",
+        "wbmp" => "image/vnd.wap.wbmp",
+        "wbm" => "image/vnd.wap.wbmp",
+        "xbm" => "image/x-xbitmap",
+        "mp3" => "audio/x-mpeg",
+        "wma" => "audio/x-ms-wma",
+        "wav" => "audio/x-wav",
+        "au" => "audio/basic",
+        "aif" => "audio/x-aiff",
+        "aiff" => "audio/x-aiff",
+        "ogg" => "audio/x-ogg", 
+        "oga" => "audio/x-ogg",
+        "mid" => "audio/midi",
+        "wma" => "audio/x-ms-wma",
+        "mpeg" => "video/mpeg",
+        "mpg" => "video/mpeg",
+        "aac" => "audio/aac",
+        "ogv" => "video/x-ogg",
+        "ogx" => "application/x-ogg",
+        "avi" => "video/x-msvideo",
+        "wmv" => "video/x-ms-wmv",
+        "asf" => "video/x-ms-asf",
+        "mov" => "video/quicktime",
+        "mp4" => "video/mp4",
+        "rv" => "video/vnd.m-realvideo",
+        "rm" => "application/vnd.m-realmedia",
+        "ra" => "audio/vnd.m-realaudio",
+        "ram" => "audio/vnd.m-realaudio",
+        "pdf" => "application/pdf",
+        "fdf" => "application/vnd.fdf",
+        "class" => "application/octet-stream",
+        "jar" => "application/octet-stream",
+        "js" => "application/x-javascript",
+        "lnk" => "application/x-hyperlink",
+        "prg" => "application/x-c64-prg-binary",
+        "d64" => "application/x-c64-disk-image",
+        "tar" => "application/x-tar",
+        "sit" => "application/x-stuffit",
+        "Z" => "application/x-compress",
+        "gz"  => "application/x-gzip",
+        "dmg" => "application/octet-stream",
+        "img" => "application/octet-stream",
+        "lzh" => "application/octet-stream",
+        "lha" => "application/octet-stream",
+        "exe" => "application/octet-stream",
+        "com" => "application/octet-stream",
+        "zip" => "application/x-zip-compressed",
+        "hqx" => "application/x-binhex",
+        "swf" => "x-shockwave-flash",
+        "flv" => "video/x-flv",
+
+        "bin" => "application/octet-stream");
+
+# comment in to enable logs
+$logfile = "./access.log";
+$path = "./htdocs";
+$sockaddr = 'S n a4 x8';
+
+$server_host = $ARGV[0];
+$server_port = $ARGV[1];
+
+die("$0 [host] [port] required. got >$server_host< >$server_port<") unless ($server_host and $server_port); 
+   
+%content_types =
+       ("html" => "text/html",
+        "htm" => "text/html",
+    "shtml" => "text/html"
+        );
+%restrictions = (
+        "/nw" => "^10\.##^Mozilla#MSIE",
+        "/status" => "####voyeur:daNrZR3TcSwD2",
+        "/" => "###(NPBot|WebZIP|HTTrack|eCatch|Offline Explorer|UdmSearch|WebCopier|internetseer|MSIECrawler|SuperBot|LinkWalker|Tutorial Crawler|WebReaper)",
+       );
+               # See documentation for interpreting this string.
+
+$headers = <<"EOF";
+Server: TRB3-DAQ based on HTTPi/$VERSION
+MIME-Version: 1.0
+EOF
+
+
+%content_types = (%system_content_types, %content_types);
+undef %system_content_types;
+
+#if ($pid = fork()) { exit; }
+$0 = "dhttpi: binding port ...";
+$bindthis = pack($sockaddr, 2, $server_port, pack('C4', 0, 0, 0, 0));
+socket(S, 2, 1, 6);
+setsockopt(S, 1, 2, 1);
+bind(S, $bindthis) || die("$0: while binding port $server_port:\n\"$!\"\n");
+listen(S, 128);
+$0 = "dhttpi: connected and waiting ANY:$server_port";
+
+$statiosuptime = time();
+
+sub sock_to_host {
+       return ($cache_hn, $cache_port, $cache_ip)
+               if (length($cache_ip));
+
+       return (undef, undef, undef) if (!$sock);
+       my($AFC, $cache_port, $thataddr, $zero) = unpack($sockaddr, $sock);
+       $cache_ip = join('.', unpack("C4", $thataddr));
+       $cache_hn =
+               gethostbyaddr($thataddr, 2) ||
+               $cache_ip;
+       return ($cache_hn, $cache_port, $cache_ip);
+}
+
+
+sub htsponse {
+       ($currentcode, $currentstring) = (@_);
+       return if (0+$httpver < 1);
+       my($what) = <<"EOF";
+HTTP/$httpver $currentcode $currentstring
+${headers}Date: $rfcdate
+EOF
+       $what =~ s/\n/\r\n/g;
+       print STDOUT $what;
+       &hthead("Connection: close") if (0+$httpver > 1);
+}
+
+sub hthead {
+       my($header, $term) = (@_);
+       return if (0+$httpver < 1);
+       print STDOUT "$header\r\n" , ($term) ? "\r\n" : "";
+}
+
+sub htcontent {
+       my($what, $ctype, $mode) = (@_);
+       ($contentlength) = $mode || length($what);
+       &hthead("Content-Length: $contentlength");
+       &hthead("Content-Type: $ctype", 1);
+       return if ($method eq 'HEAD' || $mode);
+       print STDOUT $what;
+}
+
+sub log {
+       if ($logfile && open(J, ">>$logfile")) {
+               my $q = $address . (($variables) ? "?$variables" : "");
+               $contentlength += 0;
+               $contentlength = 0 if ($method eq 'HEAD');
+               my ($hostname, $port, $ip) = &sock_to_host();
+               $hostname ||= "-";
+               $httpuser ||= "-";
+               print J <<"EOF";
+$hostname - $httpuser [$date] "$method $q HTTP/$httpver" $currentcode $contentlength "$httpref" "$httpua"
+EOF
+               close(J);
+       }
+}
+
+
+sub bye { exit; }
+sub byebye { kill(9,$secondary_pid) if ($secondary_pid); exit; }
+
+sub dead {
+       &htsponse(500, "Server Error");
+       &hterror("Server Error", <<"EOF");
+The server cannot comply with your request for resource <tt>$::address</tt>.
+Please attempt to notify the administrators.
+<p>Useful(?) debugging information:
+<pre>
+@_
+</pre>
+EOF
+       &log; exit;
+}
+
+sub defaultsignals {
+       $SIG{'__DIE__'} = \&dead;
+       sigaction SIGALRM, new POSIX::SigAction \&bye
+               or die "sigalrm failed: $!\n";
+       sigaction SIGTERM, new POSIX::SigAction \&byebye
+               or die "sigterm failed: $!\n";
+}
+&defaultsignals;
+
+sub alarmsignals {
+       undef $SIG{'__DIE__'};
+       sigaction SIGALRM, new POSIX::SigAction sub { die; }
+               or die "sigalrm failed: $!\n";
+}
+
+sub master {
+       $0 = "dhttpi: handling request";
+$sock = getpeername(STDIN);
+$rfcdate = &rfctime(scalar gmtime, 1);
+$date = scalar localtime;
+($dow, $mon, $dt, $tm, $yr) = ($date =~
+       m/(...) (...) (..) (..:..:..) (....)/);
+$dt += 0;
+$dt = substr("0$dt", length("0$dt") - 2, 2);
+$date = "$dt/$mon/$yr:$tm +0000"; 
+
+select(STDOUT); $|=1; $address = 0; 
+alarm 5;
+while (<STDIN>) {
+       if(/^([A-Z]+)\s+([^\s]+)\s+([^\s\r\l\n]*)/) {
+               $method = $1;
+               $address = $2; 
+               $httpver = $3;
+               $httpref = '';
+               $httpua = '';
+               $httpver = ($httpver =~ m#HTTP/([0-9]\.[0-9]+)#) ?
+                       ($1) : (0.9);
+               $address =~ s#^http://[^/]+/#/#;
+               $0 = $execstring = "dhttpi: $method $address $httpver";
+               next unless ($httpver < 1);
+       } else {
+               s/[\r\l\n\s]+$//;
+               (/^Host:\s+(.+)/i) && ($httphost = substr($1, 0, 255))
+                       && ($httphost =~ s/:\d+$//);
+               (/^Referer:\s+(.+)/i) && ($httpref = substr($1, 0, 1024));
+               (/^User-agent:\s+(.+)/i) && ($httpua = substr($1, 0, 1024));
+               (/^Content-length:\s+(\d+)/i) &&
+                       ($ENV{'CONTENT_LENGTH'} = $httpcl = 0+$1);
+               (/^Content-type:\s+(.+)/i) &&
+                       ($ENV{'CONTENT_TYPE'} = $httpct = substr($1, 0, 255));
+               (/^Expect:\s+/) && ($expect = 1);
+               (/^Cookie:\s+(.+)/i) &&
+                       ($ENV{'HTTP_COOKIE'} = substr($1, 0, 16384));
+               (/^Authorization:\s+Basic (.+)/i) &&
+                       ($httprawu = substr($1, 0, 1024));
+               (/^Range:\s+(.+)/i) &&
+                       ($ENV{'CONTENT_RANGE'} = substr($1, 0, 255));
+               (/^If-Modified-Since:\s+(.+)/i) &&
+                       ($modsince = $ENV{'HTTP_IF_MODIFIED_SINCE'} =
+                               substr($1, 0, 255));
+               (/^Accept:\s+(.+)/i) &&
+                       ($ENV{'HTTP_ACCEPT'} = substr($1, 0, 255));
+               (/^Accept-([a-zA-Z0-9]+):\s+(.+)/i) &&
+                       ($ENV{'HTTP_ACCEPT_'.uc(substr($1, 0, 16))} =
+                               substr($2, 0, 255));
+               (/^X-Requested-With:\s+(.+)/i) &&
+                       ($ENV{'HTTP_X_REQUESTED_WITH'} = substr($1, 0, 1024));
+
+               (/^Origin:\s+(.+)/i) &&
+                       ($ENV{'HTTP_ORIGIN'} = substr($1, 0, 1024));
+               (/^Upgrade:\s+(.+)/i) &&
+                       ($ENV{'HTTP_UPGRADE'} = substr($1, 0, 1024));
+               (/^Sec-WebSocket-Protocol:\s+(.+)/i) &&
+                       ($ENV{'WEBSOCKET_PROTOCOL'} = substr($1, 0, 1024));
+               (/^Sec-WebSocket-Version:\s+(-?\d+)/i) &&
+                       ($ENV{'WEBSOCKET_VERSION'} = substr($1, 0, 8));
+               (/^Sec-WebSocket-Extensions:\s+(-?\d+)/i) &&
+                       ($ENV{'WEBSOCKET_EXTENSIONS'} = substr($1, 0, 1024));
+               (/^Sec-WebSocket-Key:\s+(\S+)/i) &&
+                       ($ENV{'WEBSOCKET_KEY'} = substr($1, 0, 1024));
+               
+               next unless (/^$/);
+       }
+       if ($expect) {
+               &htsponse(417, "Expectation Failed");
+               &hterror("Expectation Failed",
+                       "The server does not support this method.");
+               &log; exit;
+       }
+       if (!length($address) || (0+$httpver > 1 && !$httphost)) {
+               &htsponse(400, "Bad Request");
+               &hterror("Bad Request",
+                       "The server cannot understand your request.");
+               &log; exit;
+       }
+       if ($method !~ /^(GET|HEAD|POST)$/) {
+               &htsponse(501, "Not Implemented");
+               &hterror("Not Implemented",
+                       "Only GET, HEAD and POST are supported.");
+               &log; exit;
+       }
+       
+       
+       if ($ENV{'HTTP_UPGRADE'} eq 'websocket') {
+           if ($method ne "GET" || !$ENV{'WEBSOCKET_KEY'}) {
+               &htsponse(400, "Bad request");
+               &hterror("Bad request",
+                       "Illegal websocket opening handshake");
+               &log; exit;
+           }
+           
+           $ENV{'WEBSOCKET_ACCEPT'} = 
+               sha1_base64($ENV{'WEBSOCKET_KEY'} . "258EAFA5-E914-47DA-95CA-C5AB0DC85B11") . "=";
+               
+           
+       }
+       
+       
+       
+       ($address, $variables) = split(/\?/, $address);
+       $address =~ s/%([0-9a-fA-F]{2})/pack("H2", $1)/eg;
+       $address=~ s#^/?#/#;
+       1 while $address =~ s#/\.(/|$)#\1#;
+        1 while $address =~ s#/[^/]*/\.\.(/|$)#\1#;
+       1 while $address =~ s#^/\.\.(/|$)#\1#;
+       $fail = 0;
+       J: foreach(sort { length $a <=> length $b }
+                       keys %restrictions) {
+               next if ($address !~ /^$_/);
+               ($allowip, $denyip, $allowua, $denyua, $auser) =
+                       split(/#/, $restrictions{$_});
+               if ($allowip || $denyip) {
+                       ($hostname, $port, $ip) = &sock_to_host();
+                       ($allowip && $ip !~ /$allowip/) && ($fail = 1,
+                               last J);
+                       ($denyip && $ip =~ /$denyip/) && ($fail = 1,
+                               last J);
+               }
+               ($allowua && $httpua !~ /$allowua/) &&
+                       ($fail = 2, last J);
+               ($denyua && $httpua =~ /$denyua/) &&
+                       ($fail = 2, last J);
+       }
+       if ($fail) {
+               &htsponse(403, "Forbidden");
+               if ($fail == 1) {
+                       &hterror("Forbidden (Client Disallowed)", <<"EOF");
+Your network address (<i>$ip</i>) is not allowed to access this resource.
+EOF
+                       &log; exit;
+               } else {
+                       &hterror("Forbidden (Browser Disallowed)", <<"EOF");
+The browser you are using (<i>$httpua</i>) is not capable of or
+is not allowed access to this resource.
+EOF
+                       &log; exit;
+               }
+       }
+       if ($auser) {
+               $httprawu =~ tr#A-Za-z0-9+/##cd;
+               $httprawu =~ tr#A-Za-z0-9+/# -_#;
+               $httprawu = unpack("u", pack("c", 32+0.75*length($httprawu))
+                       . $httprawu);
+               ($httpuser, $httppw) = split(/:/, $httprawu);
+               $fail = 1;
+               foreach $user (split(/,/, $auser)) {
+                       ($user, $pw) = split(/:/, $user);
+                       ($fail = 0, last) if ($user eq $httpuser &&
+                               crypt($httppw, substr($pw, 0, 2)) eq $pw);
+               }
+               if ($fail) {
+                       $httpuser = '';
+                       &htsponse(401, "Authorization Required");
+                       &hthead("WWW-Authenticate: Basic realm=\"$address\"");
+                       &hterror("Authorization Required", <<"EOF");
+You must provide a username and password to use this resource. Either you
+entered this information incorrectly, or your browser does not know how to
+present the credentials required.
+EOF
+                       &log; exit;
+               }
+       }
+
+       alarm 0;
+
+
+
+
+       $raddress = "$path$address"
+       ;
+       1 while ($raddress =~ s#//#/#);
+       &hterror301("http://$server_host:$server_port$address/")
+               if ($address !~ m#/$# && -d $raddress);
+       $raddress = (-r "${raddress}index.shtml") ?
+               "${raddress}index.shtml" : "${raddress}index.html"
+                       if (-d $raddress);
+       IRED: ($hostname, $port, $ip) = &sock_to_host();
+       if(!sysopen(S, $raddress, 0)) { &hterror404; } else {
+               if ((-x $raddress) 
+                       ) {
+                       $currentcode = 100; &nsecmodel;
+                       $ENV{'REQUEST_METHOD'} = $method;
+                       $ENV{'SERVER_NAME'} = $server_host;
+                       $ENV{'SERVER_PROTOCOL'} = "HTTP/$httpver";
+                       $ENV{'SERVER_SOFTWARE'} = "HTTPi/$VERSION";
+                       $ENV{'SERVER_PORT'} = "$server_port";
+                       $ENV{'SERVER_URL'} = "http://$server_host:$server_port/";
+                       $ENV{'SCRIPT_FILENAME'} = $raddress;
+                       $ENV{'SCRIPT_NAME'} = $address;
+                       $ENV{'REMOTE_HOST'} = $hostname;
+                       $ENV{'REMOTE_ADDR'} = $ip;
+                       $ENV{'REMOTE_PORT'} = $port;
+                       $ENV{'QUERY_STRING'} = $variables;
+                       $ENV{'HTTP_USER_AGENT'} = $httpua;
+                       $ENV{'HTTP_REFERER'} = $httpref;
+                       undef $pid;
+                       if ($pid = fork()) { kill 15, $$; exit; }
+                       elsif (!defined($pid)) {
+                               die
+                       "temporary(?) fork error, please retry request: $!\n";
+                       } else {
+                                my $scriptdir = dirname($raddress);
+                                chdir($scriptdir);
+                                push(@INC,$scriptdir);
+                                my $scriptname = basename($raddress);
+                               require $scriptname;
+                               exit;
+                       }
+               }
+               ($x,$x,$x,$x,$x,$x,$x,$length,$x,$mtime) = stat(S);
+               $ctype = 0;
+               foreach(keys %content_types) {
+                       if ($raddress =~ /\.$_$/i) {
+                               $ctype = $content_types{$_};
+                       }
+               }
+               $mtime = &rfctime($mtime);
+SERVEIT:       
+               if ($mtime eq $modsince) {
+                       &htsponse(304, "Not Modified");
+                       &hthead("Last-Modified: $mtime", 1);
+                       &log; exit;
+               }
+               $ctype ||= 'text/plain';
+               if ($pid = fork()) { kill 15, $$; exit; }
+               $contentlength ||= $length;
+                       &htsponse(200, "OK");
+                       &hthead("Last-Modified: $mtime");
+                       &htcontent("", $ctype, $length);
+                       &nsecmodel;
+                       $bytecount = 0;
+                       unless ($method eq 'HEAD') {
+                               while(!eof(S)) {
+                                       read(S, $q, 32768);
+                                       print STDOUT $q;
+                                       $bytecount += 32768;
+                                       $0 = $execstring .
+                                               " ($bytecount bytes sent)";
+                               }
+                       }
+               alarm 0;
+       }
+       exit;
+}
+
+exit;
+}
+
+
+sub nsecmodel {
+       &log;
+       ($x,$x,$x,$x,$uid,$gid) = stat(S);
+       (!$uid || !$gid || $uid < 2 ) &&
+               die "resource is root-owned, secured or not stat-able\n";
+       if (!$<) {
+               ($) = "$gid $gid") || die "can't set egid to $gid";
+               ($> = $uid) || die "can't set euid to $uid";
+               ($( = "$gid $gid") || die "can't set rgid to $gid";
+               ($< = $uid) || die "can't set ruid to $uid";
+       }
+}
+
+sub rfctime {
+       my $mtime = shift;
+       $mtime = (scalar gmtime $mtime) if (!(shift));
+       my ($dow, $mon, $dt, $tm, $yr) =
+               ($mtime =~ m/(...) (...) (..) (..:..:..) (....)/);
+       $dt += 0; $yr += 0;
+       return "$dow, $dt $mon $yr $tm GMT";
+}
+
+sub hterror {
+       my($errstr, @expl) = (@_);
+       &htcontent(<<"EOF", "text/html");
+<html>
+<body>
+<h1>$errstr</h1>
+@expl
+<hr>
+<address><a href = "http://httpi.floodgap.com/">httpi/$VERSION</a>
+by Cameron Kaiser</address>
+</body>
+</html>
+EOF
+       }
+
+sub hterror404 {
+       &htsponse(404, "Not Found");
+       &hterror("Not Found",
+               "The resource <tt>$address</tt> was not found on this system.");
+       &log; exit;
+}
+
+sub hterror301 {
+       &htsponse(301, "Moved Permanently");
+       &hthead("Location: @_");
+       &hterror("Resource Moved Permanently",
+               "This resource has moved <a href = \"@_\">here</a>.");
+       &log; exit;
+}
+
+
+$0 = "dhttpi: on ANY:$server_port, ready!";
+$master_pid = $$;
+for (;;) {
+       if ($secondary_pid = fork()) {
+               waitpid($secondary_pid, 0);
+               $0 = "dhttpi: on ANY:$server_port, last request " .
+                       scalar localtime;
+       } else {
+               $0 = "dhttpi (child of $master_pid): waiting for connect";
+               $addr=accept(NS,S);
+               open(STDIN, "<&NS");
+               open(STDOUT, ">&NS");
+               &defaultsignals;
+               &master;
+               exit;
+       }
+}
diff --git a/HldRec/js/HldRec.js b/HldRec/js/HldRec.js
new file mode 100644 (file)
index 0000000..185081d
--- /dev/null
@@ -0,0 +1,170 @@
+
+var timer;
+
+var backendUrl='HldRec.pl';
+var shm_path = './shm/HldRec/';
+
+
+$(document).ready(function(){
+
+  armUnfoldButtons();
+  
+  timer = $.timer(function() {
+    update_displays();
+    $("#field2").html(Math.floor((new Date).getTime()/1000));
+  });
+  
+  
+  armSettingsForms();
+  
+  armAllAnything('input');
+  
+  $('#text_dump_path').attr('value',settings.dump_dir);
+  $('#text_shm_id').attr('value',settings.shm_id);
+  $('#text_ports').attr('value',settings.ports);
+  $('#text_acq_time').attr('value',settings.acquisition_time);
+  
+  update_log_links();
+  
+  set_clear_timer();
+  
+  
+});
+
+
+function set_clear_timer(){
+     timer.set({time:1000,autostart: true});
+}
+
+function stop_timer(){
+     timer.stop();
+}
+
+
+// function btn_evtb_log_click(){
+//   var win = window.open(shm_path+"daq_evtbuild"+$('#text_shm_id').val()+".log", '_blank');
+//   if(win){
+//       //Browser has allowed it to be opened
+//       win.focus();
+//   }else{
+//       //Broswer has blocked it
+//       alert('Please allow popups for this site');
+//   }
+// }
+// function btn_netm_log_click(){
+//   var win = window.open(shm_path+"daq_netmem"+$('#text_shm_id').val()+".log", '_blank');
+//   if(win){
+//       //Browser has allowed it to be opened
+//       win.focus();
+//   }else{
+//       //Broswer has blocked it
+//       alert('Please allow popups for this site');
+//   }
+// }
+
+function text_shm_id_change() {
+  update_log_links();
+}
+
+function update_log_links(){
+  $('#a_evtb_log').attr("href",shm_path+"daq_evtbuild"+$('#text_shm_id').val()+".log");
+  $('#a_netm_log').attr("href",shm_path+"daq_netmem"+$('#text_shm_id').val()+".log");
+}
+  
+function btn_record_click(){
+  backendCall(
+    {
+      'sub'    : 'record',
+      'time'   : $('#text_acq_time').val(),
+      'ports'  : $('#text_ports').val(),
+      'path'   : $('#text_dump_path').val(), 
+      'shm_id' : $('#text_shm_id').val(), 
+    },{
+      success : debugOut
+    }
+  );
+}
+function btn_stop_click(){
+  backendCall(
+    {
+      'sub':'stop',
+      'shm_id':$('#text_shm_id').val(),
+    },{
+      success : debugOut
+    }
+  );
+}
+function btn_test_click(){
+  var demo_json = { 'baum':5, 'schaf':6 };
+  update_log_links();
+  backendCall(
+    {
+      'sub' :'dump_json',
+      'data': JSON.stringify(demo_json)
+    },{
+      success : myAlert
+    }
+  );
+}
+
+
+
+
+function myAlert(text) {
+  alert(text);
+}
+
+function debugOut(text){
+  $('#debug_output').append(text);
+}
+function btn_clear_debug_click(){
+  $('#debug_output').html("");
+}  
+
+function backendCall(args,options){
+  var ajaxObj = 
+    {
+        url:       backendUrl,
+        cache:     false,
+        async:     true,
+        dataType:  "text",
+        data:      args,
+     };
+  $.ajax($.extend(ajaxObj,options));
+}
+
+function update_displays(){
+  
+  if ( typeof update_displays.dotpos == 'undefined' ) {
+    update_displays.dotpos = 0;
+  }
+  
+  var status_file = shm_path+"HldRec"+$('#text_shm_id').val()+".state.json";
+  
+  $.ajax({
+        url:       status_file,
+        cache:     false,
+        async:     true,
+        dataType:  "json",
+        success:   function(answer) {
+          var data = answer.data;
+          update_displays.timestamp = answer.timestamp;
+          for (selector in data){
+            $(selector).html(data[selector]);
+          }
+        }
+     });
+  update_displays.dotpos = (update_displays.dotpos+1)%4;
+  var backend_status;
+  if ( epoch() - update_displays.timestamp < settings.backend_timeout ) {
+    backend_status = "running";
+  } else {
+    backend_status = "not running";
+  }
+  for( var i=0; i < update_displays.dotpos; i++) {
+    backend_status = backend_status+".";
+  }
+  $('#backend_status').html(backend_status);
+  
+}
+
diff --git a/HldRec/js/cookies.js b/HldRec/js/cookies.js
new file mode 100644 (file)
index 0000000..cf7c617
--- /dev/null
@@ -0,0 +1,28 @@
+
+function createCookie(name, value, days) {
+    var expires;
+
+    if (days) {
+        var date = new Date();
+        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
+        expires = "; expires=" + date.toGMTString();
+    } else {
+        expires = "";
+    }
+    document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + expires + "; path=/";
+}
+
+function readCookie(name) {
+    var nameEQ = encodeURIComponent(name) + "=";
+    var ca = document.cookie.split(';');
+    for (var i = 0; i < ca.length; i++) {
+        var c = ca[i];
+        while (c.charAt(0) === ' ') c = c.substring(1, c.length);
+        if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length, c.length));
+    }
+    return null;
+}
+
+function eraseCookie(name) {
+    createCookie(name, "", -1);
+}
\ No newline at end of file
diff --git a/HldRec/js/has_settings.js b/HldRec/js/has_settings.js
new file mode 100644 (file)
index 0000000..9eab349
--- /dev/null
@@ -0,0 +1,32 @@
+
+function armSettingsForms() {
+  $(".has_settings_form").submit(function( event ){
+      var url = $(this).attr("action");
+      event.preventDefault();
+      $.ajax({
+          url: url,
+          type: 'post',
+          dataType: 'text',
+          data: $(this).serialize(),
+          success: function(data) {
+            alert(data);
+          }
+      });
+  });
+  
+  $(".has_settings_form").each(function(){
+    var url = $(this).attr("action");
+    $(this).find('input[value="reset"]').click(function(){
+      $.ajax({
+          url: url,
+          dataType: 'text',
+          data: {
+            sub : "reset_settings"
+          },
+          success: function(data) {
+            alert(data);
+          }
+      });
+    });
+  });
+};
\ No newline at end of file
diff --git a/HldRec/js/jquery-ui.js b/HldRec/js/jquery-ui.js
new file mode 100644 (file)
index 0000000..ce8731b
--- /dev/null
@@ -0,0 +1,16582 @@
+/*! jQuery UI - v1.11.2 - 2014-10-16
+* http://jqueryui.com
+* Includes: core.js, widget.js, mouse.js, position.js, accordion.js, autocomplete.js, button.js, datepicker.js, dialog.js, draggable.js, droppable.js, effect.js, effect-blind.js, effect-bounce.js, effect-clip.js, effect-drop.js, effect-explode.js, effect-fade.js, effect-fold.js, effect-highlight.js, effect-puff.js, effect-pulsate.js, effect-scale.js, effect-shake.js, effect-size.js, effect-slide.js, effect-transfer.js, menu.js, progressbar.js, resizable.js, selectable.js, selectmenu.js, slider.js, sortable.js, spinner.js, tabs.js, tooltip.js
+* Copyright 2014 jQuery Foundation and other contributors; Licensed MIT */
+
+(function( factory ) {
+       if ( typeof define === "function" && define.amd ) {
+
+               // AMD. Register as an anonymous module.
+               define([ "jquery" ], factory );
+       } else {
+
+               // Browser globals
+               factory( jQuery );
+       }
+}(function( $ ) {
+/*!
+ * jQuery UI Core 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/ui-core/
+ */
+
+
+// $.ui might exist from components with no dependencies, e.g., $.ui.position
+$.ui = $.ui || {};
+
+$.extend( $.ui, {
+       version: "1.11.2",
+
+       keyCode: {
+               BACKSPACE: 8,
+               COMMA: 188,
+               DELETE: 46,
+               DOWN: 40,
+               END: 35,
+               ENTER: 13,
+               ESCAPE: 27,
+               HOME: 36,
+               LEFT: 37,
+               PAGE_DOWN: 34,
+               PAGE_UP: 33,
+               PERIOD: 190,
+               RIGHT: 39,
+               SPACE: 32,
+               TAB: 9,
+               UP: 38
+       }
+});
+
+// plugins
+$.fn.extend({
+       scrollParent: function( includeHidden ) {
+               var position = this.css( "position" ),
+                       excludeStaticParent = position === "absolute",
+                       overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
+                       scrollParent = this.parents().filter( function() {
+                               var parent = $( this );
+                               if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
+                                       return false;
+                               }
+                               return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
+                       }).eq( 0 );
+
+               return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
+       },
+
+       uniqueId: (function() {
+               var uuid = 0;
+
+               return function() {
+                       return this.each(function() {
+                               if ( !this.id ) {
+                                       this.id = "ui-id-" + ( ++uuid );
+                               }
+                       });
+               };
+       })(),
+
+       removeUniqueId: function() {
+               return this.each(function() {
+                       if ( /^ui-id-\d+$/.test( this.id ) ) {
+                               $( this ).removeAttr( "id" );
+                       }
+               });
+       }
+});
+
+// selectors
+function focusable( element, isTabIndexNotNaN ) {
+       var map, mapName, img,
+               nodeName = element.nodeName.toLowerCase();
+       if ( "area" === nodeName ) {
+               map = element.parentNode;
+               mapName = map.name;
+               if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
+                       return false;
+               }
+               img = $( "img[usemap='#" + mapName + "']" )[ 0 ];
+               return !!img && visible( img );
+       }
+       return ( /input|select|textarea|button|object/.test( nodeName ) ?
+               !element.disabled :
+               "a" === nodeName ?
+                       element.href || isTabIndexNotNaN :
+                       isTabIndexNotNaN) &&
+               // the element and all of its ancestors must be visible
+               visible( element );
+}
+
+function visible( element ) {
+       return $.expr.filters.visible( element ) &&
+               !$( element ).parents().addBack().filter(function() {
+                       return $.css( this, "visibility" ) === "hidden";
+               }).length;
+}
+
+$.extend( $.expr[ ":" ], {
+       data: $.expr.createPseudo ?
+               $.expr.createPseudo(function( dataName ) {
+                       return function( elem ) {
+                               return !!$.data( elem, dataName );
+                       };
+               }) :
+               // support: jQuery <1.8
+               function( elem, i, match ) {
+                       return !!$.data( elem, match[ 3 ] );
+               },
+
+       focusable: function( element ) {
+               return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
+       },
+
+       tabbable: function( element ) {
+               var tabIndex = $.attr( element, "tabindex" ),
+                       isTabIndexNaN = isNaN( tabIndex );
+               return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
+       }
+});
+
+// support: jQuery <1.8
+if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
+       $.each( [ "Width", "Height" ], function( i, name ) {
+               var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
+                       type = name.toLowerCase(),
+                       orig = {
+                               innerWidth: $.fn.innerWidth,
+                               innerHeight: $.fn.innerHeight,
+                               outerWidth: $.fn.outerWidth,
+                               outerHeight: $.fn.outerHeight
+                       };
+
+               function reduce( elem, size, border, margin ) {
+                       $.each( side, function() {
+                               size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
+                               if ( border ) {
+                                       size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
+                               }
+                               if ( margin ) {
+                                       size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
+                               }
+                       });
+                       return size;
+               }
+
+               $.fn[ "inner" + name ] = function( size ) {
+                       if ( size === undefined ) {
+                               return orig[ "inner" + name ].call( this );
+                       }
+
+                       return this.each(function() {
+                               $( this ).css( type, reduce( this, size ) + "px" );
+                       });
+               };
+
+               $.fn[ "outer" + name] = function( size, margin ) {
+                       if ( typeof size !== "number" ) {
+                               return orig[ "outer" + name ].call( this, size );
+                       }
+
+                       return this.each(function() {
+                               $( this).css( type, reduce( this, size, true, margin ) + "px" );
+                       });
+               };
+       });
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+       $.fn.addBack = function( selector ) {
+               return this.add( selector == null ?
+                       this.prevObject : this.prevObject.filter( selector )
+               );
+       };
+}
+
+// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
+if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
+       $.fn.removeData = (function( removeData ) {
+               return function( key ) {
+                       if ( arguments.length ) {
+                               return removeData.call( this, $.camelCase( key ) );
+                       } else {
+                               return removeData.call( this );
+                       }
+               };
+       })( $.fn.removeData );
+}
+
+// deprecated
+$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
+
+$.fn.extend({
+       focus: (function( orig ) {
+               return function( delay, fn ) {
+                       return typeof delay === "number" ?
+                               this.each(function() {
+                                       var elem = this;
+                                       setTimeout(function() {
+                                               $( elem ).focus();
+                                               if ( fn ) {
+                                                       fn.call( elem );
+                                               }
+                                       }, delay );
+                               }) :
+                               orig.apply( this, arguments );
+               };
+       })( $.fn.focus ),
+
+       disableSelection: (function() {
+               var eventType = "onselectstart" in document.createElement( "div" ) ?
+                       "selectstart" :
+                       "mousedown";
+
+               return function() {
+                       return this.bind( eventType + ".ui-disableSelection", function( event ) {
+                               event.preventDefault();
+                       });
+               };
+       })(),
+
+       enableSelection: function() {
+               return this.unbind( ".ui-disableSelection" );
+       },
+
+       zIndex: function( zIndex ) {
+               if ( zIndex !== undefined ) {
+                       return this.css( "zIndex", zIndex );
+               }
+
+               if ( this.length ) {
+                       var elem = $( this[ 0 ] ), position, value;
+                       while ( elem.length && elem[ 0 ] !== document ) {
+                               // Ignore z-index if position is set to a value where z-index is ignored by the browser
+                               // This makes behavior of this function consistent across browsers
+                               // WebKit always returns auto if the element is positioned
+                               position = elem.css( "position" );
+                               if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+                                       // IE returns 0 when zIndex is not specified
+                                       // other browsers return a string
+                                       // we ignore the case of nested elements with an explicit value of 0
+                                       // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+                                       value = parseInt( elem.css( "zIndex" ), 10 );
+                                       if ( !isNaN( value ) && value !== 0 ) {
+                                               return value;
+                                       }
+                               }
+                               elem = elem.parent();
+                       }
+               }
+
+               return 0;
+       }
+});
+
+// $.ui.plugin is deprecated. Use $.widget() extensions instead.
+$.ui.plugin = {
+       add: function( module, option, set ) {
+               var i,
+                       proto = $.ui[ module ].prototype;
+               for ( i in set ) {
+                       proto.plugins[ i ] = proto.plugins[ i ] || [];
+                       proto.plugins[ i ].push( [ option, set[ i ] ] );
+               }
+       },
+       call: function( instance, name, args, allowDisconnected ) {
+               var i,
+                       set = instance.plugins[ name ];
+
+               if ( !set ) {
+                       return;
+               }
+
+               if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
+                       return;
+               }
+
+               for ( i = 0; i < set.length; i++ ) {
+                       if ( instance.options[ set[ i ][ 0 ] ] ) {
+                               set[ i ][ 1 ].apply( instance.element, args );
+                       }
+               }
+       }
+};
+
+
+/*!
+ * jQuery UI Widget 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/jQuery.widget/
+ */
+
+
+var widget_uuid = 0,
+       widget_slice = Array.prototype.slice;
+
+$.cleanData = (function( orig ) {
+       return function( elems ) {
+               var events, elem, i;
+               for ( i = 0; (elem = elems[i]) != null; i++ ) {
+                       try {
+
+                               // Only trigger remove when necessary to save time
+                               events = $._data( elem, "events" );
+                               if ( events && events.remove ) {
+                                       $( elem ).triggerHandler( "remove" );
+                               }
+
+                       // http://bugs.jquery.com/ticket/8235
+                       } catch ( e ) {}
+               }
+               orig( elems );
+       };
+})( $.cleanData );
+
+$.widget = function( name, base, prototype ) {
+       var fullName, existingConstructor, constructor, basePrototype,
+               // proxiedPrototype allows the provided prototype to remain unmodified
+               // so that it can be used as a mixin for multiple widgets (#8876)
+               proxiedPrototype = {},
+               namespace = name.split( "." )[ 0 ];
+
+       name = name.split( "." )[ 1 ];
+       fullName = namespace + "-" + name;
+
+       if ( !prototype ) {
+               prototype = base;
+               base = $.Widget;
+       }
+
+       // create selector for plugin
+       $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
+               return !!$.data( elem, fullName );
+       };
+
+       $[ namespace ] = $[ namespace ] || {};
+       existingConstructor = $[ namespace ][ name ];
+       constructor = $[ namespace ][ name ] = function( options, element ) {
+               // allow instantiation without "new" keyword
+               if ( !this._createWidget ) {
+                       return new constructor( options, element );
+               }
+
+               // allow instantiation without initializing for simple inheritance
+               // must use "new" keyword (the code above always passes args)
+               if ( arguments.length ) {
+                       this._createWidget( options, element );
+               }
+       };
+       // extend with the existing constructor to carry over any static properties
+       $.extend( constructor, existingConstructor, {
+               version: prototype.version,
+               // copy the object used to create the prototype in case we need to
+               // redefine the widget later
+               _proto: $.extend( {}, prototype ),
+               // track widgets that inherit from this widget in case this widget is
+               // redefined after a widget inherits from it
+               _childConstructors: []
+       });
+
+       basePrototype = new base();
+       // we need to make the options hash a property directly on the new instance
+       // otherwise we'll modify the options hash on the prototype that we're
+       // inheriting from
+       basePrototype.options = $.widget.extend( {}, basePrototype.options );
+       $.each( prototype, function( prop, value ) {
+               if ( !$.isFunction( value ) ) {
+                       proxiedPrototype[ prop ] = value;
+                       return;
+               }
+               proxiedPrototype[ prop ] = (function() {
+                       var _super = function() {
+                                       return base.prototype[ prop ].apply( this, arguments );
+                               },
+                               _superApply = function( args ) {
+                                       return base.prototype[ prop ].apply( this, args );
+                               };
+                       return function() {
+                               var __super = this._super,
+                                       __superApply = this._superApply,
+                                       returnValue;
+
+                               this._super = _super;
+                               this._superApply = _superApply;
+
+                               returnValue = value.apply( this, arguments );
+
+                               this._super = __super;
+                               this._superApply = __superApply;
+
+                               return returnValue;
+                       };
+               })();
+       });
+       constructor.prototype = $.widget.extend( basePrototype, {
+               // TODO: remove support for widgetEventPrefix
+               // always use the name + a colon as the prefix, e.g., draggable:start
+               // don't prefix for widgets that aren't DOM-based
+               widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
+       }, proxiedPrototype, {
+               constructor: constructor,
+               namespace: namespace,
+               widgetName: name,
+               widgetFullName: fullName
+       });
+
+       // If this widget is being redefined then we need to find all widgets that
+       // are inheriting from it and redefine all of them so that they inherit from
+       // the new version of this widget. We're essentially trying to replace one
+       // level in the prototype chain.
+       if ( existingConstructor ) {
+               $.each( existingConstructor._childConstructors, function( i, child ) {
+                       var childPrototype = child.prototype;
+
+                       // redefine the child widget using the same prototype that was
+                       // originally used, but inherit from the new version of the base
+                       $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
+               });
+               // remove the list of existing child constructors from the old constructor
+               // so the old child constructors can be garbage collected
+               delete existingConstructor._childConstructors;
+       } else {
+               base._childConstructors.push( constructor );
+       }
+
+       $.widget.bridge( name, constructor );
+
+       return constructor;
+};
+
+$.widget.extend = function( target ) {
+       var input = widget_slice.call( arguments, 1 ),
+               inputIndex = 0,
+               inputLength = input.length,
+               key,
+               value;
+       for ( ; inputIndex < inputLength; inputIndex++ ) {
+               for ( key in input[ inputIndex ] ) {
+                       value = input[ inputIndex ][ key ];
+                       if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
+                               // Clone objects
+                               if ( $.isPlainObject( value ) ) {
+                                       target[ key ] = $.isPlainObject( target[ key ] ) ?
+                                               $.widget.extend( {}, target[ key ], value ) :
+                                               // Don't extend strings, arrays, etc. with objects
+                                               $.widget.extend( {}, value );
+                               // Copy everything else by reference
+                               } else {
+                                       target[ key ] = value;
+                               }
+                       }
+               }
+       }
+       return target;
+};
+
+$.widget.bridge = function( name, object ) {
+       var fullName = object.prototype.widgetFullName || name;
+       $.fn[ name ] = function( options ) {
+               var isMethodCall = typeof options === "string",
+                       args = widget_slice.call( arguments, 1 ),
+                       returnValue = this;
+
+               // allow multiple hashes to be passed on init
+               options = !isMethodCall && args.length ?
+                       $.widget.extend.apply( null, [ options ].concat(args) ) :
+                       options;
+
+               if ( isMethodCall ) {
+                       this.each(function() {
+                               var methodValue,
+                                       instance = $.data( this, fullName );
+                               if ( options === "instance" ) {
+                                       returnValue = instance;
+                                       return false;
+                               }
+                               if ( !instance ) {
+                                       return $.error( "cannot call methods on " + name + " prior to initialization; " +
+                                               "attempted to call method '" + options + "'" );
+                               }
+                               if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
+                                       return $.error( "no such method '" + options + "' for " + name + " widget instance" );
+                               }
+                               methodValue = instance[ options ].apply( instance, args );
+                               if ( methodValue !== instance && methodValue !== undefined ) {
+                                       returnValue = methodValue && methodValue.jquery ?
+                                               returnValue.pushStack( methodValue.get() ) :
+                                               methodValue;
+                                       return false;
+                               }
+                       });
+               } else {
+                       this.each(function() {
+                               var instance = $.data( this, fullName );
+                               if ( instance ) {
+                                       instance.option( options || {} );
+                                       if ( instance._init ) {
+                                               instance._init();
+                                       }
+                               } else {
+                                       $.data( this, fullName, new object( options, this ) );
+                               }
+                       });
+               }
+
+               return returnValue;
+       };
+};
+
+$.Widget = function( /* options, element */ ) {};
+$.Widget._childConstructors = [];
+
+$.Widget.prototype = {
+       widgetName: "widget",
+       widgetEventPrefix: "",
+       defaultElement: "<div>",
+       options: {
+               disabled: false,
+
+               // callbacks
+               create: null
+       },
+       _createWidget: function( options, element ) {
+               element = $( element || this.defaultElement || this )[ 0 ];
+               this.element = $( element );
+               this.uuid = widget_uuid++;
+               this.eventNamespace = "." + this.widgetName + this.uuid;
+
+               this.bindings = $();
+               this.hoverable = $();
+               this.focusable = $();
+
+               if ( element !== this ) {
+                       $.data( element, this.widgetFullName, this );
+                       this._on( true, this.element, {
+                               remove: function( event ) {
+                                       if ( event.target === element ) {
+                                               this.destroy();
+                                       }
+                               }
+                       });
+                       this.document = $( element.style ?
+                               // element within the document
+                               element.ownerDocument :
+                               // element is window or document
+                               element.document || element );
+                       this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
+               }
+
+               this.options = $.widget.extend( {},
+                       this.options,
+                       this._getCreateOptions(),
+                       options );
+
+               this._create();
+               this._trigger( "create", null, this._getCreateEventData() );
+               this._init();
+       },
+       _getCreateOptions: $.noop,
+       _getCreateEventData: $.noop,
+       _create: $.noop,
+       _init: $.noop,
+
+       destroy: function() {
+               this._destroy();
+               // we can probably remove the unbind calls in 2.0
+               // all event bindings should go through this._on()
+               this.element
+                       .unbind( this.eventNamespace )
+                       .removeData( this.widgetFullName )
+                       // support: jquery <1.6.3
+                       // http://bugs.jquery.com/ticket/9413
+                       .removeData( $.camelCase( this.widgetFullName ) );
+               this.widget()
+                       .unbind( this.eventNamespace )
+                       .removeAttr( "aria-disabled" )
+                       .removeClass(
+                               this.widgetFullName + "-disabled " +
+                               "ui-state-disabled" );
+
+               // clean up events and states
+               this.bindings.unbind( this.eventNamespace );
+               this.hoverable.removeClass( "ui-state-hover" );
+               this.focusable.removeClass( "ui-state-focus" );
+       },
+       _destroy: $.noop,
+
+       widget: function() {
+               return this.element;
+       },
+
+       option: function( key, value ) {
+               var options = key,
+                       parts,
+                       curOption,
+                       i;
+
+               if ( arguments.length === 0 ) {
+                       // don't return a reference to the internal hash
+                       return $.widget.extend( {}, this.options );
+               }
+
+               if ( typeof key === "string" ) {
+                       // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
+                       options = {};
+                       parts = key.split( "." );
+                       key = parts.shift();
+                       if ( parts.length ) {
+                               curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
+                               for ( i = 0; i < parts.length - 1; i++ ) {
+                                       curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
+                                       curOption = curOption[ parts[ i ] ];
+                               }
+                               key = parts.pop();
+                               if ( arguments.length === 1 ) {
+                                       return curOption[ key ] === undefined ? null : curOption[ key ];
+                               }
+                               curOption[ key ] = value;
+                       } else {
+                               if ( arguments.length === 1 ) {
+                                       return this.options[ key ] === undefined ? null : this.options[ key ];
+                               }
+                               options[ key ] = value;
+                       }
+               }
+
+               this._setOptions( options );
+
+               return this;
+       },
+       _setOptions: function( options ) {
+               var key;
+
+               for ( key in options ) {
+                       this._setOption( key, options[ key ] );
+               }
+
+               return this;
+       },
+       _setOption: function( key, value ) {
+               this.options[ key ] = value;
+
+               if ( key === "disabled" ) {
+                       this.widget()
+                               .toggleClass( this.widgetFullName + "-disabled", !!value );
+
+                       // If the widget is becoming disabled, then nothing is interactive
+                       if ( value ) {
+                               this.hoverable.removeClass( "ui-state-hover" );
+                               this.focusable.removeClass( "ui-state-focus" );
+                       }
+               }
+
+               return this;
+       },
+
+       enable: function() {
+               return this._setOptions({ disabled: false });
+       },
+       disable: function() {
+               return this._setOptions({ disabled: true });
+       },
+
+       _on: function( suppressDisabledCheck, element, handlers ) {
+               var delegateElement,
+                       instance = this;
+
+               // no suppressDisabledCheck flag, shuffle arguments
+               if ( typeof suppressDisabledCheck !== "boolean" ) {
+                       handlers = element;
+                       element = suppressDisabledCheck;
+                       suppressDisabledCheck = false;
+               }
+
+               // no element argument, shuffle and use this.element
+               if ( !handlers ) {
+                       handlers = element;
+                       element = this.element;
+                       delegateElement = this.widget();
+               } else {
+                       element = delegateElement = $( element );
+                       this.bindings = this.bindings.add( element );
+               }
+
+               $.each( handlers, function( event, handler ) {
+                       function handlerProxy() {
+                               // allow widgets to customize the disabled handling
+                               // - disabled as an array instead of boolean
+                               // - disabled class as method for disabling individual parts
+                               if ( !suppressDisabledCheck &&
+                                               ( instance.options.disabled === true ||
+                                                       $( this ).hasClass( "ui-state-disabled" ) ) ) {
+                                       return;
+                               }
+                               return ( typeof handler === "string" ? instance[ handler ] : handler )
+                                       .apply( instance, arguments );
+                       }
+
+                       // copy the guid so direct unbinding works
+                       if ( typeof handler !== "string" ) {
+                               handlerProxy.guid = handler.guid =
+                                       handler.guid || handlerProxy.guid || $.guid++;
+                       }
+
+                       var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
+                               eventName = match[1] + instance.eventNamespace,
+                               selector = match[2];
+                       if ( selector ) {
+                               delegateElement.delegate( selector, eventName, handlerProxy );
+                       } else {
+                               element.bind( eventName, handlerProxy );
+                       }
+               });
+       },
+
+       _off: function( element, eventName ) {
+               eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
+                       this.eventNamespace;
+               element.unbind( eventName ).undelegate( eventName );
+
+               // Clear the stack to avoid memory leaks (#10056)
+               this.bindings = $( this.bindings.not( element ).get() );
+               this.focusable = $( this.focusable.not( element ).get() );
+               this.hoverable = $( this.hoverable.not( element ).get() );
+       },
+
+       _delay: function( handler, delay ) {
+               function handlerProxy() {
+                       return ( typeof handler === "string" ? instance[ handler ] : handler )
+                               .apply( instance, arguments );
+               }
+               var instance = this;
+               return setTimeout( handlerProxy, delay || 0 );
+       },
+
+       _hoverable: function( element ) {
+               this.hoverable = this.hoverable.add( element );
+               this._on( element, {
+                       mouseenter: function( event ) {
+                               $( event.currentTarget ).addClass( "ui-state-hover" );
+                       },
+                       mouseleave: function( event ) {
+                               $( event.currentTarget ).removeClass( "ui-state-hover" );
+                       }
+               });
+       },
+
+       _focusable: function( element ) {
+               this.focusable = this.focusable.add( element );
+               this._on( element, {
+                       focusin: function( event ) {
+                               $( event.currentTarget ).addClass( "ui-state-focus" );
+                       },
+                       focusout: function( event ) {
+                               $( event.currentTarget ).removeClass( "ui-state-focus" );
+                       }
+               });
+       },
+
+       _trigger: function( type, event, data ) {
+               var prop, orig,
+                       callback = this.options[ type ];
+
+               data = data || {};
+               event = $.Event( event );
+               event.type = ( type === this.widgetEventPrefix ?
+                       type :
+                       this.widgetEventPrefix + type ).toLowerCase();
+               // the original event may come from any element
+               // so we need to reset the target on the new event
+               event.target = this.element[ 0 ];
+
+               // copy original event properties over to the new event
+               orig = event.originalEvent;
+               if ( orig ) {
+                       for ( prop in orig ) {
+                               if ( !( prop in event ) ) {
+                                       event[ prop ] = orig[ prop ];
+                               }
+                       }
+               }
+
+               this.element.trigger( event, data );
+               return !( $.isFunction( callback ) &&
+                       callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
+                       event.isDefaultPrevented() );
+       }
+};
+
+$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
+       $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
+               if ( typeof options === "string" ) {
+                       options = { effect: options };
+               }
+               var hasOptions,
+                       effectName = !options ?
+                               method :
+                               options === true || typeof options === "number" ?
+                                       defaultEffect :
+                                       options.effect || defaultEffect;
+               options = options || {};
+               if ( typeof options === "number" ) {
+                       options = { duration: options };
+               }
+               hasOptions = !$.isEmptyObject( options );
+               options.complete = callback;
+               if ( options.delay ) {
+                       element.delay( options.delay );
+               }
+               if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
+                       element[ method ]( options );
+               } else if ( effectName !== method && element[ effectName ] ) {
+                       element[ effectName ]( options.duration, options.easing, callback );
+               } else {
+                       element.queue(function( next ) {
+                               $( this )[ method ]();
+                               if ( callback ) {
+                                       callback.call( element[ 0 ] );
+                               }
+                               next();
+                       });
+               }
+       };
+});
+
+var widget = $.widget;
+
+
+/*!
+ * jQuery UI Mouse 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/mouse/
+ */
+
+
+var mouseHandled = false;
+$( document ).mouseup( function() {
+       mouseHandled = false;
+});
+
+var mouse = $.widget("ui.mouse", {
+       version: "1.11.2",
+       options: {
+               cancel: "input,textarea,button,select,option",
+               distance: 1,
+               delay: 0
+       },
+       _mouseInit: function() {
+               var that = this;
+
+               this.element
+                       .bind("mousedown." + this.widgetName, function(event) {
+                               return that._mouseDown(event);
+                       })
+                       .bind("click." + this.widgetName, function(event) {
+                               if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) {
+                                       $.removeData(event.target, that.widgetName + ".preventClickEvent");
+                                       event.stopImmediatePropagation();
+                                       return false;
+                               }
+                       });
+
+               this.started = false;
+       },
+
+       // TODO: make sure destroying one instance of mouse doesn't mess with
+       // other instances of mouse
+       _mouseDestroy: function() {
+               this.element.unbind("." + this.widgetName);
+               if ( this._mouseMoveDelegate ) {
+                       this.document
+                               .unbind("mousemove." + this.widgetName, this._mouseMoveDelegate)
+                               .unbind("mouseup." + this.widgetName, this._mouseUpDelegate);
+               }
+       },
+
+       _mouseDown: function(event) {
+               // don't let more than one widget handle mouseStart
+               if ( mouseHandled ) {
+                       return;
+               }
+
+               this._mouseMoved = false;
+
+               // we may have missed mouseup (out of window)
+               (this._mouseStarted && this._mouseUp(event));
+
+               this._mouseDownEvent = event;
+
+               var that = this,
+                       btnIsLeft = (event.which === 1),
+                       // event.target.nodeName works around a bug in IE 8 with
+                       // disabled inputs (#7620)
+                       elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false);
+               if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+                       return true;
+               }
+
+               this.mouseDelayMet = !this.options.delay;
+               if (!this.mouseDelayMet) {
+                       this._mouseDelayTimer = setTimeout(function() {
+                               that.mouseDelayMet = true;
+                       }, this.options.delay);
+               }
+
+               if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+                       this._mouseStarted = (this._mouseStart(event) !== false);
+                       if (!this._mouseStarted) {
+                               event.preventDefault();
+                               return true;
+                       }
+               }
+
+               // Click event may never have fired (Gecko & Opera)
+               if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) {
+                       $.removeData(event.target, this.widgetName + ".preventClickEvent");
+               }
+
+               // these delegates are required to keep context
+               this._mouseMoveDelegate = function(event) {
+                       return that._mouseMove(event);
+               };
+               this._mouseUpDelegate = function(event) {
+                       return that._mouseUp(event);
+               };
+
+               this.document
+                       .bind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
+                       .bind( "mouseup." + this.widgetName, this._mouseUpDelegate );
+
+               event.preventDefault();
+
+               mouseHandled = true;
+               return true;
+       },
+
+       _mouseMove: function(event) {
+               // Only check for mouseups outside the document if you've moved inside the document
+               // at least once. This prevents the firing of mouseup in the case of IE<9, which will
+               // fire a mousemove event if content is placed under the cursor. See #7778
+               // Support: IE <9
+               if ( this._mouseMoved ) {
+                       // IE mouseup check - mouseup happened when mouse was out of window
+                       if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) {
+                               return this._mouseUp(event);
+
+                       // Iframe mouseup check - mouseup occurred in another document
+                       } else if ( !event.which ) {
+                               return this._mouseUp( event );
+                       }
+               }
+
+               if ( event.which || event.button ) {
+                       this._mouseMoved = true;
+               }
+
+               if (this._mouseStarted) {
+                       this._mouseDrag(event);
+                       return event.preventDefault();
+               }
+
+               if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+                       this._mouseStarted =
+                               (this._mouseStart(this._mouseDownEvent, event) !== false);
+                       (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+               }
+
+               return !this._mouseStarted;
+       },
+
+       _mouseUp: function(event) {
+               this.document
+                       .unbind( "mousemove." + this.widgetName, this._mouseMoveDelegate )
+                       .unbind( "mouseup." + this.widgetName, this._mouseUpDelegate );
+
+               if (this._mouseStarted) {
+                       this._mouseStarted = false;
+
+                       if (event.target === this._mouseDownEvent.target) {
+                               $.data(event.target, this.widgetName + ".preventClickEvent", true);
+                       }
+
+                       this._mouseStop(event);
+               }
+
+               mouseHandled = false;
+               return false;
+       },
+
+       _mouseDistanceMet: function(event) {
+               return (Math.max(
+                               Math.abs(this._mouseDownEvent.pageX - event.pageX),
+                               Math.abs(this._mouseDownEvent.pageY - event.pageY)
+                       ) >= this.options.distance
+               );
+       },
+
+       _mouseDelayMet: function(/* event */) {
+               return this.mouseDelayMet;
+       },
+
+       // These are placeholder methods, to be overriden by extending plugin
+       _mouseStart: function(/* event */) {},
+       _mouseDrag: function(/* event */) {},
+       _mouseStop: function(/* event */) {},
+       _mouseCapture: function(/* event */) { return true; }
+});
+
+
+/*!
+ * jQuery UI Position 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/position/
+ */
+
+(function() {
+
+$.ui = $.ui || {};
+
+var cachedScrollbarWidth, supportsOffsetFractions,
+       max = Math.max,
+       abs = Math.abs,
+       round = Math.round,
+       rhorizontal = /left|center|right/,
+       rvertical = /top|center|bottom/,
+       roffset = /[\+\-]\d+(\.[\d]+)?%?/,
+       rposition = /^\w+/,
+       rpercent = /%$/,
+       _position = $.fn.position;
+
+function getOffsets( offsets, width, height ) {
+       return [
+               parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
+               parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
+       ];
+}
+
+function parseCss( element, property ) {
+       return parseInt( $.css( element, property ), 10 ) || 0;
+}
+
+function getDimensions( elem ) {
+       var raw = elem[0];
+       if ( raw.nodeType === 9 ) {
+               return {
+                       width: elem.width(),
+                       height: elem.height(),
+                       offset: { top: 0, left: 0 }
+               };
+       }
+       if ( $.isWindow( raw ) ) {
+               return {
+                       width: elem.width(),
+                       height: elem.height(),
+                       offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
+               };
+       }
+       if ( raw.preventDefault ) {
+               return {
+                       width: 0,
+                       height: 0,
+                       offset: { top: raw.pageY, left: raw.pageX }
+               };
+       }
+       return {
+               width: elem.outerWidth(),
+               height: elem.outerHeight(),
+               offset: elem.offset()
+       };
+}
+
+$.position = {
+       scrollbarWidth: function() {
+               if ( cachedScrollbarWidth !== undefined ) {
+                       return cachedScrollbarWidth;
+               }
+               var w1, w2,
+                       div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
+                       innerDiv = div.children()[0];
+
+               $( "body" ).append( div );
+               w1 = innerDiv.offsetWidth;
+               div.css( "overflow", "scroll" );
+
+               w2 = innerDiv.offsetWidth;
+
+               if ( w1 === w2 ) {
+                       w2 = div[0].clientWidth;
+               }
+
+               div.remove();
+
+               return (cachedScrollbarWidth = w1 - w2);
+       },
+       getScrollInfo: function( within ) {
+               var overflowX = within.isWindow || within.isDocument ? "" :
+                               within.element.css( "overflow-x" ),
+                       overflowY = within.isWindow || within.isDocument ? "" :
+                               within.element.css( "overflow-y" ),
+                       hasOverflowX = overflowX === "scroll" ||
+                               ( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
+                       hasOverflowY = overflowY === "scroll" ||
+                               ( overflowY === "auto" && within.height < within.element[0].scrollHeight );
+               return {
+                       width: hasOverflowY ? $.position.scrollbarWidth() : 0,
+                       height: hasOverflowX ? $.position.scrollbarWidth() : 0
+               };
+       },
+       getWithinInfo: function( element ) {
+               var withinElement = $( element || window ),
+                       isWindow = $.isWindow( withinElement[0] ),
+                       isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
+               return {
+                       element: withinElement,
+                       isWindow: isWindow,
+                       isDocument: isDocument,
+                       offset: withinElement.offset() || { left: 0, top: 0 },
+                       scrollLeft: withinElement.scrollLeft(),
+                       scrollTop: withinElement.scrollTop(),
+
+                       // support: jQuery 1.6.x
+                       // jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows
+                       width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(),
+                       height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight()
+               };
+       }
+};
+
+$.fn.position = function( options ) {
+       if ( !options || !options.of ) {
+               return _position.apply( this, arguments );
+       }
+
+       // make a copy, we don't want to modify arguments
+       options = $.extend( {}, options );
+
+       var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
+               target = $( options.of ),
+               within = $.position.getWithinInfo( options.within ),
+               scrollInfo = $.position.getScrollInfo( within ),
+               collision = ( options.collision || "flip" ).split( " " ),
+               offsets = {};
+
+       dimensions = getDimensions( target );
+       if ( target[0].preventDefault ) {
+               // force left top to allow flipping
+               options.at = "left top";
+       }
+       targetWidth = dimensions.width;
+       targetHeight = dimensions.height;
+       targetOffset = dimensions.offset;
+       // clone to reuse original targetOffset later
+       basePosition = $.extend( {}, targetOffset );
+
+       // force my and at to have valid horizontal and vertical positions
+       // if a value is missing or invalid, it will be converted to center
+       $.each( [ "my", "at" ], function() {
+               var pos = ( options[ this ] || "" ).split( " " ),
+                       horizontalOffset,
+                       verticalOffset;
+
+               if ( pos.length === 1) {
+                       pos = rhorizontal.test( pos[ 0 ] ) ?
+                               pos.concat( [ "center" ] ) :
+                               rvertical.test( pos[ 0 ] ) ?
+                                       [ "center" ].concat( pos ) :
+                                       [ "center", "center" ];
+               }
+               pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
+               pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
+
+               // calculate offsets
+               horizontalOffset = roffset.exec( pos[ 0 ] );
+               verticalOffset = roffset.exec( pos[ 1 ] );
+               offsets[ this ] = [
+                       horizontalOffset ? horizontalOffset[ 0 ] : 0,
+                       verticalOffset ? verticalOffset[ 0 ] : 0
+               ];
+
+               // reduce to just the positions without the offsets
+               options[ this ] = [
+                       rposition.exec( pos[ 0 ] )[ 0 ],
+                       rposition.exec( pos[ 1 ] )[ 0 ]
+               ];
+       });
+
+       // normalize collision option
+       if ( collision.length === 1 ) {
+               collision[ 1 ] = collision[ 0 ];
+       }
+
+       if ( options.at[ 0 ] === "right" ) {
+               basePosition.left += targetWidth;
+       } else if ( options.at[ 0 ] === "center" ) {
+               basePosition.left += targetWidth / 2;
+       }
+
+       if ( options.at[ 1 ] === "bottom" ) {
+               basePosition.top += targetHeight;
+       } else if ( options.at[ 1 ] === "center" ) {
+               basePosition.top += targetHeight / 2;
+       }
+
+       atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
+       basePosition.left += atOffset[ 0 ];
+       basePosition.top += atOffset[ 1 ];
+
+       return this.each(function() {
+               var collisionPosition, using,
+                       elem = $( this ),
+                       elemWidth = elem.outerWidth(),
+                       elemHeight = elem.outerHeight(),
+                       marginLeft = parseCss( this, "marginLeft" ),
+                       marginTop = parseCss( this, "marginTop" ),
+                       collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
+                       collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
+                       position = $.extend( {}, basePosition ),
+                       myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
+
+               if ( options.my[ 0 ] === "right" ) {
+                       position.left -= elemWidth;
+               } else if ( options.my[ 0 ] === "center" ) {
+                       position.left -= elemWidth / 2;
+               }
+
+               if ( options.my[ 1 ] === "bottom" ) {
+                       position.top -= elemHeight;
+               } else if ( options.my[ 1 ] === "center" ) {
+                       position.top -= elemHeight / 2;
+               }
+
+               position.left += myOffset[ 0 ];
+               position.top += myOffset[ 1 ];
+
+               // if the browser doesn't support fractions, then round for consistent results
+               if ( !supportsOffsetFractions ) {
+                       position.left = round( position.left );
+                       position.top = round( position.top );
+               }
+
+               collisionPosition = {
+                       marginLeft: marginLeft,
+                       marginTop: marginTop
+               };
+
+               $.each( [ "left", "top" ], function( i, dir ) {
+                       if ( $.ui.position[ collision[ i ] ] ) {
+                               $.ui.position[ collision[ i ] ][ dir ]( position, {
+                                       targetWidth: targetWidth,
+                                       targetHeight: targetHeight,
+                                       elemWidth: elemWidth,
+                                       elemHeight: elemHeight,
+                                       collisionPosition: collisionPosition,
+                                       collisionWidth: collisionWidth,
+                                       collisionHeight: collisionHeight,
+                                       offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
+                                       my: options.my,
+                                       at: options.at,
+                                       within: within,
+                                       elem: elem
+                               });
+                       }
+               });
+
+               if ( options.using ) {
+                       // adds feedback as second argument to using callback, if present
+                       using = function( props ) {
+                               var left = targetOffset.left - position.left,
+                                       right = left + targetWidth - elemWidth,
+                                       top = targetOffset.top - position.top,
+                                       bottom = top + targetHeight - elemHeight,
+                                       feedback = {
+                                               target: {
+                                                       element: target,
+                                                       left: targetOffset.left,
+                                                       top: targetOffset.top,
+                                                       width: targetWidth,
+                                                       height: targetHeight
+                                               },
+                                               element: {
+                                                       element: elem,
+                                                       left: position.left,
+                                                       top: position.top,
+                                                       width: elemWidth,
+                                                       height: elemHeight
+                                               },
+                                               horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
+                                               vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
+                                       };
+                               if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
+                                       feedback.horizontal = "center";
+                               }
+                               if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
+                                       feedback.vertical = "middle";
+                               }
+                               if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
+                                       feedback.important = "horizontal";
+                               } else {
+                                       feedback.important = "vertical";
+                               }
+                               options.using.call( this, props, feedback );
+                       };
+               }
+
+               elem.offset( $.extend( position, { using: using } ) );
+       });
+};
+
+$.ui.position = {
+       fit: {
+               left: function( position, data ) {
+                       var within = data.within,
+                               withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
+                               outerWidth = within.width,
+                               collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+                               overLeft = withinOffset - collisionPosLeft,
+                               overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
+                               newOverRight;
+
+                       // element is wider than within
+                       if ( data.collisionWidth > outerWidth ) {
+                               // element is initially over the left side of within
+                               if ( overLeft > 0 && overRight <= 0 ) {
+                                       newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
+                                       position.left += overLeft - newOverRight;
+                               // element is initially over right side of within
+                               } else if ( overRight > 0 && overLeft <= 0 ) {
+                                       position.left = withinOffset;
+                               // element is initially over both left and right sides of within
+                               } else {
+                                       if ( overLeft > overRight ) {
+                                               position.left = withinOffset + outerWidth - data.collisionWidth;
+                                       } else {
+                                               position.left = withinOffset;
+                                       }
+                               }
+                       // too far left -> align with left edge
+                       } else if ( overLeft > 0 ) {
+                               position.left += overLeft;
+                       // too far right -> align with right edge
+                       } else if ( overRight > 0 ) {
+                               position.left -= overRight;
+                       // adjust based on position and margin
+                       } else {
+                               position.left = max( position.left - collisionPosLeft, position.left );
+                       }
+               },
+               top: function( position, data ) {
+                       var within = data.within,
+                               withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
+                               outerHeight = data.within.height,
+                               collisionPosTop = position.top - data.collisionPosition.marginTop,
+                               overTop = withinOffset - collisionPosTop,
+                               overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
+                               newOverBottom;
+
+                       // element is taller than within
+                       if ( data.collisionHeight > outerHeight ) {
+                               // element is initially over the top of within
+                               if ( overTop > 0 && overBottom <= 0 ) {
+                                       newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
+                                       position.top += overTop - newOverBottom;
+                               // element is initially over bottom of within
+                               } else if ( overBottom > 0 && overTop <= 0 ) {
+                                       position.top = withinOffset;
+                               // element is initially over both top and bottom of within
+                               } else {
+                                       if ( overTop > overBottom ) {
+                                               position.top = withinOffset + outerHeight - data.collisionHeight;
+                                       } else {
+                                               position.top = withinOffset;
+                                       }
+                               }
+                       // too far up -> align with top
+                       } else if ( overTop > 0 ) {
+                               position.top += overTop;
+                       // too far down -> align with bottom edge
+                       } else if ( overBottom > 0 ) {
+                               position.top -= overBottom;
+                       // adjust based on position and margin
+                       } else {
+                               position.top = max( position.top - collisionPosTop, position.top );
+                       }
+               }
+       },
+       flip: {
+               left: function( position, data ) {
+                       var within = data.within,
+                               withinOffset = within.offset.left + within.scrollLeft,
+                               outerWidth = within.width,
+                               offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
+                               collisionPosLeft = position.left - data.collisionPosition.marginLeft,
+                               overLeft = collisionPosLeft - offsetLeft,
+                               overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
+                               myOffset = data.my[ 0 ] === "left" ?
+                                       -data.elemWidth :
+                                       data.my[ 0 ] === "right" ?
+                                               data.elemWidth :
+                                               0,
+                               atOffset = data.at[ 0 ] === "left" ?
+                                       data.targetWidth :
+                                       data.at[ 0 ] === "right" ?
+                                               -data.targetWidth :
+                                               0,
+                               offset = -2 * data.offset[ 0 ],
+                               newOverRight,
+                               newOverLeft;
+
+                       if ( overLeft < 0 ) {
+                               newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
+                               if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
+                                       position.left += myOffset + atOffset + offset;
+                               }
+                       } else if ( overRight > 0 ) {
+                               newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
+                               if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
+                                       position.left += myOffset + atOffset + offset;
+                               }
+                       }
+               },
+               top: function( position, data ) {
+                       var within = data.within,
+                               withinOffset = within.offset.top + within.scrollTop,
+                               outerHeight = within.height,
+                               offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
+                               collisionPosTop = position.top - data.collisionPosition.marginTop,
+                               overTop = collisionPosTop - offsetTop,
+                               overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
+                               top = data.my[ 1 ] === "top",
+                               myOffset = top ?
+                                       -data.elemHeight :
+                                       data.my[ 1 ] === "bottom" ?
+                                               data.elemHeight :
+                                               0,
+                               atOffset = data.at[ 1 ] === "top" ?
+                                       data.targetHeight :
+                                       data.at[ 1 ] === "bottom" ?
+                                               -data.targetHeight :
+                                               0,
+                               offset = -2 * data.offset[ 1 ],
+                               newOverTop,
+                               newOverBottom;
+                       if ( overTop < 0 ) {
+                               newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
+                               if ( ( position.top + myOffset + atOffset + offset) > overTop && ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) ) {
+                                       position.top += myOffset + atOffset + offset;
+                               }
+                       } else if ( overBottom > 0 ) {
+                               newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
+                               if ( ( position.top + myOffset + atOffset + offset) > overBottom && ( newOverTop > 0 || abs( newOverTop ) < overBottom ) ) {
+                                       position.top += myOffset + atOffset + offset;
+                               }
+                       }
+               }
+       },
+       flipfit: {
+               left: function() {
+                       $.ui.position.flip.left.apply( this, arguments );
+                       $.ui.position.fit.left.apply( this, arguments );
+               },
+               top: function() {
+                       $.ui.position.flip.top.apply( this, arguments );
+                       $.ui.position.fit.top.apply( this, arguments );
+               }
+       }
+};
+
+// fraction support test
+(function() {
+       var testElement, testElementParent, testElementStyle, offsetLeft, i,
+               body = document.getElementsByTagName( "body" )[ 0 ],
+               div = document.createElement( "div" );
+
+       //Create a "fake body" for testing based on method used in jQuery.support
+       testElement = document.createElement( body ? "div" : "body" );
+       testElementStyle = {
+               visibility: "hidden",
+               width: 0,
+               height: 0,
+               border: 0,
+               margin: 0,
+               background: "none"
+       };
+       if ( body ) {
+               $.extend( testElementStyle, {
+                       position: "absolute",
+                       left: "-1000px",
+                       top: "-1000px"
+               });
+       }
+       for ( i in testElementStyle ) {
+               testElement.style[ i ] = testElementStyle[ i ];
+       }
+       testElement.appendChild( div );
+       testElementParent = body || document.documentElement;
+       testElementParent.insertBefore( testElement, testElementParent.firstChild );
+
+       div.style.cssText = "position: absolute; left: 10.7432222px;";
+
+       offsetLeft = $( div ).offset().left;
+       supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;
+
+       testElement.innerHTML = "";
+       testElementParent.removeChild( testElement );
+})();
+
+})();
+
+var position = $.ui.position;
+
+
+/*!
+ * jQuery UI Accordion 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/accordion/
+ */
+
+
+var accordion = $.widget( "ui.accordion", {
+       version: "1.11.2",
+       options: {
+               active: 0,
+               animate: {},
+               collapsible: false,
+               event: "click",
+               header: "> li > :first-child,> :not(li):even",
+               heightStyle: "auto",
+               icons: {
+                       activeHeader: "ui-icon-triangle-1-s",
+                       header: "ui-icon-triangle-1-e"
+               },
+
+               // callbacks
+               activate: null,
+               beforeActivate: null
+       },
+
+       hideProps: {
+               borderTopWidth: "hide",
+               borderBottomWidth: "hide",
+               paddingTop: "hide",
+               paddingBottom: "hide",
+               height: "hide"
+       },
+
+       showProps: {
+               borderTopWidth: "show",
+               borderBottomWidth: "show",
+               paddingTop: "show",
+               paddingBottom: "show",
+               height: "show"
+       },
+
+       _create: function() {
+               var options = this.options;
+               this.prevShow = this.prevHide = $();
+               this.element.addClass( "ui-accordion ui-widget ui-helper-reset" )
+                       // ARIA
+                       .attr( "role", "tablist" );
+
+               // don't allow collapsible: false and active: false / null
+               if ( !options.collapsible && (options.active === false || options.active == null) ) {
+                       options.active = 0;
+               }
+
+               this._processPanels();
+               // handle negative values
+               if ( options.active < 0 ) {
+                       options.active += this.headers.length;
+               }
+               this._refresh();
+       },
+
+       _getCreateEventData: function() {
+               return {
+                       header: this.active,
+                       panel: !this.active.length ? $() : this.active.next()
+               };
+       },
+
+       _createIcons: function() {
+               var icons = this.options.icons;
+               if ( icons ) {
+                       $( "<span>" )
+                               .addClass( "ui-accordion-header-icon ui-icon " + icons.header )
+                               .prependTo( this.headers );
+                       this.active.children( ".ui-accordion-header-icon" )
+                               .removeClass( icons.header )
+                               .addClass( icons.activeHeader );
+                       this.headers.addClass( "ui-accordion-icons" );
+               }
+       },
+
+       _destroyIcons: function() {
+               this.headers
+                       .removeClass( "ui-accordion-icons" )
+                       .children( ".ui-accordion-header-icon" )
+                               .remove();
+       },
+
+       _destroy: function() {
+               var contents;
+
+               // clean up main element
+               this.element
+                       .removeClass( "ui-accordion ui-widget ui-helper-reset" )
+                       .removeAttr( "role" );
+
+               // clean up headers
+               this.headers
+                       .removeClass( "ui-accordion-header ui-accordion-header-active ui-state-default " +
+                               "ui-corner-all ui-state-active ui-state-disabled ui-corner-top" )
+                       .removeAttr( "role" )
+                       .removeAttr( "aria-expanded" )
+                       .removeAttr( "aria-selected" )
+                       .removeAttr( "aria-controls" )
+                       .removeAttr( "tabIndex" )
+                       .removeUniqueId();
+
+               this._destroyIcons();
+
+               // clean up content panels
+               contents = this.headers.next()
+                       .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom " +
+                               "ui-accordion-content ui-accordion-content-active ui-state-disabled" )
+                       .css( "display", "" )
+                       .removeAttr( "role" )
+                       .removeAttr( "aria-hidden" )
+                       .removeAttr( "aria-labelledby" )
+                       .removeUniqueId();
+
+               if ( this.options.heightStyle !== "content" ) {
+                       contents.css( "height", "" );
+               }
+       },
+
+       _setOption: function( key, value ) {
+               if ( key === "active" ) {
+                       // _activate() will handle invalid values and update this.options
+                       this._activate( value );
+                       return;
+               }
+
+               if ( key === "event" ) {
+                       if ( this.options.event ) {
+                               this._off( this.headers, this.options.event );
+                       }
+                       this._setupEvents( value );
+               }
+
+               this._super( key, value );
+
+               // setting collapsible: false while collapsed; open first panel
+               if ( key === "collapsible" && !value && this.options.active === false ) {
+                       this._activate( 0 );
+               }
+
+               if ( key === "icons" ) {
+                       this._destroyIcons();
+                       if ( value ) {
+                               this._createIcons();
+                       }
+               }
+
+               // #5332 - opacity doesn't cascade to positioned elements in IE
+               // so we need to add the disabled class to the headers and panels
+               if ( key === "disabled" ) {
+                       this.element
+                               .toggleClass( "ui-state-disabled", !!value )
+                               .attr( "aria-disabled", value );
+                       this.headers.add( this.headers.next() )
+                               .toggleClass( "ui-state-disabled", !!value );
+               }
+       },
+
+       _keydown: function( event ) {
+               if ( event.altKey || event.ctrlKey ) {
+                       return;
+               }
+
+               var keyCode = $.ui.keyCode,
+                       length = this.headers.length,
+                       currentIndex = this.headers.index( event.target ),
+                       toFocus = false;
+
+               switch ( event.keyCode ) {
+                       case keyCode.RIGHT:
+                       case keyCode.DOWN:
+                               toFocus = this.headers[ ( currentIndex + 1 ) % length ];
+                               break;
+                       case keyCode.LEFT:
+                       case keyCode.UP:
+                               toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
+                               break;
+                       case keyCode.SPACE:
+                       case keyCode.ENTER:
+                               this._eventHandler( event );
+                               break;
+                       case keyCode.HOME:
+                               toFocus = this.headers[ 0 ];
+                               break;
+                       case keyCode.END:
+                               toFocus = this.headers[ length - 1 ];
+                               break;
+               }
+
+               if ( toFocus ) {
+                       $( event.target ).attr( "tabIndex", -1 );
+                       $( toFocus ).attr( "tabIndex", 0 );
+                       toFocus.focus();
+                       event.preventDefault();
+               }
+       },
+
+       _panelKeyDown: function( event ) {
+               if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
+                       $( event.currentTarget ).prev().focus();
+               }
+       },
+
+       refresh: function() {
+               var options = this.options;
+               this._processPanels();
+
+               // was collapsed or no panel
+               if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) {
+                       options.active = false;
+                       this.active = $();
+               // active false only when collapsible is true
+               } else if ( options.active === false ) {
+                       this._activate( 0 );
+               // was active, but active panel is gone
+               } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+                       // all remaining panel are disabled
+                       if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) {
+                               options.active = false;
+                               this.active = $();
+                       // activate previous panel
+                       } else {
+                               this._activate( Math.max( 0, options.active - 1 ) );
+                       }
+               // was active, active panel still exists
+               } else {
+                       // make sure active index is correct
+                       options.active = this.headers.index( this.active );
+               }
+
+               this._destroyIcons();
+
+               this._refresh();
+       },
+
+       _processPanels: function() {
+               var prevHeaders = this.headers,
+                       prevPanels = this.panels;
+
+               this.headers = this.element.find( this.options.header )
+                       .addClass( "ui-accordion-header ui-state-default ui-corner-all" );
+
+               this.panels = this.headers.next()
+                       .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" )
+                       .filter( ":not(.ui-accordion-content-active)" )
+                       .hide();
+
+               // Avoid memory leaks (#10056)
+               if ( prevPanels ) {
+                       this._off( prevHeaders.not( this.headers ) );
+                       this._off( prevPanels.not( this.panels ) );
+               }
+       },
+
+       _refresh: function() {
+               var maxHeight,
+                       options = this.options,
+                       heightStyle = options.heightStyle,
+                       parent = this.element.parent();
+
+               this.active = this._findActive( options.active )
+                       .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" )
+                       .removeClass( "ui-corner-all" );
+               this.active.next()
+                       .addClass( "ui-accordion-content-active" )
+                       .show();
+
+               this.headers
+                       .attr( "role", "tab" )
+                       .each(function() {
+                               var header = $( this ),
+                                       headerId = header.uniqueId().attr( "id" ),
+                                       panel = header.next(),
+                                       panelId = panel.uniqueId().attr( "id" );
+                               header.attr( "aria-controls", panelId );
+                               panel.attr( "aria-labelledby", headerId );
+                       })
+                       .next()
+                               .attr( "role", "tabpanel" );
+
+               this.headers
+                       .not( this.active )
+                       .attr({
+                               "aria-selected": "false",
+                               "aria-expanded": "false",
+                               tabIndex: -1
+                       })
+                       .next()
+                               .attr({
+                                       "aria-hidden": "true"
+                               })
+                               .hide();
+
+               // make sure at least one header is in the tab order
+               if ( !this.active.length ) {
+                       this.headers.eq( 0 ).attr( "tabIndex", 0 );
+               } else {
+                       this.active.attr({
+                               "aria-selected": "true",
+                               "aria-expanded": "true",
+                               tabIndex: 0
+                       })
+                       .next()
+                               .attr({
+                                       "aria-hidden": "false"
+                               });
+               }
+
+               this._createIcons();
+
+               this._setupEvents( options.event );
+
+               if ( heightStyle === "fill" ) {
+                       maxHeight = parent.height();
+                       this.element.siblings( ":visible" ).each(function() {
+                               var elem = $( this ),
+                                       position = elem.css( "position" );
+
+                               if ( position === "absolute" || position === "fixed" ) {
+                                       return;
+                               }
+                               maxHeight -= elem.outerHeight( true );
+                       });
+
+                       this.headers.each(function() {
+                               maxHeight -= $( this ).outerHeight( true );
+                       });
+
+                       this.headers.next()
+                               .each(function() {
+                                       $( this ).height( Math.max( 0, maxHeight -
+                                               $( this ).innerHeight() + $( this ).height() ) );
+                               })
+                               .css( "overflow", "auto" );
+               } else if ( heightStyle === "auto" ) {
+                       maxHeight = 0;
+                       this.headers.next()
+                               .each(function() {
+                                       maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
+                               })
+                               .height( maxHeight );
+               }
+       },
+
+       _activate: function( index ) {
+               var active = this._findActive( index )[ 0 ];
+
+               // trying to activate the already active panel
+               if ( active === this.active[ 0 ] ) {
+                       return;
+               }
+
+               // trying to collapse, simulate a click on the currently active header
+               active = active || this.active[ 0 ];
+
+               this._eventHandler({
+                       target: active,
+                       currentTarget: active,
+                       preventDefault: $.noop
+               });
+       },
+
+       _findActive: function( selector ) {
+               return typeof selector === "number" ? this.headers.eq( selector ) : $();
+       },
+
+       _setupEvents: function( event ) {
+               var events = {
+                       keydown: "_keydown"
+               };
+               if ( event ) {
+                       $.each( event.split( " " ), function( index, eventName ) {
+                               events[ eventName ] = "_eventHandler";
+                       });
+               }
+
+               this._off( this.headers.add( this.headers.next() ) );
+               this._on( this.headers, events );
+               this._on( this.headers.next(), { keydown: "_panelKeyDown" });
+               this._hoverable( this.headers );
+               this._focusable( this.headers );
+       },
+
+       _eventHandler: function( event ) {
+               var options = this.options,
+                       active = this.active,
+                       clicked = $( event.currentTarget ),
+                       clickedIsActive = clicked[ 0 ] === active[ 0 ],
+                       collapsing = clickedIsActive && options.collapsible,
+                       toShow = collapsing ? $() : clicked.next(),
+                       toHide = active.next(),
+                       eventData = {
+                               oldHeader: active,
+                               oldPanel: toHide,
+                               newHeader: collapsing ? $() : clicked,
+                               newPanel: toShow
+                       };
+
+               event.preventDefault();
+
+               if (
+                               // click on active header, but not collapsible
+                               ( clickedIsActive && !options.collapsible ) ||
+                               // allow canceling activation
+                               ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+                       return;
+               }
+
+               options.active = collapsing ? false : this.headers.index( clicked );
+
+               // when the call to ._toggle() comes after the class changes
+               // it causes a very odd bug in IE 8 (see #6720)
+               this.active = clickedIsActive ? $() : clicked;
+               this._toggle( eventData );
+
+               // switch classes
+               // corner classes on the previously active header stay after the animation
+               active.removeClass( "ui-accordion-header-active ui-state-active" );
+               if ( options.icons ) {
+                       active.children( ".ui-accordion-header-icon" )
+                               .removeClass( options.icons.activeHeader )
+                               .addClass( options.icons.header );
+               }
+
+               if ( !clickedIsActive ) {
+                       clicked
+                               .removeClass( "ui-corner-all" )
+                               .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" );
+                       if ( options.icons ) {
+                               clicked.children( ".ui-accordion-header-icon" )
+                                       .removeClass( options.icons.header )
+                                       .addClass( options.icons.activeHeader );
+                       }
+
+                       clicked
+                               .next()
+                               .addClass( "ui-accordion-content-active" );
+               }
+       },
+
+       _toggle: function( data ) {
+               var toShow = data.newPanel,
+                       toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
+
+               // handle activating a panel during the animation for another activation
+               this.prevShow.add( this.prevHide ).stop( true, true );
+               this.prevShow = toShow;
+               this.prevHide = toHide;
+
+               if ( this.options.animate ) {
+                       this._animate( toShow, toHide, data );
+               } else {
+                       toHide.hide();
+                       toShow.show();
+                       this._toggleComplete( data );
+               }
+
+               toHide.attr({
+                       "aria-hidden": "true"
+               });
+               toHide.prev().attr( "aria-selected", "false" );
+               // if we're switching panels, remove the old header from the tab order
+               // if we're opening from collapsed state, remove the previous header from the tab order
+               // if we're collapsing, then keep the collapsing header in the tab order
+               if ( toShow.length && toHide.length ) {
+                       toHide.prev().attr({
+                               "tabIndex": -1,
+                               "aria-expanded": "false"
+                       });
+               } else if ( toShow.length ) {
+                       this.headers.filter(function() {
+                               return $( this ).attr( "tabIndex" ) === 0;
+                       })
+                       .attr( "tabIndex", -1 );
+               }
+
+               toShow
+                       .attr( "aria-hidden", "false" )
+                       .prev()
+                               .attr({
+                                       "aria-selected": "true",
+                                       tabIndex: 0,
+                                       "aria-expanded": "true"
+                               });
+       },
+
+       _animate: function( toShow, toHide, data ) {
+               var total, easing, duration,
+                       that = this,
+                       adjust = 0,
+                       down = toShow.length &&
+                               ( !toHide.length || ( toShow.index() < toHide.index() ) ),
+                       animate = this.options.animate || {},
+                       options = down && animate.down || animate,
+                       complete = function() {
+                               that._toggleComplete( data );
+                       };
+
+               if ( typeof options === "number" ) {
+                       duration = options;
+               }
+               if ( typeof options === "string" ) {
+                       easing = options;
+               }
+               // fall back from options to animation in case of partial down settings
+               easing = easing || options.easing || animate.easing;
+               duration = duration || options.duration || animate.duration;
+
+               if ( !toHide.length ) {
+                       return toShow.animate( this.showProps, duration, easing, complete );
+               }
+               if ( !toShow.length ) {
+                       return toHide.animate( this.hideProps, duration, easing, complete );
+               }
+
+               total = toShow.show().outerHeight();
+               toHide.animate( this.hideProps, {
+                       duration: duration,
+                       easing: easing,
+                       step: function( now, fx ) {
+                               fx.now = Math.round( now );
+                       }
+               });
+               toShow
+                       .hide()
+                       .animate( this.showProps, {
+                               duration: duration,
+                               easing: easing,
+                               complete: complete,
+                               step: function( now, fx ) {
+                                       fx.now = Math.round( now );
+                                       if ( fx.prop !== "height" ) {
+                                               adjust += fx.now;
+                                       } else if ( that.options.heightStyle !== "content" ) {
+                                               fx.now = Math.round( total - toHide.outerHeight() - adjust );
+                                               adjust = 0;
+                                       }
+                               }
+                       });
+       },
+
+       _toggleComplete: function( data ) {
+               var toHide = data.oldPanel;
+
+               toHide
+                       .removeClass( "ui-accordion-content-active" )
+                       .prev()
+                               .removeClass( "ui-corner-top" )
+                               .addClass( "ui-corner-all" );
+
+               // Work around for rendering bug in IE (#5421)
+               if ( toHide.length ) {
+                       toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
+               }
+               this._trigger( "activate", null, data );
+       }
+});
+
+
+/*!
+ * jQuery UI Menu 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/menu/
+ */
+
+
+var menu = $.widget( "ui.menu", {
+       version: "1.11.2",
+       defaultElement: "<ul>",
+       delay: 300,
+       options: {
+               icons: {
+                       submenu: "ui-icon-carat-1-e"
+               },
+               items: "> *",
+               menus: "ul",
+               position: {
+                       my: "left-1 top",
+                       at: "right top"
+               },
+               role: "menu",
+
+               // callbacks
+               blur: null,
+               focus: null,
+               select: null
+       },
+
+       _create: function() {
+               this.activeMenu = this.element;
+
+               // Flag used to prevent firing of the click handler
+               // as the event bubbles up through nested menus
+               this.mouseHandled = false;
+               this.element
+                       .uniqueId()
+                       .addClass( "ui-menu ui-widget ui-widget-content" )
+                       .toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
+                       .attr({
+                               role: this.options.role,
+                               tabIndex: 0
+                       });
+
+               if ( this.options.disabled ) {
+                       this.element
+                               .addClass( "ui-state-disabled" )
+                               .attr( "aria-disabled", "true" );
+               }
+
+               this._on({
+                       // Prevent focus from sticking to links inside menu after clicking
+                       // them (focus should always stay on UL during navigation).
+                       "mousedown .ui-menu-item": function( event ) {
+                               event.preventDefault();
+                       },
+                       "click .ui-menu-item": function( event ) {
+                               var target = $( event.target );
+                               if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
+                                       this.select( event );
+
+                                       // Only set the mouseHandled flag if the event will bubble, see #9469.
+                                       if ( !event.isPropagationStopped() ) {
+                                               this.mouseHandled = true;
+                                       }
+
+                                       // Open submenu on click
+                                       if ( target.has( ".ui-menu" ).length ) {
+                                               this.expand( event );
+                                       } else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {
+
+                                               // Redirect focus to the menu
+                                               this.element.trigger( "focus", [ true ] );
+
+                                               // If the active item is on the top level, let it stay active.
+                                               // Otherwise, blur the active item since it is no longer visible.
+                                               if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
+                                                       clearTimeout( this.timer );
+                                               }
+                                       }
+                               }
+                       },
+                       "mouseenter .ui-menu-item": function( event ) {
+                               // Ignore mouse events while typeahead is active, see #10458.
+                               // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
+                               // is over an item in the menu
+                               if ( this.previousFilter ) {
+                                       return;
+                               }
+                               var target = $( event.currentTarget );
+                               // Remove ui-state-active class from siblings of the newly focused menu item
+                               // to avoid a jump caused by adjacent elements both having a class with a border
+                               target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
+                               this.focus( event, target );
+                       },
+                       mouseleave: "collapseAll",
+                       "mouseleave .ui-menu": "collapseAll",
+                       focus: function( event, keepActiveItem ) {
+                               // If there's already an active item, keep it active
+                               // If not, activate the first item
+                               var item = this.active || this.element.find( this.options.items ).eq( 0 );
+
+                               if ( !keepActiveItem ) {
+                                       this.focus( event, item );
+                               }
+                       },
+                       blur: function( event ) {
+                               this._delay(function() {
+                                       if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
+                                               this.collapseAll( event );
+                                       }
+                               });
+                       },
+                       keydown: "_keydown"
+               });
+
+               this.refresh();
+
+               // Clicks outside of a menu collapse any open menus
+               this._on( this.document, {
+                       click: function( event ) {
+                               if ( this._closeOnDocumentClick( event ) ) {
+                                       this.collapseAll( event );
+                               }
+
+                               // Reset the mouseHandled flag
+                               this.mouseHandled = false;
+                       }
+               });
+       },
+
+       _destroy: function() {
+               // Destroy (sub)menus
+               this.element
+                       .removeAttr( "aria-activedescendant" )
+                       .find( ".ui-menu" ).addBack()
+                               .removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
+                               .removeAttr( "role" )
+                               .removeAttr( "tabIndex" )
+                               .removeAttr( "aria-labelledby" )
+                               .removeAttr( "aria-expanded" )
+                               .removeAttr( "aria-hidden" )
+                               .removeAttr( "aria-disabled" )
+                               .removeUniqueId()
+                               .show();
+
+               // Destroy menu items
+               this.element.find( ".ui-menu-item" )
+                       .removeClass( "ui-menu-item" )
+                       .removeAttr( "role" )
+                       .removeAttr( "aria-disabled" )
+                       .removeUniqueId()
+                       .removeClass( "ui-state-hover" )
+                       .removeAttr( "tabIndex" )
+                       .removeAttr( "role" )
+                       .removeAttr( "aria-haspopup" )
+                       .children().each( function() {
+                               var elem = $( this );
+                               if ( elem.data( "ui-menu-submenu-carat" ) ) {
+                                       elem.remove();
+                               }
+                       });
+
+               // Destroy menu dividers
+               this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
+       },
+
+       _keydown: function( event ) {
+               var match, prev, character, skip,
+                       preventDefault = true;
+
+               switch ( event.keyCode ) {
+               case $.ui.keyCode.PAGE_UP:
+                       this.previousPage( event );
+                       break;
+               case $.ui.keyCode.PAGE_DOWN:
+                       this.nextPage( event );
+                       break;
+               case $.ui.keyCode.HOME:
+                       this._move( "first", "first", event );
+                       break;
+               case $.ui.keyCode.END:
+                       this._move( "last", "last", event );
+                       break;
+               case $.ui.keyCode.UP:
+                       this.previous( event );
+                       break;
+               case $.ui.keyCode.DOWN:
+                       this.next( event );
+                       break;
+               case $.ui.keyCode.LEFT:
+                       this.collapse( event );
+                       break;
+               case $.ui.keyCode.RIGHT:
+                       if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
+                               this.expand( event );
+                       }
+                       break;
+               case $.ui.keyCode.ENTER:
+               case $.ui.keyCode.SPACE:
+                       this._activate( event );
+                       break;
+               case $.ui.keyCode.ESCAPE:
+                       this.collapse( event );
+                       break;
+               default:
+                       preventDefault = false;
+                       prev = this.previousFilter || "";
+                       character = String.fromCharCode( event.keyCode );
+                       skip = false;
+
+                       clearTimeout( this.filterTimer );
+
+                       if ( character === prev ) {
+                               skip = true;
+                       } else {
+                               character = prev + character;
+                       }
+
+                       match = this._filterMenuItems( character );
+                       match = skip && match.index( this.active.next() ) !== -1 ?
+                               this.active.nextAll( ".ui-menu-item" ) :
+                               match;
+
+                       // If no matches on the current filter, reset to the last character pressed
+                       // to move down the menu to the first item that starts with that character
+                       if ( !match.length ) {
+                               character = String.fromCharCode( event.keyCode );
+                               match = this._filterMenuItems( character );
+                       }
+
+                       if ( match.length ) {
+                               this.focus( event, match );
+                               this.previousFilter = character;
+                               this.filterTimer = this._delay(function() {
+                                       delete this.previousFilter;
+                               }, 1000 );
+                       } else {
+                               delete this.previousFilter;
+                       }
+               }
+
+               if ( preventDefault ) {
+                       event.preventDefault();
+               }
+       },
+
+       _activate: function( event ) {
+               if ( !this.active.is( ".ui-state-disabled" ) ) {
+                       if ( this.active.is( "[aria-haspopup='true']" ) ) {
+                               this.expand( event );
+                       } else {
+                               this.select( event );
+                       }
+               }
+       },
+
+       refresh: function() {
+               var menus, items,
+                       that = this,
+                       icon = this.options.icons.submenu,
+                       submenus = this.element.find( this.options.menus );
+
+               this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );
+
+               // Initialize nested menus
+               submenus.filter( ":not(.ui-menu)" )
+                       .addClass( "ui-menu ui-widget ui-widget-content ui-front" )
+                       .hide()
+                       .attr({
+                               role: this.options.role,
+                               "aria-hidden": "true",
+                               "aria-expanded": "false"
+                       })
+                       .each(function() {
+                               var menu = $( this ),
+                                       item = menu.parent(),
+                                       submenuCarat = $( "<span>" )
+                                               .addClass( "ui-menu-icon ui-icon " + icon )
+                                               .data( "ui-menu-submenu-carat", true );
+
+                               item
+                                       .attr( "aria-haspopup", "true" )
+                                       .prepend( submenuCarat );
+                               menu.attr( "aria-labelledby", item.attr( "id" ) );
+                       });
+
+               menus = submenus.add( this.element );
+               items = menus.find( this.options.items );
+
+               // Initialize menu-items containing spaces and/or dashes only as dividers
+               items.not( ".ui-menu-item" ).each(function() {
+                       var item = $( this );
+                       if ( that._isDivider( item ) ) {
+                               item.addClass( "ui-widget-content ui-menu-divider" );
+                       }
+               });
+
+               // Don't refresh list items that are already adapted
+               items.not( ".ui-menu-item, .ui-menu-divider" )
+                       .addClass( "ui-menu-item" )
+                       .uniqueId()
+                       .attr({
+                               tabIndex: -1,
+                               role: this._itemRole()
+                       });
+
+               // Add aria-disabled attribute to any disabled menu item
+               items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
+
+               // If the active item has been removed, blur the menu
+               if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
+                       this.blur();
+               }
+       },
+
+       _itemRole: function() {
+               return {
+                       menu: "menuitem",
+                       listbox: "option"
+               }[ this.options.role ];
+       },
+
+       _setOption: function( key, value ) {
+               if ( key === "icons" ) {
+                       this.element.find( ".ui-menu-icon" )
+                               .removeClass( this.options.icons.submenu )
+                               .addClass( value.submenu );
+               }
+               if ( key === "disabled" ) {
+                       this.element
+                               .toggleClass( "ui-state-disabled", !!value )
+                               .attr( "aria-disabled", value );
+               }
+               this._super( key, value );
+       },
+
+       focus: function( event, item ) {
+               var nested, focused;
+               this.blur( event, event && event.type === "focus" );
+
+               this._scrollIntoView( item );
+
+               this.active = item.first();
+               focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
+               // Only update aria-activedescendant if there's a role
+               // otherwise we assume focus is managed elsewhere
+               if ( this.options.role ) {
+                       this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
+               }
+
+               // Highlight active parent menu item, if any
+               this.active
+                       .parent()
+                       .closest( ".ui-menu-item" )
+                       .addClass( "ui-state-active" );
+
+               if ( event && event.type === "keydown" ) {
+                       this._close();
+               } else {
+                       this.timer = this._delay(function() {
+                               this._close();
+                       }, this.delay );
+               }
+
+               nested = item.children( ".ui-menu" );
+               if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
+                       this._startOpening(nested);
+               }
+               this.activeMenu = item.parent();
+
+               this._trigger( "focus", event, { item: item } );
+       },
+
+       _scrollIntoView: function( item ) {
+               var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
+               if ( this._hasScroll() ) {
+                       borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
+                       paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
+                       offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
+                       scroll = this.activeMenu.scrollTop();
+                       elementHeight = this.activeMenu.height();
+                       itemHeight = item.outerHeight();
+
+                       if ( offset < 0 ) {
+                               this.activeMenu.scrollTop( scroll + offset );
+                       } else if ( offset + itemHeight > elementHeight ) {
+                               this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
+                       }
+               }
+       },
+
+       blur: function( event, fromFocus ) {
+               if ( !fromFocus ) {
+                       clearTimeout( this.timer );
+               }
+
+               if ( !this.active ) {
+                       return;
+               }
+
+               this.active.removeClass( "ui-state-focus" );
+               this.active = null;
+
+               this._trigger( "blur", event, { item: this.active } );
+       },
+
+       _startOpening: function( submenu ) {
+               clearTimeout( this.timer );
+
+               // Don't open if already open fixes a Firefox bug that caused a .5 pixel
+               // shift in the submenu position when mousing over the carat icon
+               if ( submenu.attr( "aria-hidden" ) !== "true" ) {
+                       return;
+               }
+
+               this.timer = this._delay(function() {
+                       this._close();
+                       this._open( submenu );
+               }, this.delay );
+       },
+
+       _open: function( submenu ) {
+               var position = $.extend({
+                       of: this.active
+               }, this.options.position );
+
+               clearTimeout( this.timer );
+               this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
+                       .hide()
+                       .attr( "aria-hidden", "true" );
+
+               submenu
+                       .show()
+                       .removeAttr( "aria-hidden" )
+                       .attr( "aria-expanded", "true" )
+                       .position( position );
+       },
+
+       collapseAll: function( event, all ) {
+               clearTimeout( this.timer );
+               this.timer = this._delay(function() {
+                       // If we were passed an event, look for the submenu that contains the event
+                       var currentMenu = all ? this.element :
+                               $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
+
+                       // If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
+                       if ( !currentMenu.length ) {
+                               currentMenu = this.element;
+                       }
+
+                       this._close( currentMenu );
+
+                       this.blur( event );
+                       this.activeMenu = currentMenu;
+               }, this.delay );
+       },
+
+       // With no arguments, closes the currently active menu - if nothing is active
+       // it closes all menus.  If passed an argument, it will search for menus BELOW
+       _close: function( startMenu ) {
+               if ( !startMenu ) {
+                       startMenu = this.active ? this.active.parent() : this.element;
+               }
+
+               startMenu
+                       .find( ".ui-menu" )
+                               .hide()
+                               .attr( "aria-hidden", "true" )
+                               .attr( "aria-expanded", "false" )
+                       .end()
+                       .find( ".ui-state-active" ).not( ".ui-state-focus" )
+                               .removeClass( "ui-state-active" );
+       },
+
+       _closeOnDocumentClick: function( event ) {
+               return !$( event.target ).closest( ".ui-menu" ).length;
+       },
+
+       _isDivider: function( item ) {
+
+               // Match hyphen, em dash, en dash
+               return !/[^\-\u2014\u2013\s]/.test( item.text() );
+       },
+
+       collapse: function( event ) {
+               var newItem = this.active &&
+                       this.active.parent().closest( ".ui-menu-item", this.element );
+               if ( newItem && newItem.length ) {
+                       this._close();
+                       this.focus( event, newItem );
+               }
+       },
+
+       expand: function( event ) {
+               var newItem = this.active &&
+                       this.active
+                               .children( ".ui-menu " )
+                               .find( this.options.items )
+                               .first();
+
+               if ( newItem && newItem.length ) {
+                       this._open( newItem.parent() );
+
+                       // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
+                       this._delay(function() {
+                               this.focus( event, newItem );
+                       });
+               }
+       },
+
+       next: function( event ) {
+               this._move( "next", "first", event );
+       },
+
+       previous: function( event ) {
+               this._move( "prev", "last", event );
+       },
+
+       isFirstItem: function() {
+               return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
+       },
+
+       isLastItem: function() {
+               return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
+       },
+
+       _move: function( direction, filter, event ) {
+               var next;
+               if ( this.active ) {
+                       if ( direction === "first" || direction === "last" ) {
+                               next = this.active
+                                       [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
+                                       .eq( -1 );
+                       } else {
+                               next = this.active
+                                       [ direction + "All" ]( ".ui-menu-item" )
+                                       .eq( 0 );
+                       }
+               }
+               if ( !next || !next.length || !this.active ) {
+                       next = this.activeMenu.find( this.options.items )[ filter ]();
+               }
+
+               this.focus( event, next );
+       },
+
+       nextPage: function( event ) {
+               var item, base, height;
+
+               if ( !this.active ) {
+                       this.next( event );
+                       return;
+               }
+               if ( this.isLastItem() ) {
+                       return;
+               }
+               if ( this._hasScroll() ) {
+                       base = this.active.offset().top;
+                       height = this.element.height();
+                       this.active.nextAll( ".ui-menu-item" ).each(function() {
+                               item = $( this );
+                               return item.offset().top - base - height < 0;
+                       });
+
+                       this.focus( event, item );
+               } else {
+                       this.focus( event, this.activeMenu.find( this.options.items )
+                               [ !this.active ? "first" : "last" ]() );
+               }
+       },
+
+       previousPage: function( event ) {
+               var item, base, height;
+               if ( !this.active ) {
+                       this.next( event );
+                       return;
+               }
+               if ( this.isFirstItem() ) {
+                       return;
+               }
+               if ( this._hasScroll() ) {
+                       base = this.active.offset().top;
+                       height = this.element.height();
+                       this.active.prevAll( ".ui-menu-item" ).each(function() {
+                               item = $( this );
+                               return item.offset().top - base + height > 0;
+                       });
+
+                       this.focus( event, item );
+               } else {
+                       this.focus( event, this.activeMenu.find( this.options.items ).first() );
+               }
+       },
+
+       _hasScroll: function() {
+               return this.element.outerHeight() < this.element.prop( "scrollHeight" );
+       },
+
+       select: function( event ) {
+               // TODO: It should never be possible to not have an active item at this
+               // point, but the tests don't trigger mouseenter before click.
+               this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
+               var ui = { item: this.active };
+               if ( !this.active.has( ".ui-menu" ).length ) {
+                       this.collapseAll( event, true );
+               }
+               this._trigger( "select", event, ui );
+       },
+
+       _filterMenuItems: function(character) {
+               var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
+                       regex = new RegExp( "^" + escapedCharacter, "i" );
+
+               return this.activeMenu
+                       .find( this.options.items )
+
+                       // Only match on items, not dividers or other content (#10571)
+                       .filter( ".ui-menu-item" )
+                       .filter(function() {
+                               return regex.test( $.trim( $( this ).text() ) );
+                       });
+       }
+});
+
+
+/*!
+ * jQuery UI Autocomplete 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/autocomplete/
+ */
+
+
+$.widget( "ui.autocomplete", {
+       version: "1.11.2",
+       defaultElement: "<input>",
+       options: {
+               appendTo: null,
+               autoFocus: false,
+               delay: 300,
+               minLength: 1,
+               position: {
+                       my: "left top",
+                       at: "left bottom",
+                       collision: "none"
+               },
+               source: null,
+
+               // callbacks
+               change: null,
+               close: null,
+               focus: null,
+               open: null,
+               response: null,
+               search: null,
+               select: null
+       },
+
+       requestIndex: 0,
+       pending: 0,
+
+       _create: function() {
+               // Some browsers only repeat keydown events, not keypress events,
+               // so we use the suppressKeyPress flag to determine if we've already
+               // handled the keydown event. #7269
+               // Unfortunately the code for & in keypress is the same as the up arrow,
+               // so we use the suppressKeyPressRepeat flag to avoid handling keypress
+               // events when we know the keydown event was used to modify the
+               // search term. #7799
+               var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
+                       nodeName = this.element[ 0 ].nodeName.toLowerCase(),
+                       isTextarea = nodeName === "textarea",
+                       isInput = nodeName === "input";
+
+               this.isMultiLine =
+                       // Textareas are always multi-line
+                       isTextarea ? true :
+                       // Inputs are always single-line, even if inside a contentEditable element
+                       // IE also treats inputs as contentEditable
+                       isInput ? false :
+                       // All other element types are determined by whether or not they're contentEditable
+                       this.element.prop( "isContentEditable" );
+
+               this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
+               this.isNewMenu = true;
+
+               this.element
+                       .addClass( "ui-autocomplete-input" )
+                       .attr( "autocomplete", "off" );
+
+               this._on( this.element, {
+                       keydown: function( event ) {
+                               if ( this.element.prop( "readOnly" ) ) {
+                                       suppressKeyPress = true;
+                                       suppressInput = true;
+                                       suppressKeyPressRepeat = true;
+                                       return;
+                               }
+
+                               suppressKeyPress = false;
+                               suppressInput = false;
+                               suppressKeyPressRepeat = false;
+                               var keyCode = $.ui.keyCode;
+                               switch ( event.keyCode ) {
+                               case keyCode.PAGE_UP:
+                                       suppressKeyPress = true;
+                                       this._move( "previousPage", event );
+                                       break;
+                               case keyCode.PAGE_DOWN:
+                                       suppressKeyPress = true;
+                                       this._move( "nextPage", event );
+                                       break;
+                               case keyCode.UP:
+                                       suppressKeyPress = true;
+                                       this._keyEvent( "previous", event );
+                                       break;
+                               case keyCode.DOWN:
+                                       suppressKeyPress = true;
+                                       this._keyEvent( "next", event );
+                                       break;
+                               case keyCode.ENTER:
+                                       // when menu is open and has focus
+                                       if ( this.menu.active ) {
+                                               // #6055 - Opera still allows the keypress to occur
+                                               // which causes forms to submit
+                                               suppressKeyPress = true;
+                                               event.preventDefault();
+                                               this.menu.select( event );
+                                       }
+                                       break;
+                               case keyCode.TAB:
+                                       if ( this.menu.active ) {
+                                               this.menu.select( event );
+                                       }
+                                       break;
+                               case keyCode.ESCAPE:
+                                       if ( this.menu.element.is( ":visible" ) ) {
+                                               if ( !this.isMultiLine ) {
+                                                       this._value( this.term );
+                                               }
+                                               this.close( event );
+                                               // Different browsers have different default behavior for escape
+                                               // Single press can mean undo or clear
+                                               // Double press in IE means clear the whole form
+                                               event.preventDefault();
+                                       }
+                                       break;
+                               default:
+                                       suppressKeyPressRepeat = true;
+                                       // search timeout should be triggered before the input value is changed
+                                       this._searchTimeout( event );
+                                       break;
+                               }
+                       },
+                       keypress: function( event ) {
+                               if ( suppressKeyPress ) {
+                                       suppressKeyPress = false;
+                                       if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+                                               event.preventDefault();
+                                       }
+                                       return;
+                               }
+                               if ( suppressKeyPressRepeat ) {
+                                       return;
+                               }
+
+                               // replicate some key handlers to allow them to repeat in Firefox and Opera
+                               var keyCode = $.ui.keyCode;
+                               switch ( event.keyCode ) {
+                               case keyCode.PAGE_UP:
+                                       this._move( "previousPage", event );
+                                       break;
+                               case keyCode.PAGE_DOWN:
+                                       this._move( "nextPage", event );
+                                       break;
+                               case keyCode.UP:
+                                       this._keyEvent( "previous", event );
+                                       break;
+                               case keyCode.DOWN:
+                                       this._keyEvent( "next", event );
+                                       break;
+                               }
+                       },
+                       input: function( event ) {
+                               if ( suppressInput ) {
+                                       suppressInput = false;
+                                       event.preventDefault();
+                                       return;
+                               }
+                               this._searchTimeout( event );
+                       },
+                       focus: function() {
+                               this.selectedItem = null;
+                               this.previous = this._value();
+                       },
+                       blur: function( event ) {
+                               if ( this.cancelBlur ) {
+                                       delete this.cancelBlur;
+                                       return;
+                               }
+
+                               clearTimeout( this.searching );
+                               this.close( event );
+                               this._change( event );
+                       }
+               });
+
+               this._initSource();
+               this.menu = $( "<ul>" )
+                       .addClass( "ui-autocomplete ui-front" )
+                       .appendTo( this._appendTo() )
+                       .menu({
+                               // disable ARIA support, the live region takes care of that
+                               role: null
+                       })
+                       .hide()
+                       .menu( "instance" );
+
+               this._on( this.menu.element, {
+                       mousedown: function( event ) {
+                               // prevent moving focus out of the text field
+                               event.preventDefault();
+
+                               // IE doesn't prevent moving focus even with event.preventDefault()
+                               // so we set a flag to know when we should ignore the blur event
+                               this.cancelBlur = true;
+                               this._delay(function() {
+                                       delete this.cancelBlur;
+                               });
+
+                               // clicking on the scrollbar causes focus to shift to the body
+                               // but we can't detect a mouseup or a click immediately afterward
+                               // so we have to track the next mousedown and close the menu if
+                               // the user clicks somewhere outside of the autocomplete
+                               var menuElement = this.menu.element[ 0 ];
+                               if ( !$( event.target ).closest( ".ui-menu-item" ).length ) {
+                                       this._delay(function() {
+                                               var that = this;
+                                               this.document.one( "mousedown", function( event ) {
+                                                       if ( event.target !== that.element[ 0 ] &&
+                                                                       event.target !== menuElement &&
+                                                                       !$.contains( menuElement, event.target ) ) {
+                                                               that.close();
+                                                       }
+                                               });
+                                       });
+                               }
+                       },
+                       menufocus: function( event, ui ) {
+                               var label, item;
+                               // support: Firefox
+                               // Prevent accidental activation of menu items in Firefox (#7024 #9118)
+                               if ( this.isNewMenu ) {
+                                       this.isNewMenu = false;
+                                       if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
+                                               this.menu.blur();
+
+                                               this.document.one( "mousemove", function() {
+                                                       $( event.target ).trigger( event.originalEvent );
+                                               });
+
+                                               return;
+                                       }
+                               }
+
+                               item = ui.item.data( "ui-autocomplete-item" );
+                               if ( false !== this._trigger( "focus", event, { item: item } ) ) {
+                                       // use value to match what will end up in the input, if it was a key event
+                                       if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
+                                               this._value( item.value );
+                                       }
+                               }
+
+                               // Announce the value in the liveRegion
+                               label = ui.item.attr( "aria-label" ) || item.value;
+                               if ( label && $.trim( label ).length ) {
+                                       this.liveRegion.children().hide();
+                                       $( "<div>" ).text( label ).appendTo( this.liveRegion );
+                               }
+                       },
+                       menuselect: function( event, ui ) {
+                               var item = ui.item.data( "ui-autocomplete-item" ),
+                                       previous = this.previous;
+
+                               // only trigger when focus was lost (click on menu)
+                               if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) {
+                                       this.element.focus();
+                                       this.previous = previous;
+                                       // #6109 - IE triggers two focus events and the second
+                                       // is asynchronous, so we need to reset the previous
+                                       // term synchronously and asynchronously :-(
+                                       this._delay(function() {
+                                               this.previous = previous;
+                                               this.selectedItem = item;
+                                       });
+                               }
+
+                               if ( false !== this._trigger( "select", event, { item: item } ) ) {
+                                       this._value( item.value );
+                               }
+                               // reset the term after the select event
+                               // this allows custom select handling to work properly
+                               this.term = this._value();
+
+                               this.close( event );
+                               this.selectedItem = item;
+                       }
+               });
+
+               this.liveRegion = $( "<span>", {
+                               role: "status",
+                               "aria-live": "assertive",
+                               "aria-relevant": "additions"
+                       })
+                       .addClass( "ui-helper-hidden-accessible" )
+                       .appendTo( this.document[ 0 ].body );
+
+               // turning off autocomplete prevents the browser from remembering the
+               // value when navigating through history, so we re-enable autocomplete
+               // if the page is unloaded before the widget is destroyed. #7790
+               this._on( this.window, {
+                       beforeunload: function() {
+                               this.element.removeAttr( "autocomplete" );
+                       }
+               });
+       },
+
+       _destroy: function() {
+               clearTimeout( this.searching );
+               this.element
+                       .removeClass( "ui-autocomplete-input" )
+                       .removeAttr( "autocomplete" );
+               this.menu.element.remove();
+               this.liveRegion.remove();
+       },
+
+       _setOption: function( key, value ) {
+               this._super( key, value );
+               if ( key === "source" ) {
+                       this._initSource();
+               }
+               if ( key === "appendTo" ) {
+                       this.menu.element.appendTo( this._appendTo() );
+               }
+               if ( key === "disabled" && value && this.xhr ) {
+                       this.xhr.abort();
+               }
+       },
+
+       _appendTo: function() {
+               var element = this.options.appendTo;
+
+               if ( element ) {
+                       element = element.jquery || element.nodeType ?
+                               $( element ) :
+                               this.document.find( element ).eq( 0 );
+               }
+
+               if ( !element || !element[ 0 ] ) {
+                       element = this.element.closest( ".ui-front" );
+               }
+
+               if ( !element.length ) {
+                       element = this.document[ 0 ].body;
+               }
+
+               return element;
+       },
+
+       _initSource: function() {
+               var array, url,
+                       that = this;
+               if ( $.isArray( this.options.source ) ) {
+                       array = this.options.source;
+                       this.source = function( request, response ) {
+                               response( $.ui.autocomplete.filter( array, request.term ) );
+                       };
+               } else if ( typeof this.options.source === "string" ) {
+                       url = this.options.source;
+                       this.source = function( request, response ) {
+                               if ( that.xhr ) {
+                                       that.xhr.abort();
+                               }
+                               that.xhr = $.ajax({
+                                       url: url,
+                                       data: request,
+                                       dataType: "json",
+                                       success: function( data ) {
+                                               response( data );
+                                       },
+                                       error: function() {
+                                               response([]);
+                                       }
+                               });
+                       };
+               } else {
+                       this.source = this.options.source;
+               }
+       },
+
+       _searchTimeout: function( event ) {
+               clearTimeout( this.searching );
+               this.searching = this._delay(function() {
+
+                       // Search if the value has changed, or if the user retypes the same value (see #7434)
+                       var equalValues = this.term === this._value(),
+                               menuVisible = this.menu.element.is( ":visible" ),
+                               modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
+
+                       if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
+                               this.selectedItem = null;
+                               this.search( null, event );
+                       }
+               }, this.options.delay );
+       },
+
+       search: function( value, event ) {
+               value = value != null ? value : this._value();
+
+               // always save the actual value, not the one passed as an argument
+               this.term = this._value();
+
+               if ( value.length < this.options.minLength ) {
+                       return this.close( event );
+               }
+
+               if ( this._trigger( "search", event ) === false ) {
+                       return;
+               }
+
+               return this._search( value );
+       },
+
+       _search: function( value ) {
+               this.pending++;
+               this.element.addClass( "ui-autocomplete-loading" );
+               this.cancelSearch = false;
+
+               this.source( { term: value }, this._response() );
+       },
+
+       _response: function() {
+               var index = ++this.requestIndex;
+
+               return $.proxy(function( content ) {
+                       if ( index === this.requestIndex ) {
+                               this.__response( content );
+                       }
+
+                       this.pending--;
+                       if ( !this.pending ) {
+                               this.element.removeClass( "ui-autocomplete-loading" );
+                       }
+               }, this );
+       },
+
+       __response: function( content ) {
+               if ( content ) {
+                       content = this._normalize( content );
+               }
+               this._trigger( "response", null, { content: content } );
+               if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
+                       this._suggest( content );
+                       this._trigger( "open" );
+               } else {
+                       // use ._close() instead of .close() so we don't cancel future searches
+                       this._close();
+               }
+       },
+
+       close: function( event ) {
+               this.cancelSearch = true;
+               this._close( event );
+       },
+
+       _close: function( event ) {
+               if ( this.menu.element.is( ":visible" ) ) {
+                       this.menu.element.hide();
+                       this.menu.blur();
+                       this.isNewMenu = true;
+                       this._trigger( "close", event );
+               }
+       },
+
+       _change: function( event ) {
+               if ( this.previous !== this._value() ) {
+                       this._trigger( "change", event, { item: this.selectedItem } );
+               }
+       },
+
+       _normalize: function( items ) {
+               // assume all items have the right format when the first item is complete
+               if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
+                       return items;
+               }
+               return $.map( items, function( item ) {
+                       if ( typeof item === "string" ) {
+                               return {
+                                       label: item,
+                                       value: item
+                               };
+                       }
+                       return $.extend( {}, item, {
+                               label: item.label || item.value,
+                               value: item.value || item.label
+                       });
+               });
+       },
+
+       _suggest: function( items ) {
+               var ul = this.menu.element.empty();
+               this._renderMenu( ul, items );
+               this.isNewMenu = true;
+               this.menu.refresh();
+
+               // size and position menu
+               ul.show();
+               this._resizeMenu();
+               ul.position( $.extend({
+                       of: this.element
+               }, this.options.position ) );
+
+               if ( this.options.autoFocus ) {
+                       this.menu.next();
+               }
+       },
+
+       _resizeMenu: function() {
+               var ul = this.menu.element;
+               ul.outerWidth( Math.max(
+                       // Firefox wraps long text (possibly a rounding bug)
+                       // so we add 1px to avoid the wrapping (#7513)
+                       ul.width( "" ).outerWidth() + 1,
+                       this.element.outerWidth()
+               ) );
+       },
+
+       _renderMenu: function( ul, items ) {
+               var that = this;
+               $.each( items, function( index, item ) {
+                       that._renderItemData( ul, item );
+               });
+       },
+
+       _renderItemData: function( ul, item ) {
+               return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
+       },
+
+       _renderItem: function( ul, item ) {
+               return $( "<li>" ).text( item.label ).appendTo( ul );
+       },
+
+       _move: function( direction, event ) {
+               if ( !this.menu.element.is( ":visible" ) ) {
+                       this.search( null, event );
+                       return;
+               }
+               if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
+                               this.menu.isLastItem() && /^next/.test( direction ) ) {
+
+                       if ( !this.isMultiLine ) {
+                               this._value( this.term );
+                       }
+
+                       this.menu.blur();
+                       return;
+               }
+               this.menu[ direction ]( event );
+       },
+
+       widget: function() {
+               return this.menu.element;
+       },
+
+       _value: function() {
+               return this.valueMethod.apply( this.element, arguments );
+       },
+
+       _keyEvent: function( keyEvent, event ) {
+               if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
+                       this._move( keyEvent, event );
+
+                       // prevents moving cursor to beginning/end of the text field in some browsers
+                       event.preventDefault();
+               }
+       }
+});
+
+$.extend( $.ui.autocomplete, {
+       escapeRegex: function( value ) {
+               return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
+       },
+       filter: function( array, term ) {
+               var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
+               return $.grep( array, function( value ) {
+                       return matcher.test( value.label || value.value || value );
+               });
+       }
+});
+
+// live region extension, adding a `messages` option
+// NOTE: This is an experimental API. We are still investigating
+// a full solution for string manipulation and internationalization.
+$.widget( "ui.autocomplete", $.ui.autocomplete, {
+       options: {
+               messages: {
+                       noResults: "No search results.",
+                       results: function( amount ) {
+                               return amount + ( amount > 1 ? " results are" : " result is" ) +
+                                       " available, use up and down arrow keys to navigate.";
+                       }
+               }
+       },
+
+       __response: function( content ) {
+               var message;
+               this._superApply( arguments );
+               if ( this.options.disabled || this.cancelSearch ) {
+                       return;
+               }
+               if ( content && content.length ) {
+                       message = this.options.messages.results( content.length );
+               } else {
+                       message = this.options.messages.noResults;
+               }
+               this.liveRegion.children().hide();
+               $( "<div>" ).text( message ).appendTo( this.liveRegion );
+       }
+});
+
+var autocomplete = $.ui.autocomplete;
+
+
+/*!
+ * jQuery UI Button 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/button/
+ */
+
+
+var lastActive,
+       baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
+       typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
+       formResetHandler = function() {
+               var form = $( this );
+               setTimeout(function() {
+                       form.find( ":ui-button" ).button( "refresh" );
+               }, 1 );
+       },
+       radioGroup = function( radio ) {
+               var name = radio.name,
+                       form = radio.form,
+                       radios = $( [] );
+               if ( name ) {
+                       name = name.replace( /'/g, "\\'" );
+                       if ( form ) {
+                               radios = $( form ).find( "[name='" + name + "'][type=radio]" );
+                       } else {
+                               radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
+                                       .filter(function() {
+                                               return !this.form;
+                                       });
+                       }
+               }
+               return radios;
+       };
+
+$.widget( "ui.button", {
+       version: "1.11.2",
+       defaultElement: "<button>",
+       options: {
+               disabled: null,
+               text: true,
+               label: null,
+               icons: {
+                       primary: null,
+                       secondary: null
+               }
+       },
+       _create: function() {
+               this.element.closest( "form" )
+                       .unbind( "reset" + this.eventNamespace )
+                       .bind( "reset" + this.eventNamespace, formResetHandler );
+
+               if ( typeof this.options.disabled !== "boolean" ) {
+                       this.options.disabled = !!this.element.prop( "disabled" );
+               } else {
+                       this.element.prop( "disabled", this.options.disabled );
+               }
+
+               this._determineButtonType();
+               this.hasTitle = !!this.buttonElement.attr( "title" );
+
+               var that = this,
+                       options = this.options,
+                       toggleButton = this.type === "checkbox" || this.type === "radio",
+                       activeClass = !toggleButton ? "ui-state-active" : "";
+
+               if ( options.label === null ) {
+                       options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
+               }
+
+               this._hoverable( this.buttonElement );
+
+               this.buttonElement
+                       .addClass( baseClasses )
+                       .attr( "role", "button" )
+                       .bind( "mouseenter" + this.eventNamespace, function() {
+                               if ( options.disabled ) {
+                                       return;
+                               }
+                               if ( this === lastActive ) {
+                                       $( this ).addClass( "ui-state-active" );
+                               }
+                       })
+                       .bind( "mouseleave" + this.eventNamespace, function() {
+                               if ( options.disabled ) {
+                                       return;
+                               }
+                               $( this ).removeClass( activeClass );
+                       })
+                       .bind( "click" + this.eventNamespace, function( event ) {
+                               if ( options.disabled ) {
+                                       event.preventDefault();
+                                       event.stopImmediatePropagation();
+                               }
+                       });
+
+               // Can't use _focusable() because the element that receives focus
+               // and the element that gets the ui-state-focus class are different
+               this._on({
+                       focus: function() {
+                               this.buttonElement.addClass( "ui-state-focus" );
+                       },
+                       blur: function() {
+                               this.buttonElement.removeClass( "ui-state-focus" );
+                       }
+               });
+
+               if ( toggleButton ) {
+                       this.element.bind( "change" + this.eventNamespace, function() {
+                               that.refresh();
+                       });
+               }
+
+               if ( this.type === "checkbox" ) {
+                       this.buttonElement.bind( "click" + this.eventNamespace, function() {
+                               if ( options.disabled ) {
+                                       return false;
+                               }
+                       });
+               } else if ( this.type === "radio" ) {
+                       this.buttonElement.bind( "click" + this.eventNamespace, function() {
+                               if ( options.disabled ) {
+                                       return false;
+                               }
+                               $( this ).addClass( "ui-state-active" );
+                               that.buttonElement.attr( "aria-pressed", "true" );
+
+                               var radio = that.element[ 0 ];
+                               radioGroup( radio )
+                                       .not( radio )
+                                       .map(function() {
+                                               return $( this ).button( "widget" )[ 0 ];
+                                       })
+                                       .removeClass( "ui-state-active" )
+                                       .attr( "aria-pressed", "false" );
+                       });
+               } else {
+                       this.buttonElement
+                               .bind( "mousedown" + this.eventNamespace, function() {
+                                       if ( options.disabled ) {
+                                               return false;
+                                       }
+                                       $( this ).addClass( "ui-state-active" );
+                                       lastActive = this;
+                                       that.document.one( "mouseup", function() {
+                                               lastActive = null;
+                                       });
+                               })
+                               .bind( "mouseup" + this.eventNamespace, function() {
+                                       if ( options.disabled ) {
+                                               return false;
+                                       }
+                                       $( this ).removeClass( "ui-state-active" );
+                               })
+                               .bind( "keydown" + this.eventNamespace, function(event) {
+                                       if ( options.disabled ) {
+                                               return false;
+                                       }
+                                       if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
+                                               $( this ).addClass( "ui-state-active" );
+                                       }
+                               })
+                               // see #8559, we bind to blur here in case the button element loses
+                               // focus between keydown and keyup, it would be left in an "active" state
+                               .bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
+                                       $( this ).removeClass( "ui-state-active" );
+                               });
+
+                       if ( this.buttonElement.is("a") ) {
+                               this.buttonElement.keyup(function(event) {
+                                       if ( event.keyCode === $.ui.keyCode.SPACE ) {
+                                               // TODO pass through original event correctly (just as 2nd argument doesn't work)
+                                               $( this ).click();
+                                       }
+                               });
+                       }
+               }
+
+               this._setOption( "disabled", options.disabled );
+               this._resetButton();
+       },
+
+       _determineButtonType: function() {
+               var ancestor, labelSelector, checked;
+
+               if ( this.element.is("[type=checkbox]") ) {
+                       this.type = "checkbox";
+               } else if ( this.element.is("[type=radio]") ) {
+                       this.type = "radio";
+               } else if ( this.element.is("input") ) {
+                       this.type = "input";
+               } else {
+                       this.type = "button";
+               }
+
+               if ( this.type === "checkbox" || this.type === "radio" ) {
+                       // we don't search against the document in case the element
+                       // is disconnected from the DOM
+                       ancestor = this.element.parents().last();
+                       labelSelector = "label[for='" + this.element.attr("id") + "']";
+                       this.buttonElement = ancestor.find( labelSelector );
+                       if ( !this.buttonElement.length ) {
+                               ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
+                               this.buttonElement = ancestor.filter( labelSelector );
+                               if ( !this.buttonElement.length ) {
+                                       this.buttonElement = ancestor.find( labelSelector );
+                               }
+                       }
+                       this.element.addClass( "ui-helper-hidden-accessible" );
+
+                       checked = this.element.is( ":checked" );
+                       if ( checked ) {
+                               this.buttonElement.addClass( "ui-state-active" );
+                       }
+                       this.buttonElement.prop( "aria-pressed", checked );
+               } else {
+                       this.buttonElement = this.element;
+               }
+       },
+
+       widget: function() {
+               return this.buttonElement;
+       },
+
+       _destroy: function() {
+               this.element
+                       .removeClass( "ui-helper-hidden-accessible" );
+               this.buttonElement
+                       .removeClass( baseClasses + " ui-state-active " + typeClasses )
+                       .removeAttr( "role" )
+                       .removeAttr( "aria-pressed" )
+                       .html( this.buttonElement.find(".ui-button-text").html() );
+
+               if ( !this.hasTitle ) {
+                       this.buttonElement.removeAttr( "title" );
+               }
+       },
+
+       _setOption: function( key, value ) {
+               this._super( key, value );
+               if ( key === "disabled" ) {
+                       this.widget().toggleClass( "ui-state-disabled", !!value );
+                       this.element.prop( "disabled", !!value );
+                       if ( value ) {
+                               if ( this.type === "checkbox" || this.type === "radio" ) {
+                                       this.buttonElement.removeClass( "ui-state-focus" );
+                               } else {
+                                       this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
+                               }
+                       }
+                       return;
+               }
+               this._resetButton();
+       },
+
+       refresh: function() {
+               //See #8237 & #8828
+               var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );
+
+               if ( isDisabled !== this.options.disabled ) {
+                       this._setOption( "disabled", isDisabled );
+               }
+               if ( this.type === "radio" ) {
+                       radioGroup( this.element[0] ).each(function() {
+                               if ( $( this ).is( ":checked" ) ) {
+                                       $( this ).button( "widget" )
+                                               .addClass( "ui-state-active" )
+                                               .attr( "aria-pressed", "true" );
+                               } else {
+                                       $( this ).button( "widget" )
+                                               .removeClass( "ui-state-active" )
+                                               .attr( "aria-pressed", "false" );
+                               }
+                       });
+               } else if ( this.type === "checkbox" ) {
+                       if ( this.element.is( ":checked" ) ) {
+                               this.buttonElement
+                                       .addClass( "ui-state-active" )
+                                       .attr( "aria-pressed", "true" );
+                       } else {
+                               this.buttonElement
+                                       .removeClass( "ui-state-active" )
+                                       .attr( "aria-pressed", "false" );
+                       }
+               }
+       },
+
+       _resetButton: function() {
+               if ( this.type === "input" ) {
+                       if ( this.options.label ) {
+                               this.element.val( this.options.label );
+                       }
+                       return;
+               }
+               var buttonElement = this.buttonElement.removeClass( typeClasses ),
+                       buttonText = $( "<span></span>", this.document[0] )
+                               .addClass( "ui-button-text" )
+                               .html( this.options.label )
+                               .appendTo( buttonElement.empty() )
+                               .text(),
+                       icons = this.options.icons,
+                       multipleIcons = icons.primary && icons.secondary,
+                       buttonClasses = [];
+
+               if ( icons.primary || icons.secondary ) {
+                       if ( this.options.text ) {
+                               buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
+                       }
+
+                       if ( icons.primary ) {
+                               buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
+                       }
+
+                       if ( icons.secondary ) {
+                               buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
+                       }
+
+                       if ( !this.options.text ) {
+                               buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );
+
+                               if ( !this.hasTitle ) {
+                                       buttonElement.attr( "title", $.trim( buttonText ) );
+                               }
+                       }
+               } else {
+                       buttonClasses.push( "ui-button-text-only" );
+               }
+               buttonElement.addClass( buttonClasses.join( " " ) );
+       }
+});
+
+$.widget( "ui.buttonset", {
+       version: "1.11.2",
+       options: {
+               items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
+       },
+
+       _create: function() {
+               this.element.addClass( "ui-buttonset" );
+       },
+
+       _init: function() {
+               this.refresh();
+       },
+
+       _setOption: function( key, value ) {
+               if ( key === "disabled" ) {
+                       this.buttons.button( "option", key, value );
+               }
+
+               this._super( key, value );
+       },
+
+       refresh: function() {
+               var rtl = this.element.css( "direction" ) === "rtl",
+                       allButtons = this.element.find( this.options.items ),
+                       existingButtons = allButtons.filter( ":ui-button" );
+
+               // Initialize new buttons
+               allButtons.not( ":ui-button" ).button();
+
+               // Refresh existing buttons
+               existingButtons.button( "refresh" );
+
+               this.buttons = allButtons
+                       .map(function() {
+                               return $( this ).button( "widget" )[ 0 ];
+                       })
+                               .removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
+                               .filter( ":first" )
+                                       .addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
+                               .end()
+                               .filter( ":last" )
+                                       .addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
+                               .end()
+                       .end();
+       },
+
+       _destroy: function() {
+               this.element.removeClass( "ui-buttonset" );
+               this.buttons
+                       .map(function() {
+                               return $( this ).button( "widget" )[ 0 ];
+                       })
+                               .removeClass( "ui-corner-left ui-corner-right" )
+                       .end()
+                       .button( "destroy" );
+       }
+});
+
+var button = $.ui.button;
+
+
+/*!
+ * jQuery UI Datepicker 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/datepicker/
+ */
+
+
+$.extend($.ui, { datepicker: { version: "1.11.2" } });
+
+var datepicker_instActive;
+
+function datepicker_getZindex( elem ) {
+       var position, value;
+       while ( elem.length && elem[ 0 ] !== document ) {
+               // Ignore z-index if position is set to a value where z-index is ignored by the browser
+               // This makes behavior of this function consistent across browsers
+               // WebKit always returns auto if the element is positioned
+               position = elem.css( "position" );
+               if ( position === "absolute" || position === "relative" || position === "fixed" ) {
+                       // IE returns 0 when zIndex is not specified
+                       // other browsers return a string
+                       // we ignore the case of nested elements with an explicit value of 0
+                       // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
+                       value = parseInt( elem.css( "zIndex" ), 10 );
+                       if ( !isNaN( value ) && value !== 0 ) {
+                               return value;
+                       }
+               }
+               elem = elem.parent();
+       }
+
+       return 0;
+}
+/* Date picker manager.
+   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
+   Settings for (groups of) date pickers are maintained in an instance object,
+   allowing multiple different settings on the same page. */
+
+function Datepicker() {
+       this._curInst = null; // The current instance in use
+       this._keyEvent = false; // If the last event was a key event
+       this._disabledInputs = []; // List of date picker inputs that have been disabled
+       this._datepickerShowing = false; // True if the popup picker is showing , false if not
+       this._inDialog = false; // True if showing within a "dialog", false if not
+       this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
+       this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
+       this._appendClass = "ui-datepicker-append"; // The name of the append marker class
+       this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
+       this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
+       this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
+       this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
+       this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
+       this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
+       this.regional = []; // Available regional settings, indexed by language code
+       this.regional[""] = { // Default regional settings
+               closeText: "Done", // Display text for close link
+               prevText: "Prev", // Display text for previous month link
+               nextText: "Next", // Display text for next month link
+               currentText: "Today", // Display text for current month link
+               monthNames: ["January","February","March","April","May","June",
+                       "July","August","September","October","November","December"], // Names of months for drop-down and formatting
+               monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
+               dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
+               dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
+               dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
+               weekHeader: "Wk", // Column header for week of the year
+               dateFormat: "mm/dd/yy", // See format options on parseDate
+               firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
+               isRTL: false, // True if right-to-left language, false if left-to-right
+               showMonthAfterYear: false, // True if the year select precedes month, false for month then year
+               yearSuffix: "" // Additional text to append to the year in the month headers
+       };
+       this._defaults = { // Global defaults for all the date picker instances
+               showOn: "focus", // "focus" for popup on focus,
+                       // "button" for trigger button, or "both" for either
+               showAnim: "fadeIn", // Name of jQuery animation for popup
+               showOptions: {}, // Options for enhanced animations
+               defaultDate: null, // Used when field is blank: actual date,
+                       // +/-number for offset from today, null for today
+               appendText: "", // Display text following the input box, e.g. showing the format
+               buttonText: "...", // Text for trigger button
+               buttonImage: "", // URL for trigger button image
+               buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
+               hideIfNoPrevNext: false, // True to hide next/previous month links
+                       // if not applicable, false to just disable them
+               navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
+               gotoCurrent: false, // True if today link goes back to current selection instead
+               changeMonth: false, // True if month can be selected directly, false if only prev/next
+               changeYear: false, // True if year can be selected directly, false if only prev/next
+               yearRange: "c-10:c+10", // Range of years to display in drop-down,
+                       // either relative to today's year (-nn:+nn), relative to currently displayed year
+                       // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
+               showOtherMonths: false, // True to show dates in other months, false to leave blank
+               selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
+               showWeek: false, // True to show week of the year, false to not show it
+               calculateWeek: this.iso8601Week, // How to calculate the week of the year,
+                       // takes a Date and returns the number of the week for it
+               shortYearCutoff: "+10", // Short year values < this are in the current century,
+                       // > this are in the previous century,
+                       // string value starting with "+" for current year + value
+               minDate: null, // The earliest selectable date, or null for no limit
+               maxDate: null, // The latest selectable date, or null for no limit
+               duration: "fast", // Duration of display/closure
+               beforeShowDay: null, // Function that takes a date and returns an array with
+                       // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
+                       // [2] = cell title (optional), e.g. $.datepicker.noWeekends
+               beforeShow: null, // Function that takes an input field and
+                       // returns a set of custom settings for the date picker
+               onSelect: null, // Define a callback function when a date is selected
+               onChangeMonthYear: null, // Define a callback function when the month or year is changed
+               onClose: null, // Define a callback function when the datepicker is closed
+               numberOfMonths: 1, // Number of months to show at a time
+               showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
+               stepMonths: 1, // Number of months to step back/forward
+               stepBigMonths: 12, // Number of months to step back/forward for the big links
+               altField: "", // Selector for an alternate field to store selected dates into
+               altFormat: "", // The date format to use for the alternate field
+               constrainInput: true, // The input is constrained by the current date format
+               showButtonPanel: false, // True to show button panel, false to not show it
+               autoSize: false, // True to size the input for the date format, false to leave as is
+               disabled: false // The initial disabled state
+       };
+       $.extend(this._defaults, this.regional[""]);
+       this.regional.en = $.extend( true, {}, this.regional[ "" ]);
+       this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
+       this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
+}
+
+$.extend(Datepicker.prototype, {
+       /* Class name added to elements to indicate already configured with a date picker. */
+       markerClassName: "hasDatepicker",
+
+       //Keep track of the maximum number of rows displayed (see #7043)
+       maxRows: 4,
+
+       // TODO rename to "widget" when switching to widget factory
+       _widgetDatepicker: function() {
+               return this.dpDiv;
+       },
+
+       /* Override the default settings for all instances of the date picker.
+        * @param  settings  object - the new settings to use as defaults (anonymous object)
+        * @return the manager object
+        */
+       setDefaults: function(settings) {
+               datepicker_extendRemove(this._defaults, settings || {});
+               return this;
+       },
+
+       /* Attach the date picker to a jQuery selection.
+        * @param  target       element - the target input field or division or span
+        * @param  settings  object - the new settings to use for this date picker instance (anonymous)
+        */
+       _attachDatepicker: function(target, settings) {
+               var nodeName, inline, inst;
+               nodeName = target.nodeName.toLowerCase();
+               inline = (nodeName === "div" || nodeName === "span");
+               if (!target.id) {
+                       this.uuid += 1;
+                       target.id = "dp" + this.uuid;
+               }
+               inst = this._newInst($(target), inline);
+               inst.settings = $.extend({}, settings || {});
+               if (nodeName === "input") {
+                       this._connectDatepicker(target, inst);
+               } else if (inline) {
+                       this._inlineDatepicker(target, inst);
+               }
+       },
+
+       /* Create a new instance object. */
+       _newInst: function(target, inline) {
+               var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
+               return {id: id, input: target, // associated target
+                       selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
+                       drawMonth: 0, drawYear: 0, // month being drawn
+                       inline: inline, // is datepicker inline or not
+                       dpDiv: (!inline ? this.dpDiv : // presentation div
+                       datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
+       },
+
+       /* Attach the date picker to an input field. */
+       _connectDatepicker: function(target, inst) {
+               var input = $(target);
+               inst.append = $([]);
+               inst.trigger = $([]);
+               if (input.hasClass(this.markerClassName)) {
+                       return;
+               }
+               this._attachments(input, inst);
+               input.addClass(this.markerClassName).keydown(this._doKeyDown).
+                       keypress(this._doKeyPress).keyup(this._doKeyUp);
+               this._autoSize(inst);
+               $.data(target, "datepicker", inst);
+               //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
+               if( inst.settings.disabled ) {
+                       this._disableDatepicker( target );
+               }
+       },
+
+       /* Make attachments based on settings. */
+       _attachments: function(input, inst) {
+               var showOn, buttonText, buttonImage,
+                       appendText = this._get(inst, "appendText"),
+                       isRTL = this._get(inst, "isRTL");
+
+               if (inst.append) {
+                       inst.append.remove();
+               }
+               if (appendText) {
+                       inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
+                       input[isRTL ? "before" : "after"](inst.append);
+               }
+
+               input.unbind("focus", this._showDatepicker);
+
+               if (inst.trigger) {
+                       inst.trigger.remove();
+               }
+
+               showOn = this._get(inst, "showOn");
+               if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
+                       input.focus(this._showDatepicker);
+               }
+               if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
+                       buttonText = this._get(inst, "buttonText");
+                       buttonImage = this._get(inst, "buttonImage");
+                       inst.trigger = $(this._get(inst, "buttonImageOnly") ?
+                               $("<img/>").addClass(this._triggerClass).
+                                       attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
+                               $("<button type='button'></button>").addClass(this._triggerClass).
+                                       html(!buttonImage ? buttonText : $("<img/>").attr(
+                                       { src:buttonImage, alt:buttonText, title:buttonText })));
+                       input[isRTL ? "before" : "after"](inst.trigger);
+                       inst.trigger.click(function() {
+                               if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
+                                       $.datepicker._hideDatepicker();
+                               } else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
+                                       $.datepicker._hideDatepicker();
+                                       $.datepicker._showDatepicker(input[0]);
+                               } else {
+                                       $.datepicker._showDatepicker(input[0]);
+                               }
+                               return false;
+                       });
+               }
+       },
+
+       /* Apply the maximum length for the date format. */
+       _autoSize: function(inst) {
+               if (this._get(inst, "autoSize") && !inst.inline) {
+                       var findMax, max, maxI, i,
+                               date = new Date(2009, 12 - 1, 20), // Ensure double digits
+                               dateFormat = this._get(inst, "dateFormat");
+
+                       if (dateFormat.match(/[DM]/)) {
+                               findMax = function(names) {
+                                       max = 0;
+                                       maxI = 0;
+                                       for (i = 0; i < names.length; i++) {
+                                               if (names[i].length > max) {
+                                                       max = names[i].length;
+                                                       maxI = i;
+                                               }
+                                       }
+                                       return maxI;
+                               };
+                               date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
+                                       "monthNames" : "monthNamesShort"))));
+                               date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
+                                       "dayNames" : "dayNamesShort"))) + 20 - date.getDay());
+                       }
+                       inst.input.attr("size", this._formatDate(inst, date).length);
+               }
+       },
+
+       /* Attach an inline date picker to a div. */
+       _inlineDatepicker: function(target, inst) {
+               var divSpan = $(target);
+               if (divSpan.hasClass(this.markerClassName)) {
+                       return;
+               }
+               divSpan.addClass(this.markerClassName).append(inst.dpDiv);
+               $.data(target, "datepicker", inst);
+               this._setDate(inst, this._getDefaultDate(inst), true);
+               this._updateDatepicker(inst);
+               this._updateAlternate(inst);
+               //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
+               if( inst.settings.disabled ) {
+                       this._disableDatepicker( target );
+               }
+               // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
+               // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
+               inst.dpDiv.css( "display", "block" );
+       },
+
+       /* Pop-up the date picker in a "dialog" box.
+        * @param  input element - ignored
+        * @param  date string or Date - the initial date to display
+        * @param  onSelect  function - the function to call when a date is selected
+        * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
+        * @param  pos int[2] - coordinates for the dialog's position within the screen or
+        *                                      event - with x/y coordinates or
+        *                                      leave empty for default (screen centre)
+        * @return the manager object
+        */
+       _dialogDatepicker: function(input, date, onSelect, settings, pos) {
+               var id, browserWidth, browserHeight, scrollX, scrollY,
+                       inst = this._dialogInst; // internal instance
+
+               if (!inst) {
+                       this.uuid += 1;
+                       id = "dp" + this.uuid;
+                       this._dialogInput = $("<input type='text' id='" + id +
+                               "' style='position: absolute; top: -100px; width: 0px;'/>");
+                       this._dialogInput.keydown(this._doKeyDown);
+                       $("body").append(this._dialogInput);
+                       inst = this._dialogInst = this._newInst(this._dialogInput, false);
+                       inst.settings = {};
+                       $.data(this._dialogInput[0], "datepicker", inst);
+               }
+               datepicker_extendRemove(inst.settings, settings || {});
+               date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
+               this._dialogInput.val(date);
+
+               this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
+               if (!this._pos) {
+                       browserWidth = document.documentElement.clientWidth;
+                       browserHeight = document.documentElement.clientHeight;
+                       scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
+                       scrollY = document.documentElement.scrollTop || document.body.scrollTop;
+                       this._pos = // should use actual width/height below
+                               [(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
+               }
+
+               // move input on screen for focus, but hidden behind dialog
+               this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
+               inst.settings.onSelect = onSelect;
+               this._inDialog = true;
+               this.dpDiv.addClass(this._dialogClass);
+               this._showDatepicker(this._dialogInput[0]);
+               if ($.blockUI) {
+                       $.blockUI(this.dpDiv);
+               }
+               $.data(this._dialogInput[0], "datepicker", inst);
+               return this;
+       },
+
+       /* Detach a datepicker from its control.
+        * @param  target       element - the target input field or division or span
+        */
+       _destroyDatepicker: function(target) {
+               var nodeName,
+                       $target = $(target),
+                       inst = $.data(target, "datepicker");
+
+               if (!$target.hasClass(this.markerClassName)) {
+                       return;
+               }
+
+               nodeName = target.nodeName.toLowerCase();
+               $.removeData(target, "datepicker");
+               if (nodeName === "input") {
+                       inst.append.remove();
+                       inst.trigger.remove();
+                       $target.removeClass(this.markerClassName).
+                               unbind("focus", this._showDatepicker).
+                               unbind("keydown", this._doKeyDown).
+                               unbind("keypress", this._doKeyPress).
+                               unbind("keyup", this._doKeyUp);
+               } else if (nodeName === "div" || nodeName === "span") {
+                       $target.removeClass(this.markerClassName).empty();
+               }
+       },
+
+       /* Enable the date picker to a jQuery selection.
+        * @param  target       element - the target input field or division or span
+        */
+       _enableDatepicker: function(target) {
+               var nodeName, inline,
+                       $target = $(target),
+                       inst = $.data(target, "datepicker");
+
+               if (!$target.hasClass(this.markerClassName)) {
+                       return;
+               }
+
+               nodeName = target.nodeName.toLowerCase();
+               if (nodeName === "input") {
+                       target.disabled = false;
+                       inst.trigger.filter("button").
+                               each(function() { this.disabled = false; }).end().
+                               filter("img").css({opacity: "1.0", cursor: ""});
+               } else if (nodeName === "div" || nodeName === "span") {
+                       inline = $target.children("." + this._inlineClass);
+                       inline.children().removeClass("ui-state-disabled");
+                       inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+                               prop("disabled", false);
+               }
+               this._disabledInputs = $.map(this._disabledInputs,
+                       function(value) { return (value === target ? null : value); }); // delete entry
+       },
+
+       /* Disable the date picker to a jQuery selection.
+        * @param  target       element - the target input field or division or span
+        */
+       _disableDatepicker: function(target) {
+               var nodeName, inline,
+                       $target = $(target),
+                       inst = $.data(target, "datepicker");
+
+               if (!$target.hasClass(this.markerClassName)) {
+                       return;
+               }
+
+               nodeName = target.nodeName.toLowerCase();
+               if (nodeName === "input") {
+                       target.disabled = true;
+                       inst.trigger.filter("button").
+                               each(function() { this.disabled = true; }).end().
+                               filter("img").css({opacity: "0.5", cursor: "default"});
+               } else if (nodeName === "div" || nodeName === "span") {
+                       inline = $target.children("." + this._inlineClass);
+                       inline.children().addClass("ui-state-disabled");
+                       inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
+                               prop("disabled", true);
+               }
+               this._disabledInputs = $.map(this._disabledInputs,
+                       function(value) { return (value === target ? null : value); }); // delete entry
+               this._disabledInputs[this._disabledInputs.length] = target;
+       },
+
+       /* Is the first field in a jQuery collection disabled as a datepicker?
+        * @param  target       element - the target input field or division or span
+        * @return boolean - true if disabled, false if enabled
+        */
+       _isDisabledDatepicker: function(target) {
+               if (!target) {
+                       return false;
+               }
+               for (var i = 0; i < this._disabledInputs.length; i++) {
+                       if (this._disabledInputs[i] === target) {
+                               return true;
+                       }
+               }
+               return false;
+       },
+
+       /* Retrieve the instance data for the target control.
+        * @param  target  element - the target input field or division or span
+        * @return  object - the associated instance data
+        * @throws  error if a jQuery problem getting data
+        */
+       _getInst: function(target) {
+               try {
+                       return $.data(target, "datepicker");
+               }
+               catch (err) {
+                       throw "Missing instance data for this datepicker";
+               }
+       },
+
+       /* Update or retrieve the settings for a date picker attached to an input field or division.
+        * @param  target  element - the target input field or division or span
+        * @param  name object - the new settings to update or
+        *                              string - the name of the setting to change or retrieve,
+        *                              when retrieving also "all" for all instance settings or
+        *                              "defaults" for all global defaults
+        * @param  value   any - the new value for the setting
+        *                              (omit if above is an object or to retrieve a value)
+        */
+       _optionDatepicker: function(target, name, value) {
+               var settings, date, minDate, maxDate,
+                       inst = this._getInst(target);
+
+               if (arguments.length === 2 && typeof name === "string") {
+                       return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
+                               (inst ? (name === "all" ? $.extend({}, inst.settings) :
+                               this._get(inst, name)) : null));
+               }
+
+               settings = name || {};
+               if (typeof name === "string") {
+                       settings = {};
+                       settings[name] = value;
+               }
+
+               if (inst) {
+                       if (this._curInst === inst) {
+                               this._hideDatepicker();
+                       }
+
+                       date = this._getDateDatepicker(target, true);
+                       minDate = this._getMinMaxDate(inst, "min");
+                       maxDate = this._getMinMaxDate(inst, "max");
+                       datepicker_extendRemove(inst.settings, settings);
+                       // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
+                       if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
+                               inst.settings.minDate = this._formatDate(inst, minDate);
+                       }
+                       if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
+                               inst.settings.maxDate = this._formatDate(inst, maxDate);
+                       }
+                       if ( "disabled" in settings ) {
+                               if ( settings.disabled ) {
+                                       this._disableDatepicker(target);
+                               } else {
+                                       this._enableDatepicker(target);
+                               }
+                       }
+                       this._attachments($(target), inst);
+                       this._autoSize(inst);
+                       this._setDate(inst, date);
+                       this._updateAlternate(inst);
+                       this._updateDatepicker(inst);
+               }
+       },
+
+       // change method deprecated
+       _changeDatepicker: function(target, name, value) {
+               this._optionDatepicker(target, name, value);
+       },
+
+       /* Redraw the date picker attached to an input field or division.
+        * @param  target  element - the target input field or division or span
+        */
+       _refreshDatepicker: function(target) {
+               var inst = this._getInst(target);
+               if (inst) {
+                       this._updateDatepicker(inst);
+               }
+       },
+
+       /* Set the dates for a jQuery selection.
+        * @param  target element - the target input field or division or span
+        * @param  date Date - the new date
+        */
+       _setDateDatepicker: function(target, date) {
+               var inst = this._getInst(target);
+               if (inst) {
+                       this._setDate(inst, date);
+                       this._updateDatepicker(inst);
+                       this._updateAlternate(inst);
+               }
+       },
+
+       /* Get the date(s) for the first entry in a jQuery selection.
+        * @param  target element - the target input field or division or span
+        * @param  noDefault boolean - true if no default date is to be used
+        * @return Date - the current date
+        */
+       _getDateDatepicker: function(target, noDefault) {
+               var inst = this._getInst(target);
+               if (inst && !inst.inline) {
+                       this._setDateFromField(inst, noDefault);
+               }
+               return (inst ? this._getDate(inst) : null);
+       },
+
+       /* Handle keystrokes. */
+       _doKeyDown: function(event) {
+               var onSelect, dateStr, sel,
+                       inst = $.datepicker._getInst(event.target),
+                       handled = true,
+                       isRTL = inst.dpDiv.is(".ui-datepicker-rtl");
+
+               inst._keyEvent = true;
+               if ($.datepicker._datepickerShowing) {
+                       switch (event.keyCode) {
+                               case 9: $.datepicker._hideDatepicker();
+                                               handled = false;
+                                               break; // hide on tab out
+                               case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
+                                                                       $.datepicker._currentClass + ")", inst.dpDiv);
+                                               if (sel[0]) {
+                                                       $.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
+                                               }
+
+                                               onSelect = $.datepicker._get(inst, "onSelect");
+                                               if (onSelect) {
+                                                       dateStr = $.datepicker._formatDate(inst);
+
+                                                       // trigger custom callback
+                                                       onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
+                                               } else {
+                                                       $.datepicker._hideDatepicker();
+                                               }
+
+                                               return false; // don't submit the form
+                               case 27: $.datepicker._hideDatepicker();
+                                               break; // hide on escape
+                               case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+                                                       -$.datepicker._get(inst, "stepBigMonths") :
+                                                       -$.datepicker._get(inst, "stepMonths")), "M");
+                                               break; // previous month/year on page up/+ ctrl
+                               case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+                                                       +$.datepicker._get(inst, "stepBigMonths") :
+                                                       +$.datepicker._get(inst, "stepMonths")), "M");
+                                               break; // next month/year on page down/+ ctrl
+                               case 35: if (event.ctrlKey || event.metaKey) {
+                                                       $.datepicker._clearDate(event.target);
+                                               }
+                                               handled = event.ctrlKey || event.metaKey;
+                                               break; // clear on ctrl or command +end
+                               case 36: if (event.ctrlKey || event.metaKey) {
+                                                       $.datepicker._gotoToday(event.target);
+                                               }
+                                               handled = event.ctrlKey || event.metaKey;
+                                               break; // current on ctrl or command +home
+                               case 37: if (event.ctrlKey || event.metaKey) {
+                                                       $.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
+                                               }
+                                               handled = event.ctrlKey || event.metaKey;
+                                               // -1 day on ctrl or command +left
+                                               if (event.originalEvent.altKey) {
+                                                       $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+                                                               -$.datepicker._get(inst, "stepBigMonths") :
+                                                               -$.datepicker._get(inst, "stepMonths")), "M");
+                                               }
+                                               // next month/year on alt +left on Mac
+                                               break;
+                               case 38: if (event.ctrlKey || event.metaKey) {
+                                                       $.datepicker._adjustDate(event.target, -7, "D");
+                                               }
+                                               handled = event.ctrlKey || event.metaKey;
+                                               break; // -1 week on ctrl or command +up
+                               case 39: if (event.ctrlKey || event.metaKey) {
+                                                       $.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
+                                               }
+                                               handled = event.ctrlKey || event.metaKey;
+                                               // +1 day on ctrl or command +right
+                                               if (event.originalEvent.altKey) {
+                                                       $.datepicker._adjustDate(event.target, (event.ctrlKey ?
+                                                               +$.datepicker._get(inst, "stepBigMonths") :
+                                                               +$.datepicker._get(inst, "stepMonths")), "M");
+                                               }
+                                               // next month/year on alt +right
+                                               break;
+                               case 40: if (event.ctrlKey || event.metaKey) {
+                                                       $.datepicker._adjustDate(event.target, +7, "D");
+                                               }
+                                               handled = event.ctrlKey || event.metaKey;
+                                               break; // +1 week on ctrl or command +down
+                               default: handled = false;
+                       }
+               } else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
+                       $.datepicker._showDatepicker(this);
+               } else {
+                       handled = false;
+               }
+
+               if (handled) {
+                       event.preventDefault();
+                       event.stopPropagation();
+               }
+       },
+
+       /* Filter entered characters - based on date format. */
+       _doKeyPress: function(event) {
+               var chars, chr,
+                       inst = $.datepicker._getInst(event.target);
+
+               if ($.datepicker._get(inst, "constrainInput")) {
+                       chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
+                       chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
+                       return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
+               }
+       },
+
+       /* Synchronise manual entry and field/alternate field. */
+       _doKeyUp: function(event) {
+               var date,
+                       inst = $.datepicker._getInst(event.target);
+
+               if (inst.input.val() !== inst.lastVal) {
+                       try {
+                               date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+                                       (inst.input ? inst.input.val() : null),
+                                       $.datepicker._getFormatConfig(inst));
+
+                               if (date) { // only if valid
+                                       $.datepicker._setDateFromField(inst);
+                                       $.datepicker._updateAlternate(inst);
+                                       $.datepicker._updateDatepicker(inst);
+                               }
+                       }
+                       catch (err) {
+                       }
+               }
+               return true;
+       },
+
+       /* Pop-up the date picker for a given input field.
+        * If false returned from beforeShow event handler do not show.
+        * @param  input  element - the input field attached to the date picker or
+        *                                      event - if triggered by focus
+        */
+       _showDatepicker: function(input) {
+               input = input.target || input;
+               if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
+                       input = $("input", input.parentNode)[0];
+               }
+
+               if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
+                       return;
+               }
+
+               var inst, beforeShow, beforeShowSettings, isFixed,
+                       offset, showAnim, duration;
+
+               inst = $.datepicker._getInst(input);
+               if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
+                       $.datepicker._curInst.dpDiv.stop(true, true);
+                       if ( inst && $.datepicker._datepickerShowing ) {
+                               $.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
+                       }
+               }
+
+               beforeShow = $.datepicker._get(inst, "beforeShow");
+               beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
+               if(beforeShowSettings === false){
+                       return;
+               }
+               datepicker_extendRemove(inst.settings, beforeShowSettings);
+
+               inst.lastVal = null;
+               $.datepicker._lastInput = input;
+               $.datepicker._setDateFromField(inst);
+
+               if ($.datepicker._inDialog) { // hide cursor
+                       input.value = "";
+               }
+               if (!$.datepicker._pos) { // position below input
+                       $.datepicker._pos = $.datepicker._findPos(input);
+                       $.datepicker._pos[1] += input.offsetHeight; // add the height
+               }
+
+               isFixed = false;
+               $(input).parents().each(function() {
+                       isFixed |= $(this).css("position") === "fixed";
+                       return !isFixed;
+               });
+
+               offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
+               $.datepicker._pos = null;
+               //to avoid flashes on Firefox
+               inst.dpDiv.empty();
+               // determine sizing offscreen
+               inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
+               $.datepicker._updateDatepicker(inst);
+               // fix width for dynamic number of date pickers
+               // and adjust position before showing
+               offset = $.datepicker._checkOffset(inst, offset, isFixed);
+               inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
+                       "static" : (isFixed ? "fixed" : "absolute")), display: "none",
+                       left: offset.left + "px", top: offset.top + "px"});
+
+               if (!inst.inline) {
+                       showAnim = $.datepicker._get(inst, "showAnim");
+                       duration = $.datepicker._get(inst, "duration");
+                       inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
+                       $.datepicker._datepickerShowing = true;
+
+                       if ( $.effects && $.effects.effect[ showAnim ] ) {
+                               inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
+                       } else {
+                               inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
+                       }
+
+                       if ( $.datepicker._shouldFocusInput( inst ) ) {
+                               inst.input.focus();
+                       }
+
+                       $.datepicker._curInst = inst;
+               }
+       },
+
+       /* Generate the date picker content. */
+       _updateDatepicker: function(inst) {
+               this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
+               datepicker_instActive = inst; // for delegate hover events
+               inst.dpDiv.empty().append(this._generateHTML(inst));
+               this._attachHandlers(inst);
+
+               var origyearshtml,
+                       numMonths = this._getNumberOfMonths(inst),
+                       cols = numMonths[1],
+                       width = 17,
+                       activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
+
+               if ( activeCell.length > 0 ) {
+                       datepicker_handleMouseover.apply( activeCell.get( 0 ) );
+               }
+
+               inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
+               if (cols > 1) {
+                       inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
+               }
+               inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
+                       "Class"]("ui-datepicker-multi");
+               inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
+                       "Class"]("ui-datepicker-rtl");
+
+               if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
+                       inst.input.focus();
+               }
+
+               // deffered render of the years select (to avoid flashes on Firefox)
+               if( inst.yearshtml ){
+                       origyearshtml = inst.yearshtml;
+                       setTimeout(function(){
+                               //assure that inst.yearshtml didn't change.
+                               if( origyearshtml === inst.yearshtml && inst.yearshtml ){
+                                       inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
+                               }
+                               origyearshtml = inst.yearshtml = null;
+                       }, 0);
+               }
+       },
+
+       // #6694 - don't focus the input if it's already focused
+       // this breaks the change event in IE
+       // Support: IE and jQuery <1.9
+       _shouldFocusInput: function( inst ) {
+               return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
+       },
+
+       /* Check positioning to remain on screen. */
+       _checkOffset: function(inst, offset, isFixed) {
+               var dpWidth = inst.dpDiv.outerWidth(),
+                       dpHeight = inst.dpDiv.outerHeight(),
+                       inputWidth = inst.input ? inst.input.outerWidth() : 0,
+                       inputHeight = inst.input ? inst.input.outerHeight() : 0,
+                       viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
+                       viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());
+
+               offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
+               offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
+               offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;
+
+               // now check if datepicker is showing outside window viewport - move to a better place if so.
+               offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
+                       Math.abs(offset.left + dpWidth - viewWidth) : 0);
+               offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
+                       Math.abs(dpHeight + inputHeight) : 0);
+
+               return offset;
+       },
+
+       /* Find an object's position on the screen. */
+       _findPos: function(obj) {
+               var position,
+                       inst = this._getInst(obj),
+                       isRTL = this._get(inst, "isRTL");
+
+               while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
+                       obj = obj[isRTL ? "previousSibling" : "nextSibling"];
+               }
+
+               position = $(obj).offset();
+               return [position.left, position.top];
+       },
+
+       /* Hide the date picker from view.
+        * @param  input  element - the input field attached to the date picker
+        */
+       _hideDatepicker: function(input) {
+               var showAnim, duration, postProcess, onClose,
+                       inst = this._curInst;
+
+               if (!inst || (input && inst !== $.data(input, "datepicker"))) {
+                       return;
+               }
+
+               if (this._datepickerShowing) {
+                       showAnim = this._get(inst, "showAnim");
+                       duration = this._get(inst, "duration");
+                       postProcess = function() {
+                               $.datepicker._tidyDialog(inst);
+                       };
+
+                       // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
+                       if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
+                               inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
+                       } else {
+                               inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
+                                       (showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
+                       }
+
+                       if (!showAnim) {
+                               postProcess();
+                       }
+                       this._datepickerShowing = false;
+
+                       onClose = this._get(inst, "onClose");
+                       if (onClose) {
+                               onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
+                       }
+
+                       this._lastInput = null;
+                       if (this._inDialog) {
+                               this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
+                               if ($.blockUI) {
+                                       $.unblockUI();
+                                       $("body").append(this.dpDiv);
+                               }
+                       }
+                       this._inDialog = false;
+               }
+       },
+
+       /* Tidy up after a dialog display. */
+       _tidyDialog: function(inst) {
+               inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
+       },
+
+       /* Close date picker if clicked elsewhere. */
+       _checkExternalClick: function(event) {
+               if (!$.datepicker._curInst) {
+                       return;
+               }
+
+               var $target = $(event.target),
+                       inst = $.datepicker._getInst($target[0]);
+
+               if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
+                               $target.parents("#" + $.datepicker._mainDivId).length === 0 &&
+                               !$target.hasClass($.datepicker.markerClassName) &&
+                               !$target.closest("." + $.datepicker._triggerClass).length &&
+                               $.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
+                       ( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
+                               $.datepicker._hideDatepicker();
+               }
+       },
+
+       /* Adjust one of the date sub-fields. */
+       _adjustDate: function(id, offset, period) {
+               var target = $(id),
+                       inst = this._getInst(target[0]);
+
+               if (this._isDisabledDatepicker(target[0])) {
+                       return;
+               }
+               this._adjustInstDate(inst, offset +
+                       (period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
+                       period);
+               this._updateDatepicker(inst);
+       },
+
+       /* Action for current link. */
+       _gotoToday: function(id) {
+               var date,
+                       target = $(id),
+                       inst = this._getInst(target[0]);
+
+               if (this._get(inst, "gotoCurrent") && inst.currentDay) {
+                       inst.selectedDay = inst.currentDay;
+                       inst.drawMonth = inst.selectedMonth = inst.currentMonth;
+                       inst.drawYear = inst.selectedYear = inst.currentYear;
+               } else {
+                       date = new Date();
+                       inst.selectedDay = date.getDate();
+                       inst.drawMonth = inst.selectedMonth = date.getMonth();
+                       inst.drawYear = inst.selectedYear = date.getFullYear();
+               }
+               this._notifyChange(inst);
+               this._adjustDate(target);
+       },
+
+       /* Action for selecting a new month/year. */
+       _selectMonthYear: function(id, select, period) {
+               var target = $(id),
+                       inst = this._getInst(target[0]);
+
+               inst["selected" + (period === "M" ? "Month" : "Year")] =
+               inst["draw" + (period === "M" ? "Month" : "Year")] =
+                       parseInt(select.options[select.selectedIndex].value,10);
+
+               this._notifyChange(inst);
+               this._adjustDate(target);
+       },
+
+       /* Action for selecting a day. */
+       _selectDay: function(id, month, year, td) {
+               var inst,
+                       target = $(id);
+
+               if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
+                       return;
+               }
+
+               inst = this._getInst(target[0]);
+               inst.selectedDay = inst.currentDay = $("a", td).html();
+               inst.selectedMonth = inst.currentMonth = month;
+               inst.selectedYear = inst.currentYear = year;
+               this._selectDate(id, this._formatDate(inst,
+                       inst.currentDay, inst.currentMonth, inst.currentYear));
+       },
+
+       /* Erase the input field and hide the date picker. */
+       _clearDate: function(id) {
+               var target = $(id);
+               this._selectDate(target, "");
+       },
+
+       /* Update the input field with the selected date. */
+       _selectDate: function(id, dateStr) {
+               var onSelect,
+                       target = $(id),
+                       inst = this._getInst(target[0]);
+
+               dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
+               if (inst.input) {
+                       inst.input.val(dateStr);
+               }
+               this._updateAlternate(inst);
+
+               onSelect = this._get(inst, "onSelect");
+               if (onSelect) {
+                       onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);  // trigger custom callback
+               } else if (inst.input) {
+                       inst.input.trigger("change"); // fire the change event
+               }
+
+               if (inst.inline){
+                       this._updateDatepicker(inst);
+               } else {
+                       this._hideDatepicker();
+                       this._lastInput = inst.input[0];
+                       if (typeof(inst.input[0]) !== "object") {
+                               inst.input.focus(); // restore focus
+                       }
+                       this._lastInput = null;
+               }
+       },
+
+       /* Update any alternate field to synchronise with the main field. */
+       _updateAlternate: function(inst) {
+               var altFormat, date, dateStr,
+                       altField = this._get(inst, "altField");
+
+               if (altField) { // update alternate field too
+                       altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
+                       date = this._getDate(inst);
+                       dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
+                       $(altField).each(function() { $(this).val(dateStr); });
+               }
+       },
+
+       /* Set as beforeShowDay function to prevent selection of weekends.
+        * @param  date  Date - the date to customise
+        * @return [boolean, string] - is this date selectable?, what is its CSS class?
+        */
+       noWeekends: function(date) {
+               var day = date.getDay();
+               return [(day > 0 && day < 6), ""];
+       },
+
+       /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
+        * @param  date  Date - the date to get the week for
+        * @return  number - the number of the week within the year that contains this date
+        */
+       iso8601Week: function(date) {
+               var time,
+                       checkDate = new Date(date.getTime());
+
+               // Find Thursday of this week starting on Monday
+               checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));
+
+               time = checkDate.getTime();
+               checkDate.setMonth(0); // Compare with Jan 1
+               checkDate.setDate(1);
+               return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
+       },
+
+       /* Parse a string value into a date object.
+        * See formatDate below for the possible formats.
+        *
+        * @param  format string - the expected format of the date
+        * @param  value string - the date in the above format
+        * @param  settings Object - attributes include:
+        *                                      shortYearCutoff  number - the cutoff year for determining the century (optional)
+        *                                      dayNamesShort   string[7] - abbreviated names of the days from Sunday (optional)
+        *                                      dayNames                string[7] - names of the days from Sunday (optional)
+        *                                      monthNamesShort string[12] - abbreviated names of the months (optional)
+        *                                      monthNames              string[12] - names of the months (optional)
+        * @return  Date - the extracted date value or null if value is blank
+        */
+       parseDate: function (format, value, settings) {
+               if (format == null || value == null) {
+                       throw "Invalid arguments";
+               }
+
+               value = (typeof value === "object" ? value.toString() : value + "");
+               if (value === "") {
+                       return null;
+               }
+
+               var iFormat, dim, extra,
+                       iValue = 0,
+                       shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
+                       shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
+                               new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
+                       dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+                       dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+                       monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+                       monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+                       year = -1,
+                       month = -1,
+                       day = -1,
+                       doy = -1,
+                       literal = false,
+                       date,
+                       // Check whether a format character is doubled
+                       lookAhead = function(match) {
+                               var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+                               if (matches) {
+                                       iFormat++;
+                               }
+                               return matches;
+                       },
+                       // Extract a number from the string value
+                       getNumber = function(match) {
+                               var isDoubled = lookAhead(match),
+                                       size = (match === "@" ? 14 : (match === "!" ? 20 :
+                                       (match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
+                                       minSize = (match === "y" ? size : 1),
+                                       digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
+                                       num = value.substring(iValue).match(digits);
+                               if (!num) {
+                                       throw "Missing number at position " + iValue;
+                               }
+                               iValue += num[0].length;
+                               return parseInt(num[0], 10);
+                       },
+                       // Extract a name from the string value and convert to an index
+                       getName = function(match, shortNames, longNames) {
+                               var index = -1,
+                                       names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
+                                               return [ [k, v] ];
+                                       }).sort(function (a, b) {
+                                               return -(a[1].length - b[1].length);
+                                       });
+
+                               $.each(names, function (i, pair) {
+                                       var name = pair[1];
+                                       if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
+                                               index = pair[0];
+                                               iValue += name.length;
+                                               return false;
+                                       }
+                               });
+                               if (index !== -1) {
+                                       return index + 1;
+                               } else {
+                                       throw "Unknown name at position " + iValue;
+                               }
+                       },
+                       // Confirm that a literal character matches the string value
+                       checkLiteral = function() {
+                               if (value.charAt(iValue) !== format.charAt(iFormat)) {
+                                       throw "Unexpected literal at position " + iValue;
+                               }
+                               iValue++;
+                       };
+
+               for (iFormat = 0; iFormat < format.length; iFormat++) {
+                       if (literal) {
+                               if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+                                       literal = false;
+                               } else {
+                                       checkLiteral();
+                               }
+                       } else {
+                               switch (format.charAt(iFormat)) {
+                                       case "d":
+                                               day = getNumber("d");
+                                               break;
+                                       case "D":
+                                               getName("D", dayNamesShort, dayNames);
+                                               break;
+                                       case "o":
+                                               doy = getNumber("o");
+                                               break;
+                                       case "m":
+                                               month = getNumber("m");
+                                               break;
+                                       case "M":
+                                               month = getName("M", monthNamesShort, monthNames);
+                                               break;
+                                       case "y":
+                                               year = getNumber("y");
+                                               break;
+                                       case "@":
+                                               date = new Date(getNumber("@"));
+                                               year = date.getFullYear();
+                                               month = date.getMonth() + 1;
+                                               day = date.getDate();
+                                               break;
+                                       case "!":
+                                               date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
+                                               year = date.getFullYear();
+                                               month = date.getMonth() + 1;
+                                               day = date.getDate();
+                                               break;
+                                       case "'":
+                                               if (lookAhead("'")){
+                                                       checkLiteral();
+                                               } else {
+                                                       literal = true;
+                                               }
+                                               break;
+                                       default:
+                                               checkLiteral();
+                               }
+                       }
+               }
+
+               if (iValue < value.length){
+                       extra = value.substr(iValue);
+                       if (!/^\s+/.test(extra)) {
+                               throw "Extra/unparsed characters found in date: " + extra;
+                       }
+               }
+
+               if (year === -1) {
+                       year = new Date().getFullYear();
+               } else if (year < 100) {
+                       year += new Date().getFullYear() - new Date().getFullYear() % 100 +
+                               (year <= shortYearCutoff ? 0 : -100);
+               }
+
+               if (doy > -1) {
+                       month = 1;
+                       day = doy;
+                       do {
+                               dim = this._getDaysInMonth(year, month - 1);
+                               if (day <= dim) {
+                                       break;
+                               }
+                               month++;
+                               day -= dim;
+                       } while (true);
+               }
+
+               date = this._daylightSavingAdjust(new Date(year, month - 1, day));
+               if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
+                       throw "Invalid date"; // E.g. 31/02/00
+               }
+               return date;
+       },
+
+       /* Standard date formats. */
+       ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
+       COOKIE: "D, dd M yy",
+       ISO_8601: "yy-mm-dd",
+       RFC_822: "D, d M y",
+       RFC_850: "DD, dd-M-y",
+       RFC_1036: "D, d M y",
+       RFC_1123: "D, d M yy",
+       RFC_2822: "D, d M yy",
+       RSS: "D, d M y", // RFC 822
+       TICKS: "!",
+       TIMESTAMP: "@",
+       W3C: "yy-mm-dd", // ISO 8601
+
+       _ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
+               Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),
+
+       /* Format a date object into a string value.
+        * The format can be combinations of the following:
+        * d  - day of month (no leading zero)
+        * dd - day of month (two digit)
+        * o  - day of year (no leading zeros)
+        * oo - day of year (three digit)
+        * D  - day name short
+        * DD - day name long
+        * m  - month of year (no leading zero)
+        * mm - month of year (two digit)
+        * M  - month name short
+        * MM - month name long
+        * y  - year (two digit)
+        * yy - year (four digit)
+        * @ - Unix timestamp (ms since 01/01/1970)
+        * ! - Windows ticks (100ns since 01/01/0001)
+        * "..." - literal text
+        * '' - single quote
+        *
+        * @param  format string - the desired format of the date
+        * @param  date Date - the date value to format
+        * @param  settings Object - attributes include:
+        *                                      dayNamesShort   string[7] - abbreviated names of the days from Sunday (optional)
+        *                                      dayNames                string[7] - names of the days from Sunday (optional)
+        *                                      monthNamesShort string[12] - abbreviated names of the months (optional)
+        *                                      monthNames              string[12] - names of the months (optional)
+        * @return  string - the date in the above format
+        */
+       formatDate: function (format, date, settings) {
+               if (!date) {
+                       return "";
+               }
+
+               var iFormat,
+                       dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
+                       dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
+                       monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
+                       monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
+                       // Check whether a format character is doubled
+                       lookAhead = function(match) {
+                               var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+                               if (matches) {
+                                       iFormat++;
+                               }
+                               return matches;
+                       },
+                       // Format a number, with leading zero if necessary
+                       formatNumber = function(match, value, len) {
+                               var num = "" + value;
+                               if (lookAhead(match)) {
+                                       while (num.length < len) {
+                                               num = "0" + num;
+                                       }
+                               }
+                               return num;
+                       },
+                       // Format a name, short or long as requested
+                       formatName = function(match, value, shortNames, longNames) {
+                               return (lookAhead(match) ? longNames[value] : shortNames[value]);
+                       },
+                       output = "",
+                       literal = false;
+
+               if (date) {
+                       for (iFormat = 0; iFormat < format.length; iFormat++) {
+                               if (literal) {
+                                       if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+                                               literal = false;
+                                       } else {
+                                               output += format.charAt(iFormat);
+                                       }
+                               } else {
+                                       switch (format.charAt(iFormat)) {
+                                               case "d":
+                                                       output += formatNumber("d", date.getDate(), 2);
+                                                       break;
+                                               case "D":
+                                                       output += formatName("D", date.getDay(), dayNamesShort, dayNames);
+                                                       break;
+                                               case "o":
+                                                       output += formatNumber("o",
+                                                               Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
+                                                       break;
+                                               case "m":
+                                                       output += formatNumber("m", date.getMonth() + 1, 2);
+                                                       break;
+                                               case "M":
+                                                       output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
+                                                       break;
+                                               case "y":
+                                                       output += (lookAhead("y") ? date.getFullYear() :
+                                                               (date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
+                                                       break;
+                                               case "@":
+                                                       output += date.getTime();
+                                                       break;
+                                               case "!":
+                                                       output += date.getTime() * 10000 + this._ticksTo1970;
+                                                       break;
+                                               case "'":
+                                                       if (lookAhead("'")) {
+                                                               output += "'";
+                                                       } else {
+                                                               literal = true;
+                                                       }
+                                                       break;
+                                               default:
+                                                       output += format.charAt(iFormat);
+                                       }
+                               }
+                       }
+               }
+               return output;
+       },
+
+       /* Extract all possible characters from the date format. */
+       _possibleChars: function (format) {
+               var iFormat,
+                       chars = "",
+                       literal = false,
+                       // Check whether a format character is doubled
+                       lookAhead = function(match) {
+                               var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
+                               if (matches) {
+                                       iFormat++;
+                               }
+                               return matches;
+                       };
+
+               for (iFormat = 0; iFormat < format.length; iFormat++) {
+                       if (literal) {
+                               if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
+                                       literal = false;
+                               } else {
+                                       chars += format.charAt(iFormat);
+                               }
+                       } else {
+                               switch (format.charAt(iFormat)) {
+                                       case "d": case "m": case "y": case "@":
+                                               chars += "0123456789";
+                                               break;
+                                       case "D": case "M":
+                                               return null; // Accept anything
+                                       case "'":
+                                               if (lookAhead("'")) {
+                                                       chars += "'";
+                                               } else {
+                                                       literal = true;
+                                               }
+                                               break;
+                                       default:
+                                               chars += format.charAt(iFormat);
+                               }
+                       }
+               }
+               return chars;
+       },
+
+       /* Get a setting value, defaulting if necessary. */
+       _get: function(inst, name) {
+               return inst.settings[name] !== undefined ?
+                       inst.settings[name] : this._defaults[name];
+       },
+
+       /* Parse existing date and initialise date picker. */
+       _setDateFromField: function(inst, noDefault) {
+               if (inst.input.val() === inst.lastVal) {
+                       return;
+               }
+
+               var dateFormat = this._get(inst, "dateFormat"),
+                       dates = inst.lastVal = inst.input ? inst.input.val() : null,
+                       defaultDate = this._getDefaultDate(inst),
+                       date = defaultDate,
+                       settings = this._getFormatConfig(inst);
+
+               try {
+                       date = this.parseDate(dateFormat, dates, settings) || defaultDate;
+               } catch (event) {
+                       dates = (noDefault ? "" : dates);
+               }
+               inst.selectedDay = date.getDate();
+               inst.drawMonth = inst.selectedMonth = date.getMonth();
+               inst.drawYear = inst.selectedYear = date.getFullYear();
+               inst.currentDay = (dates ? date.getDate() : 0);
+               inst.currentMonth = (dates ? date.getMonth() : 0);
+               inst.currentYear = (dates ? date.getFullYear() : 0);
+               this._adjustInstDate(inst);
+       },
+
+       /* Retrieve the default date shown on opening. */
+       _getDefaultDate: function(inst) {
+               return this._restrictMinMax(inst,
+                       this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
+       },
+
+       /* A date may be specified as an exact value or a relative one. */
+       _determineDate: function(inst, date, defaultDate) {
+               var offsetNumeric = function(offset) {
+                               var date = new Date();
+                               date.setDate(date.getDate() + offset);
+                               return date;
+                       },
+                       offsetString = function(offset) {
+                               try {
+                                       return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
+                                               offset, $.datepicker._getFormatConfig(inst));
+                               }
+                               catch (e) {
+                                       // Ignore
+                               }
+
+                               var date = (offset.toLowerCase().match(/^c/) ?
+                                       $.datepicker._getDate(inst) : null) || new Date(),
+                                       year = date.getFullYear(),
+                                       month = date.getMonth(),
+                                       day = date.getDate(),
+                                       pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
+                                       matches = pattern.exec(offset);
+
+                               while (matches) {
+                                       switch (matches[2] || "d") {
+                                               case "d" : case "D" :
+                                                       day += parseInt(matches[1],10); break;
+                                               case "w" : case "W" :
+                                                       day += parseInt(matches[1],10) * 7; break;
+                                               case "m" : case "M" :
+                                                       month += parseInt(matches[1],10);
+                                                       day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+                                                       break;
+                                               case "y": case "Y" :
+                                                       year += parseInt(matches[1],10);
+                                                       day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
+                                                       break;
+                                       }
+                                       matches = pattern.exec(offset);
+                               }
+                               return new Date(year, month, day);
+                       },
+                       newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
+                               (typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));
+
+               newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
+               if (newDate) {
+                       newDate.setHours(0);
+                       newDate.setMinutes(0);
+                       newDate.setSeconds(0);
+                       newDate.setMilliseconds(0);
+               }
+               return this._daylightSavingAdjust(newDate);
+       },
+
+       /* Handle switch to/from daylight saving.
+        * Hours may be non-zero on daylight saving cut-over:
+        * > 12 when midnight changeover, but then cannot generate
+        * midnight datetime, so jump to 1AM, otherwise reset.
+        * @param  date  (Date) the date to check
+        * @return  (Date) the corrected date
+        */
+       _daylightSavingAdjust: function(date) {
+               if (!date) {
+                       return null;
+               }
+               date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
+               return date;
+       },
+
+       /* Set the date(s) directly. */
+       _setDate: function(inst, date, noChange) {
+               var clear = !date,
+                       origMonth = inst.selectedMonth,
+                       origYear = inst.selectedYear,
+                       newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));
+
+               inst.selectedDay = inst.currentDay = newDate.getDate();
+               inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
+               inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
+               if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
+                       this._notifyChange(inst);
+               }
+               this._adjustInstDate(inst);
+               if (inst.input) {
+                       inst.input.val(clear ? "" : this._formatDate(inst));
+               }
+       },
+
+       /* Retrieve the date(s) directly. */
+       _getDate: function(inst) {
+               var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
+                       this._daylightSavingAdjust(new Date(
+                       inst.currentYear, inst.currentMonth, inst.currentDay)));
+                       return startDate;
+       },
+
+       /* Attach the onxxx handlers.  These are declared statically so
+        * they work with static code transformers like Caja.
+        */
+       _attachHandlers: function(inst) {
+               var stepMonths = this._get(inst, "stepMonths"),
+                       id = "#" + inst.id.replace( /\\\\/g, "\\" );
+               inst.dpDiv.find("[data-handler]").map(function () {
+                       var handler = {
+                               prev: function () {
+                                       $.datepicker._adjustDate(id, -stepMonths, "M");
+                               },
+                               next: function () {
+                                       $.datepicker._adjustDate(id, +stepMonths, "M");
+                               },
+                               hide: function () {
+                                       $.datepicker._hideDatepicker();
+                               },
+                               today: function () {
+                                       $.datepicker._gotoToday(id);
+                               },
+                               selectDay: function () {
+                                       $.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
+                                       return false;
+                               },
+                               selectMonth: function () {
+                                       $.datepicker._selectMonthYear(id, this, "M");
+                                       return false;
+                               },
+                               selectYear: function () {
+                                       $.datepicker._selectMonthYear(id, this, "Y");
+                                       return false;
+                               }
+                       };
+                       $(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
+               });
+       },
+
+       /* Generate the HTML for the current state of the date picker. */
+       _generateHTML: function(inst) {
+               var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
+                       controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
+                       monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
+                       selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
+                       cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
+                       printDate, dRow, tbody, daySettings, otherMonth, unselectable,
+                       tempDate = new Date(),
+                       today = this._daylightSavingAdjust(
+                               new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
+                       isRTL = this._get(inst, "isRTL"),
+                       showButtonPanel = this._get(inst, "showButtonPanel"),
+                       hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
+                       navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
+                       numMonths = this._getNumberOfMonths(inst),
+                       showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
+                       stepMonths = this._get(inst, "stepMonths"),
+                       isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
+                       currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
+                               new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
+                       minDate = this._getMinMaxDate(inst, "min"),
+                       maxDate = this._getMinMaxDate(inst, "max"),
+                       drawMonth = inst.drawMonth - showCurrentAtPos,
+                       drawYear = inst.drawYear;
+
+               if (drawMonth < 0) {
+                       drawMonth += 12;
+                       drawYear--;
+               }
+               if (maxDate) {
+                       maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
+                               maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
+                       maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
+                       while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
+                               drawMonth--;
+                               if (drawMonth < 0) {
+                                       drawMonth = 11;
+                                       drawYear--;
+                               }
+                       }
+               }
+               inst.drawMonth = drawMonth;
+               inst.drawYear = drawYear;
+
+               prevText = this._get(inst, "prevText");
+               prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
+                       this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
+                       this._getFormatConfig(inst)));
+
+               prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
+                       "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
+                       " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
+                       (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));
+
+               nextText = this._get(inst, "nextText");
+               nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
+                       this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
+                       this._getFormatConfig(inst)));
+
+               next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
+                       "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
+                       " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
+                       (hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));
+
+               currentText = this._get(inst, "currentText");
+               gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
+               currentText = (!navigationAsDateFormat ? currentText :
+                       this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));
+
+               controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
+                       this._get(inst, "closeText") + "</button>" : "");
+
+               buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
+                       (this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
+                       ">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";
+
+               firstDay = parseInt(this._get(inst, "firstDay"),10);
+               firstDay = (isNaN(firstDay) ? 0 : firstDay);
+
+               showWeek = this._get(inst, "showWeek");
+               dayNames = this._get(inst, "dayNames");
+               dayNamesMin = this._get(inst, "dayNamesMin");
+               monthNames = this._get(inst, "monthNames");
+               monthNamesShort = this._get(inst, "monthNamesShort");
+               beforeShowDay = this._get(inst, "beforeShowDay");
+               showOtherMonths = this._get(inst, "showOtherMonths");
+               selectOtherMonths = this._get(inst, "selectOtherMonths");
+               defaultDate = this._getDefaultDate(inst);
+               html = "";
+               dow;
+               for (row = 0; row < numMonths[0]; row++) {
+                       group = "";
+                       this.maxRows = 4;
+                       for (col = 0; col < numMonths[1]; col++) {
+                               selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
+                               cornerClass = " ui-corner-all";
+                               calender = "";
+                               if (isMultiMonth) {
+                                       calender += "<div class='ui-datepicker-group";
+                                       if (numMonths[1] > 1) {
+                                               switch (col) {
+                                                       case 0: calender += " ui-datepicker-group-first";
+                                                               cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
+                                                       case numMonths[1]-1: calender += " ui-datepicker-group-last";
+                                                               cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
+                                                       default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
+                                               }
+                                       }
+                                       calender += "'>";
+                               }
+                               calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
+                                       (/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
+                                       (/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
+                                       this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
+                                       row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
+                                       "</div><table class='ui-datepicker-calendar'><thead>" +
+                                       "<tr>";
+                               thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
+                               for (dow = 0; dow < 7; dow++) { // days of the week
+                                       day = (dow + firstDay) % 7;
+                                       thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
+                                               "<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
+                               }
+                               calender += thead + "</tr></thead><tbody>";
+                               daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
+                               if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
+                                       inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
+                               }
+                               leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
+                               curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
+                               numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
+                               this.maxRows = numRows;
+                               printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
+                               for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
+                                       calender += "<tr>";
+                                       tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
+                                               this._get(inst, "calculateWeek")(printDate) + "</td>");
+                                       for (dow = 0; dow < 7; dow++) { // create date picker days
+                                               daySettings = (beforeShowDay ?
+                                                       beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
+                                               otherMonth = (printDate.getMonth() !== drawMonth);
+                                               unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
+                                                       (minDate && printDate < minDate) || (maxDate && printDate > maxDate);
+                                               tbody += "<td class='" +
+                                                       ((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
+                                                       (otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
+                                                       ((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
+                                                       (defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
+                                                       // or defaultDate is current printedDate and defaultDate is selectedDate
+                                                       " " + this._dayOverClass : "") + // highlight selected day
+                                                       (unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") +  // highlight unselectable days
+                                                       (otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
+                                                       (printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
+                                                       (printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
+                                                       ((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
+                                                       (unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
+                                                       (otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
+                                                       (unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
+                                                       (printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
+                                                       (printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
+                                                       (otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
+                                                       "' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
+                                               printDate.setDate(printDate.getDate() + 1);
+                                               printDate = this._daylightSavingAdjust(printDate);
+                                       }
+                                       calender += tbody + "</tr>";
+                               }
+                               drawMonth++;
+                               if (drawMonth > 11) {
+                                       drawMonth = 0;
+                                       drawYear++;
+                               }
+                               calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
+                                                       ((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
+                               group += calender;
+                       }
+                       html += group;
+               }
+               html += buttonPanel;
+               inst._keyEvent = false;
+               return html;
+       },
+
+       /* Generate the month and year header. */
+       _generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
+                       secondary, monthNames, monthNamesShort) {
+
+               var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
+                       changeMonth = this._get(inst, "changeMonth"),
+                       changeYear = this._get(inst, "changeYear"),
+                       showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
+                       html = "<div class='ui-datepicker-title'>",
+                       monthHtml = "";
+
+               // month selection
+               if (secondary || !changeMonth) {
+                       monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
+               } else {
+                       inMinYear = (minDate && minDate.getFullYear() === drawYear);
+                       inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
+                       monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
+                       for ( month = 0; month < 12; month++) {
+                               if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
+                                       monthHtml += "<option value='" + month + "'" +
+                                               (month === drawMonth ? " selected='selected'" : "") +
+                                               ">" + monthNamesShort[month] + "</option>";
+                               }
+                       }
+                       monthHtml += "</select>";
+               }
+
+               if (!showMonthAfterYear) {
+                       html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
+               }
+
+               // year selection
+               if ( !inst.yearshtml ) {
+                       inst.yearshtml = "";
+                       if (secondary || !changeYear) {
+                               html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
+                       } else {
+                               // determine range of years to display
+                               years = this._get(inst, "yearRange").split(":");
+                               thisYear = new Date().getFullYear();
+                               determineYear = function(value) {
+                                       var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
+                                               (value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
+                                               parseInt(value, 10)));
+                                       return (isNaN(year) ? thisYear : year);
+                               };
+                               year = determineYear(years[0]);
+                               endYear = Math.max(year, determineYear(years[1] || ""));
+                               year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
+                               endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
+                               inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
+                               for (; year <= endYear; year++) {
+                                       inst.yearshtml += "<option value='" + year + "'" +
+                                               (year === drawYear ? " selected='selected'" : "") +
+                                               ">" + year + "</option>";
+                               }
+                               inst.yearshtml += "</select>";
+
+                               html += inst.yearshtml;
+                               inst.yearshtml = null;
+                       }
+               }
+
+               html += this._get(inst, "yearSuffix");
+               if (showMonthAfterYear) {
+                       html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
+               }
+               html += "</div>"; // Close datepicker_header
+               return html;
+       },
+
+       /* Adjust one of the date sub-fields. */
+       _adjustInstDate: function(inst, offset, period) {
+               var year = inst.drawYear + (period === "Y" ? offset : 0),
+                       month = inst.drawMonth + (period === "M" ? offset : 0),
+                       day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
+                       date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));
+
+               inst.selectedDay = date.getDate();
+               inst.drawMonth = inst.selectedMonth = date.getMonth();
+               inst.drawYear = inst.selectedYear = date.getFullYear();
+               if (period === "M" || period === "Y") {
+                       this._notifyChange(inst);
+               }
+       },
+
+       /* Ensure a date is within any min/max bounds. */
+       _restrictMinMax: function(inst, date) {
+               var minDate = this._getMinMaxDate(inst, "min"),
+                       maxDate = this._getMinMaxDate(inst, "max"),
+                       newDate = (minDate && date < minDate ? minDate : date);
+               return (maxDate && newDate > maxDate ? maxDate : newDate);
+       },
+
+       /* Notify change of month/year. */
+       _notifyChange: function(inst) {
+               var onChange = this._get(inst, "onChangeMonthYear");
+               if (onChange) {
+                       onChange.apply((inst.input ? inst.input[0] : null),
+                               [inst.selectedYear, inst.selectedMonth + 1, inst]);
+               }
+       },
+
+       /* Determine the number of months to show. */
+       _getNumberOfMonths: function(inst) {
+               var numMonths = this._get(inst, "numberOfMonths");
+               return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
+       },
+
+       /* Determine the current maximum date - ensure no time components are set. */
+       _getMinMaxDate: function(inst, minMax) {
+               return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
+       },
+
+       /* Find the number of days in a given month. */
+       _getDaysInMonth: function(year, month) {
+               return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
+       },
+
+       /* Find the day of the week of the first of a month. */
+       _getFirstDayOfMonth: function(year, month) {
+               return new Date(year, month, 1).getDay();
+       },
+
+       /* Determines if we should allow a "next/prev" month display change. */
+       _canAdjustMonth: function(inst, offset, curYear, curMonth) {
+               var numMonths = this._getNumberOfMonths(inst),
+                       date = this._daylightSavingAdjust(new Date(curYear,
+                       curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));
+
+               if (offset < 0) {
+                       date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
+               }
+               return this._isInRange(inst, date);
+       },
+
+       /* Is the given date in the accepted range? */
+       _isInRange: function(inst, date) {
+               var yearSplit, currentYear,
+                       minDate = this._getMinMaxDate(inst, "min"),
+                       maxDate = this._getMinMaxDate(inst, "max"),
+                       minYear = null,
+                       maxYear = null,
+                       years = this._get(inst, "yearRange");
+                       if (years){
+                               yearSplit = years.split(":");
+                               currentYear = new Date().getFullYear();
+                               minYear = parseInt(yearSplit[0], 10);
+                               maxYear = parseInt(yearSplit[1], 10);
+                               if ( yearSplit[0].match(/[+\-].*/) ) {
+                                       minYear += currentYear;
+                               }
+                               if ( yearSplit[1].match(/[+\-].*/) ) {
+                                       maxYear += currentYear;
+                               }
+                       }
+
+               return ((!minDate || date.getTime() >= minDate.getTime()) &&
+                       (!maxDate || date.getTime() <= maxDate.getTime()) &&
+                       (!minYear || date.getFullYear() >= minYear) &&
+                       (!maxYear || date.getFullYear() <= maxYear));
+       },
+
+       /* Provide the configuration settings for formatting/parsing. */
+       _getFormatConfig: function(inst) {
+               var shortYearCutoff = this._get(inst, "shortYearCutoff");
+               shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
+                       new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
+               return {shortYearCutoff: shortYearCutoff,
+                       dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
+                       monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
+       },
+
+       /* Format the given date for display. */
+       _formatDate: function(inst, day, month, year) {
+               if (!day) {
+                       inst.currentDay = inst.selectedDay;
+                       inst.currentMonth = inst.selectedMonth;
+                       inst.currentYear = inst.selectedYear;
+               }
+               var date = (day ? (typeof day === "object" ? day :
+                       this._daylightSavingAdjust(new Date(year, month, day))) :
+                       this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
+               return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
+       }
+});
+
+/*
+ * Bind hover events for datepicker elements.
+ * Done via delegate so the binding only occurs once in the lifetime of the parent div.
+ * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
+ */
+function datepicker_bindHover(dpDiv) {
+       var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
+       return dpDiv.delegate(selector, "mouseout", function() {
+                       $(this).removeClass("ui-state-hover");
+                       if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+                               $(this).removeClass("ui-datepicker-prev-hover");
+                       }
+                       if (this.className.indexOf("ui-datepicker-next") !== -1) {
+                               $(this).removeClass("ui-datepicker-next-hover");
+                       }
+               })
+               .delegate( selector, "mouseover", datepicker_handleMouseover );
+}
+
+function datepicker_handleMouseover() {
+       if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
+               $(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");
+               $(this).addClass("ui-state-hover");
+               if (this.className.indexOf("ui-datepicker-prev") !== -1) {
+                       $(this).addClass("ui-datepicker-prev-hover");
+               }
+               if (this.className.indexOf("ui-datepicker-next") !== -1) {
+                       $(this).addClass("ui-datepicker-next-hover");
+               }
+       }
+}
+
+/* jQuery extend now ignores nulls! */
+function datepicker_extendRemove(target, props) {
+       $.extend(target, props);
+       for (var name in props) {
+               if (props[name] == null) {
+                       target[name] = props[name];
+               }
+       }
+       return target;
+}
+
+/* Invoke the datepicker functionality.
+   @param  options  string - a command, optionally followed by additional parameters or
+                                       Object - settings for attaching new datepicker functionality
+   @return  jQuery object */
+$.fn.datepicker = function(options){
+
+       /* Verify an empty collection wasn't passed - Fixes #6976 */
+       if ( !this.length ) {
+               return this;
+       }
+
+       /* Initialise the date picker. */
+       if (!$.datepicker.initialized) {
+               $(document).mousedown($.datepicker._checkExternalClick);
+               $.datepicker.initialized = true;
+       }
+
+       /* Append datepicker main container to body if not exist. */
+       if ($("#"+$.datepicker._mainDivId).length === 0) {
+               $("body").append($.datepicker.dpDiv);
+       }
+
+       var otherArgs = Array.prototype.slice.call(arguments, 1);
+       if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
+               return $.datepicker["_" + options + "Datepicker"].
+                       apply($.datepicker, [this[0]].concat(otherArgs));
+       }
+       if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
+               return $.datepicker["_" + options + "Datepicker"].
+                       apply($.datepicker, [this[0]].concat(otherArgs));
+       }
+       return this.each(function() {
+               typeof options === "string" ?
+                       $.datepicker["_" + options + "Datepicker"].
+                               apply($.datepicker, [this].concat(otherArgs)) :
+                       $.datepicker._attachDatepicker(this, options);
+       });
+};
+
+$.datepicker = new Datepicker(); // singleton instance
+$.datepicker.initialized = false;
+$.datepicker.uuid = new Date().getTime();
+$.datepicker.version = "1.11.2";
+
+var datepicker = $.datepicker;
+
+
+/*!
+ * jQuery UI Draggable 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/draggable/
+ */
+
+
+$.widget("ui.draggable", $.ui.mouse, {
+       version: "1.11.2",
+       widgetEventPrefix: "drag",
+       options: {
+               addClasses: true,
+               appendTo: "parent",
+               axis: false,
+               connectToSortable: false,
+               containment: false,
+               cursor: "auto",
+               cursorAt: false,
+               grid: false,
+               handle: false,
+               helper: "original",
+               iframeFix: false,
+               opacity: false,
+               refreshPositions: false,
+               revert: false,
+               revertDuration: 500,
+               scope: "default",
+               scroll: true,
+               scrollSensitivity: 20,
+               scrollSpeed: 20,
+               snap: false,
+               snapMode: "both",
+               snapTolerance: 20,
+               stack: false,
+               zIndex: false,
+
+               // callbacks
+               drag: null,
+               start: null,
+               stop: null
+       },
+       _create: function() {
+
+               if ( this.options.helper === "original" ) {
+                       this._setPositionRelative();
+               }
+               if (this.options.addClasses){
+                       this.element.addClass("ui-draggable");
+               }
+               if (this.options.disabled){
+                       this.element.addClass("ui-draggable-disabled");
+               }
+               this._setHandleClassName();
+
+               this._mouseInit();
+       },
+
+       _setOption: function( key, value ) {
+               this._super( key, value );
+               if ( key === "handle" ) {
+                       this._removeHandleClassName();
+                       this._setHandleClassName();
+               }
+       },
+
+       _destroy: function() {
+               if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
+                       this.destroyOnClear = true;
+                       return;
+               }
+               this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" );
+               this._removeHandleClassName();
+               this._mouseDestroy();
+       },
+
+       _mouseCapture: function(event) {
+               var o = this.options;
+
+               this._blurActiveElement( event );
+
+               // among others, prevent a drag on a resizable-handle
+               if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) {
+                       return false;
+               }
+
+               //Quit if we're not on a valid handle
+               this.handle = this._getHandle(event);
+               if (!this.handle) {
+                       return false;
+               }
+
+               this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
+
+               return true;
+
+       },
+
+       _blockFrames: function( selector ) {
+               this.iframeBlocks = this.document.find( selector ).map(function() {
+                       var iframe = $( this );
+
+                       return $( "<div>" )
+                               .css( "position", "absolute" )
+                               .appendTo( iframe.parent() )
+                               .outerWidth( iframe.outerWidth() )
+                               .outerHeight( iframe.outerHeight() )
+                               .offset( iframe.offset() )[ 0 ];
+               });
+       },
+
+       _unblockFrames: function() {
+               if ( this.iframeBlocks ) {
+                       this.iframeBlocks.remove();
+                       delete this.iframeBlocks;
+               }
+       },
+
+       _blurActiveElement: function( event ) {
+               var document = this.document[ 0 ];
+
+               // Only need to blur if the event occurred on the draggable itself, see #10527
+               if ( !this.handleElement.is( event.target ) ) {
+                       return;
+               }
+
+               // support: IE9
+               // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
+               try {
+
+                       // Support: IE9, IE10
+                       // If the <body> is blurred, IE will switch windows, see #9520
+                       if ( document.activeElement && document.activeElement.nodeName.toLowerCase() !== "body" ) {
+
+                               // Blur any element that currently has focus, see #4261
+                               $( document.activeElement ).blur();
+                       }
+               } catch ( error ) {}
+       },
+
+       _mouseStart: function(event) {
+
+               var o = this.options;
+
+               //Create and append the visible helper
+               this.helper = this._createHelper(event);
+
+               this.helper.addClass("ui-draggable-dragging");
+
+               //Cache the helper size
+               this._cacheHelperProportions();
+
+               //If ddmanager is used for droppables, set the global draggable
+               if ($.ui.ddmanager) {
+                       $.ui.ddmanager.current = this;
+               }
+
+               /*
+                * - Position generation -
+                * This block generates everything position related - it's the core of draggables.
+                */
+
+               //Cache the margins of the original element
+               this._cacheMargins();
+
+               //Store the helper's css position
+               this.cssPosition = this.helper.css( "position" );
+               this.scrollParent = this.helper.scrollParent( true );
+               this.offsetParent = this.helper.offsetParent();
+               this.hasFixedAncestor = this.helper.parents().filter(function() {
+                               return $( this ).css( "position" ) === "fixed";
+                       }).length > 0;
+
+               //The element's absolute position on the page minus margins
+               this.positionAbs = this.element.offset();
+               this._refreshOffsets( event );
+
+               //Generate the original position
+               this.originalPosition = this.position = this._generatePosition( event, false );
+               this.originalPageX = event.pageX;
+               this.originalPageY = event.pageY;
+
+               //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+               (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+               //Set a containment if given in the options
+               this._setContainment();
+
+               //Trigger event + callbacks
+               if (this._trigger("start", event) === false) {
+                       this._clear();
+                       return false;
+               }
+
+               //Recache the helper size
+               this._cacheHelperProportions();
+
+               //Prepare the droppable offsets
+               if ($.ui.ddmanager && !o.dropBehaviour) {
+                       $.ui.ddmanager.prepareOffsets(this, event);
+               }
+
+               // Reset helper's right/bottom css if they're set and set explicit width/height instead
+               // as this prevents resizing of elements with right/bottom set (see #7772)
+               this._normalizeRightBottom();
+
+               this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+
+               //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003)
+               if ( $.ui.ddmanager ) {
+                       $.ui.ddmanager.dragStart(this, event);
+               }
+
+               return true;
+       },
+
+       _refreshOffsets: function( event ) {
+               this.offset = {
+                       top: this.positionAbs.top - this.margins.top,
+                       left: this.positionAbs.left - this.margins.left,
+                       scroll: false,
+                       parent: this._getParentOffset(),
+                       relative: this._getRelativeOffset()
+               };
+
+               this.offset.click = {
+                       left: event.pageX - this.offset.left,
+                       top: event.pageY - this.offset.top
+               };
+       },
+
+       _mouseDrag: function(event, noPropagation) {
+               // reset any necessary cached properties (see #5009)
+               if ( this.hasFixedAncestor ) {
+                       this.offset.parent = this._getParentOffset();
+               }
+
+               //Compute the helpers position
+               this.position = this._generatePosition( event, true );
+               this.positionAbs = this._convertPositionTo("absolute");
+
+               //Call plugins and callbacks and use the resulting position if something is returned
+               if (!noPropagation) {
+                       var ui = this._uiHash();
+                       if (this._trigger("drag", event, ui) === false) {
+                               this._mouseUp({});
+                               return false;
+                       }
+                       this.position = ui.position;
+               }
+
+               this.helper[ 0 ].style.left = this.position.left + "px";
+               this.helper[ 0 ].style.top = this.position.top + "px";
+
+               if ($.ui.ddmanager) {
+                       $.ui.ddmanager.drag(this, event);
+               }
+
+               return false;
+       },
+
+       _mouseStop: function(event) {
+
+               //If we are using droppables, inform the manager about the drop
+               var that = this,
+                       dropped = false;
+               if ($.ui.ddmanager && !this.options.dropBehaviour) {
+                       dropped = $.ui.ddmanager.drop(this, event);
+               }
+
+               //if a drop comes from outside (a sortable)
+               if (this.dropped) {
+                       dropped = this.dropped;
+                       this.dropped = false;
+               }
+
+               if ((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) {
+                       $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() {
+                               if (that._trigger("stop", event) !== false) {
+                                       that._clear();
+                               }
+                       });
+               } else {
+                       if (this._trigger("stop", event) !== false) {
+                               this._clear();
+                       }
+               }
+
+               return false;
+       },
+
+       _mouseUp: function( event ) {
+               this._unblockFrames();
+
+               //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003)
+               if ( $.ui.ddmanager ) {
+                       $.ui.ddmanager.dragStop(this, event);
+               }
+
+               // Only need to focus if the event occurred on the draggable itself, see #10527
+               if ( this.handleElement.is( event.target ) ) {
+                       // The interaction is over; whether or not the click resulted in a drag, focus the element
+                       this.element.focus();
+               }
+
+               return $.ui.mouse.prototype._mouseUp.call(this, event);
+       },
+
+       cancel: function() {
+
+               if (this.helper.is(".ui-draggable-dragging")) {
+                       this._mouseUp({});
+               } else {
+                       this._clear();
+               }
+
+               return this;
+
+       },
+
+       _getHandle: function(event) {
+               return this.options.handle ?
+                       !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
+                       true;
+       },
+
+       _setHandleClassName: function() {
+               this.handleElement = this.options.handle ?
+                       this.element.find( this.options.handle ) : this.element;
+               this.handleElement.addClass( "ui-draggable-handle" );
+       },
+
+       _removeHandleClassName: function() {
+               this.handleElement.removeClass( "ui-draggable-handle" );
+       },
+
+       _createHelper: function(event) {
+
+               var o = this.options,
+                       helperIsFunction = $.isFunction( o.helper ),
+                       helper = helperIsFunction ?
+                               $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
+                               ( o.helper === "clone" ?
+                                       this.element.clone().removeAttr( "id" ) :
+                                       this.element );
+
+               if (!helper.parents("body").length) {
+                       helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo));
+               }
+
+               // http://bugs.jqueryui.com/ticket/9446
+               // a helper function can return the original element
+               // which wouldn't have been set to relative in _create
+               if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
+                       this._setPositionRelative();
+               }
+
+               if (helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) {
+                       helper.css("position", "absolute");
+               }
+
+               return helper;
+
+       },
+
+       _setPositionRelative: function() {
+               if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
+                       this.element[ 0 ].style.position = "relative";
+               }
+       },
+
+       _adjustOffsetFromHelper: function(obj) {
+               if (typeof obj === "string") {
+                       obj = obj.split(" ");
+               }
+               if ($.isArray(obj)) {
+                       obj = { left: +obj[0], top: +obj[1] || 0 };
+               }
+               if ("left" in obj) {
+                       this.offset.click.left = obj.left + this.margins.left;
+               }
+               if ("right" in obj) {
+                       this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+               }
+               if ("top" in obj) {
+                       this.offset.click.top = obj.top + this.margins.top;
+               }
+               if ("bottom" in obj) {
+                       this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+               }
+       },
+
+       _isRootNode: function( element ) {
+               return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
+       },
+
+       _getParentOffset: function() {
+
+               //Get the offsetParent and cache its position
+               var po = this.offsetParent.offset(),
+                       document = this.document[ 0 ];
+
+               // This is a special case where we need to modify a offset calculated on start, since the following happened:
+               // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+               // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+               //    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+               if (this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+                       po.left += this.scrollParent.scrollLeft();
+                       po.top += this.scrollParent.scrollTop();
+               }
+
+               if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
+                       po = { top: 0, left: 0 };
+               }
+
+               return {
+                       top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"), 10) || 0),
+                       left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"), 10) || 0)
+               };
+
+       },
+
+       _getRelativeOffset: function() {
+               if ( this.cssPosition !== "relative" ) {
+                       return { top: 0, left: 0 };
+               }
+
+               var p = this.element.position(),
+                       scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
+
+               return {
+                       top: p.top - ( parseInt(this.helper.css( "top" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
+                       left: p.left - ( parseInt(this.helper.css( "left" ), 10) || 0 ) + ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
+               };
+
+       },
+
+       _cacheMargins: function() {
+               this.margins = {
+                       left: (parseInt(this.element.css("marginLeft"), 10) || 0),
+                       top: (parseInt(this.element.css("marginTop"), 10) || 0),
+                       right: (parseInt(this.element.css("marginRight"), 10) || 0),
+                       bottom: (parseInt(this.element.css("marginBottom"), 10) || 0)
+               };
+       },
+
+       _cacheHelperProportions: function() {
+               this.helperProportions = {
+                       width: this.helper.outerWidth(),
+                       height: this.helper.outerHeight()
+               };
+       },
+
+       _setContainment: function() {
+
+               var isUserScrollable, c, ce,
+                       o = this.options,
+                       document = this.document[ 0 ];
+
+               this.relativeContainer = null;
+
+               if ( !o.containment ) {
+                       this.containment = null;
+                       return;
+               }
+
+               if ( o.containment === "window" ) {
+                       this.containment = [
+                               $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
+                               $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
+                               $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left,
+                               $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+                       ];
+                       return;
+               }
+
+               if ( o.containment === "document") {
+                       this.containment = [
+                               0,
+                               0,
+                               $( document ).width() - this.helperProportions.width - this.margins.left,
+                               ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top
+                       ];
+                       return;
+               }
+
+               if ( o.containment.constructor === Array ) {
+                       this.containment = o.containment;
+                       return;
+               }
+
+               if ( o.containment === "parent" ) {
+                       o.containment = this.helper[ 0 ].parentNode;
+               }
+
+               c = $( o.containment );
+               ce = c[ 0 ];
+
+               if ( !ce ) {
+                       return;
+               }
+
+               isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
+
+               this.containment = [
+                       ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
+                       ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
+                       ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
+                               ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
+                               ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
+                               this.helperProportions.width -
+                               this.margins.left -
+                               this.margins.right,
+                       ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
+                               ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
+                               ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
+                               this.helperProportions.height -
+                               this.margins.top -
+                               this.margins.bottom
+               ];
+               this.relativeContainer = c;
+       },
+
+       _convertPositionTo: function(d, pos) {
+
+               if (!pos) {
+                       pos = this.position;
+               }
+
+               var mod = d === "absolute" ? 1 : -1,
+                       scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
+
+               return {
+                       top: (
+                               pos.top +                                                                                                                               // The absolute mouse position
+                               this.offset.relative.top * mod +                                                                                // Only for relative positioned nodes: Relative offset from element to offset parent
+                               this.offset.parent.top * mod -                                                                          // The offsetParent's offset without borders (offset + border)
+                               ( ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod)
+                       ),
+                       left: (
+                               pos.left +                                                                                                                              // The absolute mouse position
+                               this.offset.relative.left * mod +                                                                               // Only for relative positioned nodes: Relative offset from element to offset parent
+                               this.offset.parent.left * mod   -                                                                               // The offsetParent's offset without borders (offset + border)
+                               ( ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod)
+                       )
+               };
+
+       },
+
+       _generatePosition: function( event, constrainPosition ) {
+
+               var containment, co, top, left,
+                       o = this.options,
+                       scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
+                       pageX = event.pageX,
+                       pageY = event.pageY;
+
+               // Cache the scroll
+               if ( !scrollIsRootNode || !this.offset.scroll ) {
+                       this.offset.scroll = {
+                               top: this.scrollParent.scrollTop(),
+                               left: this.scrollParent.scrollLeft()
+                       };
+               }
+
+               /*
+                * - Position constraining -
+                * Constrain the position to a mix of grid, containment.
+                */
+
+               // If we are not dragging yet, we won't check for options
+               if ( constrainPosition ) {
+                       if ( this.containment ) {
+                               if ( this.relativeContainer ){
+                                       co = this.relativeContainer.offset();
+                                       containment = [
+                                               this.containment[ 0 ] + co.left,
+                                               this.containment[ 1 ] + co.top,
+                                               this.containment[ 2 ] + co.left,
+                                               this.containment[ 3 ] + co.top
+                                       ];
+                               } else {
+                                       containment = this.containment;
+                               }
+
+                               if (event.pageX - this.offset.click.left < containment[0]) {
+                                       pageX = containment[0] + this.offset.click.left;
+                               }
+                               if (event.pageY - this.offset.click.top < containment[1]) {
+                                       pageY = containment[1] + this.offset.click.top;
+                               }
+                               if (event.pageX - this.offset.click.left > containment[2]) {
+                                       pageX = containment[2] + this.offset.click.left;
+                               }
+                               if (event.pageY - this.offset.click.top > containment[3]) {
+                                       pageY = containment[3] + this.offset.click.top;
+                               }
+                       }
+
+                       if (o.grid) {
+                               //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950)
+                               top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY;
+                               pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+                               left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX;
+                               pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+                       }
+
+                       if ( o.axis === "y" ) {
+                               pageX = this.originalPageX;
+                       }
+
+                       if ( o.axis === "x" ) {
+                               pageY = this.originalPageY;
+                       }
+               }
+
+               return {
+                       top: (
+                               pageY -                                                                                                                                 // The absolute mouse position
+                               this.offset.click.top   -                                                                                               // Click offset (relative to the element)
+                               this.offset.relative.top -                                                                                              // Only for relative positioned nodes: Relative offset from element to offset parent
+                               this.offset.parent.top +                                                                                                // The offsetParent's offset without borders (offset + border)
+                               ( this.cssPosition === "fixed" ? -this.offset.scroll.top : ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
+                       ),
+                       left: (
+                               pageX -                                                                                                                                 // The absolute mouse position
+                               this.offset.click.left -                                                                                                // Click offset (relative to the element)
+                               this.offset.relative.left -                                                                                             // Only for relative positioned nodes: Relative offset from element to offset parent
+                               this.offset.parent.left +                                                                                               // The offsetParent's offset without borders (offset + border)
+                               ( this.cssPosition === "fixed" ? -this.offset.scroll.left : ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
+                       )
+               };
+
+       },
+
+       _clear: function() {
+               this.helper.removeClass("ui-draggable-dragging");
+               if (this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) {
+                       this.helper.remove();
+               }
+               this.helper = null;
+               this.cancelHelperRemoval = false;
+               if ( this.destroyOnClear ) {
+                       this.destroy();
+               }
+       },
+
+       _normalizeRightBottom: function() {
+               if ( this.options.axis !== "y" && this.helper.css( "right" ) !== "auto" ) {
+                       this.helper.width( this.helper.width() );
+                       this.helper.css( "right", "auto" );
+               }
+               if ( this.options.axis !== "x" && this.helper.css( "bottom" ) !== "auto" ) {
+                       this.helper.height( this.helper.height() );
+                       this.helper.css( "bottom", "auto" );
+               }
+       },
+
+       // From now on bulk stuff - mainly helpers
+
+       _trigger: function( type, event, ui ) {
+               ui = ui || this._uiHash();
+               $.ui.plugin.call( this, type, [ event, ui, this ], true );
+
+               // Absolute position and offset (see #6884 ) have to be recalculated after plugins
+               if ( /^(drag|start|stop)/.test( type ) ) {
+                       this.positionAbs = this._convertPositionTo( "absolute" );
+                       ui.offset = this.positionAbs;
+               }
+               return $.Widget.prototype._trigger.call( this, type, event, ui );
+       },
+
+       plugins: {},
+
+       _uiHash: function() {
+               return {
+                       helper: this.helper,
+                       position: this.position,
+                       originalPosition: this.originalPosition,
+                       offset: this.positionAbs
+               };
+       }
+
+});
+
+$.ui.plugin.add( "draggable", "connectToSortable", {
+       start: function( event, ui, draggable ) {
+               var uiSortable = $.extend( {}, ui, {
+                       item: draggable.element
+               });
+
+               draggable.sortables = [];
+               $( draggable.options.connectToSortable ).each(function() {
+                       var sortable = $( this ).sortable( "instance" );
+
+                       if ( sortable && !sortable.options.disabled ) {
+                               draggable.sortables.push( sortable );
+
+                               // refreshPositions is called at drag start to refresh the containerCache
+                               // which is used in drag. This ensures it's initialized and synchronized
+                               // with any changes that might have happened on the page since initialization.
+                               sortable.refreshPositions();
+                               sortable._trigger("activate", event, uiSortable);
+                       }
+               });
+       },
+       stop: function( event, ui, draggable ) {
+               var uiSortable = $.extend( {}, ui, {
+                       item: draggable.element
+               });
+
+               draggable.cancelHelperRemoval = false;
+
+               $.each( draggable.sortables, function() {
+                       var sortable = this;
+
+                       if ( sortable.isOver ) {
+                               sortable.isOver = 0;
+
+                               // Allow this sortable to handle removing the helper
+                               draggable.cancelHelperRemoval = true;
+                               sortable.cancelHelperRemoval = false;
+
+                               // Use _storedCSS To restore properties in the sortable,
+                               // as this also handles revert (#9675) since the draggable
+                               // may have modified them in unexpected ways (#8809)
+                               sortable._storedCSS = {
+                                       position: sortable.placeholder.css( "position" ),
+                                       top: sortable.placeholder.css( "top" ),
+                                       left: sortable.placeholder.css( "left" )
+                               };
+
+                               sortable._mouseStop(event);
+
+                               // Once drag has ended, the sortable should return to using
+                               // its original helper, not the shared helper from draggable
+                               sortable.options.helper = sortable.options._helper;
+                       } else {
+                               // Prevent this Sortable from removing the helper.
+                               // However, don't set the draggable to remove the helper
+                               // either as another connected Sortable may yet handle the removal.
+                               sortable.cancelHelperRemoval = true;
+
+                               sortable._trigger( "deactivate", event, uiSortable );
+                       }
+               });
+       },
+       drag: function( event, ui, draggable ) {
+               $.each( draggable.sortables, function() {
+                       var innermostIntersecting = false,
+                               sortable = this;
+
+                       // Copy over variables that sortable's _intersectsWith uses
+                       sortable.positionAbs = draggable.positionAbs;
+                       sortable.helperProportions = draggable.helperProportions;
+                       sortable.offset.click = draggable.offset.click;
+
+                       if ( sortable._intersectsWith( sortable.containerCache ) ) {
+                               innermostIntersecting = true;
+
+                               $.each( draggable.sortables, function() {
+                                       // Copy over variables that sortable's _intersectsWith uses
+                                       this.positionAbs = draggable.positionAbs;
+                                       this.helperProportions = draggable.helperProportions;
+                                       this.offset.click = draggable.offset.click;
+
+                                       if ( this !== sortable &&
+                                                       this._intersectsWith( this.containerCache ) &&
+                                                       $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
+                                               innermostIntersecting = false;
+                                       }
+
+                                       return innermostIntersecting;
+                               });
+                       }
+
+                       if ( innermostIntersecting ) {
+                               // If it intersects, we use a little isOver variable and set it once,
+                               // so that the move-in stuff gets fired only once.
+                               if ( !sortable.isOver ) {
+                                       sortable.isOver = 1;
+
+                                       sortable.currentItem = ui.helper
+                                               .appendTo( sortable.element )
+                                               .data( "ui-sortable-item", true );
+
+                                       // Store helper option to later restore it
+                                       sortable.options._helper = sortable.options.helper;
+
+                                       sortable.options.helper = function() {
+                                               return ui.helper[ 0 ];
+                                       };
+
+                                       // Fire the start events of the sortable with our passed browser event,
+                                       // and our own helper (so it doesn't create a new one)
+                                       event.target = sortable.currentItem[ 0 ];
+                                       sortable._mouseCapture( event, true );
+                                       sortable._mouseStart( event, true, true );
+
+                                       // Because the browser event is way off the new appended portlet,
+                                       // modify necessary variables to reflect the changes
+                                       sortable.offset.click.top = draggable.offset.click.top;
+                                       sortable.offset.click.left = draggable.offset.click.left;
+                                       sortable.offset.parent.left -= draggable.offset.parent.left -
+                                               sortable.offset.parent.left;
+                                       sortable.offset.parent.top -= draggable.offset.parent.top -
+                                               sortable.offset.parent.top;
+
+                                       draggable._trigger( "toSortable", event );
+
+                                       // Inform draggable that the helper is in a valid drop zone,
+                                       // used solely in the revert option to handle "valid/invalid".
+                                       draggable.dropped = sortable.element;
+
+                                       // Need to refreshPositions of all sortables in the case that
+                                       // adding to one sortable changes the location of the other sortables (#9675)
+                                       $.each( draggable.sortables, function() {
+                                               this.refreshPositions();
+                                       });
+
+                                       // hack so receive/update callbacks work (mostly)
+                                       draggable.currentItem = draggable.element;
+                                       sortable.fromOutside = draggable;
+                               }
+
+                               if ( sortable.currentItem ) {
+                                       sortable._mouseDrag( event );
+                                       // Copy the sortable's position because the draggable's can potentially reflect
+                                       // a relative position, while sortable is always absolute, which the dragged
+                                       // element has now become. (#8809)
+                                       ui.position = sortable.position;
+                               }
+                       } else {
+                               // If it doesn't intersect with the sortable, and it intersected before,
+                               // we fake the drag stop of the sortable, but make sure it doesn't remove
+                               // the helper by using cancelHelperRemoval.
+                               if ( sortable.isOver ) {
+
+                                       sortable.isOver = 0;
+                                       sortable.cancelHelperRemoval = true;
+
+                                       // Calling sortable's mouseStop would trigger a revert,
+                                       // so revert must be temporarily false until after mouseStop is called.
+                                       sortable.options._revert = sortable.options.revert;
+                                       sortable.options.revert = false;
+
+                                       sortable._trigger( "out", event, sortable._uiHash( sortable ) );
+                                       sortable._mouseStop( event, true );
+
+                                       // restore sortable behaviors that were modfied
+                                       // when the draggable entered the sortable area (#9481)
+                                       sortable.options.revert = sortable.options._revert;
+                                       sortable.options.helper = sortable.options._helper;
+
+                                       if ( sortable.placeholder ) {
+                                               sortable.placeholder.remove();
+                                       }
+
+                                       // Recalculate the draggable's offset considering the sortable
+                                       // may have modified them in unexpected ways (#8809)
+                                       draggable._refreshOffsets( event );
+                                       ui.position = draggable._generatePosition( event, true );
+
+                                       draggable._trigger( "fromSortable", event );
+
+                                       // Inform draggable that the helper is no longer in a valid drop zone
+                                       draggable.dropped = false;
+
+                                       // Need to refreshPositions of all sortables just in case removing
+                                       // from one sortable changes the location of other sortables (#9675)
+                                       $.each( draggable.sortables, function() {
+                                               this.refreshPositions();
+                                       });
+                               }
+                       }
+               });
+       }
+});
+
+$.ui.plugin.add("draggable", "cursor", {
+       start: function( event, ui, instance ) {
+               var t = $( "body" ),
+                       o = instance.options;
+
+               if (t.css("cursor")) {
+                       o._cursor = t.css("cursor");
+               }
+               t.css("cursor", o.cursor);
+       },
+       stop: function( event, ui, instance ) {
+               var o = instance.options;
+               if (o._cursor) {
+                       $("body").css("cursor", o._cursor);
+               }
+       }
+});
+
+$.ui.plugin.add("draggable", "opacity", {
+       start: function( event, ui, instance ) {
+               var t = $( ui.helper ),
+                       o = instance.options;
+               if (t.css("opacity")) {
+                       o._opacity = t.css("opacity");
+               }
+               t.css("opacity", o.opacity);
+       },
+       stop: function( event, ui, instance ) {
+               var o = instance.options;
+               if (o._opacity) {
+                       $(ui.helper).css("opacity", o._opacity);
+               }
+       }
+});
+
+$.ui.plugin.add("draggable", "scroll", {
+       start: function( event, ui, i ) {
+               if ( !i.scrollParentNotHidden ) {
+                       i.scrollParentNotHidden = i.helper.scrollParent( false );
+               }
+
+               if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] && i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
+                       i.overflowOffset = i.scrollParentNotHidden.offset();
+               }
+       },
+       drag: function( event, ui, i  ) {
+
+               var o = i.options,
+                       scrolled = false,
+                       scrollParent = i.scrollParentNotHidden[ 0 ],
+                       document = i.document[ 0 ];
+
+               if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
+                       if ( !o.axis || o.axis !== "x" ) {
+                               if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY < o.scrollSensitivity ) {
+                                       scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
+                               } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
+                                       scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
+                               }
+                       }
+
+                       if ( !o.axis || o.axis !== "y" ) {
+                               if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX < o.scrollSensitivity ) {
+                                       scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
+                               } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
+                                       scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
+                               }
+                       }
+
+               } else {
+
+                       if (!o.axis || o.axis !== "x") {
+                               if (event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+                                       scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+                               } else if ($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+                                       scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+                               }
+                       }
+
+                       if (!o.axis || o.axis !== "y") {
+                               if (event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+                                       scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+                               } else if ($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+                                       scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+                               }
+                       }
+
+               }
+
+               if (scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+                       $.ui.ddmanager.prepareOffsets(i, event);
+               }
+
+       }
+});
+
+$.ui.plugin.add("draggable", "snap", {
+       start: function( event, ui, i ) {
+
+               var o = i.options;
+
+               i.snapElements = [];
+
+               $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() {
+                       var $t = $(this),
+                               $o = $t.offset();
+                       if (this !== i.element[0]) {
+                               i.snapElements.push({
+                                       item: this,
+                                       width: $t.outerWidth(), height: $t.outerHeight(),
+                                       top: $o.top, left: $o.left
+                               });
+                       }
+               });
+
+       },
+       drag: function( event, ui, inst ) {
+
+               var ts, bs, ls, rs, l, r, t, b, i, first,
+                       o = inst.options,
+                       d = o.snapTolerance,
+                       x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
+                       y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
+
+               for (i = inst.snapElements.length - 1; i >= 0; i--){
+
+                       l = inst.snapElements[i].left - inst.margins.left;
+                       r = l + inst.snapElements[i].width;
+                       t = inst.snapElements[i].top - inst.margins.top;
+                       b = t + inst.snapElements[i].height;
+
+                       if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) {
+                               if (inst.snapElements[i].snapping) {
+                                       (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+                               }
+                               inst.snapElements[i].snapping = false;
+                               continue;
+                       }
+
+                       if (o.snapMode !== "inner") {
+                               ts = Math.abs(t - y2) <= d;
+                               bs = Math.abs(b - y1) <= d;
+                               ls = Math.abs(l - x2) <= d;
+                               rs = Math.abs(r - x1) <= d;
+                               if (ts) {
+                                       ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top;
+                               }
+                               if (bs) {
+                                       ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top;
+                               }
+                               if (ls) {
+                                       ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left;
+                               }
+                               if (rs) {
+                                       ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left;
+                               }
+                       }
+
+                       first = (ts || bs || ls || rs);
+
+                       if (o.snapMode !== "outer") {
+                               ts = Math.abs(t - y1) <= d;
+                               bs = Math.abs(b - y2) <= d;
+                               ls = Math.abs(l - x1) <= d;
+                               rs = Math.abs(r - x2) <= d;
+                               if (ts) {
+                                       ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top;
+                               }
+                               if (bs) {
+                                       ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top;
+                               }
+                               if (ls) {
+                                       ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left;
+                               }
+                               if (rs) {
+                                       ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left;
+                               }
+                       }
+
+                       if (!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) {
+                               (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item })));
+                       }
+                       inst.snapElements[i].snapping = (ts || bs || ls || rs || first);
+
+               }
+
+       }
+});
+
+$.ui.plugin.add("draggable", "stack", {
+       start: function( event, ui, instance ) {
+               var min,
+                       o = instance.options,
+                       group = $.makeArray($(o.stack)).sort(function(a, b) {
+                               return (parseInt($(a).css("zIndex"), 10) || 0) - (parseInt($(b).css("zIndex"), 10) || 0);
+                       });
+
+               if (!group.length) { return; }
+
+               min = parseInt($(group[0]).css("zIndex"), 10) || 0;
+               $(group).each(function(i) {
+                       $(this).css("zIndex", min + i);
+               });
+               this.css("zIndex", (min + group.length));
+       }
+});
+
+$.ui.plugin.add("draggable", "zIndex", {
+       start: function( event, ui, instance ) {
+               var t = $( ui.helper ),
+                       o = instance.options;
+
+               if (t.css("zIndex")) {
+                       o._zIndex = t.css("zIndex");
+               }
+               t.css("zIndex", o.zIndex);
+       },
+       stop: function( event, ui, instance ) {
+               var o = instance.options;
+
+               if (o._zIndex) {
+                       $(ui.helper).css("zIndex", o._zIndex);
+               }
+       }
+});
+
+var draggable = $.ui.draggable;
+
+
+/*!
+ * jQuery UI Resizable 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/resizable/
+ */
+
+
+$.widget("ui.resizable", $.ui.mouse, {
+       version: "1.11.2",
+       widgetEventPrefix: "resize",
+       options: {
+               alsoResize: false,
+               animate: false,
+               animateDuration: "slow",
+               animateEasing: "swing",
+               aspectRatio: false,
+               autoHide: false,
+               containment: false,
+               ghost: false,
+               grid: false,
+               handles: "e,s,se",
+               helper: false,
+               maxHeight: null,
+               maxWidth: null,
+               minHeight: 10,
+               minWidth: 10,
+               // See #7960
+               zIndex: 90,
+
+               // callbacks
+               resize: null,
+               start: null,
+               stop: null
+       },
+
+       _num: function( value ) {
+               return parseInt( value, 10 ) || 0;
+       },
+
+       _isNumber: function( value ) {
+               return !isNaN( parseInt( value, 10 ) );
+       },
+
+       _hasScroll: function( el, a ) {
+
+               if ( $( el ).css( "overflow" ) === "hidden") {
+                       return false;
+               }
+
+               var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
+                       has = false;
+
+               if ( el[ scroll ] > 0 ) {
+                       return true;
+               }
+
+               // TODO: determine which cases actually cause this to happen
+               // if the element doesn't have the scroll set, see if it's possible to
+               // set the scroll
+               el[ scroll ] = 1;
+               has = ( el[ scroll ] > 0 );
+               el[ scroll ] = 0;
+               return has;
+       },
+
+       _create: function() {
+
+               var n, i, handle, axis, hname,
+                       that = this,
+                       o = this.options;
+               this.element.addClass("ui-resizable");
+
+               $.extend(this, {
+                       _aspectRatio: !!(o.aspectRatio),
+                       aspectRatio: o.aspectRatio,
+                       originalElement: this.element,
+                       _proportionallyResizeElements: [],
+                       _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
+               });
+
+               // Wrap the element if it cannot hold child nodes
+               if (this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) {
+
+                       this.element.wrap(
+                               $("<div class='ui-wrapper' style='overflow: hidden;'></div>").css({
+                                       position: this.element.css("position"),
+                                       width: this.element.outerWidth(),
+                                       height: this.element.outerHeight(),
+                                       top: this.element.css("top"),
+                                       left: this.element.css("left")
+                               })
+                       );
+
+                       this.element = this.element.parent().data(
+                               "ui-resizable", this.element.resizable( "instance" )
+                       );
+
+                       this.elementIsWrapper = true;
+
+                       this.element.css({
+                               marginLeft: this.originalElement.css("marginLeft"),
+                               marginTop: this.originalElement.css("marginTop"),
+                               marginRight: this.originalElement.css("marginRight"),
+                               marginBottom: this.originalElement.css("marginBottom")
+                       });
+                       this.originalElement.css({
+                               marginLeft: 0,
+                               marginTop: 0,
+                               marginRight: 0,
+                               marginBottom: 0
+                       });
+                       // support: Safari
+                       // Prevent Safari textarea resize
+                       this.originalResizeStyle = this.originalElement.css("resize");
+                       this.originalElement.css("resize", "none");
+
+                       this._proportionallyResizeElements.push( this.originalElement.css({
+                               position: "static",
+                               zoom: 1,
+                               display: "block"
+                       }) );
+
+                       // support: IE9
+                       // avoid IE jump (hard set the margin)
+                       this.originalElement.css({ margin: this.originalElement.css("margin") });
+
+                       this._proportionallyResize();
+               }
+
+               this.handles = o.handles ||
+                       ( !$(".ui-resizable-handle", this.element).length ?
+                               "e,s,se" : {
+                                       n: ".ui-resizable-n",
+                                       e: ".ui-resizable-e",
+                                       s: ".ui-resizable-s",
+                                       w: ".ui-resizable-w",
+                                       se: ".ui-resizable-se",
+                                       sw: ".ui-resizable-sw",
+                                       ne: ".ui-resizable-ne",
+                                       nw: ".ui-resizable-nw"
+                               } );
+
+               if (this.handles.constructor === String) {
+
+                       if ( this.handles === "all") {
+                               this.handles = "n,e,s,w,se,sw,ne,nw";
+                       }
+
+                       n = this.handles.split(",");
+                       this.handles = {};
+
+                       for (i = 0; i < n.length; i++) {
+
+                               handle = $.trim(n[i]);
+                               hname = "ui-resizable-" + handle;
+                               axis = $("<div class='ui-resizable-handle " + hname + "'></div>");
+
+                               axis.css({ zIndex: o.zIndex });
+
+                               // TODO : What's going on here?
+                               if ("se" === handle) {
+                                       axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se");
+                               }
+
+                               this.handles[handle] = ".ui-resizable-" + handle;
+                               this.element.append(axis);
+                       }
+
+               }
+
+               this._renderAxis = function(target) {
+
+                       var i, axis, padPos, padWrapper;
+
+                       target = target || this.element;
+
+                       for (i in this.handles) {
+
+                               if (this.handles[i].constructor === String) {
+                                       this.handles[i] = this.element.children( this.handles[ i ] ).first().show();
+                               }
+
+                               if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) {
+
+                                       axis = $(this.handles[i], this.element);
+
+                                       padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth();
+
+                                       padPos = [ "padding",
+                                               /ne|nw|n/.test(i) ? "Top" :
+                                               /se|sw|s/.test(i) ? "Bottom" :
+                                               /^e$/.test(i) ? "Right" : "Left" ].join("");
+
+                                       target.css(padPos, padWrapper);
+
+                                       this._proportionallyResize();
+
+                               }
+
+                               // TODO: What's that good for? There's not anything to be executed left
+                               if (!$(this.handles[i]).length) {
+                                       continue;
+                               }
+                       }
+               };
+
+               // TODO: make renderAxis a prototype function
+               this._renderAxis(this.element);
+
+               this._handles = $(".ui-resizable-handle", this.element)
+                       .disableSelection();
+
+               this._handles.mouseover(function() {
+                       if (!that.resizing) {
+                               if (this.className) {
+                                       axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);
+                               }
+                               that.axis = axis && axis[1] ? axis[1] : "se";
+                       }
+               });
+
+               if (o.autoHide) {
+                       this._handles.hide();
+                       $(this.element)
+                               .addClass("ui-resizable-autohide")
+                               .mouseenter(function() {
+                                       if (o.disabled) {
+                                               return;
+                                       }
+                                       $(this).removeClass("ui-resizable-autohide");
+                                       that._handles.show();
+                               })
+                               .mouseleave(function() {
+                                       if (o.disabled) {
+                                               return;
+                                       }
+                                       if (!that.resizing) {
+                                               $(this).addClass("ui-resizable-autohide");
+                                               that._handles.hide();
+                                       }
+                               });
+               }
+
+               this._mouseInit();
+
+       },
+
+       _destroy: function() {
+
+               this._mouseDestroy();
+
+               var wrapper,
+                       _destroy = function(exp) {
+                               $(exp)
+                                       .removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing")
+                                       .removeData("resizable")
+                                       .removeData("ui-resizable")
+                                       .unbind(".resizable")
+                                       .find(".ui-resizable-handle")
+                                               .remove();
+                       };
+
+               // TODO: Unwrap at same DOM position
+               if (this.elementIsWrapper) {
+                       _destroy(this.element);
+                       wrapper = this.element;
+                       this.originalElement.css({
+                               position: wrapper.css("position"),
+                               width: wrapper.outerWidth(),
+                               height: wrapper.outerHeight(),
+                               top: wrapper.css("top"),
+                               left: wrapper.css("left")
+                       }).insertAfter( wrapper );
+                       wrapper.remove();
+               }
+
+               this.originalElement.css("resize", this.originalResizeStyle);
+               _destroy(this.originalElement);
+
+               return this;
+       },
+
+       _mouseCapture: function(event) {
+               var i, handle,
+                       capture = false;
+
+               for (i in this.handles) {
+                       handle = $(this.handles[i])[0];
+                       if (handle === event.target || $.contains(handle, event.target)) {
+                               capture = true;
+                       }
+               }
+
+               return !this.options.disabled && capture;
+       },
+
+       _mouseStart: function(event) {
+
+               var curleft, curtop, cursor,
+                       o = this.options,
+                       el = this.element;
+
+               this.resizing = true;
+
+               this._renderProxy();
+
+               curleft = this._num(this.helper.css("left"));
+               curtop = this._num(this.helper.css("top"));
+
+               if (o.containment) {
+                       curleft += $(o.containment).scrollLeft() || 0;
+                       curtop += $(o.containment).scrollTop() || 0;
+               }
+
+               this.offset = this.helper.offset();
+               this.position = { left: curleft, top: curtop };
+
+               this.size = this._helper ? {
+                               width: this.helper.width(),
+                               height: this.helper.height()
+                       } : {
+                               width: el.width(),
+                               height: el.height()
+                       };
+
+               this.originalSize = this._helper ? {
+                               width: el.outerWidth(),
+                               height: el.outerHeight()
+                       } : {
+                               width: el.width(),
+                               height: el.height()
+                       };
+
+               this.sizeDiff = {
+                       width: el.outerWidth() - el.width(),
+                       height: el.outerHeight() - el.height()
+               };
+
+               this.originalPosition = { left: curleft, top: curtop };
+               this.originalMousePosition = { left: event.pageX, top: event.pageY };
+
+               this.aspectRatio = (typeof o.aspectRatio === "number") ?
+                       o.aspectRatio :
+                       ((this.originalSize.width / this.originalSize.height) || 1);
+
+               cursor = $(".ui-resizable-" + this.axis).css("cursor");
+               $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor);
+
+               el.addClass("ui-resizable-resizing");
+               this._propagate("start", event);
+               return true;
+       },
+
+       _mouseDrag: function(event) {
+
+               var data, props,
+                       smp = this.originalMousePosition,
+                       a = this.axis,
+                       dx = (event.pageX - smp.left) || 0,
+                       dy = (event.pageY - smp.top) || 0,
+                       trigger = this._change[a];
+
+               this._updatePrevProperties();
+
+               if (!trigger) {
+                       return false;
+               }
+
+               data = trigger.apply(this, [ event, dx, dy ]);
+
+               this._updateVirtualBoundaries(event.shiftKey);
+               if (this._aspectRatio || event.shiftKey) {
+                       data = this._updateRatio(data, event);
+               }
+
+               data = this._respectSize(data, event);
+
+               this._updateCache(data);
+
+               this._propagate("resize", event);
+
+               props = this._applyChanges();
+
+               if ( !this._helper && this._proportionallyResizeElements.length ) {
+                       this._proportionallyResize();
+               }
+
+               if ( !$.isEmptyObject( props ) ) {
+                       this._updatePrevProperties();
+                       this._trigger( "resize", event, this.ui() );
+                       this._applyChanges();
+               }
+
+               return false;
+       },
+
+       _mouseStop: function(event) {
+
+               this.resizing = false;
+               var pr, ista, soffseth, soffsetw, s, left, top,
+                       o = this.options, that = this;
+
+               if (this._helper) {
+
+                       pr = this._proportionallyResizeElements;
+                       ista = pr.length && (/textarea/i).test(pr[0].nodeName);
+                       soffseth = ista && this._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height;
+                       soffsetw = ista ? 0 : that.sizeDiff.width;
+
+                       s = {
+                               width: (that.helper.width()  - soffsetw),
+                               height: (that.helper.height() - soffseth)
+                       };
+                       left = (parseInt(that.element.css("left"), 10) +
+                               (that.position.left - that.originalPosition.left)) || null;
+                       top = (parseInt(that.element.css("top"), 10) +
+                               (that.position.top - that.originalPosition.top)) || null;
+
+                       if (!o.animate) {
+                               this.element.css($.extend(s, { top: top, left: left }));
+                       }
+
+                       that.helper.height(that.size.height);
+                       that.helper.width(that.size.width);
+
+                       if (this._helper && !o.animate) {
+                               this._proportionallyResize();
+                       }
+               }
+
+               $("body").css("cursor", "auto");
+
+               this.element.removeClass("ui-resizable-resizing");
+
+               this._propagate("stop", event);
+
+               if (this._helper) {
+                       this.helper.remove();
+               }
+
+               return false;
+
+       },
+
+       _updatePrevProperties: function() {
+               this.prevPosition = {
+                       top: this.position.top,
+                       left: this.position.left
+               };
+               this.prevSize = {
+                       width: this.size.width,
+                       height: this.size.height
+               };
+       },
+
+       _applyChanges: function() {
+               var props = {};
+
+               if ( this.position.top !== this.prevPosition.top ) {
+                       props.top = this.position.top + "px";
+               }
+               if ( this.position.left !== this.prevPosition.left ) {
+                       props.left = this.position.left + "px";
+               }
+               if ( this.size.width !== this.prevSize.width ) {
+                       props.width = this.size.width + "px";
+               }
+               if ( this.size.height !== this.prevSize.height ) {
+                       props.height = this.size.height + "px";
+               }
+
+               this.helper.css( props );
+
+               return props;
+       },
+
+       _updateVirtualBoundaries: function(forceAspectRatio) {
+               var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
+                       o = this.options;
+
+               b = {
+                       minWidth: this._isNumber(o.minWidth) ? o.minWidth : 0,
+                       maxWidth: this._isNumber(o.maxWidth) ? o.maxWidth : Infinity,
+                       minHeight: this._isNumber(o.minHeight) ? o.minHeight : 0,
+                       maxHeight: this._isNumber(o.maxHeight) ? o.maxHeight : Infinity
+               };
+
+               if (this._aspectRatio || forceAspectRatio) {
+                       pMinWidth = b.minHeight * this.aspectRatio;
+                       pMinHeight = b.minWidth / this.aspectRatio;
+                       pMaxWidth = b.maxHeight * this.aspectRatio;
+                       pMaxHeight = b.maxWidth / this.aspectRatio;
+
+                       if (pMinWidth > b.minWidth) {
+                               b.minWidth = pMinWidth;
+                       }
+                       if (pMinHeight > b.minHeight) {
+                               b.minHeight = pMinHeight;
+                       }
+                       if (pMaxWidth < b.maxWidth) {
+                               b.maxWidth = pMaxWidth;
+                       }
+                       if (pMaxHeight < b.maxHeight) {
+                               b.maxHeight = pMaxHeight;
+                       }
+               }
+               this._vBoundaries = b;
+       },
+
+       _updateCache: function(data) {
+               this.offset = this.helper.offset();
+               if (this._isNumber(data.left)) {
+                       this.position.left = data.left;
+               }
+               if (this._isNumber(data.top)) {
+                       this.position.top = data.top;
+               }
+               if (this._isNumber(data.height)) {
+                       this.size.height = data.height;
+               }
+               if (this._isNumber(data.width)) {
+                       this.size.width = data.width;
+               }
+       },
+
+       _updateRatio: function( data ) {
+
+               var cpos = this.position,
+                       csize = this.size,
+                       a = this.axis;
+
+               if (this._isNumber(data.height)) {
+                       data.width = (data.height * this.aspectRatio);
+               } else if (this._isNumber(data.width)) {
+                       data.height = (data.width / this.aspectRatio);
+               }
+
+               if (a === "sw") {
+                       data.left = cpos.left + (csize.width - data.width);
+                       data.top = null;
+               }
+               if (a === "nw") {
+                       data.top = cpos.top + (csize.height - data.height);
+                       data.left = cpos.left + (csize.width - data.width);
+               }
+
+               return data;
+       },
+
+       _respectSize: function( data ) {
+
+               var o = this._vBoundaries,
+                       a = this.axis,
+                       ismaxw = this._isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width),
+                       ismaxh = this._isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height),
+                       isminw = this._isNumber(data.width) && o.minWidth && (o.minWidth > data.width),
+                       isminh = this._isNumber(data.height) && o.minHeight && (o.minHeight > data.height),
+                       dw = this.originalPosition.left + this.originalSize.width,
+                       dh = this.position.top + this.size.height,
+                       cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a);
+               if (isminw) {
+                       data.width = o.minWidth;
+               }
+               if (isminh) {
+                       data.height = o.minHeight;
+               }
+               if (ismaxw) {
+                       data.width = o.maxWidth;
+               }
+               if (ismaxh) {
+                       data.height = o.maxHeight;
+               }
+
+               if (isminw && cw) {
+                       data.left = dw - o.minWidth;
+               }
+               if (ismaxw && cw) {
+                       data.left = dw - o.maxWidth;
+               }
+               if (isminh && ch) {
+                       data.top = dh - o.minHeight;
+               }
+               if (ismaxh && ch) {
+                       data.top = dh - o.maxHeight;
+               }
+
+               // Fixing jump error on top/left - bug #2330
+               if (!data.width && !data.height && !data.left && data.top) {
+                       data.top = null;
+               } else if (!data.width && !data.height && !data.top && data.left) {
+                       data.left = null;
+               }
+
+               return data;
+       },
+
+       _getPaddingPlusBorderDimensions: function( element ) {
+               var i = 0,
+                       widths = [],
+                       borders = [
+                               element.css( "borderTopWidth" ),
+                               element.css( "borderRightWidth" ),
+                               element.css( "borderBottomWidth" ),
+                               element.css( "borderLeftWidth" )
+                       ],
+                       paddings = [
+                               element.css( "paddingTop" ),
+                               element.css( "paddingRight" ),
+                               element.css( "paddingBottom" ),
+                               element.css( "paddingLeft" )
+                       ];
+
+               for ( ; i < 4; i++ ) {
+                       widths[ i ] = ( parseInt( borders[ i ], 10 ) || 0 );
+                       widths[ i ] += ( parseInt( paddings[ i ], 10 ) || 0 );
+               }
+
+               return {
+                       height: widths[ 0 ] + widths[ 2 ],
+                       width: widths[ 1 ] + widths[ 3 ]
+               };
+       },
+
+       _proportionallyResize: function() {
+
+               if (!this._proportionallyResizeElements.length) {
+                       return;
+               }
+
+               var prel,
+                       i = 0,
+                       element = this.helper || this.element;
+
+               for ( ; i < this._proportionallyResizeElements.length; i++) {
+
+                       prel = this._proportionallyResizeElements[i];
+
+                       // TODO: Seems like a bug to cache this.outerDimensions
+                       // considering that we are in a loop.
+                       if (!this.outerDimensions) {
+                               this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
+                       }
+
+                       prel.css({
+                               height: (element.height() - this.outerDimensions.height) || 0,
+                               width: (element.width() - this.outerDimensions.width) || 0
+                       });
+
+               }
+
+       },
+
+       _renderProxy: function() {
+
+               var el = this.element, o = this.options;
+               this.elementOffset = el.offset();
+
+               if (this._helper) {
+
+                       this.helper = this.helper || $("<div style='overflow:hidden;'></div>");
+
+                       this.helper.addClass(this._helper).css({
+                               width: this.element.outerWidth() - 1,
+                               height: this.element.outerHeight() - 1,
+                               position: "absolute",
+                               left: this.elementOffset.left + "px",
+                               top: this.elementOffset.top + "px",
+                               zIndex: ++o.zIndex //TODO: Don't modify option
+                       });
+
+                       this.helper
+                               .appendTo("body")
+                               .disableSelection();
+
+               } else {
+                       this.helper = this.element;
+               }
+
+       },
+
+       _change: {
+               e: function(event, dx) {
+                       return { width: this.originalSize.width + dx };
+               },
+               w: function(event, dx) {
+                       var cs = this.originalSize, sp = this.originalPosition;
+                       return { left: sp.left + dx, width: cs.width - dx };
+               },
+               n: function(event, dx, dy) {
+                       var cs = this.originalSize, sp = this.originalPosition;
+                       return { top: sp.top + dy, height: cs.height - dy };
+               },
+               s: function(event, dx, dy) {
+                       return { height: this.originalSize.height + dy };
+               },
+               se: function(event, dx, dy) {
+                       return $.extend(this._change.s.apply(this, arguments),
+                               this._change.e.apply(this, [ event, dx, dy ]));
+               },
+               sw: function(event, dx, dy) {
+                       return $.extend(this._change.s.apply(this, arguments),
+                               this._change.w.apply(this, [ event, dx, dy ]));
+               },
+               ne: function(event, dx, dy) {
+                       return $.extend(this._change.n.apply(this, arguments),
+                               this._change.e.apply(this, [ event, dx, dy ]));
+               },
+               nw: function(event, dx, dy) {
+                       return $.extend(this._change.n.apply(this, arguments),
+                               this._change.w.apply(this, [ event, dx, dy ]));
+               }
+       },
+
+       _propagate: function(n, event) {
+               $.ui.plugin.call(this, n, [ event, this.ui() ]);
+               (n !== "resize" && this._trigger(n, event, this.ui()));
+       },
+
+       plugins: {},
+
+       ui: function() {
+               return {
+                       originalElement: this.originalElement,
+                       element: this.element,
+                       helper: this.helper,
+                       position: this.position,
+                       size: this.size,
+                       originalSize: this.originalSize,
+                       originalPosition: this.originalPosition
+               };
+       }
+
+});
+
+/*
+ * Resizable Extensions
+ */
+
+$.ui.plugin.add("resizable", "animate", {
+
+       stop: function( event ) {
+               var that = $(this).resizable( "instance" ),
+                       o = that.options,
+                       pr = that._proportionallyResizeElements,
+                       ista = pr.length && (/textarea/i).test(pr[0].nodeName),
+                       soffseth = ista && that._hasScroll(pr[0], "left") ? 0 : that.sizeDiff.height,
+                       soffsetw = ista ? 0 : that.sizeDiff.width,
+                       style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) },
+                       left = (parseInt(that.element.css("left"), 10) +
+                               (that.position.left - that.originalPosition.left)) || null,
+                       top = (parseInt(that.element.css("top"), 10) +
+                               (that.position.top - that.originalPosition.top)) || null;
+
+               that.element.animate(
+                       $.extend(style, top && left ? { top: top, left: left } : {}), {
+                               duration: o.animateDuration,
+                               easing: o.animateEasing,
+                               step: function() {
+
+                                       var data = {
+                                               width: parseInt(that.element.css("width"), 10),
+                                               height: parseInt(that.element.css("height"), 10),
+                                               top: parseInt(that.element.css("top"), 10),
+                                               left: parseInt(that.element.css("left"), 10)
+                                       };
+
+                                       if (pr && pr.length) {
+                                               $(pr[0]).css({ width: data.width, height: data.height });
+                                       }
+
+                                       // propagating resize, and updating values for each animation step
+                                       that._updateCache(data);
+                                       that._propagate("resize", event);
+
+                               }
+                       }
+               );
+       }
+
+});
+
+$.ui.plugin.add( "resizable", "containment", {
+
+       start: function() {
+               var element, p, co, ch, cw, width, height,
+                       that = $( this ).resizable( "instance" ),
+                       o = that.options,
+                       el = that.element,
+                       oc = o.containment,
+                       ce = ( oc instanceof $ ) ? oc.get( 0 ) : ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
+
+               if ( !ce ) {
+                       return;
+               }
+
+               that.containerElement = $( ce );
+
+               if ( /document/.test( oc ) || oc === document ) {
+                       that.containerOffset = {
+                               left: 0,
+                               top: 0
+                       };
+                       that.containerPosition = {
+                               left: 0,
+                               top: 0
+                       };
+
+                       that.parentData = {
+                               element: $( document ),
+                               left: 0,
+                               top: 0,
+                               width: $( document ).width(),
+                               height: $( document ).height() || document.body.parentNode.scrollHeight
+                       };
+               } else {
+                       element = $( ce );
+                       p = [];
+                       $([ "Top", "Right", "Left", "Bottom" ]).each(function( i, name ) {
+                               p[ i ] = that._num( element.css( "padding" + name ) );
+                       });
+
+                       that.containerOffset = element.offset();
+                       that.containerPosition = element.position();
+                       that.containerSize = {
+                               height: ( element.innerHeight() - p[ 3 ] ),
+                               width: ( element.innerWidth() - p[ 1 ] )
+                       };
+
+                       co = that.containerOffset;
+                       ch = that.containerSize.height;
+                       cw = that.containerSize.width;
+                       width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
+                       height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
+
+                       that.parentData = {
+                               element: ce,
+                               left: co.left,
+                               top: co.top,
+                               width: width,
+                               height: height
+                       };
+               }
+       },
+
+       resize: function( event ) {
+               var woset, hoset, isParent, isOffsetRelative,
+                       that = $( this ).resizable( "instance" ),
+                       o = that.options,
+                       co = that.containerOffset,
+                       cp = that.position,
+                       pRatio = that._aspectRatio || event.shiftKey,
+                       cop = {
+                               top: 0,
+                               left: 0
+                       },
+                       ce = that.containerElement,
+                       continueResize = true;
+
+               if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
+                       cop = co;
+               }
+
+               if ( cp.left < ( that._helper ? co.left : 0 ) ) {
+                       that.size.width = that.size.width +
+                               ( that._helper ?
+                                       ( that.position.left - co.left ) :
+                                       ( that.position.left - cop.left ) );
+
+                       if ( pRatio ) {
+                               that.size.height = that.size.width / that.aspectRatio;
+                               continueResize = false;
+                       }
+                       that.position.left = o.helper ? co.left : 0;
+               }
+
+               if ( cp.top < ( that._helper ? co.top : 0 ) ) {
+                       that.size.height = that.size.height +
+                               ( that._helper ?
+                                       ( that.position.top - co.top ) :
+                                       that.position.top );
+
+                       if ( pRatio ) {
+                               that.size.width = that.size.height * that.aspectRatio;
+                               continueResize = false;
+                       }
+                       that.position.top = that._helper ? co.top : 0;
+               }
+
+               isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
+               isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
+
+               if ( isParent && isOffsetRelative ) {
+                       that.offset.left = that.parentData.left + that.position.left;
+                       that.offset.top = that.parentData.top + that.position.top;
+               } else {
+                       that.offset.left = that.element.offset().left;
+                       that.offset.top = that.element.offset().top;
+               }
+
+               woset = Math.abs( that.sizeDiff.width +
+                       (that._helper ?
+                               that.offset.left - cop.left :
+                               (that.offset.left - co.left)) );
+
+               hoset = Math.abs( that.sizeDiff.height +
+                       (that._helper ?
+                               that.offset.top - cop.top :
+                               (that.offset.top - co.top)) );
+
+               if ( woset + that.size.width >= that.parentData.width ) {
+                       that.size.width = that.parentData.width - woset;
+                       if ( pRatio ) {
+                               that.size.height = that.size.width / that.aspectRatio;
+                               continueResize = false;
+                       }
+               }
+
+               if ( hoset + that.size.height >= that.parentData.height ) {
+                       that.size.height = that.parentData.height - hoset;
+                       if ( pRatio ) {
+                               that.size.width = that.size.height * that.aspectRatio;
+                               continueResize = false;
+                       }
+               }
+
+               if ( !continueResize ){
+                       that.position.left = that.prevPosition.left;
+                       that.position.top = that.prevPosition.top;
+                       that.size.width = that.prevSize.width;
+                       that.size.height = that.prevSize.height;
+               }
+       },
+
+       stop: function() {
+               var that = $( this ).resizable( "instance" ),
+                       o = that.options,
+                       co = that.containerOffset,
+                       cop = that.containerPosition,
+                       ce = that.containerElement,
+                       helper = $( that.helper ),
+                       ho = helper.offset(),
+                       w = helper.outerWidth() - that.sizeDiff.width,
+                       h = helper.outerHeight() - that.sizeDiff.height;
+
+               if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
+                       $( this ).css({
+                               left: ho.left - cop.left - co.left,
+                               width: w,
+                               height: h
+                       });
+               }
+
+               if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
+                       $( this ).css({
+                               left: ho.left - cop.left - co.left,
+                               width: w,
+                               height: h
+                       });
+               }
+       }
+});
+
+$.ui.plugin.add("resizable", "alsoResize", {
+
+       start: function() {
+               var that = $(this).resizable( "instance" ),
+                       o = that.options,
+                       _store = function(exp) {
+                               $(exp).each(function() {
+                                       var el = $(this);
+                                       el.data("ui-resizable-alsoresize", {
+                                               width: parseInt(el.width(), 10), height: parseInt(el.height(), 10),
+                                               left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10)
+                                       });
+                               });
+                       };
+
+               if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) {
+                       if (o.alsoResize.length) {
+                               o.alsoResize = o.alsoResize[0];
+                               _store(o.alsoResize);
+                       } else {
+                               $.each(o.alsoResize, function(exp) {
+                                       _store(exp);
+                               });
+                       }
+               } else {
+                       _store(o.alsoResize);
+               }
+       },
+
+       resize: function(event, ui) {
+               var that = $(this).resizable( "instance" ),
+                       o = that.options,
+                       os = that.originalSize,
+                       op = that.originalPosition,
+                       delta = {
+                               height: (that.size.height - os.height) || 0,
+                               width: (that.size.width - os.width) || 0,
+                               top: (that.position.top - op.top) || 0,
+                               left: (that.position.left - op.left) || 0
+                       },
+
+                       _alsoResize = function(exp, c) {
+                               $(exp).each(function() {
+                                       var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {},
+                                               css = c && c.length ?
+                                                       c :
+                                                       el.parents(ui.originalElement[0]).length ?
+                                                               [ "width", "height" ] :
+                                                               [ "width", "height", "top", "left" ];
+
+                                       $.each(css, function(i, prop) {
+                                               var sum = (start[prop] || 0) + (delta[prop] || 0);
+                                               if (sum && sum >= 0) {
+                                                       style[prop] = sum || null;
+                                               }
+                                       });
+
+                                       el.css(style);
+                               });
+                       };
+
+               if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) {
+                       $.each(o.alsoResize, function(exp, c) {
+                               _alsoResize(exp, c);
+                       });
+               } else {
+                       _alsoResize(o.alsoResize);
+               }
+       },
+
+       stop: function() {
+               $(this).removeData("resizable-alsoresize");
+       }
+});
+
+$.ui.plugin.add("resizable", "ghost", {
+
+       start: function() {
+
+               var that = $(this).resizable( "instance" ), o = that.options, cs = that.size;
+
+               that.ghost = that.originalElement.clone();
+               that.ghost
+                       .css({
+                               opacity: 0.25,
+                               display: "block",
+                               position: "relative",
+                               height: cs.height,
+                               width: cs.width,
+                               margin: 0,
+                               left: 0,
+                               top: 0
+                       })
+                       .addClass("ui-resizable-ghost")
+                       .addClass(typeof o.ghost === "string" ? o.ghost : "");
+
+               that.ghost.appendTo(that.helper);
+
+       },
+
+       resize: function() {
+               var that = $(this).resizable( "instance" );
+               if (that.ghost) {
+                       that.ghost.css({
+                               position: "relative",
+                               height: that.size.height,
+                               width: that.size.width
+                       });
+               }
+       },
+
+       stop: function() {
+               var that = $(this).resizable( "instance" );
+               if (that.ghost && that.helper) {
+                       that.helper.get(0).removeChild(that.ghost.get(0));
+               }
+       }
+
+});
+
+$.ui.plugin.add("resizable", "grid", {
+
+       resize: function() {
+               var outerDimensions,
+                       that = $(this).resizable( "instance" ),
+                       o = that.options,
+                       cs = that.size,
+                       os = that.originalSize,
+                       op = that.originalPosition,
+                       a = that.axis,
+                       grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
+                       gridX = (grid[0] || 1),
+                       gridY = (grid[1] || 1),
+                       ox = Math.round((cs.width - os.width) / gridX) * gridX,
+                       oy = Math.round((cs.height - os.height) / gridY) * gridY,
+                       newWidth = os.width + ox,
+                       newHeight = os.height + oy,
+                       isMaxWidth = o.maxWidth && (o.maxWidth < newWidth),
+                       isMaxHeight = o.maxHeight && (o.maxHeight < newHeight),
+                       isMinWidth = o.minWidth && (o.minWidth > newWidth),
+                       isMinHeight = o.minHeight && (o.minHeight > newHeight);
+
+               o.grid = grid;
+
+               if (isMinWidth) {
+                       newWidth += gridX;
+               }
+               if (isMinHeight) {
+                       newHeight += gridY;
+               }
+               if (isMaxWidth) {
+                       newWidth -= gridX;
+               }
+               if (isMaxHeight) {
+                       newHeight -= gridY;
+               }
+
+               if (/^(se|s|e)$/.test(a)) {
+                       that.size.width = newWidth;
+                       that.size.height = newHeight;
+               } else if (/^(ne)$/.test(a)) {
+                       that.size.width = newWidth;
+                       that.size.height = newHeight;
+                       that.position.top = op.top - oy;
+               } else if (/^(sw)$/.test(a)) {
+                       that.size.width = newWidth;
+                       that.size.height = newHeight;
+                       that.position.left = op.left - ox;
+               } else {
+                       if ( newHeight - gridY <= 0 || newWidth - gridX <= 0) {
+                               outerDimensions = that._getPaddingPlusBorderDimensions( this );
+                       }
+
+                       if ( newHeight - gridY > 0 ) {
+                               that.size.height = newHeight;
+                               that.position.top = op.top - oy;
+                       } else {
+                               newHeight = gridY - outerDimensions.height;
+                               that.size.height = newHeight;
+                               that.position.top = op.top + os.height - newHeight;
+                       }
+                       if ( newWidth - gridX > 0 ) {
+                               that.size.width = newWidth;
+                               that.position.left = op.left - ox;
+                       } else {
+                               newWidth = gridY - outerDimensions.height;
+                               that.size.width = newWidth;
+                               that.position.left = op.left + os.width - newWidth;
+                       }
+               }
+       }
+
+});
+
+var resizable = $.ui.resizable;
+
+
+/*!
+ * jQuery UI Dialog 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/dialog/
+ */
+
+
+var dialog = $.widget( "ui.dialog", {
+       version: "1.11.2",
+       options: {
+               appendTo: "body",
+               autoOpen: true,
+               buttons: [],
+               closeOnEscape: true,
+               closeText: "Close",
+               dialogClass: "",
+               draggable: true,
+               hide: null,
+               height: "auto",
+               maxHeight: null,
+               maxWidth: null,
+               minHeight: 150,
+               minWidth: 150,
+               modal: false,
+               position: {
+                       my: "center",
+                       at: "center",
+                       of: window,
+                       collision: "fit",
+                       // Ensure the titlebar is always visible
+                       using: function( pos ) {
+                               var topOffset = $( this ).css( pos ).offset().top;
+                               if ( topOffset < 0 ) {
+                                       $( this ).css( "top", pos.top - topOffset );
+                               }
+                       }
+               },
+               resizable: true,
+               show: null,
+               title: null,
+               width: 300,
+
+               // callbacks
+               beforeClose: null,
+               close: null,
+               drag: null,
+               dragStart: null,
+               dragStop: null,
+               focus: null,
+               open: null,
+               resize: null,
+               resizeStart: null,
+               resizeStop: null
+       },
+
+       sizeRelatedOptions: {
+               buttons: true,
+               height: true,
+               maxHeight: true,
+               maxWidth: true,
+               minHeight: true,
+               minWidth: true,
+               width: true
+       },
+
+       resizableRelatedOptions: {
+               maxHeight: true,
+               maxWidth: true,
+               minHeight: true,
+               minWidth: true
+       },
+
+       _create: function() {
+               this.originalCss = {
+                       display: this.element[ 0 ].style.display,
+                       width: this.element[ 0 ].style.width,
+                       minHeight: this.element[ 0 ].style.minHeight,
+                       maxHeight: this.element[ 0 ].style.maxHeight,
+                       height: this.element[ 0 ].style.height
+               };
+               this.originalPosition = {
+                       parent: this.element.parent(),
+                       index: this.element.parent().children().index( this.element )
+               };
+               this.originalTitle = this.element.attr( "title" );
+               this.options.title = this.options.title || this.originalTitle;
+
+               this._createWrapper();
+
+               this.element
+                       .show()
+                       .removeAttr( "title" )
+                       .addClass( "ui-dialog-content ui-widget-content" )
+                       .appendTo( this.uiDialog );
+
+               this._createTitlebar();
+               this._createButtonPane();
+
+               if ( this.options.draggable && $.fn.draggable ) {
+                       this._makeDraggable();
+               }
+               if ( this.options.resizable && $.fn.resizable ) {
+                       this._makeResizable();
+               }
+
+               this._isOpen = false;
+
+               this._trackFocus();
+       },
+
+       _init: function() {
+               if ( this.options.autoOpen ) {
+                       this.open();
+               }
+       },
+
+       _appendTo: function() {
+               var element = this.options.appendTo;
+               if ( element && (element.jquery || element.nodeType) ) {
+                       return $( element );
+               }
+               return this.document.find( element || "body" ).eq( 0 );
+       },
+
+       _destroy: function() {
+               var next,
+                       originalPosition = this.originalPosition;
+
+               this._destroyOverlay();
+
+               this.element
+                       .removeUniqueId()
+                       .removeClass( "ui-dialog-content ui-widget-content" )
+                       .css( this.originalCss )
+                       // Without detaching first, the following becomes really slow
+                       .detach();
+
+               this.uiDialog.stop( true, true ).remove();
+
+               if ( this.originalTitle ) {
+                       this.element.attr( "title", this.originalTitle );
+               }
+
+               next = originalPosition.parent.children().eq( originalPosition.index );
+               // Don't try to place the dialog next to itself (#8613)
+               if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
+                       next.before( this.element );
+               } else {
+                       originalPosition.parent.append( this.element );
+               }
+       },
+
+       widget: function() {
+               return this.uiDialog;
+       },
+
+       disable: $.noop,
+       enable: $.noop,
+
+       close: function( event ) {
+               var activeElement,
+                       that = this;
+
+               if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
+                       return;
+               }
+
+               this._isOpen = false;
+               this._focusedElement = null;
+               this._destroyOverlay();
+               this._untrackInstance();
+
+               if ( !this.opener.filter( ":focusable" ).focus().length ) {
+
+                       // support: IE9
+                       // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
+                       try {
+                               activeElement = this.document[ 0 ].activeElement;
+
+                               // Support: IE9, IE10
+                               // If the <body> is blurred, IE will switch windows, see #4520
+                               if ( activeElement && activeElement.nodeName.toLowerCase() !== "body" ) {
+
+                                       // Hiding a focused element doesn't trigger blur in WebKit
+                                       // so in case we have nothing to focus on, explicitly blur the active element
+                                       // https://bugs.webkit.org/show_bug.cgi?id=47182
+                                       $( activeElement ).blur();
+                               }
+                       } catch ( error ) {}
+               }
+
+               this._hide( this.uiDialog, this.options.hide, function() {
+                       that._trigger( "close", event );
+               });
+       },
+
+       isOpen: function() {
+               return this._isOpen;
+       },
+
+       moveToTop: function() {
+               this._moveToTop();
+       },
+
+       _moveToTop: function( event, silent ) {
+               var moved = false,
+                       zIndicies = this.uiDialog.siblings( ".ui-front:visible" ).map(function() {
+                               return +$( this ).css( "z-index" );
+                       }).get(),
+                       zIndexMax = Math.max.apply( null, zIndicies );
+
+               if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
+                       this.uiDialog.css( "z-index", zIndexMax + 1 );
+                       moved = true;
+               }
+
+               if ( moved && !silent ) {
+                       this._trigger( "focus", event );
+               }
+               return moved;
+       },
+
+       open: function() {
+               var that = this;
+               if ( this._isOpen ) {
+                       if ( this._moveToTop() ) {
+                               this._focusTabbable();
+                       }
+                       return;
+               }
+
+               this._isOpen = true;
+               this.opener = $( this.document[ 0 ].activeElement );
+
+               this._size();
+               this._position();
+               this._createOverlay();
+               this._moveToTop( null, true );
+
+               // Ensure the overlay is moved to the top with the dialog, but only when
+               // opening. The overlay shouldn't move after the dialog is open so that
+               // modeless dialogs opened after the modal dialog stack properly.
+               if ( this.overlay ) {
+                       this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
+               }
+
+               this._show( this.uiDialog, this.options.show, function() {
+                       that._focusTabbable();
+                       that._trigger( "focus" );
+               });
+
+               // Track the dialog immediately upon openening in case a focus event
+               // somehow occurs outside of the dialog before an element inside the
+               // dialog is focused (#10152)
+               this._makeFocusTarget();
+
+               this._trigger( "open" );
+       },
+
+       _focusTabbable: function() {
+               // Set focus to the first match:
+               // 1. An element that was focused previously
+               // 2. First element inside the dialog matching [autofocus]
+               // 3. Tabbable element inside the content element
+               // 4. Tabbable element inside the buttonpane
+               // 5. The close button
+               // 6. The dialog itself
+               var hasFocus = this._focusedElement;
+               if ( !hasFocus ) {
+                       hasFocus = this.element.find( "[autofocus]" );
+               }
+               if ( !hasFocus.length ) {
+                       hasFocus = this.element.find( ":tabbable" );
+               }
+               if ( !hasFocus.length ) {
+                       hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
+               }
+               if ( !hasFocus.length ) {
+                       hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
+               }
+               if ( !hasFocus.length ) {
+                       hasFocus = this.uiDialog;
+               }
+               hasFocus.eq( 0 ).focus();
+       },
+
+       _keepFocus: function( event ) {
+               function checkFocus() {
+                       var activeElement = this.document[0].activeElement,
+                               isActive = this.uiDialog[0] === activeElement ||
+                                       $.contains( this.uiDialog[0], activeElement );
+                       if ( !isActive ) {
+                               this._focusTabbable();
+                       }
+               }
+               event.preventDefault();
+               checkFocus.call( this );
+               // support: IE
+               // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
+               // so we check again later
+               this._delay( checkFocus );
+       },
+
+       _createWrapper: function() {
+               this.uiDialog = $("<div>")
+                       .addClass( "ui-dialog ui-widget ui-widget-content ui-corner-all ui-front " +
+                               this.options.dialogClass )
+                       .hide()
+                       .attr({
+                               // Setting tabIndex makes the div focusable
+                               tabIndex: -1,
+                               role: "dialog"
+                       })
+                       .appendTo( this._appendTo() );
+
+               this._on( this.uiDialog, {
+                       keydown: function( event ) {
+                               if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
+                                               event.keyCode === $.ui.keyCode.ESCAPE ) {
+                                       event.preventDefault();
+                                       this.close( event );
+                                       return;
+                               }
+
+                               // prevent tabbing out of dialogs
+                               if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
+                                       return;
+                               }
+                               var tabbables = this.uiDialog.find( ":tabbable" ),
+                                       first = tabbables.filter( ":first" ),
+                                       last = tabbables.filter( ":last" );
+
+                               if ( ( event.target === last[0] || event.target === this.uiDialog[0] ) && !event.shiftKey ) {
+                                       this._delay(function() {
+                                               first.focus();
+                                       });
+                                       event.preventDefault();
+                               } else if ( ( event.target === first[0] || event.target === this.uiDialog[0] ) && event.shiftKey ) {
+                                       this._delay(function() {
+                                               last.focus();
+                                       });
+                                       event.preventDefault();
+                               }
+                       },
+                       mousedown: function( event ) {
+                               if ( this._moveToTop( event ) ) {
+                                       this._focusTabbable();
+                               }
+                       }
+               });
+
+               // We assume that any existing aria-describedby attribute means
+               // that the dialog content is marked up properly
+               // otherwise we brute force the content as the description
+               if ( !this.element.find( "[aria-describedby]" ).length ) {
+                       this.uiDialog.attr({
+                               "aria-describedby": this.element.uniqueId().attr( "id" )
+                       });
+               }
+       },
+
+       _createTitlebar: function() {
+               var uiDialogTitle;
+
+               this.uiDialogTitlebar = $( "<div>" )
+                       .addClass( "ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix" )
+                       .prependTo( this.uiDialog );
+               this._on( this.uiDialogTitlebar, {
+                       mousedown: function( event ) {
+                               // Don't prevent click on close button (#8838)
+                               // Focusing a dialog that is partially scrolled out of view
+                               // causes the browser to scroll it into view, preventing the click event
+                               if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
+                                       // Dialog isn't getting focus when dragging (#8063)
+                                       this.uiDialog.focus();
+                               }
+                       }
+               });
+
+               // support: IE
+               // Use type="button" to prevent enter keypresses in textboxes from closing the
+               // dialog in IE (#9312)
+               this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
+                       .button({
+                               label: this.options.closeText,
+                               icons: {
+                                       primary: "ui-icon-closethick"
+                               },
+                               text: false
+                       })
+                       .addClass( "ui-dialog-titlebar-close" )
+                       .appendTo( this.uiDialogTitlebar );
+               this._on( this.uiDialogTitlebarClose, {
+                       click: function( event ) {
+                               event.preventDefault();
+                               this.close( event );
+                       }
+               });
+
+               uiDialogTitle = $( "<span>" )
+                       .uniqueId()
+                       .addClass( "ui-dialog-title" )
+                       .prependTo( this.uiDialogTitlebar );
+               this._title( uiDialogTitle );
+
+               this.uiDialog.attr({
+                       "aria-labelledby": uiDialogTitle.attr( "id" )
+               });
+       },
+
+       _title: function( title ) {
+               if ( !this.options.title ) {
+                       title.html( "&#160;" );
+               }
+               title.text( this.options.title );
+       },
+
+       _createButtonPane: function() {
+               this.uiDialogButtonPane = $( "<div>" )
+                       .addClass( "ui-dialog-buttonpane ui-widget-content ui-helper-clearfix" );
+
+               this.uiButtonSet = $( "<div>" )
+                       .addClass( "ui-dialog-buttonset" )
+                       .appendTo( this.uiDialogButtonPane );
+
+               this._createButtons();
+       },
+
+       _createButtons: function() {
+               var that = this,
+                       buttons = this.options.buttons;
+
+               // if we already have a button pane, remove it
+               this.uiDialogButtonPane.remove();
+               this.uiButtonSet.empty();
+
+               if ( $.isEmptyObject( buttons ) || ($.isArray( buttons ) && !buttons.length) ) {
+                       this.uiDialog.removeClass( "ui-dialog-buttons" );
+                       return;
+               }
+
+               $.each( buttons, function( name, props ) {
+                       var click, buttonOptions;
+                       props = $.isFunction( props ) ?
+                               { click: props, text: name } :
+                               props;
+                       // Default to a non-submitting button
+                       props = $.extend( { type: "button" }, props );
+                       // Change the context for the click callback to be the main element
+                       click = props.click;
+                       props.click = function() {
+                               click.apply( that.element[ 0 ], arguments );
+                       };
+                       buttonOptions = {
+                               icons: props.icons,
+                               text: props.showText
+                       };
+                       delete props.icons;
+                       delete props.showText;
+                       $( "<button></button>", props )
+                               .button( buttonOptions )
+                               .appendTo( that.uiButtonSet );
+               });
+               this.uiDialog.addClass( "ui-dialog-buttons" );
+               this.uiDialogButtonPane.appendTo( this.uiDialog );
+       },
+
+       _makeDraggable: function() {
+               var that = this,
+                       options = this.options;
+
+               function filteredUi( ui ) {
+                       return {
+                               position: ui.position,
+                               offset: ui.offset
+                       };
+               }
+
+               this.uiDialog.draggable({
+                       cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
+                       handle: ".ui-dialog-titlebar",
+                       containment: "document",
+                       start: function( event, ui ) {
+                               $( this ).addClass( "ui-dialog-dragging" );
+                               that._blockFrames();
+                               that._trigger( "dragStart", event, filteredUi( ui ) );
+                       },
+                       drag: function( event, ui ) {
+                               that._trigger( "drag", event, filteredUi( ui ) );
+                       },
+                       stop: function( event, ui ) {
+                               var left = ui.offset.left - that.document.scrollLeft(),
+                                       top = ui.offset.top - that.document.scrollTop();
+
+                               options.position = {
+                                       my: "left top",
+                                       at: "left" + (left >= 0 ? "+" : "") + left + " " +
+                                               "top" + (top >= 0 ? "+" : "") + top,
+                                       of: that.window
+                               };
+                               $( this ).removeClass( "ui-dialog-dragging" );
+                               that._unblockFrames();
+                               that._trigger( "dragStop", event, filteredUi( ui ) );
+                       }
+               });
+       },
+
+       _makeResizable: function() {
+               var that = this,
+                       options = this.options,
+                       handles = options.resizable,
+                       // .ui-resizable has position: relative defined in the stylesheet
+                       // but dialogs have to use absolute or fixed positioning
+                       position = this.uiDialog.css("position"),
+                       resizeHandles = typeof handles === "string" ?
+                               handles :
+                               "n,e,s,w,se,sw,ne,nw";
+
+               function filteredUi( ui ) {
+                       return {
+                               originalPosition: ui.originalPosition,
+                               originalSize: ui.originalSize,
+                               position: ui.position,
+                               size: ui.size
+                       };
+               }
+
+               this.uiDialog.resizable({
+                       cancel: ".ui-dialog-content",
+                       containment: "document",
+                       alsoResize: this.element,
+                       maxWidth: options.maxWidth,
+                       maxHeight: options.maxHeight,
+                       minWidth: options.minWidth,
+                       minHeight: this._minHeight(),
+                       handles: resizeHandles,
+                       start: function( event, ui ) {
+                               $( this ).addClass( "ui-dialog-resizing" );
+                               that._blockFrames();
+                               that._trigger( "resizeStart", event, filteredUi( ui ) );
+                       },
+                       resize: function( event, ui ) {
+                               that._trigger( "resize", event, filteredUi( ui ) );
+                       },
+                       stop: function( event, ui ) {
+                               var offset = that.uiDialog.offset(),
+                                       left = offset.left - that.document.scrollLeft(),
+                                       top = offset.top - that.document.scrollTop();
+
+                               options.height = that.uiDialog.height();
+                               options.width = that.uiDialog.width();
+                               options.position = {
+                                       my: "left top",
+                                       at: "left" + (left >= 0 ? "+" : "") + left + " " +
+                                               "top" + (top >= 0 ? "+" : "") + top,
+                                       of: that.window
+                               };
+                               $( this ).removeClass( "ui-dialog-resizing" );
+                               that._unblockFrames();
+                               that._trigger( "resizeStop", event, filteredUi( ui ) );
+                       }
+               })
+               .css( "position", position );
+       },
+
+       _trackFocus: function() {
+               this._on( this.widget(), {
+                       focusin: function( event ) {
+                               this._makeFocusTarget();
+                               this._focusedElement = $( event.target );
+                       }
+               });
+       },
+
+       _makeFocusTarget: function() {
+               this._untrackInstance();
+               this._trackingInstances().unshift( this );
+       },
+
+       _untrackInstance: function() {
+               var instances = this._trackingInstances(),
+                       exists = $.inArray( this, instances );
+               if ( exists !== -1 ) {
+                       instances.splice( exists, 1 );
+               }
+       },
+
+       _trackingInstances: function() {
+               var instances = this.document.data( "ui-dialog-instances" );
+               if ( !instances ) {
+                       instances = [];
+                       this.document.data( "ui-dialog-instances", instances );
+               }
+               return instances;
+       },
+
+       _minHeight: function() {
+               var options = this.options;
+
+               return options.height === "auto" ?
+                       options.minHeight :
+                       Math.min( options.minHeight, options.height );
+       },
+
+       _position: function() {
+               // Need to show the dialog to get the actual offset in the position plugin
+               var isVisible = this.uiDialog.is( ":visible" );
+               if ( !isVisible ) {
+                       this.uiDialog.show();
+               }
+               this.uiDialog.position( this.options.position );
+               if ( !isVisible ) {
+                       this.uiDialog.hide();
+               }
+       },
+
+       _setOptions: function( options ) {
+               var that = this,
+                       resize = false,
+                       resizableOptions = {};
+
+               $.each( options, function( key, value ) {
+                       that._setOption( key, value );
+
+                       if ( key in that.sizeRelatedOptions ) {
+                               resize = true;
+                       }
+                       if ( key in that.resizableRelatedOptions ) {
+                               resizableOptions[ key ] = value;
+                       }
+               });
+
+               if ( resize ) {
+                       this._size();
+                       this._position();
+               }
+               if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
+                       this.uiDialog.resizable( "option", resizableOptions );
+               }
+       },
+
+       _setOption: function( key, value ) {
+               var isDraggable, isResizable,
+                       uiDialog = this.uiDialog;
+
+               if ( key === "dialogClass" ) {
+                       uiDialog
+                               .removeClass( this.options.dialogClass )
+                               .addClass( value );
+               }
+
+               if ( key === "disabled" ) {
+                       return;
+               }
+
+               this._super( key, value );
+
+               if ( key === "appendTo" ) {
+                       this.uiDialog.appendTo( this._appendTo() );
+               }
+
+               if ( key === "buttons" ) {
+                       this._createButtons();
+               }
+
+               if ( key === "closeText" ) {
+                       this.uiDialogTitlebarClose.button({
+                               // Ensure that we always pass a string
+                               label: "" + value
+                       });
+               }
+
+               if ( key === "draggable" ) {
+                       isDraggable = uiDialog.is( ":data(ui-draggable)" );
+                       if ( isDraggable && !value ) {
+                               uiDialog.draggable( "destroy" );
+                       }
+
+                       if ( !isDraggable && value ) {
+                               this._makeDraggable();
+                       }
+               }
+
+               if ( key === "position" ) {
+                       this._position();
+               }
+
+               if ( key === "resizable" ) {
+                       // currently resizable, becoming non-resizable
+                       isResizable = uiDialog.is( ":data(ui-resizable)" );
+                       if ( isResizable && !value ) {
+                               uiDialog.resizable( "destroy" );
+                       }
+
+                       // currently resizable, changing handles
+                       if ( isResizable && typeof value === "string" ) {
+                               uiDialog.resizable( "option", "handles", value );
+                       }
+
+                       // currently non-resizable, becoming resizable
+                       if ( !isResizable && value !== false ) {
+                               this._makeResizable();
+                       }
+               }
+
+               if ( key === "title" ) {
+                       this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
+               }
+       },
+
+       _size: function() {
+               // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
+               // divs will both have width and height set, so we need to reset them
+               var nonContentHeight, minContentHeight, maxContentHeight,
+                       options = this.options;
+
+               // Reset content sizing
+               this.element.show().css({
+                       width: "auto",
+                       minHeight: 0,
+                       maxHeight: "none",
+                       height: 0
+               });
+
+               if ( options.minWidth > options.width ) {
+                       options.width = options.minWidth;
+               }
+
+               // reset wrapper sizing
+               // determine the height of all the non-content elements
+               nonContentHeight = this.uiDialog.css({
+                               height: "auto",
+                               width: options.width
+                       })
+                       .outerHeight();
+               minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
+               maxContentHeight = typeof options.maxHeight === "number" ?
+                       Math.max( 0, options.maxHeight - nonContentHeight ) :
+                       "none";
+
+               if ( options.height === "auto" ) {
+                       this.element.css({
+                               minHeight: minContentHeight,
+                               maxHeight: maxContentHeight,
+                               height: "auto"
+                       });
+               } else {
+                       this.element.height( Math.max( 0, options.height - nonContentHeight ) );
+               }
+
+               if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
+                       this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
+               }
+       },
+
+       _blockFrames: function() {
+               this.iframeBlocks = this.document.find( "iframe" ).map(function() {
+                       var iframe = $( this );
+
+                       return $( "<div>" )
+                               .css({
+                                       position: "absolute",
+                                       width: iframe.outerWidth(),
+                                       height: iframe.outerHeight()
+                               })
+                               .appendTo( iframe.parent() )
+                               .offset( iframe.offset() )[0];
+               });
+       },
+
+       _unblockFrames: function() {
+               if ( this.iframeBlocks ) {
+                       this.iframeBlocks.remove();
+                       delete this.iframeBlocks;
+               }
+       },
+
+       _allowInteraction: function( event ) {
+               if ( $( event.target ).closest( ".ui-dialog" ).length ) {
+                       return true;
+               }
+
+               // TODO: Remove hack when datepicker implements
+               // the .ui-front logic (#8989)
+               return !!$( event.target ).closest( ".ui-datepicker" ).length;
+       },
+
+       _createOverlay: function() {
+               if ( !this.options.modal ) {
+                       return;
+               }
+
+               // We use a delay in case the overlay is created from an
+               // event that we're going to be cancelling (#2804)
+               var isOpening = true;
+               this._delay(function() {
+                       isOpening = false;
+               });
+
+               if ( !this.document.data( "ui-dialog-overlays" ) ) {
+
+                       // Prevent use of anchors and inputs
+                       // Using _on() for an event handler shared across many instances is
+                       // safe because the dialogs stack and must be closed in reverse order
+                       this._on( this.document, {
+                               focusin: function( event ) {
+                                       if ( isOpening ) {
+                                               return;
+                                       }
+
+                                       if ( !this._allowInteraction( event ) ) {
+                                               event.preventDefault();
+                                               this._trackingInstances()[ 0 ]._focusTabbable();
+                                       }
+                               }
+                       });
+               }
+
+               this.overlay = $( "<div>" )
+                       .addClass( "ui-widget-overlay ui-front" )
+                       .appendTo( this._appendTo() );
+               this._on( this.overlay, {
+                       mousedown: "_keepFocus"
+               });
+               this.document.data( "ui-dialog-overlays",
+                       (this.document.data( "ui-dialog-overlays" ) || 0) + 1 );
+       },
+
+       _destroyOverlay: function() {
+               if ( !this.options.modal ) {
+                       return;
+               }
+
+               if ( this.overlay ) {
+                       var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
+
+                       if ( !overlays ) {
+                               this.document
+                                       .unbind( "focusin" )
+                                       .removeData( "ui-dialog-overlays" );
+                       } else {
+                               this.document.data( "ui-dialog-overlays", overlays );
+                       }
+
+                       this.overlay.remove();
+                       this.overlay = null;
+               }
+       }
+});
+
+
+/*!
+ * jQuery UI Droppable 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/droppable/
+ */
+
+
+$.widget( "ui.droppable", {
+       version: "1.11.2",
+       widgetEventPrefix: "drop",
+       options: {
+               accept: "*",
+               activeClass: false,
+               addClasses: true,
+               greedy: false,
+               hoverClass: false,
+               scope: "default",
+               tolerance: "intersect",
+
+               // callbacks
+               activate: null,
+               deactivate: null,
+               drop: null,
+               out: null,
+               over: null
+       },
+       _create: function() {
+
+               var proportions,
+                       o = this.options,
+                       accept = o.accept;
+
+               this.isover = false;
+               this.isout = true;
+
+               this.accept = $.isFunction( accept ) ? accept : function( d ) {
+                       return d.is( accept );
+               };
+
+               this.proportions = function( /* valueToWrite */ ) {
+                       if ( arguments.length ) {
+                               // Store the droppable's proportions
+                               proportions = arguments[ 0 ];
+                       } else {
+                               // Retrieve or derive the droppable's proportions
+                               return proportions ?
+                                       proportions :
+                                       proportions = {
+                                               width: this.element[ 0 ].offsetWidth,
+                                               height: this.element[ 0 ].offsetHeight
+                                       };
+                       }
+               };
+
+               this._addToManager( o.scope );
+
+               o.addClasses && this.element.addClass( "ui-droppable" );
+
+       },
+
+       _addToManager: function( scope ) {
+               // Add the reference and positions to the manager
+               $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
+               $.ui.ddmanager.droppables[ scope ].push( this );
+       },
+
+       _splice: function( drop ) {
+               var i = 0;
+               for ( ; i < drop.length; i++ ) {
+                       if ( drop[ i ] === this ) {
+                               drop.splice( i, 1 );
+                       }
+               }
+       },
+
+       _destroy: function() {
+               var drop = $.ui.ddmanager.droppables[ this.options.scope ];
+
+               this._splice( drop );
+
+               this.element.removeClass( "ui-droppable ui-droppable-disabled" );
+       },
+
+       _setOption: function( key, value ) {
+
+               if ( key === "accept" ) {
+                       this.accept = $.isFunction( value ) ? value : function( d ) {
+                               return d.is( value );
+                       };
+               } else if ( key === "scope" ) {
+                       var drop = $.ui.ddmanager.droppables[ this.options.scope ];
+
+                       this._splice( drop );
+                       this._addToManager( value );
+               }
+
+               this._super( key, value );
+       },
+
+       _activate: function( event ) {
+               var draggable = $.ui.ddmanager.current;
+               if ( this.options.activeClass ) {
+                       this.element.addClass( this.options.activeClass );
+               }
+               if ( draggable ){
+                       this._trigger( "activate", event, this.ui( draggable ) );
+               }
+       },
+
+       _deactivate: function( event ) {
+               var draggable = $.ui.ddmanager.current;
+               if ( this.options.activeClass ) {
+                       this.element.removeClass( this.options.activeClass );
+               }
+               if ( draggable ){
+                       this._trigger( "deactivate", event, this.ui( draggable ) );
+               }
+       },
+
+       _over: function( event ) {
+
+               var draggable = $.ui.ddmanager.current;
+
+               // Bail if draggable and droppable are same element
+               if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
+                       return;
+               }
+
+               if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
+                       if ( this.options.hoverClass ) {
+                               this.element.addClass( this.options.hoverClass );
+                       }
+                       this._trigger( "over", event, this.ui( draggable ) );
+               }
+
+       },
+
+       _out: function( event ) {
+
+               var draggable = $.ui.ddmanager.current;
+
+               // Bail if draggable and droppable are same element
+               if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
+                       return;
+               }
+
+               if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
+                       if ( this.options.hoverClass ) {
+                               this.element.removeClass( this.options.hoverClass );
+                       }
+                       this._trigger( "out", event, this.ui( draggable ) );
+               }
+
+       },
+
+       _drop: function( event, custom ) {
+
+               var draggable = custom || $.ui.ddmanager.current,
+                       childrenIntersection = false;
+
+               // Bail if draggable and droppable are same element
+               if ( !draggable || ( draggable.currentItem || draggable.element )[ 0 ] === this.element[ 0 ] ) {
+                       return false;
+               }
+
+               this.element.find( ":data(ui-droppable)" ).not( ".ui-draggable-dragging" ).each(function() {
+                       var inst = $( this ).droppable( "instance" );
+                       if (
+                               inst.options.greedy &&
+                               !inst.options.disabled &&
+                               inst.options.scope === draggable.options.scope &&
+                               inst.accept.call( inst.element[ 0 ], ( draggable.currentItem || draggable.element ) ) &&
+                               $.ui.intersect( draggable, $.extend( inst, { offset: inst.element.offset() } ), inst.options.tolerance, event )
+                       ) { childrenIntersection = true; return false; }
+               });
+               if ( childrenIntersection ) {
+                       return false;
+               }
+
+               if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
+                       if ( this.options.activeClass ) {
+                               this.element.removeClass( this.options.activeClass );
+                       }
+                       if ( this.options.hoverClass ) {
+                               this.element.removeClass( this.options.hoverClass );
+                       }
+                       this._trigger( "drop", event, this.ui( draggable ) );
+                       return this.element;
+               }
+
+               return false;
+
+       },
+
+       ui: function( c ) {
+               return {
+                       draggable: ( c.currentItem || c.element ),
+                       helper: c.helper,
+                       position: c.position,
+                       offset: c.positionAbs
+               };
+       }
+
+});
+
+$.ui.intersect = (function() {
+       function isOverAxis( x, reference, size ) {
+               return ( x >= reference ) && ( x < ( reference + size ) );
+       }
+
+       return function( draggable, droppable, toleranceMode, event ) {
+
+               if ( !droppable.offset ) {
+                       return false;
+               }
+
+               var x1 = ( draggable.positionAbs || draggable.position.absolute ).left + draggable.margins.left,
+                       y1 = ( draggable.positionAbs || draggable.position.absolute ).top + draggable.margins.top,
+                       x2 = x1 + draggable.helperProportions.width,
+                       y2 = y1 + draggable.helperProportions.height,
+                       l = droppable.offset.left,
+                       t = droppable.offset.top,
+                       r = l + droppable.proportions().width,
+                       b = t + droppable.proportions().height;
+
+               switch ( toleranceMode ) {
+               case "fit":
+                       return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
+               case "intersect":
+                       return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
+                               x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
+                               t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
+                               y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
+               case "pointer":
+                       return isOverAxis( event.pageY, t, droppable.proportions().height ) && isOverAxis( event.pageX, l, droppable.proportions().width );
+               case "touch":
+                       return (
+                               ( y1 >= t && y1 <= b ) || // Top edge touching
+                               ( y2 >= t && y2 <= b ) || // Bottom edge touching
+                               ( y1 < t && y2 > b ) // Surrounded vertically
+                       ) && (
+                               ( x1 >= l && x1 <= r ) || // Left edge touching
+                               ( x2 >= l && x2 <= r ) || // Right edge touching
+                               ( x1 < l && x2 > r ) // Surrounded horizontally
+                       );
+               default:
+                       return false;
+               }
+       };
+})();
+
+/*
+       This manager tracks offsets of draggables and droppables
+*/
+$.ui.ddmanager = {
+       current: null,
+       droppables: { "default": [] },
+       prepareOffsets: function( t, event ) {
+
+               var i, j,
+                       m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
+                       type = event ? event.type : null, // workaround for #2317
+                       list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
+
+               droppablesLoop: for ( i = 0; i < m.length; i++ ) {
+
+                       // No disabled and non-accepted
+                       if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], ( t.currentItem || t.element ) ) ) ) {
+                               continue;
+                       }
+
+                       // Filter out elements in the current dragged item
+                       for ( j = 0; j < list.length; j++ ) {
+                               if ( list[ j ] === m[ i ].element[ 0 ] ) {
+                                       m[ i ].proportions().height = 0;
+                                       continue droppablesLoop;
+                               }
+                       }
+
+                       m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
+                       if ( !m[ i ].visible ) {
+                               continue;
+                       }
+
+                       // Activate the droppable if used directly from draggables
+                       if ( type === "mousedown" ) {
+                               m[ i ]._activate.call( m[ i ], event );
+                       }
+
+                       m[ i ].offset = m[ i ].element.offset();
+                       m[ i ].proportions({ width: m[ i ].element[ 0 ].offsetWidth, height: m[ i ].element[ 0 ].offsetHeight });
+
+               }
+
+       },
+       drop: function( draggable, event ) {
+
+               var dropped = false;
+               // Create a copy of the droppables in case the list changes during the drop (#9116)
+               $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
+
+                       if ( !this.options ) {
+                               return;
+                       }
+                       if ( !this.options.disabled && this.visible && $.ui.intersect( draggable, this, this.options.tolerance, event ) ) {
+                               dropped = this._drop.call( this, event ) || dropped;
+                       }
+
+                       if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], ( draggable.currentItem || draggable.element ) ) ) {
+                               this.isout = true;
+                               this.isover = false;
+                               this._deactivate.call( this, event );
+                       }
+
+               });
+               return dropped;
+
+       },
+       dragStart: function( draggable, event ) {
+               // Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003)
+               draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() {
+                       if ( !draggable.options.refreshPositions ) {
+                               $.ui.ddmanager.prepareOffsets( draggable, event );
+                       }
+               });
+       },
+       drag: function( draggable, event ) {
+
+               // If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse.
+               if ( draggable.options.refreshPositions ) {
+                       $.ui.ddmanager.prepareOffsets( draggable, event );
+               }
+
+               // Run through all droppables and check their positions based on specific tolerance options
+               $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
+
+                       if ( this.options.disabled || this.greedyChild || !this.visible ) {
+                               return;
+                       }
+
+                       var parentInstance, scope, parent,
+                               intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ),
+                               c = !intersects && this.isover ? "isout" : ( intersects && !this.isover ? "isover" : null );
+                       if ( !c ) {
+                               return;
+                       }
+
+                       if ( this.options.greedy ) {
+                               // find droppable parents with same scope
+                               scope = this.options.scope;
+                               parent = this.element.parents( ":data(ui-droppable)" ).filter(function() {
+                                       return $( this ).droppable( "instance" ).options.scope === scope;
+                               });
+
+                               if ( parent.length ) {
+                                       parentInstance = $( parent[ 0 ] ).droppable( "instance" );
+                                       parentInstance.greedyChild = ( c === "isover" );
+                               }
+                       }
+
+                       // we just moved into a greedy child
+                       if ( parentInstance && c === "isover" ) {
+                               parentInstance.isover = false;
+                               parentInstance.isout = true;
+                               parentInstance._out.call( parentInstance, event );
+                       }
+
+                       this[ c ] = true;
+                       this[c === "isout" ? "isover" : "isout"] = false;
+                       this[c === "isover" ? "_over" : "_out"].call( this, event );
+
+                       // we just moved out of a greedy child
+                       if ( parentInstance && c === "isout" ) {
+                               parentInstance.isout = false;
+                               parentInstance.isover = true;
+                               parentInstance._over.call( parentInstance, event );
+                       }
+               });
+
+       },
+       dragStop: function( draggable, event ) {
+               draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" );
+               // Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003)
+               if ( !draggable.options.refreshPositions ) {
+                       $.ui.ddmanager.prepareOffsets( draggable, event );
+               }
+       }
+};
+
+var droppable = $.ui.droppable;
+
+
+/*!
+ * jQuery UI Effects 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/category/effects-core/
+ */
+
+
+var dataSpace = "ui-effects-",
+
+       // Create a local jQuery because jQuery Color relies on it and the
+       // global may not exist with AMD and a custom build (#10199)
+       jQuery = $;
+
+$.effects = {
+       effect: {}
+};
+
+/*!
+ * jQuery Color Animations v2.1.2
+ * https://github.com/jquery/jquery-color
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * Date: Wed Jan 16 08:47:09 2013 -0600
+ */
+(function( jQuery, undefined ) {
+
+       var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
+
+       // plusequals test for += 100 -= 100
+       rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
+       // a set of RE's that can match strings and generate color tuples.
+       stringParsers = [ {
+                       re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+                       parse: function( execResult ) {
+                               return [
+                                       execResult[ 1 ],
+                                       execResult[ 2 ],
+                                       execResult[ 3 ],
+                                       execResult[ 4 ]
+                               ];
+                       }
+               }, {
+                       re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+                       parse: function( execResult ) {
+                               return [
+                                       execResult[ 1 ] * 2.55,
+                                       execResult[ 2 ] * 2.55,
+                                       execResult[ 3 ] * 2.55,
+                                       execResult[ 4 ]
+                               ];
+                       }
+               }, {
+                       // this regex ignores A-F because it's compared against an already lowercased string
+                       re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
+                       parse: function( execResult ) {
+                               return [
+                                       parseInt( execResult[ 1 ], 16 ),
+                                       parseInt( execResult[ 2 ], 16 ),
+                                       parseInt( execResult[ 3 ], 16 )
+                               ];
+                       }
+               }, {
+                       // this regex ignores A-F because it's compared against an already lowercased string
+                       re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
+                       parse: function( execResult ) {
+                               return [
+                                       parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
+                                       parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
+                                       parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
+                               ];
+                       }
+               }, {
+                       re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
+                       space: "hsla",
+                       parse: function( execResult ) {
+                               return [
+                                       execResult[ 1 ],
+                                       execResult[ 2 ] / 100,
+                                       execResult[ 3 ] / 100,
+                                       execResult[ 4 ]
+                               ];
+                       }
+               } ],
+
+       // jQuery.Color( )
+       color = jQuery.Color = function( color, green, blue, alpha ) {
+               return new jQuery.Color.fn.parse( color, green, blue, alpha );
+       },
+       spaces = {
+               rgba: {
+                       props: {
+                               red: {
+                                       idx: 0,
+                                       type: "byte"
+                               },
+                               green: {
+                                       idx: 1,
+                                       type: "byte"
+                               },
+                               blue: {
+                                       idx: 2,
+                                       type: "byte"
+                               }
+                       }
+               },
+
+               hsla: {
+                       props: {
+                               hue: {
+                                       idx: 0,
+                                       type: "degrees"
+                               },
+                               saturation: {
+                                       idx: 1,
+                                       type: "percent"
+                               },
+                               lightness: {
+                                       idx: 2,
+                                       type: "percent"
+                               }
+                       }
+               }
+       },
+       propTypes = {
+               "byte": {
+                       floor: true,
+                       max: 255
+               },
+               "percent": {
+                       max: 1
+               },
+               "degrees": {
+                       mod: 360,
+                       floor: true
+               }
+       },
+       support = color.support = {},
+
+       // element for support tests
+       supportElem = jQuery( "<p>" )[ 0 ],
+
+       // colors = jQuery.Color.names
+       colors,
+
+       // local aliases of functions called often
+       each = jQuery.each;
+
+// determine rgba support immediately
+supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
+support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
+
+// define cache name and alpha properties
+// for rgba and hsla spaces
+each( spaces, function( spaceName, space ) {
+       space.cache = "_" + spaceName;
+       space.props.alpha = {
+               idx: 3,
+               type: "percent",
+               def: 1
+       };
+});
+
+function clamp( value, prop, allowEmpty ) {
+       var type = propTypes[ prop.type ] || {};
+
+       if ( value == null ) {
+               return (allowEmpty || !prop.def) ? null : prop.def;
+       }
+
+       // ~~ is an short way of doing floor for positive numbers
+       value = type.floor ? ~~value : parseFloat( value );
+
+       // IE will pass in empty strings as value for alpha,
+       // which will hit this case
+       if ( isNaN( value ) ) {
+               return prop.def;
+       }
+
+       if ( type.mod ) {
+               // we add mod before modding to make sure that negatives values
+               // get converted properly: -10 -> 350
+               return (value + type.mod) % type.mod;
+       }
+
+       // for now all property types without mod have min and max
+       return 0 > value ? 0 : type.max < value ? type.max : value;
+}
+
+function stringParse( string ) {
+       var inst = color(),
+               rgba = inst._rgba = [];
+
+       string = string.toLowerCase();
+
+       each( stringParsers, function( i, parser ) {
+               var parsed,
+                       match = parser.re.exec( string ),
+                       values = match && parser.parse( match ),
+                       spaceName = parser.space || "rgba";
+
+               if ( values ) {
+                       parsed = inst[ spaceName ]( values );
+
+                       // if this was an rgba parse the assignment might happen twice
+                       // oh well....
+                       inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
+                       rgba = inst._rgba = parsed._rgba;
+
+                       // exit each( stringParsers ) here because we matched
+                       return false;
+               }
+       });
+
+       // Found a stringParser that handled it
+       if ( rgba.length ) {
+
+               // if this came from a parsed string, force "transparent" when alpha is 0
+               // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
+               if ( rgba.join() === "0,0,0,0" ) {
+                       jQuery.extend( rgba, colors.transparent );
+               }
+               return inst;
+       }
+
+       // named colors
+       return colors[ string ];
+}
+
+color.fn = jQuery.extend( color.prototype, {
+       parse: function( red, green, blue, alpha ) {
+               if ( red === undefined ) {
+                       this._rgba = [ null, null, null, null ];
+                       return this;
+               }
+               if ( red.jquery || red.nodeType ) {
+                       red = jQuery( red ).css( green );
+                       green = undefined;
+               }
+
+               var inst = this,
+                       type = jQuery.type( red ),
+                       rgba = this._rgba = [];
+
+               // more than 1 argument specified - assume ( red, green, blue, alpha )
+               if ( green !== undefined ) {
+                       red = [ red, green, blue, alpha ];
+                       type = "array";
+               }
+
+               if ( type === "string" ) {
+                       return this.parse( stringParse( red ) || colors._default );
+               }
+
+               if ( type === "array" ) {
+                       each( spaces.rgba.props, function( key, prop ) {
+                               rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
+                       });
+                       return this;
+               }
+
+               if ( type === "object" ) {
+                       if ( red instanceof color ) {
+                               each( spaces, function( spaceName, space ) {
+                                       if ( red[ space.cache ] ) {
+                                               inst[ space.cache ] = red[ space.cache ].slice();
+                                       }
+                               });
+                       } else {
+                               each( spaces, function( spaceName, space ) {
+                                       var cache = space.cache;
+                                       each( space.props, function( key, prop ) {
+
+                                               // if the cache doesn't exist, and we know how to convert
+                                               if ( !inst[ cache ] && space.to ) {
+
+                                                       // if the value was null, we don't need to copy it
+                                                       // if the key was alpha, we don't need to copy it either
+                                                       if ( key === "alpha" || red[ key ] == null ) {
+                                                               return;
+                                                       }
+                                                       inst[ cache ] = space.to( inst._rgba );
+                                               }
+
+                                               // this is the only case where we allow nulls for ALL properties.
+                                               // call clamp with alwaysAllowEmpty
+                                               inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
+                                       });
+
+                                       // everything defined but alpha?
+                                       if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
+                                               // use the default of 1
+                                               inst[ cache ][ 3 ] = 1;
+                                               if ( space.from ) {
+                                                       inst._rgba = space.from( inst[ cache ] );
+                                               }
+                                       }
+                               });
+                       }
+                       return this;
+               }
+       },
+       is: function( compare ) {
+               var is = color( compare ),
+                       same = true,
+                       inst = this;
+
+               each( spaces, function( _, space ) {
+                       var localCache,
+                               isCache = is[ space.cache ];
+                       if (isCache) {
+                               localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
+                               each( space.props, function( _, prop ) {
+                                       if ( isCache[ prop.idx ] != null ) {
+                                               same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
+                                               return same;
+                                       }
+                               });
+                       }
+                       return same;
+               });
+               return same;
+       },
+       _space: function() {
+               var used = [],
+                       inst = this;
+               each( spaces, function( spaceName, space ) {
+                       if ( inst[ space.cache ] ) {
+                               used.push( spaceName );
+                       }
+               });
+               return used.pop();
+       },
+       transition: function( other, distance ) {
+               var end = color( other ),
+                       spaceName = end._space(),
+                       space = spaces[ spaceName ],
+                       startColor = this.alpha() === 0 ? color( "transparent" ) : this,
+                       start = startColor[ space.cache ] || space.to( startColor._rgba ),
+                       result = start.slice();
+
+               end = end[ space.cache ];
+               each( space.props, function( key, prop ) {
+                       var index = prop.idx,
+                               startValue = start[ index ],
+                               endValue = end[ index ],
+                               type = propTypes[ prop.type ] || {};
+
+                       // if null, don't override start value
+                       if ( endValue === null ) {
+                               return;
+                       }
+                       // if null - use end
+                       if ( startValue === null ) {
+                               result[ index ] = endValue;
+                       } else {
+                               if ( type.mod ) {
+                                       if ( endValue - startValue > type.mod / 2 ) {
+                                               startValue += type.mod;
+                                       } else if ( startValue - endValue > type.mod / 2 ) {
+                                               startValue -= type.mod;
+                                       }
+                               }
+                               result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
+                       }
+               });
+               return this[ spaceName ]( result );
+       },
+       blend: function( opaque ) {
+               // if we are already opaque - return ourself
+               if ( this._rgba[ 3 ] === 1 ) {
+                       return this;
+               }
+
+               var rgb = this._rgba.slice(),
+                       a = rgb.pop(),
+                       blend = color( opaque )._rgba;
+
+               return color( jQuery.map( rgb, function( v, i ) {
+                       return ( 1 - a ) * blend[ i ] + a * v;
+               }));
+       },
+       toRgbaString: function() {
+               var prefix = "rgba(",
+                       rgba = jQuery.map( this._rgba, function( v, i ) {
+                               return v == null ? ( i > 2 ? 1 : 0 ) : v;
+                       });
+
+               if ( rgba[ 3 ] === 1 ) {
+                       rgba.pop();
+                       prefix = "rgb(";
+               }
+
+               return prefix + rgba.join() + ")";
+       },
+       toHslaString: function() {
+               var prefix = "hsla(",
+                       hsla = jQuery.map( this.hsla(), function( v, i ) {
+                               if ( v == null ) {
+                                       v = i > 2 ? 1 : 0;
+                               }
+
+                               // catch 1 and 2
+                               if ( i && i < 3 ) {
+                                       v = Math.round( v * 100 ) + "%";
+                               }
+                               return v;
+                       });
+
+               if ( hsla[ 3 ] === 1 ) {
+                       hsla.pop();
+                       prefix = "hsl(";
+               }
+               return prefix + hsla.join() + ")";
+       },
+       toHexString: function( includeAlpha ) {
+               var rgba = this._rgba.slice(),
+                       alpha = rgba.pop();
+
+               if ( includeAlpha ) {
+                       rgba.push( ~~( alpha * 255 ) );
+               }
+
+               return "#" + jQuery.map( rgba, function( v ) {
+
+                       // default to 0 when nulls exist
+                       v = ( v || 0 ).toString( 16 );
+                       return v.length === 1 ? "0" + v : v;
+               }).join("");
+       },
+       toString: function() {
+               return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
+       }
+});
+color.fn.parse.prototype = color.fn;
+
+// hsla conversions adapted from:
+// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
+
+function hue2rgb( p, q, h ) {
+       h = ( h + 1 ) % 1;
+       if ( h * 6 < 1 ) {
+               return p + ( q - p ) * h * 6;
+       }
+       if ( h * 2 < 1) {
+               return q;
+       }
+       if ( h * 3 < 2 ) {
+               return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
+       }
+       return p;
+}
+
+spaces.hsla.to = function( rgba ) {
+       if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
+               return [ null, null, null, rgba[ 3 ] ];
+       }
+       var r = rgba[ 0 ] / 255,
+               g = rgba[ 1 ] / 255,
+               b = rgba[ 2 ] / 255,
+               a = rgba[ 3 ],
+               max = Math.max( r, g, b ),
+               min = Math.min( r, g, b ),
+               diff = max - min,
+               add = max + min,
+               l = add * 0.5,
+               h, s;
+
+       if ( min === max ) {
+               h = 0;
+       } else if ( r === max ) {
+               h = ( 60 * ( g - b ) / diff ) + 360;
+       } else if ( g === max ) {
+               h = ( 60 * ( b - r ) / diff ) + 120;
+       } else {
+               h = ( 60 * ( r - g ) / diff ) + 240;
+       }
+
+       // chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
+       // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
+       if ( diff === 0 ) {
+               s = 0;
+       } else if ( l <= 0.5 ) {
+               s = diff / add;
+       } else {
+               s = diff / ( 2 - add );
+       }
+       return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
+};
+
+spaces.hsla.from = function( hsla ) {
+       if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
+               return [ null, null, null, hsla[ 3 ] ];
+       }
+       var h = hsla[ 0 ] / 360,
+               s = hsla[ 1 ],
+               l = hsla[ 2 ],
+               a = hsla[ 3 ],
+               q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
+               p = 2 * l - q;
+
+       return [
+               Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
+               Math.round( hue2rgb( p, q, h ) * 255 ),
+               Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
+               a
+       ];
+};
+
+each( spaces, function( spaceName, space ) {
+       var props = space.props,
+               cache = space.cache,
+               to = space.to,
+               from = space.from;
+
+       // makes rgba() and hsla()
+       color.fn[ spaceName ] = function( value ) {
+
+               // generate a cache for this space if it doesn't exist
+               if ( to && !this[ cache ] ) {
+                       this[ cache ] = to( this._rgba );
+               }
+               if ( value === undefined ) {
+                       return this[ cache ].slice();
+               }
+
+               var ret,
+                       type = jQuery.type( value ),
+                       arr = ( type === "array" || type === "object" ) ? value : arguments,
+                       local = this[ cache ].slice();
+
+               each( props, function( key, prop ) {
+                       var val = arr[ type === "object" ? key : prop.idx ];
+                       if ( val == null ) {
+                               val = local[ prop.idx ];
+                       }
+                       local[ prop.idx ] = clamp( val, prop );
+               });
+
+               if ( from ) {
+                       ret = color( from( local ) );
+                       ret[ cache ] = local;
+                       return ret;
+               } else {
+                       return color( local );
+               }
+       };
+
+       // makes red() green() blue() alpha() hue() saturation() lightness()
+       each( props, function( key, prop ) {
+               // alpha is included in more than one space
+               if ( color.fn[ key ] ) {
+                       return;
+               }
+               color.fn[ key ] = function( value ) {
+                       var vtype = jQuery.type( value ),
+                               fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
+                               local = this[ fn ](),
+                               cur = local[ prop.idx ],
+                               match;
+
+                       if ( vtype === "undefined" ) {
+                               return cur;
+                       }
+
+                       if ( vtype === "function" ) {
+                               value = value.call( this, cur );
+                               vtype = jQuery.type( value );
+                       }
+                       if ( value == null && prop.empty ) {
+                               return this;
+                       }
+                       if ( vtype === "string" ) {
+                               match = rplusequals.exec( value );
+                               if ( match ) {
+                                       value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
+                               }
+                       }
+                       local[ prop.idx ] = value;
+                       return this[ fn ]( local );
+               };
+       });
+});
+
+// add cssHook and .fx.step function for each named hook.
+// accept a space separated string of properties
+color.hook = function( hook ) {
+       var hooks = hook.split( " " );
+       each( hooks, function( i, hook ) {
+               jQuery.cssHooks[ hook ] = {
+                       set: function( elem, value ) {
+                               var parsed, curElem,
+                                       backgroundColor = "";
+
+                               if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) {
+                                       value = color( parsed || value );
+                                       if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
+                                               curElem = hook === "backgroundColor" ? elem.parentNode : elem;
+                                               while (
+                                                       (backgroundColor === "" || backgroundColor === "transparent") &&
+                                                       curElem && curElem.style
+                                               ) {
+                                                       try {
+                                                               backgroundColor = jQuery.css( curElem, "backgroundColor" );
+                                                               curElem = curElem.parentNode;
+                                                       } catch ( e ) {
+                                                       }
+                                               }
+
+                                               value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
+                                                       backgroundColor :
+                                                       "_default" );
+                                       }
+
+                                       value = value.toRgbaString();
+                               }
+                               try {
+                                       elem.style[ hook ] = value;
+                               } catch ( e ) {
+                                       // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
+                               }
+                       }
+               };
+               jQuery.fx.step[ hook ] = function( fx ) {
+                       if ( !fx.colorInit ) {
+                               fx.start = color( fx.elem, hook );
+                               fx.end = color( fx.end );
+                               fx.colorInit = true;
+                       }
+                       jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
+               };
+       });
+
+};
+
+color.hook( stepHooks );
+
+jQuery.cssHooks.borderColor = {
+       expand: function( value ) {
+               var expanded = {};
+
+               each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
+                       expanded[ "border" + part + "Color" ] = value;
+               });
+               return expanded;
+       }
+};
+
+// Basic color names only.
+// Usage of any of the other color names requires adding yourself or including
+// jquery.color.svg-names.js.
+colors = jQuery.Color.names = {
+       // 4.1. Basic color keywords
+       aqua: "#00ffff",
+       black: "#000000",
+       blue: "#0000ff",
+       fuchsia: "#ff00ff",
+       gray: "#808080",
+       green: "#008000",
+       lime: "#00ff00",
+       maroon: "#800000",
+       navy: "#000080",
+       olive: "#808000",
+       purple: "#800080",
+       red: "#ff0000",
+       silver: "#c0c0c0",
+       teal: "#008080",
+       white: "#ffffff",
+       yellow: "#ffff00",
+
+       // 4.2.3. "transparent" color keyword
+       transparent: [ null, null, null, 0 ],
+
+       _default: "#ffffff"
+};
+
+})( jQuery );
+
+/******************************************************************************/
+/****************************** CLASS ANIMATIONS ******************************/
+/******************************************************************************/
+(function() {
+
+var classAnimationActions = [ "add", "remove", "toggle" ],
+       shorthandStyles = {
+               border: 1,
+               borderBottom: 1,
+               borderColor: 1,
+               borderLeft: 1,
+               borderRight: 1,
+               borderTop: 1,
+               borderWidth: 1,
+               margin: 1,
+               padding: 1
+       };
+
+$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) {
+       $.fx.step[ prop ] = function( fx ) {
+               if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
+                       jQuery.style( fx.elem, prop, fx.end );
+                       fx.setAttr = true;
+               }
+       };
+});
+
+function getElementStyles( elem ) {
+       var key, len,
+               style = elem.ownerDocument.defaultView ?
+                       elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
+                       elem.currentStyle,
+               styles = {};
+
+       if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
+               len = style.length;
+               while ( len-- ) {
+                       key = style[ len ];
+                       if ( typeof style[ key ] === "string" ) {
+                               styles[ $.camelCase( key ) ] = style[ key ];
+                       }
+               }
+       // support: Opera, IE <9
+       } else {
+               for ( key in style ) {
+                       if ( typeof style[ key ] === "string" ) {
+                               styles[ key ] = style[ key ];
+                       }
+               }
+       }
+
+       return styles;
+}
+
+function styleDifference( oldStyle, newStyle ) {
+       var diff = {},
+               name, value;
+
+       for ( name in newStyle ) {
+               value = newStyle[ name ];
+               if ( oldStyle[ name ] !== value ) {
+                       if ( !shorthandStyles[ name ] ) {
+                               if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
+                                       diff[ name ] = value;
+                               }
+                       }
+               }
+       }
+
+       return diff;
+}
+
+// support: jQuery <1.8
+if ( !$.fn.addBack ) {
+       $.fn.addBack = function( selector ) {
+               return this.add( selector == null ?
+                       this.prevObject : this.prevObject.filter( selector )
+               );
+       };
+}
+
+$.effects.animateClass = function( value, duration, easing, callback ) {
+       var o = $.speed( duration, easing, callback );
+
+       return this.queue( function() {
+               var animated = $( this ),
+                       baseClass = animated.attr( "class" ) || "",
+                       applyClassChange,
+                       allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
+
+               // map the animated objects to store the original styles.
+               allAnimations = allAnimations.map(function() {
+                       var el = $( this );
+                       return {
+                               el: el,
+                               start: getElementStyles( this )
+                       };
+               });
+
+               // apply class change
+               applyClassChange = function() {
+                       $.each( classAnimationActions, function(i, action) {
+                               if ( value[ action ] ) {
+                                       animated[ action + "Class" ]( value[ action ] );
+                               }
+                       });
+               };
+               applyClassChange();
+
+               // map all animated objects again - calculate new styles and diff
+               allAnimations = allAnimations.map(function() {
+                       this.end = getElementStyles( this.el[ 0 ] );
+                       this.diff = styleDifference( this.start, this.end );
+                       return this;
+               });
+
+               // apply original class
+               animated.attr( "class", baseClass );
+
+               // map all animated objects again - this time collecting a promise
+               allAnimations = allAnimations.map(function() {
+                       var styleInfo = this,
+                               dfd = $.Deferred(),
+                               opts = $.extend({}, o, {
+                                       queue: false,
+                                       complete: function() {
+                                               dfd.resolve( styleInfo );
+                                       }
+                               });
+
+                       this.el.animate( this.diff, opts );
+                       return dfd.promise();
+               });
+
+               // once all animations have completed:
+               $.when.apply( $, allAnimations.get() ).done(function() {
+
+                       // set the final class
+                       applyClassChange();
+
+                       // for each animated element,
+                       // clear all css properties that were animated
+                       $.each( arguments, function() {
+                               var el = this.el;
+                               $.each( this.diff, function(key) {
+                                       el.css( key, "" );
+                               });
+                       });
+
+                       // this is guarnteed to be there if you use jQuery.speed()
+                       // it also handles dequeuing the next anim...
+                       o.complete.call( animated[ 0 ] );
+               });
+       });
+};
+
+$.fn.extend({
+       addClass: (function( orig ) {
+               return function( classNames, speed, easing, callback ) {
+                       return speed ?
+                               $.effects.animateClass.call( this,
+                                       { add: classNames }, speed, easing, callback ) :
+                               orig.apply( this, arguments );
+               };
+       })( $.fn.addClass ),
+
+       removeClass: (function( orig ) {
+               return function( classNames, speed, easing, callback ) {
+                       return arguments.length > 1 ?
+                               $.effects.animateClass.call( this,
+                                       { remove: classNames }, speed, easing, callback ) :
+                               orig.apply( this, arguments );
+               };
+       })( $.fn.removeClass ),
+
+       toggleClass: (function( orig ) {
+               return function( classNames, force, speed, easing, callback ) {
+                       if ( typeof force === "boolean" || force === undefined ) {
+                               if ( !speed ) {
+                                       // without speed parameter
+                                       return orig.apply( this, arguments );
+                               } else {
+                                       return $.effects.animateClass.call( this,
+                                               (force ? { add: classNames } : { remove: classNames }),
+                                               speed, easing, callback );
+                               }
+                       } else {
+                               // without force parameter
+                               return $.effects.animateClass.call( this,
+                                       { toggle: classNames }, force, speed, easing );
+                       }
+               };
+       })( $.fn.toggleClass ),
+
+       switchClass: function( remove, add, speed, easing, callback) {
+               return $.effects.animateClass.call( this, {
+                       add: add,
+                       remove: remove
+               }, speed, easing, callback );
+       }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EFFECTS **********************************/
+/******************************************************************************/
+
+(function() {
+
+$.extend( $.effects, {
+       version: "1.11.2",
+
+       // Saves a set of properties in a data storage
+       save: function( element, set ) {
+               for ( var i = 0; i < set.length; i++ ) {
+                       if ( set[ i ] !== null ) {
+                               element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
+                       }
+               }
+       },
+
+       // Restores a set of previously saved properties from a data storage
+       restore: function( element, set ) {
+               var val, i;
+               for ( i = 0; i < set.length; i++ ) {
+                       if ( set[ i ] !== null ) {
+                               val = element.data( dataSpace + set[ i ] );
+                               // support: jQuery 1.6.2
+                               // http://bugs.jquery.com/ticket/9917
+                               // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
+                               // We can't differentiate between "" and 0 here, so we just assume
+                               // empty string since it's likely to be a more common value...
+                               if ( val === undefined ) {
+                                       val = "";
+                               }
+                               element.css( set[ i ], val );
+                       }
+               }
+       },
+
+       setMode: function( el, mode ) {
+               if (mode === "toggle") {
+                       mode = el.is( ":hidden" ) ? "show" : "hide";
+               }
+               return mode;
+       },
+
+       // Translates a [top,left] array into a baseline value
+       // this should be a little more flexible in the future to handle a string & hash
+       getBaseline: function( origin, original ) {
+               var y, x;
+               switch ( origin[ 0 ] ) {
+                       case "top": y = 0; break;
+                       case "middle": y = 0.5; break;
+                       case "bottom": y = 1; break;
+                       default: y = origin[ 0 ] / original.height;
+               }
+               switch ( origin[ 1 ] ) {
+                       case "left": x = 0; break;
+                       case "center": x = 0.5; break;
+                       case "right": x = 1; break;
+                       default: x = origin[ 1 ] / original.width;
+               }
+               return {
+                       x: x,
+                       y: y
+               };
+       },
+
+       // Wraps the element around a wrapper that copies position properties
+       createWrapper: function( element ) {
+
+               // if the element is already wrapped, return it
+               if ( element.parent().is( ".ui-effects-wrapper" )) {
+                       return element.parent();
+               }
+
+               // wrap the element
+               var props = {
+                               width: element.outerWidth(true),
+                               height: element.outerHeight(true),
+                               "float": element.css( "float" )
+                       },
+                       wrapper = $( "<div></div>" )
+                               .addClass( "ui-effects-wrapper" )
+                               .css({
+                                       fontSize: "100%",
+                                       background: "transparent",
+                                       border: "none",
+                                       margin: 0,
+                                       padding: 0
+                               }),
+                       // Store the size in case width/height are defined in % - Fixes #5245
+                       size = {
+                               width: element.width(),
+                               height: element.height()
+                       },
+                       active = document.activeElement;
+
+               // support: Firefox
+               // Firefox incorrectly exposes anonymous content
+               // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
+               try {
+                       active.id;
+               } catch ( e ) {
+                       active = document.body;
+               }
+
+               element.wrap( wrapper );
+
+               // Fixes #7595 - Elements lose focus when wrapped.
+               if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+                       $( active ).focus();
+               }
+
+               wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
+
+               // transfer positioning properties to the wrapper
+               if ( element.css( "position" ) === "static" ) {
+                       wrapper.css({ position: "relative" });
+                       element.css({ position: "relative" });
+               } else {
+                       $.extend( props, {
+                               position: element.css( "position" ),
+                               zIndex: element.css( "z-index" )
+                       });
+                       $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
+                               props[ pos ] = element.css( pos );
+                               if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
+                                       props[ pos ] = "auto";
+                               }
+                       });
+                       element.css({
+                               position: "relative",
+                               top: 0,
+                               left: 0,
+                               right: "auto",
+                               bottom: "auto"
+                       });
+               }
+               element.css(size);
+
+               return wrapper.css( props ).show();
+       },
+
+       removeWrapper: function( element ) {
+               var active = document.activeElement;
+
+               if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+                       element.parent().replaceWith( element );
+
+                       // Fixes #7595 - Elements lose focus when wrapped.
+                       if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+                               $( active ).focus();
+                       }
+               }
+
+               return element;
+       },
+
+       setTransition: function( element, list, factor, value ) {
+               value = value || {};
+               $.each( list, function( i, x ) {
+                       var unit = element.cssUnit( x );
+                       if ( unit[ 0 ] > 0 ) {
+                               value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
+                       }
+               });
+               return value;
+       }
+});
+
+// return an effect options object for the given parameters:
+function _normalizeArguments( effect, options, speed, callback ) {
+
+       // allow passing all options as the first parameter
+       if ( $.isPlainObject( effect ) ) {
+               options = effect;
+               effect = effect.effect;
+       }
+
+       // convert to an object
+       effect = { effect: effect };
+
+       // catch (effect, null, ...)
+       if ( options == null ) {
+               options = {};
+       }
+
+       // catch (effect, callback)
+       if ( $.isFunction( options ) ) {
+               callback = options;
+               speed = null;
+               options = {};
+       }
+
+       // catch (effect, speed, ?)
+       if ( typeof options === "number" || $.fx.speeds[ options ] ) {
+               callback = speed;
+               speed = options;
+               options = {};
+       }
+
+       // catch (effect, options, callback)
+       if ( $.isFunction( speed ) ) {
+               callback = speed;
+               speed = null;
+       }
+
+       // add options to effect
+       if ( options ) {
+               $.extend( effect, options );
+       }
+
+       speed = speed || options.duration;
+       effect.duration = $.fx.off ? 0 :
+               typeof speed === "number" ? speed :
+               speed in $.fx.speeds ? $.fx.speeds[ speed ] :
+               $.fx.speeds._default;
+
+       effect.complete = callback || options.complete;
+
+       return effect;
+}
+
+function standardAnimationOption( option ) {
+       // Valid standard speeds (nothing, number, named speed)
+       if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
+               return true;
+       }
+
+       // Invalid strings - treat as "normal" speed
+       if ( typeof option === "string" && !$.effects.effect[ option ] ) {
+               return true;
+       }
+
+       // Complete callback
+       if ( $.isFunction( option ) ) {
+               return true;
+       }
+
+       // Options hash (but not naming an effect)
+       if ( typeof option === "object" && !option.effect ) {
+               return true;
+       }
+
+       // Didn't match any standard API
+       return false;
+}
+
+$.fn.extend({
+       effect: function( /* effect, options, speed, callback */ ) {
+               var args = _normalizeArguments.apply( this, arguments ),
+                       mode = args.mode,
+                       queue = args.queue,
+                       effectMethod = $.effects.effect[ args.effect ];
+
+               if ( $.fx.off || !effectMethod ) {
+                       // delegate to the original method (e.g., .show()) if possible
+                       if ( mode ) {
+                               return this[ mode ]( args.duration, args.complete );
+                       } else {
+                               return this.each( function() {
+                                       if ( args.complete ) {
+                                               args.complete.call( this );
+                                       }
+                               });
+                       }
+               }
+
+               function run( next ) {
+                       var elem = $( this ),
+                               complete = args.complete,
+                               mode = args.mode;
+
+                       function done() {
+                               if ( $.isFunction( complete ) ) {
+                                       complete.call( elem[0] );
+                               }
+                               if ( $.isFunction( next ) ) {
+                                       next();
+                               }
+                       }
+
+                       // If the element already has the correct final state, delegate to
+                       // the core methods so the internal tracking of "olddisplay" works.
+                       if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
+                               elem[ mode ]();
+                               done();
+                       } else {
+                               effectMethod.call( elem[0], args, done );
+                       }
+               }
+
+               return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
+       },
+
+       show: (function( orig ) {
+               return function( option ) {
+                       if ( standardAnimationOption( option ) ) {
+                               return orig.apply( this, arguments );
+                       } else {
+                               var args = _normalizeArguments.apply( this, arguments );
+                               args.mode = "show";
+                               return this.effect.call( this, args );
+                       }
+               };
+       })( $.fn.show ),
+
+       hide: (function( orig ) {
+               return function( option ) {
+                       if ( standardAnimationOption( option ) ) {
+                               return orig.apply( this, arguments );
+                       } else {
+                               var args = _normalizeArguments.apply( this, arguments );
+                               args.mode = "hide";
+                               return this.effect.call( this, args );
+                       }
+               };
+       })( $.fn.hide ),
+
+       toggle: (function( orig ) {
+               return function( option ) {
+                       if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
+                               return orig.apply( this, arguments );
+                       } else {
+                               var args = _normalizeArguments.apply( this, arguments );
+                               args.mode = "toggle";
+                               return this.effect.call( this, args );
+                       }
+               };
+       })( $.fn.toggle ),
+
+       // helper functions
+       cssUnit: function(key) {
+               var style = this.css( key ),
+                       val = [];
+
+               $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
+                       if ( style.indexOf( unit ) > 0 ) {
+                               val = [ parseFloat( style ), unit ];
+                       }
+               });
+               return val;
+       }
+});
+
+})();
+
+/******************************************************************************/
+/*********************************** EASING ***********************************/
+/******************************************************************************/
+
+(function() {
+
+// based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
+
+var baseEasings = {};
+
+$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
+       baseEasings[ name ] = function( p ) {
+               return Math.pow( p, i + 2 );
+       };
+});
+
+$.extend( baseEasings, {
+       Sine: function( p ) {
+               return 1 - Math.cos( p * Math.PI / 2 );
+       },
+       Circ: function( p ) {
+               return 1 - Math.sqrt( 1 - p * p );
+       },
+       Elastic: function( p ) {
+               return p === 0 || p === 1 ? p :
+                       -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 );
+       },
+       Back: function( p ) {
+               return p * p * ( 3 * p - 2 );
+       },
+       Bounce: function( p ) {
+               var pow2,
+                       bounce = 4;
+
+               while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
+               return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
+       }
+});
+
+$.each( baseEasings, function( name, easeIn ) {
+       $.easing[ "easeIn" + name ] = easeIn;
+       $.easing[ "easeOut" + name ] = function( p ) {
+               return 1 - easeIn( 1 - p );
+       };
+       $.easing[ "easeInOut" + name ] = function( p ) {
+               return p < 0.5 ?
+                       easeIn( p * 2 ) / 2 :
+                       1 - easeIn( p * -2 + 2 ) / 2;
+       };
+});
+
+})();
+
+var effect = $.effects;
+
+
+/*!
+ * jQuery UI Effects Blind 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/blind-effect/
+ */
+
+
+var effectBlind = $.effects.effect.blind = function( o, done ) {
+       // Create element
+       var el = $( this ),
+               rvertical = /up|down|vertical/,
+               rpositivemotion = /up|left|vertical|horizontal/,
+               props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+               mode = $.effects.setMode( el, o.mode || "hide" ),
+               direction = o.direction || "up",
+               vertical = rvertical.test( direction ),
+               ref = vertical ? "height" : "width",
+               ref2 = vertical ? "top" : "left",
+               motion = rpositivemotion.test( direction ),
+               animation = {},
+               show = mode === "show",
+               wrapper, distance, margin;
+
+       // if already wrapped, the wrapper's properties are my property. #6245
+       if ( el.parent().is( ".ui-effects-wrapper" ) ) {
+               $.effects.save( el.parent(), props );
+       } else {
+               $.effects.save( el, props );
+       }
+       el.show();
+       wrapper = $.effects.createWrapper( el ).css({
+               overflow: "hidden"
+       });
+
+       distance = wrapper[ ref ]();
+       margin = parseFloat( wrapper.css( ref2 ) ) || 0;
+
+       animation[ ref ] = show ? distance : 0;
+       if ( !motion ) {
+               el
+                       .css( vertical ? "bottom" : "right", 0 )
+                       .css( vertical ? "top" : "left", "auto" )
+                       .css({ position: "absolute" });
+
+               animation[ ref2 ] = show ? margin : distance + margin;
+       }
+
+       // start at 0 if we are showing
+       if ( show ) {
+               wrapper.css( ref, 0 );
+               if ( !motion ) {
+                       wrapper.css( ref2, margin + distance );
+               }
+       }
+
+       // Animate
+       wrapper.animate( animation, {
+               duration: o.duration,
+               easing: o.easing,
+               queue: false,
+               complete: function() {
+                       if ( mode === "hide" ) {
+                               el.hide();
+                       }
+                       $.effects.restore( el, props );
+                       $.effects.removeWrapper( el );
+                       done();
+               }
+       });
+};
+
+
+/*!
+ * jQuery UI Effects Bounce 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/bounce-effect/
+ */
+
+
+var effectBounce = $.effects.effect.bounce = function( o, done ) {
+       var el = $( this ),
+               props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+
+               // defaults:
+               mode = $.effects.setMode( el, o.mode || "effect" ),
+               hide = mode === "hide",
+               show = mode === "show",
+               direction = o.direction || "up",
+               distance = o.distance,
+               times = o.times || 5,
+
+               // number of internal animations
+               anims = times * 2 + ( show || hide ? 1 : 0 ),
+               speed = o.duration / anims,
+               easing = o.easing,
+
+               // utility:
+               ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+               motion = ( direction === "up" || direction === "left" ),
+               i,
+               upAnim,
+               downAnim,
+
+               // we will need to re-assemble the queue to stack our animations in place
+               queue = el.queue(),
+               queuelen = queue.length;
+
+       // Avoid touching opacity to prevent clearType and PNG issues in IE
+       if ( show || hide ) {
+               props.push( "opacity" );
+       }
+
+       $.effects.save( el, props );
+       el.show();
+       $.effects.createWrapper( el ); // Create Wrapper
+
+       // default distance for the BIGGEST bounce is the outer Distance / 3
+       if ( !distance ) {
+               distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
+       }
+
+       if ( show ) {
+               downAnim = { opacity: 1 };
+               downAnim[ ref ] = 0;
+
+               // if we are showing, force opacity 0 and set the initial position
+               // then do the "first" animation
+               el.css( "opacity", 0 )
+                       .css( ref, motion ? -distance * 2 : distance * 2 )
+                       .animate( downAnim, speed, easing );
+       }
+
+       // start at the smallest distance if we are hiding
+       if ( hide ) {
+               distance = distance / Math.pow( 2, times - 1 );
+       }
+
+       downAnim = {};
+       downAnim[ ref ] = 0;
+       // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
+       for ( i = 0; i < times; i++ ) {
+               upAnim = {};
+               upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+               el.animate( upAnim, speed, easing )
+                       .animate( downAnim, speed, easing );
+
+               distance = hide ? distance * 2 : distance / 2;
+       }
+
+       // Last Bounce when Hiding
+       if ( hide ) {
+               upAnim = { opacity: 0 };
+               upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
+
+               el.animate( upAnim, speed, easing );
+       }
+
+       el.queue(function() {
+               if ( hide ) {
+                       el.hide();
+               }
+               $.effects.restore( el, props );
+               $.effects.removeWrapper( el );
+               done();
+       });
+
+       // inject all the animations we just queued to be first in line (after "inprogress")
+       if ( queuelen > 1) {
+               queue.splice.apply( queue,
+                       [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+       }
+       el.dequeue();
+
+};
+
+
+/*!
+ * jQuery UI Effects Clip 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/clip-effect/
+ */
+
+
+var effectClip = $.effects.effect.clip = function( o, done ) {
+       // Create element
+       var el = $( this ),
+               props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+               mode = $.effects.setMode( el, o.mode || "hide" ),
+               show = mode === "show",
+               direction = o.direction || "vertical",
+               vert = direction === "vertical",
+               size = vert ? "height" : "width",
+               position = vert ? "top" : "left",
+               animation = {},
+               wrapper, animate, distance;
+
+       // Save & Show
+       $.effects.save( el, props );
+       el.show();
+
+       // Create Wrapper
+       wrapper = $.effects.createWrapper( el ).css({
+               overflow: "hidden"
+       });
+       animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
+       distance = animate[ size ]();
+
+       // Shift
+       if ( show ) {
+               animate.css( size, 0 );
+               animate.css( position, distance / 2 );
+       }
+
+       // Create Animation Object:
+       animation[ size ] = show ? distance : 0;
+       animation[ position ] = show ? 0 : distance / 2;
+
+       // Animate
+       animate.animate( animation, {
+               queue: false,
+               duration: o.duration,
+               easing: o.easing,
+               complete: function() {
+                       if ( !show ) {
+                               el.hide();
+                       }
+                       $.effects.restore( el, props );
+                       $.effects.removeWrapper( el );
+                       done();
+               }
+       });
+
+};
+
+
+/*!
+ * jQuery UI Effects Drop 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/drop-effect/
+ */
+
+
+var effectDrop = $.effects.effect.drop = function( o, done ) {
+
+       var el = $( this ),
+               props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
+               mode = $.effects.setMode( el, o.mode || "hide" ),
+               show = mode === "show",
+               direction = o.direction || "left",
+               ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+               motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
+               animation = {
+                       opacity: show ? 1 : 0
+               },
+               distance;
+
+       // Adjust
+       $.effects.save( el, props );
+       el.show();
+       $.effects.createWrapper( el );
+
+       distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
+
+       if ( show ) {
+               el
+                       .css( "opacity", 0 )
+                       .css( ref, motion === "pos" ? -distance : distance );
+       }
+
+       // Animation
+       animation[ ref ] = ( show ?
+               ( motion === "pos" ? "+=" : "-=" ) :
+               ( motion === "pos" ? "-=" : "+=" ) ) +
+               distance;
+
+       // Animate
+       el.animate( animation, {
+               queue: false,
+               duration: o.duration,
+               easing: o.easing,
+               complete: function() {
+                       if ( mode === "hide" ) {
+                               el.hide();
+                       }
+                       $.effects.restore( el, props );
+                       $.effects.removeWrapper( el );
+                       done();
+               }
+       });
+};
+
+
+/*!
+ * jQuery UI Effects Explode 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/explode-effect/
+ */
+
+
+var effectExplode = $.effects.effect.explode = function( o, done ) {
+
+       var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
+               cells = rows,
+               el = $( this ),
+               mode = $.effects.setMode( el, o.mode || "hide" ),
+               show = mode === "show",
+
+               // show and then visibility:hidden the element before calculating offset
+               offset = el.show().css( "visibility", "hidden" ).offset(),
+
+               // width and height of a piece
+               width = Math.ceil( el.outerWidth() / cells ),
+               height = Math.ceil( el.outerHeight() / rows ),
+               pieces = [],
+
+               // loop
+               i, j, left, top, mx, my;
+
+       // children animate complete:
+       function childComplete() {
+               pieces.push( this );
+               if ( pieces.length === rows * cells ) {
+                       animComplete();
+               }
+       }
+
+       // clone the element for each row and cell.
+       for ( i = 0; i < rows ; i++ ) { // ===>
+               top = offset.top + i * height;
+               my = i - ( rows - 1 ) / 2 ;
+
+               for ( j = 0; j < cells ; j++ ) { // |||
+                       left = offset.left + j * width;
+                       mx = j - ( cells - 1 ) / 2 ;
+
+                       // Create a clone of the now hidden main element that will be absolute positioned
+                       // within a wrapper div off the -left and -top equal to size of our pieces
+                       el
+                               .clone()
+                               .appendTo( "body" )
+                               .wrap( "<div></div>" )
+                               .css({
+                                       position: "absolute",
+                                       visibility: "visible",
+                                       left: -j * width,
+                                       top: -i * height
+                               })
+
+                       // select the wrapper - make it overflow: hidden and absolute positioned based on
+                       // where the original was located +left and +top equal to the size of pieces
+                               .parent()
+                               .addClass( "ui-effects-explode" )
+                               .css({
+                                       position: "absolute",
+                                       overflow: "hidden",
+                                       width: width,
+                                       height: height,
+                                       left: left + ( show ? mx * width : 0 ),
+                                       top: top + ( show ? my * height : 0 ),
+                                       opacity: show ? 0 : 1
+                               }).animate({
+                                       left: left + ( show ? 0 : mx * width ),
+                                       top: top + ( show ? 0 : my * height ),
+                                       opacity: show ? 1 : 0
+                               }, o.duration || 500, o.easing, childComplete );
+               }
+       }
+
+       function animComplete() {
+               el.css({
+                       visibility: "visible"
+               });
+               $( pieces ).remove();
+               if ( !show ) {
+                       el.hide();
+               }
+               done();
+       }
+};
+
+
+/*!
+ * jQuery UI Effects Fade 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/fade-effect/
+ */
+
+
+var effectFade = $.effects.effect.fade = function( o, done ) {
+       var el = $( this ),
+               mode = $.effects.setMode( el, o.mode || "toggle" );
+
+       el.animate({
+               opacity: mode
+       }, {
+               queue: false,
+               duration: o.duration,
+               easing: o.easing,
+               complete: done
+       });
+};
+
+
+/*!
+ * jQuery UI Effects Fold 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/fold-effect/
+ */
+
+
+var effectFold = $.effects.effect.fold = function( o, done ) {
+
+       // Create element
+       var el = $( this ),
+               props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+               mode = $.effects.setMode( el, o.mode || "hide" ),
+               show = mode === "show",
+               hide = mode === "hide",
+               size = o.size || 15,
+               percent = /([0-9]+)%/.exec( size ),
+               horizFirst = !!o.horizFirst,
+               widthFirst = show !== horizFirst,
+               ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
+               duration = o.duration / 2,
+               wrapper, distance,
+               animation1 = {},
+               animation2 = {};
+
+       $.effects.save( el, props );
+       el.show();
+
+       // Create Wrapper
+       wrapper = $.effects.createWrapper( el ).css({
+               overflow: "hidden"
+       });
+       distance = widthFirst ?
+               [ wrapper.width(), wrapper.height() ] :
+               [ wrapper.height(), wrapper.width() ];
+
+       if ( percent ) {
+               size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
+       }
+       if ( show ) {
+               wrapper.css( horizFirst ? {
+                       height: 0,
+                       width: size
+               } : {
+                       height: size,
+                       width: 0
+               });
+       }
+
+       // Animation
+       animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
+       animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
+
+       // Animate
+       wrapper
+               .animate( animation1, duration, o.easing )
+               .animate( animation2, duration, o.easing, function() {
+                       if ( hide ) {
+                               el.hide();
+                       }
+                       $.effects.restore( el, props );
+                       $.effects.removeWrapper( el );
+                       done();
+               });
+
+};
+
+
+/*!
+ * jQuery UI Effects Highlight 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/highlight-effect/
+ */
+
+
+var effectHighlight = $.effects.effect.highlight = function( o, done ) {
+       var elem = $( this ),
+               props = [ "backgroundImage", "backgroundColor", "opacity" ],
+               mode = $.effects.setMode( elem, o.mode || "show" ),
+               animation = {
+                       backgroundColor: elem.css( "backgroundColor" )
+               };
+
+       if (mode === "hide") {
+               animation.opacity = 0;
+       }
+
+       $.effects.save( elem, props );
+
+       elem
+               .show()
+               .css({
+                       backgroundImage: "none",
+                       backgroundColor: o.color || "#ffff99"
+               })
+               .animate( animation, {
+                       queue: false,
+                       duration: o.duration,
+                       easing: o.easing,
+                       complete: function() {
+                               if ( mode === "hide" ) {
+                                       elem.hide();
+                               }
+                               $.effects.restore( elem, props );
+                               done();
+                       }
+               });
+};
+
+
+/*!
+ * jQuery UI Effects Size 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/size-effect/
+ */
+
+
+var effectSize = $.effects.effect.size = function( o, done ) {
+
+       // Create element
+       var original, baseline, factor,
+               el = $( this ),
+               props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
+
+               // Always restore
+               props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
+
+               // Copy for children
+               props2 = [ "width", "height", "overflow" ],
+               cProps = [ "fontSize" ],
+               vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
+               hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
+
+               // Set options
+               mode = $.effects.setMode( el, o.mode || "effect" ),
+               restore = o.restore || mode !== "effect",
+               scale = o.scale || "both",
+               origin = o.origin || [ "middle", "center" ],
+               position = el.css( "position" ),
+               props = restore ? props0 : props1,
+               zero = {
+                       height: 0,
+                       width: 0,
+                       outerHeight: 0,
+                       outerWidth: 0
+               };
+
+       if ( mode === "show" ) {
+               el.show();
+       }
+       original = {
+               height: el.height(),
+               width: el.width(),
+               outerHeight: el.outerHeight(),
+               outerWidth: el.outerWidth()
+       };
+
+       if ( o.mode === "toggle" && mode === "show" ) {
+               el.from = o.to || zero;
+               el.to = o.from || original;
+       } else {
+               el.from = o.from || ( mode === "show" ? zero : original );
+               el.to = o.to || ( mode === "hide" ? zero : original );
+       }
+
+       // Set scaling factor
+       factor = {
+               from: {
+                       y: el.from.height / original.height,
+                       x: el.from.width / original.width
+               },
+               to: {
+                       y: el.to.height / original.height,
+                       x: el.to.width / original.width
+               }
+       };
+
+       // Scale the css box
+       if ( scale === "box" || scale === "both" ) {
+
+               // Vertical props scaling
+               if ( factor.from.y !== factor.to.y ) {
+                       props = props.concat( vProps );
+                       el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
+                       el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
+               }
+
+               // Horizontal props scaling
+               if ( factor.from.x !== factor.to.x ) {
+                       props = props.concat( hProps );
+                       el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
+                       el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
+               }
+       }
+
+       // Scale the content
+       if ( scale === "content" || scale === "both" ) {
+
+               // Vertical props scaling
+               if ( factor.from.y !== factor.to.y ) {
+                       props = props.concat( cProps ).concat( props2 );
+                       el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
+                       el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
+               }
+       }
+
+       $.effects.save( el, props );
+       el.show();
+       $.effects.createWrapper( el );
+       el.css( "overflow", "hidden" ).css( el.from );
+
+       // Adjust
+       if (origin) { // Calculate baseline shifts
+               baseline = $.effects.getBaseline( origin, original );
+               el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
+               el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
+               el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
+               el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
+       }
+       el.css( el.from ); // set top & left
+
+       // Animate
+       if ( scale === "content" || scale === "both" ) { // Scale the children
+
+               // Add margins/font-size
+               vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
+               hProps = hProps.concat([ "marginLeft", "marginRight" ]);
+               props2 = props0.concat(vProps).concat(hProps);
+
+               el.find( "*[width]" ).each( function() {
+                       var child = $( this ),
+                               c_original = {
+                                       height: child.height(),
+                                       width: child.width(),
+                                       outerHeight: child.outerHeight(),
+                                       outerWidth: child.outerWidth()
+                               };
+                       if (restore) {
+                               $.effects.save(child, props2);
+                       }
+
+                       child.from = {
+                               height: c_original.height * factor.from.y,
+                               width: c_original.width * factor.from.x,
+                               outerHeight: c_original.outerHeight * factor.from.y,
+                               outerWidth: c_original.outerWidth * factor.from.x
+                       };
+                       child.to = {
+                               height: c_original.height * factor.to.y,
+                               width: c_original.width * factor.to.x,
+                               outerHeight: c_original.height * factor.to.y,
+                               outerWidth: c_original.width * factor.to.x
+                       };
+
+                       // Vertical props scaling
+                       if ( factor.from.y !== factor.to.y ) {
+                               child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
+                               child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
+                       }
+
+                       // Horizontal props scaling
+                       if ( factor.from.x !== factor.to.x ) {
+                               child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
+                               child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
+                       }
+
+                       // Animate children
+                       child.css( child.from );
+                       child.animate( child.to, o.duration, o.easing, function() {
+
+                               // Restore children
+                               if ( restore ) {
+                                       $.effects.restore( child, props2 );
+                               }
+                       });
+               });
+       }
+
+       // Animate
+       el.animate( el.to, {
+               queue: false,
+               duration: o.duration,
+               easing: o.easing,
+               complete: function() {
+                       if ( el.to.opacity === 0 ) {
+                               el.css( "opacity", el.from.opacity );
+                       }
+                       if ( mode === "hide" ) {
+                               el.hide();
+                       }
+                       $.effects.restore( el, props );
+                       if ( !restore ) {
+
+                               // we need to calculate our new positioning based on the scaling
+                               if ( position === "static" ) {
+                                       el.css({
+                                               position: "relative",
+                                               top: el.to.top,
+                                               left: el.to.left
+                                       });
+                               } else {
+                                       $.each([ "top", "left" ], function( idx, pos ) {
+                                               el.css( pos, function( _, str ) {
+                                                       var val = parseInt( str, 10 ),
+                                                               toRef = idx ? el.to.left : el.to.top;
+
+                                                       // if original was "auto", recalculate the new value from wrapper
+                                                       if ( str === "auto" ) {
+                                                               return toRef + "px";
+                                                       }
+
+                                                       return val + toRef + "px";
+                                               });
+                                       });
+                               }
+                       }
+
+                       $.effects.removeWrapper( el );
+                       done();
+               }
+       });
+
+};
+
+
+/*!
+ * jQuery UI Effects Scale 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/scale-effect/
+ */
+
+
+var effectScale = $.effects.effect.scale = function( o, done ) {
+
+       // Create element
+       var el = $( this ),
+               options = $.extend( true, {}, o ),
+               mode = $.effects.setMode( el, o.mode || "effect" ),
+               percent = parseInt( o.percent, 10 ) ||
+                       ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
+               direction = o.direction || "both",
+               origin = o.origin,
+               original = {
+                       height: el.height(),
+                       width: el.width(),
+                       outerHeight: el.outerHeight(),
+                       outerWidth: el.outerWidth()
+               },
+               factor = {
+                       y: direction !== "horizontal" ? (percent / 100) : 1,
+                       x: direction !== "vertical" ? (percent / 100) : 1
+               };
+
+       // We are going to pass this effect to the size effect:
+       options.effect = "size";
+       options.queue = false;
+       options.complete = done;
+
+       // Set default origin and restore for show/hide
+       if ( mode !== "effect" ) {
+               options.origin = origin || [ "middle", "center" ];
+               options.restore = true;
+       }
+
+       options.from = o.from || ( mode === "show" ? {
+               height: 0,
+               width: 0,
+               outerHeight: 0,
+               outerWidth: 0
+       } : original );
+       options.to = {
+               height: original.height * factor.y,
+               width: original.width * factor.x,
+               outerHeight: original.outerHeight * factor.y,
+               outerWidth: original.outerWidth * factor.x
+       };
+
+       // Fade option to support puff
+       if ( options.fade ) {
+               if ( mode === "show" ) {
+                       options.from.opacity = 0;
+                       options.to.opacity = 1;
+               }
+               if ( mode === "hide" ) {
+                       options.from.opacity = 1;
+                       options.to.opacity = 0;
+               }
+       }
+
+       // Animate
+       el.effect( options );
+
+};
+
+
+/*!
+ * jQuery UI Effects Puff 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/puff-effect/
+ */
+
+
+var effectPuff = $.effects.effect.puff = function( o, done ) {
+       var elem = $( this ),
+               mode = $.effects.setMode( elem, o.mode || "hide" ),
+               hide = mode === "hide",
+               percent = parseInt( o.percent, 10 ) || 150,
+               factor = percent / 100,
+               original = {
+                       height: elem.height(),
+                       width: elem.width(),
+                       outerHeight: elem.outerHeight(),
+                       outerWidth: elem.outerWidth()
+               };
+
+       $.extend( o, {
+               effect: "scale",
+               queue: false,
+               fade: true,
+               mode: mode,
+               complete: done,
+               percent: hide ? percent : 100,
+               from: hide ?
+                       original :
+                       {
+                               height: original.height * factor,
+                               width: original.width * factor,
+                               outerHeight: original.outerHeight * factor,
+                               outerWidth: original.outerWidth * factor
+                       }
+       });
+
+       elem.effect( o );
+};
+
+
+/*!
+ * jQuery UI Effects Pulsate 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/pulsate-effect/
+ */
+
+
+var effectPulsate = $.effects.effect.pulsate = function( o, done ) {
+       var elem = $( this ),
+               mode = $.effects.setMode( elem, o.mode || "show" ),
+               show = mode === "show",
+               hide = mode === "hide",
+               showhide = ( show || mode === "hide" ),
+
+               // showing or hiding leaves of the "last" animation
+               anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
+               duration = o.duration / anims,
+               animateTo = 0,
+               queue = elem.queue(),
+               queuelen = queue.length,
+               i;
+
+       if ( show || !elem.is(":visible")) {
+               elem.css( "opacity", 0 ).show();
+               animateTo = 1;
+       }
+
+       // anims - 1 opacity "toggles"
+       for ( i = 1; i < anims; i++ ) {
+               elem.animate({
+                       opacity: animateTo
+               }, duration, o.easing );
+               animateTo = 1 - animateTo;
+       }
+
+       elem.animate({
+               opacity: animateTo
+       }, duration, o.easing);
+
+       elem.queue(function() {
+               if ( hide ) {
+                       elem.hide();
+               }
+               done();
+       });
+
+       // We just queued up "anims" animations, we need to put them next in the queue
+       if ( queuelen > 1 ) {
+               queue.splice.apply( queue,
+                       [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+       }
+       elem.dequeue();
+};
+
+
+/*!
+ * jQuery UI Effects Shake 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/shake-effect/
+ */
+
+
+var effectShake = $.effects.effect.shake = function( o, done ) {
+
+       var el = $( this ),
+               props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+               mode = $.effects.setMode( el, o.mode || "effect" ),
+               direction = o.direction || "left",
+               distance = o.distance || 20,
+               times = o.times || 3,
+               anims = times * 2 + 1,
+               speed = Math.round( o.duration / anims ),
+               ref = (direction === "up" || direction === "down") ? "top" : "left",
+               positiveMotion = (direction === "up" || direction === "left"),
+               animation = {},
+               animation1 = {},
+               animation2 = {},
+               i,
+
+               // we will need to re-assemble the queue to stack our animations in place
+               queue = el.queue(),
+               queuelen = queue.length;
+
+       $.effects.save( el, props );
+       el.show();
+       $.effects.createWrapper( el );
+
+       // Animation
+       animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
+       animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
+       animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
+
+       // Animate
+       el.animate( animation, speed, o.easing );
+
+       // Shakes
+       for ( i = 1; i < times; i++ ) {
+               el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
+       }
+       el
+               .animate( animation1, speed, o.easing )
+               .animate( animation, speed / 2, o.easing )
+               .queue(function() {
+                       if ( mode === "hide" ) {
+                               el.hide();
+                       }
+                       $.effects.restore( el, props );
+                       $.effects.removeWrapper( el );
+                       done();
+               });
+
+       // inject all the animations we just queued to be first in line (after "inprogress")
+       if ( queuelen > 1) {
+               queue.splice.apply( queue,
+                       [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
+       }
+       el.dequeue();
+
+};
+
+
+/*!
+ * jQuery UI Effects Slide 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/slide-effect/
+ */
+
+
+var effectSlide = $.effects.effect.slide = function( o, done ) {
+
+       // Create element
+       var el = $( this ),
+               props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
+               mode = $.effects.setMode( el, o.mode || "show" ),
+               show = mode === "show",
+               direction = o.direction || "left",
+               ref = (direction === "up" || direction === "down") ? "top" : "left",
+               positiveMotion = (direction === "up" || direction === "left"),
+               distance,
+               animation = {};
+
+       // Adjust
+       $.effects.save( el, props );
+       el.show();
+       distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
+
+       $.effects.createWrapper( el ).css({
+               overflow: "hidden"
+       });
+
+       if ( show ) {
+               el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
+       }
+
+       // Animation
+       animation[ ref ] = ( show ?
+               ( positiveMotion ? "+=" : "-=") :
+               ( positiveMotion ? "-=" : "+=")) +
+               distance;
+
+       // Animate
+       el.animate( animation, {
+               queue: false,
+               duration: o.duration,
+               easing: o.easing,
+               complete: function() {
+                       if ( mode === "hide" ) {
+                               el.hide();
+                       }
+                       $.effects.restore( el, props );
+                       $.effects.removeWrapper( el );
+                       done();
+               }
+       });
+};
+
+
+/*!
+ * jQuery UI Effects Transfer 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/transfer-effect/
+ */
+
+
+var effectTransfer = $.effects.effect.transfer = function( o, done ) {
+       var elem = $( this ),
+               target = $( o.to ),
+               targetFixed = target.css( "position" ) === "fixed",
+               body = $("body"),
+               fixTop = targetFixed ? body.scrollTop() : 0,
+               fixLeft = targetFixed ? body.scrollLeft() : 0,
+               endPosition = target.offset(),
+               animation = {
+                       top: endPosition.top - fixTop,
+                       left: endPosition.left - fixLeft,
+                       height: target.innerHeight(),
+                       width: target.innerWidth()
+               },
+               startPosition = elem.offset(),
+               transfer = $( "<div class='ui-effects-transfer'></div>" )
+                       .appendTo( document.body )
+                       .addClass( o.className )
+                       .css({
+                               top: startPosition.top - fixTop,
+                               left: startPosition.left - fixLeft,
+                               height: elem.innerHeight(),
+                               width: elem.innerWidth(),
+                               position: targetFixed ? "fixed" : "absolute"
+                       })
+                       .animate( animation, o.duration, o.easing, function() {
+                               transfer.remove();
+                               done();
+                       });
+};
+
+
+/*!
+ * jQuery UI Progressbar 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/progressbar/
+ */
+
+
+var progressbar = $.widget( "ui.progressbar", {
+       version: "1.11.2",
+       options: {
+               max: 100,
+               value: 0,
+
+               change: null,
+               complete: null
+       },
+
+       min: 0,
+
+       _create: function() {
+               // Constrain initial value
+               this.oldValue = this.options.value = this._constrainedValue();
+
+               this.element
+                       .addClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+                       .attr({
+                               // Only set static values, aria-valuenow and aria-valuemax are
+                               // set inside _refreshValue()
+                               role: "progressbar",
+                               "aria-valuemin": this.min
+                       });
+
+               this.valueDiv = $( "<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>" )
+                       .appendTo( this.element );
+
+               this._refreshValue();
+       },
+
+       _destroy: function() {
+               this.element
+                       .removeClass( "ui-progressbar ui-widget ui-widget-content ui-corner-all" )
+                       .removeAttr( "role" )
+                       .removeAttr( "aria-valuemin" )
+                       .removeAttr( "aria-valuemax" )
+                       .removeAttr( "aria-valuenow" );
+
+               this.valueDiv.remove();
+       },
+
+       value: function( newValue ) {
+               if ( newValue === undefined ) {
+                       return this.options.value;
+               }
+
+               this.options.value = this._constrainedValue( newValue );
+               this._refreshValue();
+       },
+
+       _constrainedValue: function( newValue ) {
+               if ( newValue === undefined ) {
+                       newValue = this.options.value;
+               }
+
+               this.indeterminate = newValue === false;
+
+               // sanitize value
+               if ( typeof newValue !== "number" ) {
+                       newValue = 0;
+               }
+
+               return this.indeterminate ? false :
+                       Math.min( this.options.max, Math.max( this.min, newValue ) );
+       },
+
+       _setOptions: function( options ) {
+               // Ensure "value" option is set after other values (like max)
+               var value = options.value;
+               delete options.value;
+
+               this._super( options );
+
+               this.options.value = this._constrainedValue( value );
+               this._refreshValue();
+       },
+
+       _setOption: function( key, value ) {
+               if ( key === "max" ) {
+                       // Don't allow a max less than min
+                       value = Math.max( this.min, value );
+               }
+               if ( key === "disabled" ) {
+                       this.element
+                               .toggleClass( "ui-state-disabled", !!value )
+                               .attr( "aria-disabled", value );
+               }
+               this._super( key, value );
+       },
+
+       _percentage: function() {
+               return this.indeterminate ? 100 : 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
+       },
+
+       _refreshValue: function() {
+               var value = this.options.value,
+                       percentage = this._percentage();
+
+               this.valueDiv
+                       .toggle( this.indeterminate || value > this.min )
+                       .toggleClass( "ui-corner-right", value === this.options.max )
+                       .width( percentage.toFixed(0) + "%" );
+
+               this.element.toggleClass( "ui-progressbar-indeterminate", this.indeterminate );
+
+               if ( this.indeterminate ) {
+                       this.element.removeAttr( "aria-valuenow" );
+                       if ( !this.overlayDiv ) {
+                               this.overlayDiv = $( "<div class='ui-progressbar-overlay'></div>" ).appendTo( this.valueDiv );
+                       }
+               } else {
+                       this.element.attr({
+                               "aria-valuemax": this.options.max,
+                               "aria-valuenow": value
+                       });
+                       if ( this.overlayDiv ) {
+                               this.overlayDiv.remove();
+                               this.overlayDiv = null;
+                       }
+               }
+
+               if ( this.oldValue !== value ) {
+                       this.oldValue = value;
+                       this._trigger( "change" );
+               }
+               if ( value === this.options.max ) {
+                       this._trigger( "complete" );
+               }
+       }
+});
+
+
+/*!
+ * jQuery UI Selectable 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/selectable/
+ */
+
+
+var selectable = $.widget("ui.selectable", $.ui.mouse, {
+       version: "1.11.2",
+       options: {
+               appendTo: "body",
+               autoRefresh: true,
+               distance: 0,
+               filter: "*",
+               tolerance: "touch",
+
+               // callbacks
+               selected: null,
+               selecting: null,
+               start: null,
+               stop: null,
+               unselected: null,
+               unselecting: null
+       },
+       _create: function() {
+               var selectees,
+                       that = this;
+
+               this.element.addClass("ui-selectable");
+
+               this.dragged = false;
+
+               // cache selectee children based on filter
+               this.refresh = function() {
+                       selectees = $(that.options.filter, that.element[0]);
+                       selectees.addClass("ui-selectee");
+                       selectees.each(function() {
+                               var $this = $(this),
+                                       pos = $this.offset();
+                               $.data(this, "selectable-item", {
+                                       element: this,
+                                       $element: $this,
+                                       left: pos.left,
+                                       top: pos.top,
+                                       right: pos.left + $this.outerWidth(),
+                                       bottom: pos.top + $this.outerHeight(),
+                                       startselected: false,
+                                       selected: $this.hasClass("ui-selected"),
+                                       selecting: $this.hasClass("ui-selecting"),
+                                       unselecting: $this.hasClass("ui-unselecting")
+                               });
+                       });
+               };
+               this.refresh();
+
+               this.selectees = selectees.addClass("ui-selectee");
+
+               this._mouseInit();
+
+               this.helper = $("<div class='ui-selectable-helper'></div>");
+       },
+
+       _destroy: function() {
+               this.selectees
+                       .removeClass("ui-selectee")
+                       .removeData("selectable-item");
+               this.element
+                       .removeClass("ui-selectable ui-selectable-disabled");
+               this._mouseDestroy();
+       },
+
+       _mouseStart: function(event) {
+               var that = this,
+                       options = this.options;
+
+               this.opos = [ event.pageX, event.pageY ];
+
+               if (this.options.disabled) {
+                       return;
+               }
+
+               this.selectees = $(options.filter, this.element[0]);
+
+               this._trigger("start", event);
+
+               $(options.appendTo).append(this.helper);
+               // position helper (lasso)
+               this.helper.css({
+                       "left": event.pageX,
+                       "top": event.pageY,
+                       "width": 0,
+                       "height": 0
+               });
+
+               if (options.autoRefresh) {
+                       this.refresh();
+               }
+
+               this.selectees.filter(".ui-selected").each(function() {
+                       var selectee = $.data(this, "selectable-item");
+                       selectee.startselected = true;
+                       if (!event.metaKey && !event.ctrlKey) {
+                               selectee.$element.removeClass("ui-selected");
+                               selectee.selected = false;
+                               selectee.$element.addClass("ui-unselecting");
+                               selectee.unselecting = true;
+                               // selectable UNSELECTING callback
+                               that._trigger("unselecting", event, {
+                                       unselecting: selectee.element
+                               });
+                       }
+               });
+
+               $(event.target).parents().addBack().each(function() {
+                       var doSelect,
+                               selectee = $.data(this, "selectable-item");
+                       if (selectee) {
+                               doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected");
+                               selectee.$element
+                                       .removeClass(doSelect ? "ui-unselecting" : "ui-selected")
+                                       .addClass(doSelect ? "ui-selecting" : "ui-unselecting");
+                               selectee.unselecting = !doSelect;
+                               selectee.selecting = doSelect;
+                               selectee.selected = doSelect;
+                               // selectable (UN)SELECTING callback
+                               if (doSelect) {
+                                       that._trigger("selecting", event, {
+                                               selecting: selectee.element
+                                       });
+                               } else {
+                                       that._trigger("unselecting", event, {
+                                               unselecting: selectee.element
+                                       });
+                               }
+                               return false;
+                       }
+               });
+
+       },
+
+       _mouseDrag: function(event) {
+
+               this.dragged = true;
+
+               if (this.options.disabled) {
+                       return;
+               }
+
+               var tmp,
+                       that = this,
+                       options = this.options,
+                       x1 = this.opos[0],
+                       y1 = this.opos[1],
+                       x2 = event.pageX,
+                       y2 = event.pageY;
+
+               if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; }
+               if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; }
+               this.helper.css({ left: x1, top: y1, width: x2 - x1, height: y2 - y1 });
+
+               this.selectees.each(function() {
+                       var selectee = $.data(this, "selectable-item"),
+                               hit = false;
+
+                       //prevent helper from being selected if appendTo: selectable
+                       if (!selectee || selectee.element === that.element[0]) {
+                               return;
+                       }
+
+                       if (options.tolerance === "touch") {
+                               hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) );
+                       } else if (options.tolerance === "fit") {
+                               hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2);
+                       }
+
+                       if (hit) {
+                               // SELECT
+                               if (selectee.selected) {
+                                       selectee.$element.removeClass("ui-selected");
+                                       selectee.selected = false;
+                               }
+                               if (selectee.unselecting) {
+                                       selectee.$element.removeClass("ui-unselecting");
+                                       selectee.unselecting = false;
+                               }
+                               if (!selectee.selecting) {
+                                       selectee.$element.addClass("ui-selecting");
+                                       selectee.selecting = true;
+                                       // selectable SELECTING callback
+                                       that._trigger("selecting", event, {
+                                               selecting: selectee.element
+                                       });
+                               }
+                       } else {
+                               // UNSELECT
+                               if (selectee.selecting) {
+                                       if ((event.metaKey || event.ctrlKey) && selectee.startselected) {
+                                               selectee.$element.removeClass("ui-selecting");
+                                               selectee.selecting = false;
+                                               selectee.$element.addClass("ui-selected");
+                                               selectee.selected = true;
+                                       } else {
+                                               selectee.$element.removeClass("ui-selecting");
+                                               selectee.selecting = false;
+                                               if (selectee.startselected) {
+                                                       selectee.$element.addClass("ui-unselecting");
+                                                       selectee.unselecting = true;
+                                               }
+                                               // selectable UNSELECTING callback
+                                               that._trigger("unselecting", event, {
+                                                       unselecting: selectee.element
+                                               });
+                                       }
+                               }
+                               if (selectee.selected) {
+                                       if (!event.metaKey && !event.ctrlKey && !selectee.startselected) {
+                                               selectee.$element.removeClass("ui-selected");
+                                               selectee.selected = false;
+
+                                               selectee.$element.addClass("ui-unselecting");
+                                               selectee.unselecting = true;
+                                               // selectable UNSELECTING callback
+                                               that._trigger("unselecting", event, {
+                                                       unselecting: selectee.element
+                                               });
+                                       }
+                               }
+                       }
+               });
+
+               return false;
+       },
+
+       _mouseStop: function(event) {
+               var that = this;
+
+               this.dragged = false;
+
+               $(".ui-unselecting", this.element[0]).each(function() {
+                       var selectee = $.data(this, "selectable-item");
+                       selectee.$element.removeClass("ui-unselecting");
+                       selectee.unselecting = false;
+                       selectee.startselected = false;
+                       that._trigger("unselected", event, {
+                               unselected: selectee.element
+                       });
+               });
+               $(".ui-selecting", this.element[0]).each(function() {
+                       var selectee = $.data(this, "selectable-item");
+                       selectee.$element.removeClass("ui-selecting").addClass("ui-selected");
+                       selectee.selecting = false;
+                       selectee.selected = true;
+                       selectee.startselected = true;
+                       that._trigger("selected", event, {
+                               selected: selectee.element
+                       });
+               });
+               this._trigger("stop", event);
+
+               this.helper.remove();
+
+               return false;
+       }
+
+});
+
+
+/*!
+ * jQuery UI Selectmenu 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/selectmenu
+ */
+
+
+var selectmenu = $.widget( "ui.selectmenu", {
+       version: "1.11.2",
+       defaultElement: "<select>",
+       options: {
+               appendTo: null,
+               disabled: null,
+               icons: {
+                       button: "ui-icon-triangle-1-s"
+               },
+               position: {
+                       my: "left top",
+                       at: "left bottom",
+                       collision: "none"
+               },
+               width: null,
+
+               // callbacks
+               change: null,
+               close: null,
+               focus: null,
+               open: null,
+               select: null
+       },
+
+       _create: function() {
+               var selectmenuId = this.element.uniqueId().attr( "id" );
+               this.ids = {
+                       element: selectmenuId,
+                       button: selectmenuId + "-button",
+                       menu: selectmenuId + "-menu"
+               };
+
+               this._drawButton();
+               this._drawMenu();
+
+               if ( this.options.disabled ) {
+                       this.disable();
+               }
+       },
+
+       _drawButton: function() {
+               var that = this,
+                       tabindex = this.element.attr( "tabindex" );
+
+               // Associate existing label with the new button
+               this.label = $( "label[for='" + this.ids.element + "']" ).attr( "for", this.ids.button );
+               this._on( this.label, {
+                       click: function( event ) {
+                               this.button.focus();
+                               event.preventDefault();
+                       }
+               });
+
+               // Hide original select element
+               this.element.hide();
+
+               // Create button
+               this.button = $( "<span>", {
+                       "class": "ui-selectmenu-button ui-widget ui-state-default ui-corner-all",
+                       tabindex: tabindex || this.options.disabled ? -1 : 0,
+                       id: this.ids.button,
+                       role: "combobox",
+                       "aria-expanded": "false",
+                       "aria-autocomplete": "list",
+                       "aria-owns": this.ids.menu,
+                       "aria-haspopup": "true"
+               })
+                       .insertAfter( this.element );
+
+               $( "<span>", {
+                       "class": "ui-icon " + this.options.icons.button
+               })
+                       .prependTo( this.button );
+
+               this.buttonText = $( "<span>", {
+                       "class": "ui-selectmenu-text"
+               })
+                       .appendTo( this.button );
+
+               this._setText( this.buttonText, this.element.find( "option:selected" ).text() );
+               this._resizeButton();
+
+               this._on( this.button, this._buttonEvents );
+               this.button.one( "focusin", function() {
+
+                       // Delay rendering the menu items until the button receives focus.
+                       // The menu may have already been rendered via a programmatic open.
+                       if ( !that.menuItems ) {
+                               that._refreshMenu();
+                       }
+               });
+               this._hoverable( this.button );
+               this._focusable( this.button );
+       },
+
+       _drawMenu: function() {
+               var that = this;
+
+               // Create menu
+               this.menu = $( "<ul>", {
+                       "aria-hidden": "true",
+                       "aria-labelledby": this.ids.button,
+                       id: this.ids.menu
+               });
+
+               // Wrap menu
+               this.menuWrap = $( "<div>", {
+                       "class": "ui-selectmenu-menu ui-front"
+               })
+                       .append( this.menu )
+                       .appendTo( this._appendTo() );
+
+               // Initialize menu widget
+               this.menuInstance = this.menu
+                       .menu({
+                               role: "listbox",
+                               select: function( event, ui ) {
+                                       event.preventDefault();
+
+                                       // support: IE8
+                                       // If the item was selected via a click, the text selection
+                                       // will be destroyed in IE
+                                       that._setSelection();
+
+                                       that._select( ui.item.data( "ui-selectmenu-item" ), event );
+                               },
+                               focus: function( event, ui ) {
+                                       var item = ui.item.data( "ui-selectmenu-item" );
+
+                                       // Prevent inital focus from firing and check if its a newly focused item
+                                       if ( that.focusIndex != null && item.index !== that.focusIndex ) {
+                                               that._trigger( "focus", event, { item: item } );
+                                               if ( !that.isOpen ) {
+                                                       that._select( item, event );
+                                               }
+                                       }
+                                       that.focusIndex = item.index;
+
+                                       that.button.attr( "aria-activedescendant",
+                                               that.menuItems.eq( item.index ).attr( "id" ) );
+                               }
+                       })
+                       .menu( "instance" );
+
+               // Adjust menu styles to dropdown
+               this.menu
+                       .addClass( "ui-corner-bottom" )
+                       .removeClass( "ui-corner-all" );
+
+               // Don't close the menu on mouseleave
+               this.menuInstance._off( this.menu, "mouseleave" );
+
+               // Cancel the menu's collapseAll on document click
+               this.menuInstance._closeOnDocumentClick = function() {
+                       return false;
+               };
+
+               // Selects often contain empty items, but never contain dividers
+               this.menuInstance._isDivider = function() {
+                       return false;
+               };
+       },
+
+       refresh: function() {
+               this._refreshMenu();
+               this._setText( this.buttonText, this._getSelectedItem().text() );
+               if ( !this.options.width ) {
+                       this._resizeButton();
+               }
+       },
+
+       _refreshMenu: function() {
+               this.menu.empty();
+
+               var item,
+                       options = this.element.find( "option" );
+
+               if ( !options.length ) {
+                       return;
+               }
+
+               this._parseOptions( options );
+               this._renderMenu( this.menu, this.items );
+
+               this.menuInstance.refresh();
+               this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );
+
+               item = this._getSelectedItem();
+
+               // Update the menu to have the correct item focused
+               this.menuInstance.focus( null, item );
+               this._setAria( item.data( "ui-selectmenu-item" ) );
+
+               // Set disabled state
+               this._setOption( "disabled", this.element.prop( "disabled" ) );
+       },
+
+       open: function( event ) {
+               if ( this.options.disabled ) {
+                       return;
+               }
+
+               // If this is the first time the menu is being opened, render the items
+               if ( !this.menuItems ) {
+                       this._refreshMenu();
+               } else {
+
+                       // Menu clears focus on close, reset focus to selected item
+                       this.menu.find( ".ui-state-focus" ).removeClass( "ui-state-focus" );
+                       this.menuInstance.focus( null, this._getSelectedItem() );
+               }
+
+               this.isOpen = true;
+               this._toggleAttr();
+               this._resizeMenu();
+               this._position();
+
+               this._on( this.document, this._documentClick );
+
+               this._trigger( "open", event );
+       },
+
+       _position: function() {
+               this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
+       },
+
+       close: function( event ) {
+               if ( !this.isOpen ) {
+                       return;
+               }
+
+               this.isOpen = false;
+               this._toggleAttr();
+
+               this.range = null;
+               this._off( this.document );
+
+               this._trigger( "close", event );
+       },
+
+       widget: function() {
+               return this.button;
+       },
+
+       menuWidget: function() {
+               return this.menu;
+       },
+
+       _renderMenu: function( ul, items ) {
+               var that = this,
+                       currentOptgroup = "";
+
+               $.each( items, function( index, item ) {
+                       if ( item.optgroup !== currentOptgroup ) {
+                               $( "<li>", {
+                                       "class": "ui-selectmenu-optgroup ui-menu-divider" +
+                                               ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
+                                                       " ui-state-disabled" :
+                                                       "" ),
+                                       text: item.optgroup
+                               })
+                                       .appendTo( ul );
+
+                               currentOptgroup = item.optgroup;
+                       }
+
+                       that._renderItemData( ul, item );
+               });
+       },
+
+       _renderItemData: function( ul, item ) {
+               return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
+       },
+
+       _renderItem: function( ul, item ) {
+               var li = $( "<li>" );
+
+               if ( item.disabled ) {
+                       li.addClass( "ui-state-disabled" );
+               }
+               this._setText( li, item.label );
+
+               return li.appendTo( ul );
+       },
+
+       _setText: function( element, value ) {
+               if ( value ) {
+                       element.text( value );
+               } else {
+                       element.html( "&#160;" );
+               }
+       },
+
+       _move: function( direction, event ) {
+               var item, next,
+                       filter = ".ui-menu-item";
+
+               if ( this.isOpen ) {
+                       item = this.menuItems.eq( this.focusIndex );
+               } else {
+                       item = this.menuItems.eq( this.element[ 0 ].selectedIndex );
+                       filter += ":not(.ui-state-disabled)";
+               }
+
+               if ( direction === "first" || direction === "last" ) {
+                       next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
+               } else {
+                       next = item[ direction + "All" ]( filter ).eq( 0 );
+               }
+
+               if ( next.length ) {
+                       this.menuInstance.focus( event, next );
+               }
+       },
+
+       _getSelectedItem: function() {
+               return this.menuItems.eq( this.element[ 0 ].selectedIndex );
+       },
+
+       _toggle: function( event ) {
+               this[ this.isOpen ? "close" : "open" ]( event );
+       },
+
+       _setSelection: function() {
+               var selection;
+
+               if ( !this.range ) {
+                       return;
+               }
+
+               if ( window.getSelection ) {
+                       selection = window.getSelection();
+                       selection.removeAllRanges();
+                       selection.addRange( this.range );
+
+               // support: IE8
+               } else {
+                       this.range.select();
+               }
+
+               // support: IE
+               // Setting the text selection kills the button focus in IE, but
+               // restoring the focus doesn't kill the selection.
+               this.button.focus();
+       },
+
+       _documentClick: {
+               mousedown: function( event ) {
+                       if ( !this.isOpen ) {
+                               return;
+                       }
+
+                       if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" + this.ids.button ).length ) {
+                               this.close( event );
+                       }
+               }
+       },
+
+       _buttonEvents: {
+
+               // Prevent text selection from being reset when interacting with the selectmenu (#10144)
+               mousedown: function() {
+                       var selection;
+
+                       if ( window.getSelection ) {
+                               selection = window.getSelection();
+                               if ( selection.rangeCount ) {
+                                       this.range = selection.getRangeAt( 0 );
+                               }
+
+                       // support: IE8
+                       } else {
+                               this.range = document.selection.createRange();
+                       }
+               },
+
+               click: function( event ) {
+                       this._setSelection();
+                       this._toggle( event );
+               },
+
+               keydown: function( event ) {
+                       var preventDefault = true;
+                       switch ( event.keyCode ) {
+                               case $.ui.keyCode.TAB:
+                               case $.ui.keyCode.ESCAPE:
+                                       this.close( event );
+                                       preventDefault = false;
+                                       break;
+                               case $.ui.keyCode.ENTER:
+                                       if ( this.isOpen ) {
+                                               this._selectFocusedItem( event );
+                                       }
+                                       break;
+                               case $.ui.keyCode.UP:
+                                       if ( event.altKey ) {
+                                               this._toggle( event );
+                                       } else {
+                                               this._move( "prev", event );
+                                       }
+                                       break;
+                               case $.ui.keyCode.DOWN:
+                                       if ( event.altKey ) {
+                                               this._toggle( event );
+                                       } else {
+                                               this._move( "next", event );
+                                       }
+                                       break;
+                               case $.ui.keyCode.SPACE:
+                                       if ( this.isOpen ) {
+                                               this._selectFocusedItem( event );
+                                       } else {
+                                               this._toggle( event );
+                                       }
+                                       break;
+                               case $.ui.keyCode.LEFT:
+                                       this._move( "prev", event );
+                                       break;
+                               case $.ui.keyCode.RIGHT:
+                                       this._move( "next", event );
+                                       break;
+                               case $.ui.keyCode.HOME:
+                               case $.ui.keyCode.PAGE_UP:
+                                       this._move( "first", event );
+                                       break;
+                               case $.ui.keyCode.END:
+                               case $.ui.keyCode.PAGE_DOWN:
+                                       this._move( "last", event );
+                                       break;
+                               default:
+                                       this.menu.trigger( event );
+                                       preventDefault = false;
+                       }
+
+                       if ( preventDefault ) {
+                               event.preventDefault();
+                       }
+               }
+       },
+
+       _selectFocusedItem: function( event ) {
+               var item = this.menuItems.eq( this.focusIndex );
+               if ( !item.hasClass( "ui-state-disabled" ) ) {
+                       this._select( item.data( "ui-selectmenu-item" ), event );
+               }
+       },
+
+       _select: function( item, event ) {
+               var oldIndex = this.element[ 0 ].selectedIndex;
+
+               // Change native select element
+               this.element[ 0 ].selectedIndex = item.index;
+               this._setText( this.buttonText, item.label );
+               this._setAria( item );
+               this._trigger( "select", event, { item: item } );
+
+               if ( item.index !== oldIndex ) {
+                       this._trigger( "change", event, { item: item } );
+               }
+
+               this.close( event );
+       },
+
+       _setAria: function( item ) {
+               var id = this.menuItems.eq( item.index ).attr( "id" );
+
+               this.button.attr({
+                       "aria-labelledby": id,
+                       "aria-activedescendant": id
+               });
+               this.menu.attr( "aria-activedescendant", id );
+       },
+
+       _setOption: function( key, value ) {
+               if ( key === "icons" ) {
+                       this.button.find( "span.ui-icon" )
+                               .removeClass( this.options.icons.button )
+                               .addClass( value.button );
+               }
+
+               this._super( key, value );
+
+               if ( key === "appendTo" ) {
+                       this.menuWrap.appendTo( this._appendTo() );
+               }
+
+               if ( key === "disabled" ) {
+                       this.menuInstance.option( "disabled", value );
+                       this.button
+                               .toggleClass( "ui-state-disabled", value )
+                               .attr( "aria-disabled", value );
+
+                       this.element.prop( "disabled", value );
+                       if ( value ) {
+                               this.button.attr( "tabindex", -1 );
+                               this.close();
+                       } else {
+                               this.button.attr( "tabindex", 0 );
+                       }
+               }
+
+               if ( key === "width" ) {
+                       this._resizeButton();
+               }
+       },
+
+       _appendTo: function() {
+               var element = this.options.appendTo;
+
+               if ( element ) {
+                       element = element.jquery || element.nodeType ?
+                               $( element ) :
+                               this.document.find( element ).eq( 0 );
+               }
+
+               if ( !element || !element[ 0 ] ) {
+                       element = this.element.closest( ".ui-front" );
+               }
+
+               if ( !element.length ) {
+                       element = this.document[ 0 ].body;
+               }
+
+               return element;
+       },
+
+       _toggleAttr: function() {
+               this.button
+                       .toggleClass( "ui-corner-top", this.isOpen )
+                       .toggleClass( "ui-corner-all", !this.isOpen )
+                       .attr( "aria-expanded", this.isOpen );
+               this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
+               this.menu.attr( "aria-hidden", !this.isOpen );
+       },
+
+       _resizeButton: function() {
+               var width = this.options.width;
+
+               if ( !width ) {
+                       width = this.element.show().outerWidth();
+                       this.element.hide();
+               }
+
+               this.button.outerWidth( width );
+       },
+
+       _resizeMenu: function() {
+               this.menu.outerWidth( Math.max(
+                       this.button.outerWidth(),
+
+                       // support: IE10
+                       // IE10 wraps long text (possibly a rounding bug)
+                       // so we add 1px to avoid the wrapping
+                       this.menu.width( "" ).outerWidth() + 1
+               ) );
+       },
+
+       _getCreateOptions: function() {
+               return { disabled: this.element.prop( "disabled" ) };
+       },
+
+       _parseOptions: function( options ) {
+               var data = [];
+               options.each(function( index, item ) {
+                       var option = $( item ),
+                               optgroup = option.parent( "optgroup" );
+                       data.push({
+                               element: option,
+                               index: index,
+                               value: option.attr( "value" ),
+                               label: option.text(),
+                               optgroup: optgroup.attr( "label" ) || "",
+                               disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
+                       });
+               });
+               this.items = data;
+       },
+
+       _destroy: function() {
+               this.menuWrap.remove();
+               this.button.remove();
+               this.element.show();
+               this.element.removeUniqueId();
+               this.label.attr( "for", this.ids.element );
+       }
+});
+
+
+/*!
+ * jQuery UI Slider 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/slider/
+ */
+
+
+var slider = $.widget( "ui.slider", $.ui.mouse, {
+       version: "1.11.2",
+       widgetEventPrefix: "slide",
+
+       options: {
+               animate: false,
+               distance: 0,
+               max: 100,
+               min: 0,
+               orientation: "horizontal",
+               range: false,
+               step: 1,
+               value: 0,
+               values: null,
+
+               // callbacks
+               change: null,
+               slide: null,
+               start: null,
+               stop: null
+       },
+
+       // number of pages in a slider
+       // (how many times can you page up/down to go through the whole range)
+       numPages: 5,
+
+       _create: function() {
+               this._keySliding = false;
+               this._mouseSliding = false;
+               this._animateOff = true;
+               this._handleIndex = null;
+               this._detectOrientation();
+               this._mouseInit();
+               this._calculateNewMax();
+
+               this.element
+                       .addClass( "ui-slider" +
+                               " ui-slider-" + this.orientation +
+                               " ui-widget" +
+                               " ui-widget-content" +
+                               " ui-corner-all");
+
+               this._refresh();
+               this._setOption( "disabled", this.options.disabled );
+
+               this._animateOff = false;
+       },
+
+       _refresh: function() {
+               this._createRange();
+               this._createHandles();
+               this._setupEvents();
+               this._refreshValue();
+       },
+
+       _createHandles: function() {
+               var i, handleCount,
+                       options = this.options,
+                       existingHandles = this.element.find( ".ui-slider-handle" ).addClass( "ui-state-default ui-corner-all" ),
+                       handle = "<span class='ui-slider-handle ui-state-default ui-corner-all' tabindex='0'></span>",
+                       handles = [];
+
+               handleCount = ( options.values && options.values.length ) || 1;
+
+               if ( existingHandles.length > handleCount ) {
+                       existingHandles.slice( handleCount ).remove();
+                       existingHandles = existingHandles.slice( 0, handleCount );
+               }
+
+               for ( i = existingHandles.length; i < handleCount; i++ ) {
+                       handles.push( handle );
+               }
+
+               this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
+
+               this.handle = this.handles.eq( 0 );
+
+               this.handles.each(function( i ) {
+                       $( this ).data( "ui-slider-handle-index", i );
+               });
+       },
+
+       _createRange: function() {
+               var options = this.options,
+                       classes = "";
+
+               if ( options.range ) {
+                       if ( options.range === true ) {
+                               if ( !options.values ) {
+                                       options.values = [ this._valueMin(), this._valueMin() ];
+                               } else if ( options.values.length && options.values.length !== 2 ) {
+                                       options.values = [ options.values[0], options.values[0] ];
+                               } else if ( $.isArray( options.values ) ) {
+                                       options.values = options.values.slice(0);
+                               }
+                       }
+
+                       if ( !this.range || !this.range.length ) {
+                               this.range = $( "<div></div>" )
+                                       .appendTo( this.element );
+
+                               classes = "ui-slider-range" +
+                               // note: this isn't the most fittingly semantic framework class for this element,
+                               // but worked best visually with a variety of themes
+                               " ui-widget-header ui-corner-all";
+                       } else {
+                               this.range.removeClass( "ui-slider-range-min ui-slider-range-max" )
+                                       // Handle range switching from true to min/max
+                                       .css({
+                                               "left": "",
+                                               "bottom": ""
+                                       });
+                       }
+
+                       this.range.addClass( classes +
+                               ( ( options.range === "min" || options.range === "max" ) ? " ui-slider-range-" + options.range : "" ) );
+               } else {
+                       if ( this.range ) {
+                               this.range.remove();
+                       }
+                       this.range = null;
+               }
+       },
+
+       _setupEvents: function() {
+               this._off( this.handles );
+               this._on( this.handles, this._handleEvents );
+               this._hoverable( this.handles );
+               this._focusable( this.handles );
+       },
+
+       _destroy: function() {
+               this.handles.remove();
+               if ( this.range ) {
+                       this.range.remove();
+               }
+
+               this.element
+                       .removeClass( "ui-slider" +
+                               " ui-slider-horizontal" +
+                               " ui-slider-vertical" +
+                               " ui-widget" +
+                               " ui-widget-content" +
+                               " ui-corner-all" );
+
+               this._mouseDestroy();
+       },
+
+       _mouseCapture: function( event ) {
+               var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
+                       that = this,
+                       o = this.options;
+
+               if ( o.disabled ) {
+                       return false;
+               }
+
+               this.elementSize = {
+                       width: this.element.outerWidth(),
+                       height: this.element.outerHeight()
+               };
+               this.elementOffset = this.element.offset();
+
+               position = { x: event.pageX, y: event.pageY };
+               normValue = this._normValueFromMouse( position );
+               distance = this._valueMax() - this._valueMin() + 1;
+               this.handles.each(function( i ) {
+                       var thisDistance = Math.abs( normValue - that.values(i) );
+                       if (( distance > thisDistance ) ||
+                               ( distance === thisDistance &&
+                                       (i === that._lastChangedValue || that.values(i) === o.min ))) {
+                               distance = thisDistance;
+                               closestHandle = $( this );
+                               index = i;
+                       }
+               });
+
+               allowed = this._start( event, index );
+               if ( allowed === false ) {
+                       return false;
+               }
+               this._mouseSliding = true;
+
+               this._handleIndex = index;
+
+               closestHandle
+                       .addClass( "ui-state-active" )
+                       .focus();
+
+               offset = closestHandle.offset();
+               mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
+               this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
+                       left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
+                       top: event.pageY - offset.top -
+                               ( closestHandle.height() / 2 ) -
+                               ( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
+                               ( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
+                               ( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
+               };
+
+               if ( !this.handles.hasClass( "ui-state-hover" ) ) {
+                       this._slide( event, index, normValue );
+               }
+               this._animateOff = true;
+               return true;
+       },
+
+       _mouseStart: function() {
+               return true;
+       },
+
+       _mouseDrag: function( event ) {
+               var position = { x: event.pageX, y: event.pageY },
+                       normValue = this._normValueFromMouse( position );
+
+               this._slide( event, this._handleIndex, normValue );
+
+               return false;
+       },
+
+       _mouseStop: function( event ) {
+               this.handles.removeClass( "ui-state-active" );
+               this._mouseSliding = false;
+
+               this._stop( event, this._handleIndex );
+               this._change( event, this._handleIndex );
+
+               this._handleIndex = null;
+               this._clickOffset = null;
+               this._animateOff = false;
+
+               return false;
+       },
+
+       _detectOrientation: function() {
+               this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
+       },
+
+       _normValueFromMouse: function( position ) {
+               var pixelTotal,
+                       pixelMouse,
+                       percentMouse,
+                       valueTotal,
+                       valueMouse;
+
+               if ( this.orientation === "horizontal" ) {
+                       pixelTotal = this.elementSize.width;
+                       pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
+               } else {
+                       pixelTotal = this.elementSize.height;
+                       pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
+               }
+
+               percentMouse = ( pixelMouse / pixelTotal );
+               if ( percentMouse > 1 ) {
+                       percentMouse = 1;
+               }
+               if ( percentMouse < 0 ) {
+                       percentMouse = 0;
+               }
+               if ( this.orientation === "vertical" ) {
+                       percentMouse = 1 - percentMouse;
+               }
+
+               valueTotal = this._valueMax() - this._valueMin();
+               valueMouse = this._valueMin() + percentMouse * valueTotal;
+
+               return this._trimAlignValue( valueMouse );
+       },
+
+       _start: function( event, index ) {
+               var uiHash = {
+                       handle: this.handles[ index ],
+                       value: this.value()
+               };
+               if ( this.options.values && this.options.values.length ) {
+                       uiHash.value = this.values( index );
+                       uiHash.values = this.values();
+               }
+               return this._trigger( "start", event, uiHash );
+       },
+
+       _slide: function( event, index, newVal ) {
+               var otherVal,
+                       newValues,
+                       allowed;
+
+               if ( this.options.values && this.options.values.length ) {
+                       otherVal = this.values( index ? 0 : 1 );
+
+                       if ( ( this.options.values.length === 2 && this.options.range === true ) &&
+                                       ( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
+                               ) {
+                               newVal = otherVal;
+                       }
+
+                       if ( newVal !== this.values( index ) ) {
+                               newValues = this.values();
+                               newValues[ index ] = newVal;
+                               // A slide can be canceled by returning false from the slide callback
+                               allowed = this._trigger( "slide", event, {
+                                       handle: this.handles[ index ],
+                                       value: newVal,
+                                       values: newValues
+                               } );
+                               otherVal = this.values( index ? 0 : 1 );
+                               if ( allowed !== false ) {
+                                       this.values( index, newVal );
+                               }
+                       }
+               } else {
+                       if ( newVal !== this.value() ) {
+                               // A slide can be canceled by returning false from the slide callback
+                               allowed = this._trigger( "slide", event, {
+                                       handle: this.handles[ index ],
+                                       value: newVal
+                               } );
+                               if ( allowed !== false ) {
+                                       this.value( newVal );
+                               }
+                       }
+               }
+       },
+
+       _stop: function( event, index ) {
+               var uiHash = {
+                       handle: this.handles[ index ],
+                       value: this.value()
+               };
+               if ( this.options.values && this.options.values.length ) {
+                       uiHash.value = this.values( index );
+                       uiHash.values = this.values();
+               }
+
+               this._trigger( "stop", event, uiHash );
+       },
+
+       _change: function( event, index ) {
+               if ( !this._keySliding && !this._mouseSliding ) {
+                       var uiHash = {
+                               handle: this.handles[ index ],
+                               value: this.value()
+                       };
+                       if ( this.options.values && this.options.values.length ) {
+                               uiHash.value = this.values( index );
+                               uiHash.values = this.values();
+                       }
+
+                       //store the last changed value index for reference when handles overlap
+                       this._lastChangedValue = index;
+
+                       this._trigger( "change", event, uiHash );
+               }
+       },
+
+       value: function( newValue ) {
+               if ( arguments.length ) {
+                       this.options.value = this._trimAlignValue( newValue );
+                       this._refreshValue();
+                       this._change( null, 0 );
+                       return;
+               }
+
+               return this._value();
+       },
+
+       values: function( index, newValue ) {
+               var vals,
+                       newValues,
+                       i;
+
+               if ( arguments.length > 1 ) {
+                       this.options.values[ index ] = this._trimAlignValue( newValue );
+                       this._refreshValue();
+                       this._change( null, index );
+                       return;
+               }
+
+               if ( arguments.length ) {
+                       if ( $.isArray( arguments[ 0 ] ) ) {
+                               vals = this.options.values;
+                               newValues = arguments[ 0 ];
+                               for ( i = 0; i < vals.length; i += 1 ) {
+                                       vals[ i ] = this._trimAlignValue( newValues[ i ] );
+                                       this._change( null, i );
+                               }
+                               this._refreshValue();
+                       } else {
+                               if ( this.options.values && this.options.values.length ) {
+                                       return this._values( index );
+                               } else {
+                                       return this.value();
+                               }
+                       }
+               } else {
+                       return this._values();
+               }
+       },
+
+       _setOption: function( key, value ) {
+               var i,
+                       valsLength = 0;
+
+               if ( key === "range" && this.options.range === true ) {
+                       if ( value === "min" ) {
+                               this.options.value = this._values( 0 );
+                               this.options.values = null;
+                       } else if ( value === "max" ) {
+                               this.options.value = this._values( this.options.values.length - 1 );
+                               this.options.values = null;
+                       }
+               }
+
+               if ( $.isArray( this.options.values ) ) {
+                       valsLength = this.options.values.length;
+               }
+
+               if ( key === "disabled" ) {
+                       this.element.toggleClass( "ui-state-disabled", !!value );
+               }
+
+               this._super( key, value );
+
+               switch ( key ) {
+                       case "orientation":
+                               this._detectOrientation();
+                               this.element
+                                       .removeClass( "ui-slider-horizontal ui-slider-vertical" )
+                                       .addClass( "ui-slider-" + this.orientation );
+                               this._refreshValue();
+
+                               // Reset positioning from previous orientation
+                               this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
+                               break;
+                       case "value":
+                               this._animateOff = true;
+                               this._refreshValue();
+                               this._change( null, 0 );
+                               this._animateOff = false;
+                               break;
+                       case "values":
+                               this._animateOff = true;
+                               this._refreshValue();
+                               for ( i = 0; i < valsLength; i += 1 ) {
+                                       this._change( null, i );
+                               }
+                               this._animateOff = false;
+                               break;
+                       case "step":
+                       case "min":
+                       case "max":
+                               this._animateOff = true;
+                               this._calculateNewMax();
+                               this._refreshValue();
+                               this._animateOff = false;
+                               break;
+                       case "range":
+                               this._animateOff = true;
+                               this._refresh();
+                               this._animateOff = false;
+                               break;
+               }
+       },
+
+       //internal value getter
+       // _value() returns value trimmed by min and max, aligned by step
+       _value: function() {
+               var val = this.options.value;
+               val = this._trimAlignValue( val );
+
+               return val;
+       },
+
+       //internal values getter
+       // _values() returns array of values trimmed by min and max, aligned by step
+       // _values( index ) returns single value trimmed by min and max, aligned by step
+       _values: function( index ) {
+               var val,
+                       vals,
+                       i;
+
+               if ( arguments.length ) {
+                       val = this.options.values[ index ];
+                       val = this._trimAlignValue( val );
+
+                       return val;
+               } else if ( this.options.values && this.options.values.length ) {
+                       // .slice() creates a copy of the array
+                       // this copy gets trimmed by min and max and then returned
+                       vals = this.options.values.slice();
+                       for ( i = 0; i < vals.length; i += 1) {
+                               vals[ i ] = this._trimAlignValue( vals[ i ] );
+                       }
+
+                       return vals;
+               } else {
+                       return [];
+               }
+       },
+
+       // returns the step-aligned value that val is closest to, between (inclusive) min and max
+       _trimAlignValue: function( val ) {
+               if ( val <= this._valueMin() ) {
+                       return this._valueMin();
+               }
+               if ( val >= this._valueMax() ) {
+                       return this._valueMax();
+               }
+               var step = ( this.options.step > 0 ) ? this.options.step : 1,
+                       valModStep = (val - this._valueMin()) % step,
+                       alignValue = val - valModStep;
+
+               if ( Math.abs(valModStep) * 2 >= step ) {
+                       alignValue += ( valModStep > 0 ) ? step : ( -step );
+               }
+
+               // Since JavaScript has problems with large floats, round
+               // the final value to 5 digits after the decimal point (see #4124)
+               return parseFloat( alignValue.toFixed(5) );
+       },
+
+       _calculateNewMax: function() {
+               var remainder = ( this.options.max - this._valueMin() ) % this.options.step;
+               this.max = this.options.max - remainder;
+       },
+
+       _valueMin: function() {
+               return this.options.min;
+       },
+
+       _valueMax: function() {
+               return this.max;
+       },
+
+       _refreshValue: function() {
+               var lastValPercent, valPercent, value, valueMin, valueMax,
+                       oRange = this.options.range,
+                       o = this.options,
+                       that = this,
+                       animate = ( !this._animateOff ) ? o.animate : false,
+                       _set = {};
+
+               if ( this.options.values && this.options.values.length ) {
+                       this.handles.each(function( i ) {
+                               valPercent = ( that.values(i) - that._valueMin() ) / ( that._valueMax() - that._valueMin() ) * 100;
+                               _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+                               $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+                               if ( that.options.range === true ) {
+                                       if ( that.orientation === "horizontal" ) {
+                                               if ( i === 0 ) {
+                                                       that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
+                                               }
+                                               if ( i === 1 ) {
+                                                       that.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+                                               }
+                                       } else {
+                                               if ( i === 0 ) {
+                                                       that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
+                                               }
+                                               if ( i === 1 ) {
+                                                       that.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+                                               }
+                                       }
+                               }
+                               lastValPercent = valPercent;
+                       });
+               } else {
+                       value = this.value();
+                       valueMin = this._valueMin();
+                       valueMax = this._valueMax();
+                       valPercent = ( valueMax !== valueMin ) ?
+                                       ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
+                                       0;
+                       _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+                       this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+
+                       if ( oRange === "min" && this.orientation === "horizontal" ) {
+                               this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
+                       }
+                       if ( oRange === "max" && this.orientation === "horizontal" ) {
+                               this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+                       }
+                       if ( oRange === "min" && this.orientation === "vertical" ) {
+                               this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
+                       }
+                       if ( oRange === "max" && this.orientation === "vertical" ) {
+                               this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+                       }
+               }
+       },
+
+       _handleEvents: {
+               keydown: function( event ) {
+                       var allowed, curVal, newVal, step,
+                               index = $( event.target ).data( "ui-slider-handle-index" );
+
+                       switch ( event.keyCode ) {
+                               case $.ui.keyCode.HOME:
+                               case $.ui.keyCode.END:
+                               case $.ui.keyCode.PAGE_UP:
+                               case $.ui.keyCode.PAGE_DOWN:
+                               case $.ui.keyCode.UP:
+                               case $.ui.keyCode.RIGHT:
+                               case $.ui.keyCode.DOWN:
+                               case $.ui.keyCode.LEFT:
+                                       event.preventDefault();
+                                       if ( !this._keySliding ) {
+                                               this._keySliding = true;
+                                               $( event.target ).addClass( "ui-state-active" );
+                                               allowed = this._start( event, index );
+                                               if ( allowed === false ) {
+                                                       return;
+                                               }
+                                       }
+                                       break;
+                       }
+
+                       step = this.options.step;
+                       if ( this.options.values && this.options.values.length ) {
+                               curVal = newVal = this.values( index );
+                       } else {
+                               curVal = newVal = this.value();
+                       }
+
+                       switch ( event.keyCode ) {
+                               case $.ui.keyCode.HOME:
+                                       newVal = this._valueMin();
+                                       break;
+                               case $.ui.keyCode.END:
+                                       newVal = this._valueMax();
+                                       break;
+                               case $.ui.keyCode.PAGE_UP:
+                                       newVal = this._trimAlignValue(
+                                               curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
+                                       );
+                                       break;
+                               case $.ui.keyCode.PAGE_DOWN:
+                                       newVal = this._trimAlignValue(
+                                               curVal - ( (this._valueMax() - this._valueMin()) / this.numPages ) );
+                                       break;
+                               case $.ui.keyCode.UP:
+                               case $.ui.keyCode.RIGHT:
+                                       if ( curVal === this._valueMax() ) {
+                                               return;
+                                       }
+                                       newVal = this._trimAlignValue( curVal + step );
+                                       break;
+                               case $.ui.keyCode.DOWN:
+                               case $.ui.keyCode.LEFT:
+                                       if ( curVal === this._valueMin() ) {
+                                               return;
+                                       }
+                                       newVal = this._trimAlignValue( curVal - step );
+                                       break;
+                       }
+
+                       this._slide( event, index, newVal );
+               },
+               keyup: function( event ) {
+                       var index = $( event.target ).data( "ui-slider-handle-index" );
+
+                       if ( this._keySliding ) {
+                               this._keySliding = false;
+                               this._stop( event, index );
+                               this._change( event, index );
+                               $( event.target ).removeClass( "ui-state-active" );
+                       }
+               }
+       }
+});
+
+
+/*!
+ * jQuery UI Sortable 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/sortable/
+ */
+
+
+var sortable = $.widget("ui.sortable", $.ui.mouse, {
+       version: "1.11.2",
+       widgetEventPrefix: "sort",
+       ready: false,
+       options: {
+               appendTo: "parent",
+               axis: false,
+               connectWith: false,
+               containment: false,
+               cursor: "auto",
+               cursorAt: false,
+               dropOnEmpty: true,
+               forcePlaceholderSize: false,
+               forceHelperSize: false,
+               grid: false,
+               handle: false,
+               helper: "original",
+               items: "> *",
+               opacity: false,
+               placeholder: false,
+               revert: false,
+               scroll: true,
+               scrollSensitivity: 20,
+               scrollSpeed: 20,
+               scope: "default",
+               tolerance: "intersect",
+               zIndex: 1000,
+
+               // callbacks
+               activate: null,
+               beforeStop: null,
+               change: null,
+               deactivate: null,
+               out: null,
+               over: null,
+               receive: null,
+               remove: null,
+               sort: null,
+               start: null,
+               stop: null,
+               update: null
+       },
+
+       _isOverAxis: function( x, reference, size ) {
+               return ( x >= reference ) && ( x < ( reference + size ) );
+       },
+
+       _isFloating: function( item ) {
+               return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display"));
+       },
+
+       _create: function() {
+
+               var o = this.options;
+               this.containerCache = {};
+               this.element.addClass("ui-sortable");
+
+               //Get the items
+               this.refresh();
+
+               //Let's determine if the items are being displayed horizontally
+               this.floating = this.items.length ? o.axis === "x" || this._isFloating(this.items[0].item) : false;
+
+               //Let's determine the parent's offset
+               this.offset = this.element.offset();
+
+               //Initialize mouse events for interaction
+               this._mouseInit();
+
+               this._setHandleClassName();
+
+               //We're ready to go
+               this.ready = true;
+
+       },
+
+       _setOption: function( key, value ) {
+               this._super( key, value );
+
+               if ( key === "handle" ) {
+                       this._setHandleClassName();
+               }
+       },
+
+       _setHandleClassName: function() {
+               this.element.find( ".ui-sortable-handle" ).removeClass( "ui-sortable-handle" );
+               $.each( this.items, function() {
+                       ( this.instance.options.handle ?
+                               this.item.find( this.instance.options.handle ) : this.item )
+                               .addClass( "ui-sortable-handle" );
+               });
+       },
+
+       _destroy: function() {
+               this.element
+                       .removeClass( "ui-sortable ui-sortable-disabled" )
+                       .find( ".ui-sortable-handle" )
+                               .removeClass( "ui-sortable-handle" );
+               this._mouseDestroy();
+
+               for ( var i = this.items.length - 1; i >= 0; i-- ) {
+                       this.items[i].item.removeData(this.widgetName + "-item");
+               }
+
+               return this;
+       },
+
+       _mouseCapture: function(event, overrideHandle) {
+               var currentItem = null,
+                       validHandle = false,
+                       that = this;
+
+               if (this.reverting) {
+                       return false;
+               }
+
+               if(this.options.disabled || this.options.type === "static") {
+                       return false;
+               }
+
+               //We have to refresh the items data once first
+               this._refreshItems(event);
+
+               //Find out if the clicked node (or one of its parents) is a actual item in this.items
+               $(event.target).parents().each(function() {
+                       if($.data(this, that.widgetName + "-item") === that) {
+                               currentItem = $(this);
+                               return false;
+                       }
+               });
+               if($.data(event.target, that.widgetName + "-item") === that) {
+                       currentItem = $(event.target);
+               }
+
+               if(!currentItem) {
+                       return false;
+               }
+               if(this.options.handle && !overrideHandle) {
+                       $(this.options.handle, currentItem).find("*").addBack().each(function() {
+                               if(this === event.target) {
+                                       validHandle = true;
+                               }
+                       });
+                       if(!validHandle) {
+                               return false;
+                       }
+               }
+
+               this.currentItem = currentItem;
+               this._removeCurrentsFromItems();
+               return true;
+
+       },
+
+       _mouseStart: function(event, overrideHandle, noActivation) {
+
+               var i, body,
+                       o = this.options;
+
+               this.currentContainer = this;
+
+               //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture
+               this.refreshPositions();
+
+               //Create and append the visible helper
+               this.helper = this._createHelper(event);
+
+               //Cache the helper size
+               this._cacheHelperProportions();
+
+               /*
+                * - Position generation -
+                * This block generates everything position related - it's the core of draggables.
+                */
+
+               //Cache the margins of the original element
+               this._cacheMargins();
+
+               //Get the next scrolling parent
+               this.scrollParent = this.helper.scrollParent();
+
+               //The element's absolute position on the page minus margins
+               this.offset = this.currentItem.offset();
+               this.offset = {
+                       top: this.offset.top - this.margins.top,
+                       left: this.offset.left - this.margins.left
+               };
+
+               $.extend(this.offset, {
+                       click: { //Where the click happened, relative to the element
+                               left: event.pageX - this.offset.left,
+                               top: event.pageY - this.offset.top
+                       },
+                       parent: this._getParentOffset(),
+                       relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper
+               });
+
+               // Only after we got the offset, we can change the helper's position to absolute
+               // TODO: Still need to figure out a way to make relative sorting possible
+               this.helper.css("position", "absolute");
+               this.cssPosition = this.helper.css("position");
+
+               //Generate the original position
+               this.originalPosition = this._generatePosition(event);
+               this.originalPageX = event.pageX;
+               this.originalPageY = event.pageY;
+
+               //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
+               (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt));
+
+               //Cache the former DOM position
+               this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] };
+
+               //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way
+               if(this.helper[0] !== this.currentItem[0]) {
+                       this.currentItem.hide();
+               }
+
+               //Create the placeholder
+               this._createPlaceholder();
+
+               //Set a containment if given in the options
+               if(o.containment) {
+                       this._setContainment();
+               }
+
+               if( o.cursor && o.cursor !== "auto" ) { // cursor option
+                       body = this.document.find( "body" );
+
+                       // support: IE
+                       this.storedCursor = body.css( "cursor" );
+                       body.css( "cursor", o.cursor );
+
+                       this.storedStylesheet = $( "<style>*{ cursor: "+o.cursor+" !important; }</style>" ).appendTo( body );
+               }
+
+               if(o.opacity) { // opacity option
+                       if (this.helper.css("opacity")) {
+                               this._storedOpacity = this.helper.css("opacity");
+                       }
+                       this.helper.css("opacity", o.opacity);
+               }
+
+               if(o.zIndex) { // zIndex option
+                       if (this.helper.css("zIndex")) {
+                               this._storedZIndex = this.helper.css("zIndex");
+                       }
+                       this.helper.css("zIndex", o.zIndex);
+               }
+
+               //Prepare scrolling
+               if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+                       this.overflowOffset = this.scrollParent.offset();
+               }
+
+               //Call callbacks
+               this._trigger("start", event, this._uiHash());
+
+               //Recache the helper size
+               if(!this._preserveHelperProportions) {
+                       this._cacheHelperProportions();
+               }
+
+
+               //Post "activate" events to possible containers
+               if( !noActivation ) {
+                       for ( i = this.containers.length - 1; i >= 0; i-- ) {
+                               this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
+                       }
+               }
+
+               //Prepare possible droppables
+               if($.ui.ddmanager) {
+                       $.ui.ddmanager.current = this;
+               }
+
+               if ($.ui.ddmanager && !o.dropBehaviour) {
+                       $.ui.ddmanager.prepareOffsets(this, event);
+               }
+
+               this.dragging = true;
+
+               this.helper.addClass("ui-sortable-helper");
+               this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position
+               return true;
+
+       },
+
+       _mouseDrag: function(event) {
+               var i, item, itemElement, intersection,
+                       o = this.options,
+                       scrolled = false;
+
+               //Compute the helpers position
+               this.position = this._generatePosition(event);
+               this.positionAbs = this._convertPositionTo("absolute");
+
+               if (!this.lastPositionAbs) {
+                       this.lastPositionAbs = this.positionAbs;
+               }
+
+               //Do scrolling
+               if(this.options.scroll) {
+                       if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") {
+
+                               if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) {
+                                       this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed;
+                               } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) {
+                                       this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed;
+                               }
+
+                               if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) {
+                                       this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed;
+                               } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) {
+                                       this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed;
+                               }
+
+                       } else {
+
+                               if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) {
+                                       scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed);
+                               } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) {
+                                       scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed);
+                               }
+
+                               if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) {
+                                       scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed);
+                               } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) {
+                                       scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed);
+                               }
+
+                       }
+
+                       if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) {
+                               $.ui.ddmanager.prepareOffsets(this, event);
+                       }
+               }
+
+               //Regenerate the absolute position used for position checks
+               this.positionAbs = this._convertPositionTo("absolute");
+
+               //Set the helper position
+               if(!this.options.axis || this.options.axis !== "y") {
+                       this.helper[0].style.left = this.position.left+"px";
+               }
+               if(!this.options.axis || this.options.axis !== "x") {
+                       this.helper[0].style.top = this.position.top+"px";
+               }
+
+               //Rearrange
+               for (i = this.items.length - 1; i >= 0; i--) {
+
+                       //Cache variables and intersection, continue if no intersection
+                       item = this.items[i];
+                       itemElement = item.item[0];
+                       intersection = this._intersectsWithPointer(item);
+                       if (!intersection) {
+                               continue;
+                       }
+
+                       // Only put the placeholder inside the current Container, skip all
+                       // items from other containers. This works because when moving
+                       // an item from one container to another the
+                       // currentContainer is switched before the placeholder is moved.
+                       //
+                       // Without this, moving items in "sub-sortables" can cause
+                       // the placeholder to jitter between the outer and inner container.
+                       if (item.instance !== this.currentContainer) {
+                               continue;
+                       }
+
+                       // cannot intersect with itself
+                       // no useless actions that have been done before
+                       // no action if the item moved is the parent of the item checked
+                       if (itemElement !== this.currentItem[0] &&
+                               this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement &&
+                               !$.contains(this.placeholder[0], itemElement) &&
+                               (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true)
+                       ) {
+
+                               this.direction = intersection === 1 ? "down" : "up";
+
+                               if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) {
+                                       this._rearrange(event, item);
+                               } else {
+                                       break;
+                               }
+
+                               this._trigger("change", event, this._uiHash());
+                               break;
+                       }
+               }
+
+               //Post events to containers
+               this._contactContainers(event);
+
+               //Interconnect with droppables
+               if($.ui.ddmanager) {
+                       $.ui.ddmanager.drag(this, event);
+               }
+
+               //Call callbacks
+               this._trigger("sort", event, this._uiHash());
+
+               this.lastPositionAbs = this.positionAbs;
+               return false;
+
+       },
+
+       _mouseStop: function(event, noPropagation) {
+
+               if(!event) {
+                       return;
+               }
+
+               //If we are using droppables, inform the manager about the drop
+               if ($.ui.ddmanager && !this.options.dropBehaviour) {
+                       $.ui.ddmanager.drop(this, event);
+               }
+
+               if(this.options.revert) {
+                       var that = this,
+                               cur = this.placeholder.offset(),
+                               axis = this.options.axis,
+                               animation = {};
+
+                       if ( !axis || axis === "x" ) {
+                               animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft);
+                       }
+                       if ( !axis || axis === "y" ) {
+                               animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop);
+                       }
+                       this.reverting = true;
+                       $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() {
+                               that._clear(event);
+                       });
+               } else {
+                       this._clear(event, noPropagation);
+               }
+
+               return false;
+
+       },
+
+       cancel: function() {
+
+               if(this.dragging) {
+
+                       this._mouseUp({ target: null });
+
+                       if(this.options.helper === "original") {
+                               this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+                       } else {
+                               this.currentItem.show();
+                       }
+
+                       //Post deactivating events to containers
+                       for (var i = this.containers.length - 1; i >= 0; i--){
+                               this.containers[i]._trigger("deactivate", null, this._uiHash(this));
+                               if(this.containers[i].containerCache.over) {
+                                       this.containers[i]._trigger("out", null, this._uiHash(this));
+                                       this.containers[i].containerCache.over = 0;
+                               }
+                       }
+
+               }
+
+               if (this.placeholder) {
+                       //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+                       if(this.placeholder[0].parentNode) {
+                               this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+                       }
+                       if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) {
+                               this.helper.remove();
+                       }
+
+                       $.extend(this, {
+                               helper: null,
+                               dragging: false,
+                               reverting: false,
+                               _noFinalSort: null
+                       });
+
+                       if(this.domPosition.prev) {
+                               $(this.domPosition.prev).after(this.currentItem);
+                       } else {
+                               $(this.domPosition.parent).prepend(this.currentItem);
+                       }
+               }
+
+               return this;
+
+       },
+
+       serialize: function(o) {
+
+               var items = this._getItemsAsjQuery(o && o.connected),
+                       str = [];
+               o = o || {};
+
+               $(items).each(function() {
+                       var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/));
+                       if (res) {
+                               str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2]));
+                       }
+               });
+
+               if(!str.length && o.key) {
+                       str.push(o.key + "=");
+               }
+
+               return str.join("&");
+
+       },
+
+       toArray: function(o) {
+
+               var items = this._getItemsAsjQuery(o && o.connected),
+                       ret = [];
+
+               o = o || {};
+
+               items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); });
+               return ret;
+
+       },
+
+       /* Be careful with the following core functions */
+       _intersectsWith: function(item) {
+
+               var x1 = this.positionAbs.left,
+                       x2 = x1 + this.helperProportions.width,
+                       y1 = this.positionAbs.top,
+                       y2 = y1 + this.helperProportions.height,
+                       l = item.left,
+                       r = l + item.width,
+                       t = item.top,
+                       b = t + item.height,
+                       dyClick = this.offset.click.top,
+                       dxClick = this.offset.click.left,
+                       isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ),
+                       isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ),
+                       isOverElement = isOverElementHeight && isOverElementWidth;
+
+               if ( this.options.tolerance === "pointer" ||
+                       this.options.forcePointerForContainers ||
+                       (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"])
+               ) {
+                       return isOverElement;
+               } else {
+
+                       return (l < x1 + (this.helperProportions.width / 2) && // Right Half
+                               x2 - (this.helperProportions.width / 2) < r && // Left Half
+                               t < y1 + (this.helperProportions.height / 2) && // Bottom Half
+                               y2 - (this.helperProportions.height / 2) < b ); // Top Half
+
+               }
+       },
+
+       _intersectsWithPointer: function(item) {
+
+               var isOverElementHeight = (this.options.axis === "x") || this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height),
+                       isOverElementWidth = (this.options.axis === "y") || this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width),
+                       isOverElement = isOverElementHeight && isOverElementWidth,
+                       verticalDirection = this._getDragVerticalDirection(),
+                       horizontalDirection = this._getDragHorizontalDirection();
+
+               if (!isOverElement) {
+                       return false;
+               }
+
+               return this.floating ?
+                       ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 )
+                       : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) );
+
+       },
+
+       _intersectsWithSides: function(item) {
+
+               var isOverBottomHalf = this._isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height),
+                       isOverRightHalf = this._isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width),
+                       verticalDirection = this._getDragVerticalDirection(),
+                       horizontalDirection = this._getDragHorizontalDirection();
+
+               if (this.floating && horizontalDirection) {
+                       return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf));
+               } else {
+                       return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf));
+               }
+
+       },
+
+       _getDragVerticalDirection: function() {
+               var delta = this.positionAbs.top - this.lastPositionAbs.top;
+               return delta !== 0 && (delta > 0 ? "down" : "up");
+       },
+
+       _getDragHorizontalDirection: function() {
+               var delta = this.positionAbs.left - this.lastPositionAbs.left;
+               return delta !== 0 && (delta > 0 ? "right" : "left");
+       },
+
+       refresh: function(event) {
+               this._refreshItems(event);
+               this._setHandleClassName();
+               this.refreshPositions();
+               return this;
+       },
+
+       _connectWith: function() {
+               var options = this.options;
+               return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith;
+       },
+
+       _getItemsAsjQuery: function(connected) {
+
+               var i, j, cur, inst,
+                       items = [],
+                       queries = [],
+                       connectWith = this._connectWith();
+
+               if(connectWith && connected) {
+                       for (i = connectWith.length - 1; i >= 0; i--){
+                               cur = $(connectWith[i]);
+                               for ( j = cur.length - 1; j >= 0; j--){
+                                       inst = $.data(cur[j], this.widgetFullName);
+                                       if(inst && inst !== this && !inst.options.disabled) {
+                                               queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]);
+                                       }
+                               }
+                       }
+               }
+
+               queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]);
+
+               function addItems() {
+                       items.push( this );
+               }
+               for (i = queries.length - 1; i >= 0; i--){
+                       queries[i][0].each( addItems );
+               }
+
+               return $(items);
+
+       },
+
+       _removeCurrentsFromItems: function() {
+
+               var list = this.currentItem.find(":data(" + this.widgetName + "-item)");
+
+               this.items = $.grep(this.items, function (item) {
+                       for (var j=0; j < list.length; j++) {
+                               if(list[j] === item.item[0]) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               });
+
+       },
+
+       _refreshItems: function(event) {
+
+               this.items = [];
+               this.containers = [this];
+
+               var i, j, cur, inst, targetData, _queries, item, queriesLength,
+                       items = this.items,
+                       queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]],
+                       connectWith = this._connectWith();
+
+               if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down
+                       for (i = connectWith.length - 1; i >= 0; i--){
+                               cur = $(connectWith[i]);
+                               for (j = cur.length - 1; j >= 0; j--){
+                                       inst = $.data(cur[j], this.widgetFullName);
+                                       if(inst && inst !== this && !inst.options.disabled) {
+                                               queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]);
+                                               this.containers.push(inst);
+                                       }
+                               }
+                       }
+               }
+
+               for (i = queries.length - 1; i >= 0; i--) {
+                       targetData = queries[i][1];
+                       _queries = queries[i][0];
+
+                       for (j=0, queriesLength = _queries.length; j < queriesLength; j++) {
+                               item = $(_queries[j]);
+
+                               item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager)
+
+                               items.push({
+                                       item: item,
+                                       instance: targetData,
+                                       width: 0, height: 0,
+                                       left: 0, top: 0
+                               });
+                       }
+               }
+
+       },
+
+       refreshPositions: function(fast) {
+
+               //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change
+               if(this.offsetParent && this.helper) {
+                       this.offset.parent = this._getParentOffset();
+               }
+
+               var i, item, t, p;
+
+               for (i = this.items.length - 1; i >= 0; i--){
+                       item = this.items[i];
+
+                       //We ignore calculating positions of all connected containers when we're not over them
+                       if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) {
+                               continue;
+                       }
+
+                       t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item;
+
+                       if (!fast) {
+                               item.width = t.outerWidth();
+                               item.height = t.outerHeight();
+                       }
+
+                       p = t.offset();
+                       item.left = p.left;
+                       item.top = p.top;
+               }
+
+               if(this.options.custom && this.options.custom.refreshContainers) {
+                       this.options.custom.refreshContainers.call(this);
+               } else {
+                       for (i = this.containers.length - 1; i >= 0; i--){
+                               p = this.containers[i].element.offset();
+                               this.containers[i].containerCache.left = p.left;
+                               this.containers[i].containerCache.top = p.top;
+                               this.containers[i].containerCache.width = this.containers[i].element.outerWidth();
+                               this.containers[i].containerCache.height = this.containers[i].element.outerHeight();
+                       }
+               }
+
+               return this;
+       },
+
+       _createPlaceholder: function(that) {
+               that = that || this;
+               var className,
+                       o = that.options;
+
+               if(!o.placeholder || o.placeholder.constructor === String) {
+                       className = o.placeholder;
+                       o.placeholder = {
+                               element: function() {
+
+                                       var nodeName = that.currentItem[0].nodeName.toLowerCase(),
+                                               element = $( "<" + nodeName + ">", that.document[0] )
+                                                       .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder")
+                                                       .removeClass("ui-sortable-helper");
+
+                                       if ( nodeName === "tr" ) {
+                                               that.currentItem.children().each(function() {
+                                                       $( "<td>&#160;</td>", that.document[0] )
+                                                               .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
+                                                               .appendTo( element );
+                                               });
+                                       } else if ( nodeName === "img" ) {
+                                               element.attr( "src", that.currentItem.attr( "src" ) );
+                                       }
+
+                                       if ( !className ) {
+                                               element.css( "visibility", "hidden" );
+                                       }
+
+                                       return element;
+                               },
+                               update: function(container, p) {
+
+                                       // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that
+                                       // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified
+                                       if(className && !o.forcePlaceholderSize) {
+                                               return;
+                                       }
+
+                                       //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item
+                                       if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); }
+                                       if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); }
+                               }
+                       };
+               }
+
+               //Create the placeholder
+               that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem));
+
+               //Append it after the actual current item
+               that.currentItem.after(that.placeholder);
+
+               //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
+               o.placeholder.update(that, that.placeholder);
+
+       },
+
+       _contactContainers: function(event) {
+               var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom, floating, axis,
+                       innermostContainer = null,
+                       innermostIndex = null;
+
+               // get innermost container that intersects with item
+               for (i = this.containers.length - 1; i >= 0; i--) {
+
+                       // never consider a container that's located within the item itself
+                       if($.contains(this.currentItem[0], this.containers[i].element[0])) {
+                               continue;
+                       }
+
+                       if(this._intersectsWith(this.containers[i].containerCache)) {
+
+                               // if we've already found a container and it's more "inner" than this, then continue
+                               if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) {
+                                       continue;
+                               }
+
+                               innermostContainer = this.containers[i];
+                               innermostIndex = i;
+
+                       } else {
+                               // container doesn't intersect. trigger "out" event if necessary
+                               if(this.containers[i].containerCache.over) {
+                                       this.containers[i]._trigger("out", event, this._uiHash(this));
+                                       this.containers[i].containerCache.over = 0;
+                               }
+                       }
+
+               }
+
+               // if no intersecting containers found, return
+               if(!innermostContainer) {
+                       return;
+               }
+
+               // move the item into the container if it's not there already
+               if(this.containers.length === 1) {
+                       if (!this.containers[innermostIndex].containerCache.over) {
+                               this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+                               this.containers[innermostIndex].containerCache.over = 1;
+                       }
+               } else {
+
+                       //When entering a new container, we will find the item with the least distance and append our item near it
+                       dist = 10000;
+                       itemWithLeastDistance = null;
+                       floating = innermostContainer.floating || this._isFloating(this.currentItem);
+                       posProperty = floating ? "left" : "top";
+                       sizeProperty = floating ? "width" : "height";
+                       axis = floating ? "clientX" : "clientY";
+
+                       for (j = this.items.length - 1; j >= 0; j--) {
+                               if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) {
+                                       continue;
+                               }
+                               if(this.items[j].item[0] === this.currentItem[0]) {
+                                       continue;
+                               }
+
+                               cur = this.items[j].item.offset()[posProperty];
+                               nearBottom = false;
+                               if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
+                                       nearBottom = true;
+                               }
+
+                               if ( Math.abs( event[ axis ] - cur ) < dist ) {
+                                       dist = Math.abs( event[ axis ] - cur );
+                                       itemWithLeastDistance = this.items[ j ];
+                                       this.direction = nearBottom ? "up": "down";
+                               }
+                       }
+
+                       //Check if dropOnEmpty is enabled
+                       if(!itemWithLeastDistance && !this.options.dropOnEmpty) {
+                               return;
+                       }
+
+                       if(this.currentContainer === this.containers[innermostIndex]) {
+                               if ( !this.currentContainer.containerCache.over ) {
+                                       this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
+                                       this.currentContainer.containerCache.over = 1;
+                               }
+                               return;
+                       }
+
+                       itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true);
+                       this._trigger("change", event, this._uiHash());
+                       this.containers[innermostIndex]._trigger("change", event, this._uiHash(this));
+                       this.currentContainer = this.containers[innermostIndex];
+
+                       //Update the placeholder
+                       this.options.placeholder.update(this.currentContainer, this.placeholder);
+
+                       this.containers[innermostIndex]._trigger("over", event, this._uiHash(this));
+                       this.containers[innermostIndex].containerCache.over = 1;
+               }
+
+
+       },
+
+       _createHelper: function(event) {
+
+               var o = this.options,
+                       helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem);
+
+               //Add the helper to the DOM if that didn't happen already
+               if(!helper.parents("body").length) {
+                       $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]);
+               }
+
+               if(helper[0] === this.currentItem[0]) {
+                       this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") };
+               }
+
+               if(!helper[0].style.width || o.forceHelperSize) {
+                       helper.width(this.currentItem.width());
+               }
+               if(!helper[0].style.height || o.forceHelperSize) {
+                       helper.height(this.currentItem.height());
+               }
+
+               return helper;
+
+       },
+
+       _adjustOffsetFromHelper: function(obj) {
+               if (typeof obj === "string") {
+                       obj = obj.split(" ");
+               }
+               if ($.isArray(obj)) {
+                       obj = {left: +obj[0], top: +obj[1] || 0};
+               }
+               if ("left" in obj) {
+                       this.offset.click.left = obj.left + this.margins.left;
+               }
+               if ("right" in obj) {
+                       this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
+               }
+               if ("top" in obj) {
+                       this.offset.click.top = obj.top + this.margins.top;
+               }
+               if ("bottom" in obj) {
+                       this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
+               }
+       },
+
+       _getParentOffset: function() {
+
+
+               //Get the offsetParent and cache its position
+               this.offsetParent = this.helper.offsetParent();
+               var po = this.offsetParent.offset();
+
+               // This is a special case where we need to modify a offset calculated on start, since the following happened:
+               // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent
+               // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that
+               //    the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag
+               if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) {
+                       po.left += this.scrollParent.scrollLeft();
+                       po.top += this.scrollParent.scrollTop();
+               }
+
+               // This needs to be actually done for all browsers, since pageX/pageY includes this information
+               // with an ugly IE fix
+               if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) {
+                       po = { top: 0, left: 0 };
+               }
+
+               return {
+                       top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0),
+                       left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0)
+               };
+
+       },
+
+       _getRelativeOffset: function() {
+
+               if(this.cssPosition === "relative") {
+                       var p = this.currentItem.position();
+                       return {
+                               top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(),
+                               left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft()
+                       };
+               } else {
+                       return { top: 0, left: 0 };
+               }
+
+       },
+
+       _cacheMargins: function() {
+               this.margins = {
+                       left: (parseInt(this.currentItem.css("marginLeft"),10) || 0),
+                       top: (parseInt(this.currentItem.css("marginTop"),10) || 0)
+               };
+       },
+
+       _cacheHelperProportions: function() {
+               this.helperProportions = {
+                       width: this.helper.outerWidth(),
+                       height: this.helper.outerHeight()
+               };
+       },
+
+       _setContainment: function() {
+
+               var ce, co, over,
+                       o = this.options;
+               if(o.containment === "parent") {
+                       o.containment = this.helper[0].parentNode;
+               }
+               if(o.containment === "document" || o.containment === "window") {
+                       this.containment = [
+                               0 - this.offset.relative.left - this.offset.parent.left,
+                               0 - this.offset.relative.top - this.offset.parent.top,
+                               $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left,
+                               ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top
+                       ];
+               }
+
+               if(!(/^(document|window|parent)$/).test(o.containment)) {
+                       ce = $(o.containment)[0];
+                       co = $(o.containment).offset();
+                       over = ($(ce).css("overflow") !== "hidden");
+
+                       this.containment = [
+                               co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left,
+                               co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top,
+                               co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left,
+                               co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top
+                       ];
+               }
+
+       },
+
+       _convertPositionTo: function(d, pos) {
+
+               if(!pos) {
+                       pos = this.position;
+               }
+               var mod = d === "absolute" ? 1 : -1,
+                       scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent,
+                       scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+               return {
+                       top: (
+                               pos.top +                                                                                                                               // The absolute mouse position
+                               this.offset.relative.top * mod +                                                                                // Only for relative positioned nodes: Relative offset from element to offset parent
+                               this.offset.parent.top * mod -                                                                                  // The offsetParent's offset without borders (offset + border)
+                               ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod)
+                       ),
+                       left: (
+                               pos.left +                                                                                                                              // The absolute mouse position
+                               this.offset.relative.left * mod +                                                                               // Only for relative positioned nodes: Relative offset from element to offset parent
+                               this.offset.parent.left * mod   -                                                                               // The offsetParent's offset without borders (offset + border)
+                               ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod)
+                       )
+               };
+
+       },
+
+       _generatePosition: function(event) {
+
+               var top, left,
+                       o = this.options,
+                       pageX = event.pageX,
+                       pageY = event.pageY,
+                       scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName);
+
+               // This is another very weird special case that only happens for relative elements:
+               // 1. If the css position is relative
+               // 2. and the scroll parent is the document or similar to the offset parent
+               // we have to refresh the relative offset during the scroll so there are no jumps
+               if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) {
+                       this.offset.relative = this._getRelativeOffset();
+               }
+
+               /*
+                * - Position constraining -
+                * Constrain the position to a mix of grid, containment.
+                */
+
+               if(this.originalPosition) { //If we are not dragging yet, we won't check for options
+
+                       if(this.containment) {
+                               if(event.pageX - this.offset.click.left < this.containment[0]) {
+                                       pageX = this.containment[0] + this.offset.click.left;
+                               }
+                               if(event.pageY - this.offset.click.top < this.containment[1]) {
+                                       pageY = this.containment[1] + this.offset.click.top;
+                               }
+                               if(event.pageX - this.offset.click.left > this.containment[2]) {
+                                       pageX = this.containment[2] + this.offset.click.left;
+                               }
+                               if(event.pageY - this.offset.click.top > this.containment[3]) {
+                                       pageY = this.containment[3] + this.offset.click.top;
+                               }
+                       }
+
+                       if(o.grid) {
+                               top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1];
+                               pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top;
+
+                               left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0];
+                               pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left;
+                       }
+
+               }
+
+               return {
+                       top: (
+                               pageY -                                                                                                                         // The absolute mouse position
+                               this.offset.click.top -                                                                                                 // Click offset (relative to the element)
+                               this.offset.relative.top        -                                                                                       // Only for relative positioned nodes: Relative offset from element to offset parent
+                               this.offset.parent.top +                                                                                                // The offsetParent's offset without borders (offset + border)
+                               ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ))
+                       ),
+                       left: (
+                               pageX -                                                                                                                         // The absolute mouse position
+                               this.offset.click.left -                                                                                                // Click offset (relative to the element)
+                               this.offset.relative.left       -                                                                                       // Only for relative positioned nodes: Relative offset from element to offset parent
+                               this.offset.parent.left +                                                                                               // The offsetParent's offset without borders (offset + border)
+                               ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ))
+                       )
+               };
+
+       },
+
+       _rearrange: function(event, i, a, hardRefresh) {
+
+               a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling));
+
+               //Various things done here to improve the performance:
+               // 1. we create a setTimeout, that calls refreshPositions
+               // 2. on the instance, we have a counter variable, that get's higher after every append
+               // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same
+               // 4. this lets only the last addition to the timeout stack through
+               this.counter = this.counter ? ++this.counter : 1;
+               var counter = this.counter;
+
+               this._delay(function() {
+                       if(counter === this.counter) {
+                               this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove
+                       }
+               });
+
+       },
+
+       _clear: function(event, noPropagation) {
+
+               this.reverting = false;
+               // We delay all events that have to be triggered to after the point where the placeholder has been removed and
+               // everything else normalized again
+               var i,
+                       delayedTriggers = [];
+
+               // We first have to update the dom position of the actual currentItem
+               // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088)
+               if(!this._noFinalSort && this.currentItem.parent().length) {
+                       this.placeholder.before(this.currentItem);
+               }
+               this._noFinalSort = null;
+
+               if(this.helper[0] === this.currentItem[0]) {
+                       for(i in this._storedCSS) {
+                               if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") {
+                                       this._storedCSS[i] = "";
+                               }
+                       }
+                       this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper");
+               } else {
+                       this.currentItem.show();
+               }
+
+               if(this.fromOutside && !noPropagation) {
+                       delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); });
+               }
+               if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) {
+                       delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed
+               }
+
+               // Check if the items Container has Changed and trigger appropriate
+               // events.
+               if (this !== this.currentContainer) {
+                       if(!noPropagation) {
+                               delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); });
+                               delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); };  }).call(this, this.currentContainer));
+                               delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this));  }; }).call(this, this.currentContainer));
+                       }
+               }
+
+
+               //Post events to containers
+               function delayEvent( type, instance, container ) {
+                       return function( event ) {
+                               container._trigger( type, event, instance._uiHash( instance ) );
+                       };
+               }
+               for (i = this.containers.length - 1; i >= 0; i--){
+                       if (!noPropagation) {
+                               delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
+                       }
+                       if(this.containers[i].containerCache.over) {
+                               delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
+                               this.containers[i].containerCache.over = 0;
+                       }
+               }
+
+               //Do what was originally in plugins
+               if ( this.storedCursor ) {
+                       this.document.find( "body" ).css( "cursor", this.storedCursor );
+                       this.storedStylesheet.remove();
+               }
+               if(this._storedOpacity) {
+                       this.helper.css("opacity", this._storedOpacity);
+               }
+               if(this._storedZIndex) {
+                       this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex);
+               }
+
+               this.dragging = false;
+
+               if(!noPropagation) {
+                       this._trigger("beforeStop", event, this._uiHash());
+               }
+
+               //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node!
+               this.placeholder[0].parentNode.removeChild(this.placeholder[0]);
+
+               if ( !this.cancelHelperRemoval ) {
+                       if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
+                               this.helper.remove();
+                       }
+                       this.helper = null;
+               }
+
+               if(!noPropagation) {
+                       for (i=0; i < delayedTriggers.length; i++) {
+                               delayedTriggers[i].call(this, event);
+                       } //Trigger all delayed events
+                       this._trigger("stop", event, this._uiHash());
+               }
+
+               this.fromOutside = false;
+               return !this.cancelHelperRemoval;
+
+       },
+
+       _trigger: function() {
+               if ($.Widget.prototype._trigger.apply(this, arguments) === false) {
+                       this.cancel();
+               }
+       },
+
+       _uiHash: function(_inst) {
+               var inst = _inst || this;
+               return {
+                       helper: inst.helper,
+                       placeholder: inst.placeholder || $([]),
+                       position: inst.position,
+                       originalPosition: inst.originalPosition,
+                       offset: inst.positionAbs,
+                       item: inst.currentItem,
+                       sender: _inst ? _inst.element : null
+               };
+       }
+
+});
+
+
+/*!
+ * jQuery UI Spinner 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/spinner/
+ */
+
+
+function spinner_modifier( fn ) {
+       return function() {
+               var previous = this.element.val();
+               fn.apply( this, arguments );
+               this._refresh();
+               if ( previous !== this.element.val() ) {
+                       this._trigger( "change" );
+               }
+       };
+}
+
+var spinner = $.widget( "ui.spinner", {
+       version: "1.11.2",
+       defaultElement: "<input>",
+       widgetEventPrefix: "spin",
+       options: {
+               culture: null,
+               icons: {
+                       down: "ui-icon-triangle-1-s",
+                       up: "ui-icon-triangle-1-n"
+               },
+               incremental: true,
+               max: null,
+               min: null,
+               numberFormat: null,
+               page: 10,
+               step: 1,
+
+               change: null,
+               spin: null,
+               start: null,
+               stop: null
+       },
+
+       _create: function() {
+               // handle string values that need to be parsed
+               this._setOption( "max", this.options.max );
+               this._setOption( "min", this.options.min );
+               this._setOption( "step", this.options.step );
+
+               // Only format if there is a value, prevents the field from being marked
+               // as invalid in Firefox, see #9573.
+               if ( this.value() !== "" ) {
+                       // Format the value, but don't constrain.
+                       this._value( this.element.val(), true );
+               }
+
+               this._draw();
+               this._on( this._events );
+               this._refresh();
+
+               // turning off autocomplete prevents the browser from remembering the
+               // value when navigating through history, so we re-enable autocomplete
+               // if the page is unloaded before the widget is destroyed. #7790
+               this._on( this.window, {
+                       beforeunload: function() {
+                               this.element.removeAttr( "autocomplete" );
+                       }
+               });
+       },
+
+       _getCreateOptions: function() {
+               var options = {},
+                       element = this.element;
+
+               $.each( [ "min", "max", "step" ], function( i, option ) {
+                       var value = element.attr( option );
+                       if ( value !== undefined && value.length ) {
+                               options[ option ] = value;
+                       }
+               });
+
+               return options;
+       },
+
+       _events: {
+               keydown: function( event ) {
+                       if ( this._start( event ) && this._keydown( event ) ) {
+                               event.preventDefault();
+                       }
+               },
+               keyup: "_stop",
+               focus: function() {
+                       this.previous = this.element.val();
+               },
+               blur: function( event ) {
+                       if ( this.cancelBlur ) {
+                               delete this.cancelBlur;
+                               return;
+                       }
+
+                       this._stop();
+                       this._refresh();
+                       if ( this.previous !== this.element.val() ) {
+                               this._trigger( "change", event );
+                       }
+               },
+               mousewheel: function( event, delta ) {
+                       if ( !delta ) {
+                               return;
+                       }
+                       if ( !this.spinning && !this._start( event ) ) {
+                               return false;
+                       }
+
+                       this._spin( (delta > 0 ? 1 : -1) * this.options.step, event );
+                       clearTimeout( this.mousewheelTimer );
+                       this.mousewheelTimer = this._delay(function() {
+                               if ( this.spinning ) {
+                                       this._stop( event );
+                               }
+                       }, 100 );
+                       event.preventDefault();
+               },
+               "mousedown .ui-spinner-button": function( event ) {
+                       var previous;
+
+                       // We never want the buttons to have focus; whenever the user is
+                       // interacting with the spinner, the focus should be on the input.
+                       // If the input is focused then this.previous is properly set from
+                       // when the input first received focus. If the input is not focused
+                       // then we need to set this.previous based on the value before spinning.
+                       previous = this.element[0] === this.document[0].activeElement ?
+                               this.previous : this.element.val();
+                       function checkFocus() {
+                               var isActive = this.element[0] === this.document[0].activeElement;
+                               if ( !isActive ) {
+                                       this.element.focus();
+                                       this.previous = previous;
+                                       // support: IE
+                                       // IE sets focus asynchronously, so we need to check if focus
+                                       // moved off of the input because the user clicked on the button.
+                                       this._delay(function() {
+                                               this.previous = previous;
+                                       });
+                               }
+                       }
+
+                       // ensure focus is on (or stays on) the text field
+                       event.preventDefault();
+                       checkFocus.call( this );
+
+                       // support: IE
+                       // IE doesn't prevent moving focus even with event.preventDefault()
+                       // so we set a flag to know when we should ignore the blur event
+                       // and check (again) if focus moved off of the input.
+                       this.cancelBlur = true;
+                       this._delay(function() {
+                               delete this.cancelBlur;
+                               checkFocus.call( this );
+                       });
+
+                       if ( this._start( event ) === false ) {
+                               return;
+                       }
+
+                       this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+               },
+               "mouseup .ui-spinner-button": "_stop",
+               "mouseenter .ui-spinner-button": function( event ) {
+                       // button will add ui-state-active if mouse was down while mouseleave and kept down
+                       if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
+                               return;
+                       }
+
+                       if ( this._start( event ) === false ) {
+                               return false;
+                       }
+                       this._repeat( null, $( event.currentTarget ).hasClass( "ui-spinner-up" ) ? 1 : -1, event );
+               },
+               // TODO: do we really want to consider this a stop?
+               // shouldn't we just stop the repeater and wait until mouseup before
+               // we trigger the stop event?
+               "mouseleave .ui-spinner-button": "_stop"
+       },
+
+       _draw: function() {
+               var uiSpinner = this.uiSpinner = this.element
+                       .addClass( "ui-spinner-input" )
+                       .attr( "autocomplete", "off" )
+                       .wrap( this._uiSpinnerHtml() )
+                       .parent()
+                               // add buttons
+                               .append( this._buttonHtml() );
+
+               this.element.attr( "role", "spinbutton" );
+
+               // button bindings
+               this.buttons = uiSpinner.find( ".ui-spinner-button" )
+                       .attr( "tabIndex", -1 )
+                       .button()
+                       .removeClass( "ui-corner-all" );
+
+               // IE 6 doesn't understand height: 50% for the buttons
+               // unless the wrapper has an explicit height
+               if ( this.buttons.height() > Math.ceil( uiSpinner.height() * 0.5 ) &&
+                               uiSpinner.height() > 0 ) {
+                       uiSpinner.height( uiSpinner.height() );
+               }
+
+               // disable spinner if element was already disabled
+               if ( this.options.disabled ) {
+                       this.disable();
+               }
+       },
+
+       _keydown: function( event ) {
+               var options = this.options,
+                       keyCode = $.ui.keyCode;
+
+               switch ( event.keyCode ) {
+               case keyCode.UP:
+                       this._repeat( null, 1, event );
+                       return true;
+               case keyCode.DOWN:
+                       this._repeat( null, -1, event );
+                       return true;
+               case keyCode.PAGE_UP:
+                       this._repeat( null, options.page, event );
+                       return true;
+               case keyCode.PAGE_DOWN:
+                       this._repeat( null, -options.page, event );
+                       return true;
+               }
+
+               return false;
+       },
+
+       _uiSpinnerHtml: function() {
+               return "<span class='ui-spinner ui-widget ui-widget-content ui-corner-all'></span>";
+       },
+
+       _buttonHtml: function() {
+               return "" +
+                       "<a class='ui-spinner-button ui-spinner-up ui-corner-tr'>" +
+                               "<span class='ui-icon " + this.options.icons.up + "'>&#9650;</span>" +
+                       "</a>" +
+                       "<a class='ui-spinner-button ui-spinner-down ui-corner-br'>" +
+                               "<span class='ui-icon " + this.options.icons.down + "'>&#9660;</span>" +
+                       "</a>";
+       },
+
+       _start: function( event ) {
+               if ( !this.spinning && this._trigger( "start", event ) === false ) {
+                       return false;
+               }
+
+               if ( !this.counter ) {
+                       this.counter = 1;
+               }
+               this.spinning = true;
+               return true;
+       },
+
+       _repeat: function( i, steps, event ) {
+               i = i || 500;
+
+               clearTimeout( this.timer );
+               this.timer = this._delay(function() {
+                       this._repeat( 40, steps, event );
+               }, i );
+
+               this._spin( steps * this.options.step, event );
+       },
+
+       _spin: function( step, event ) {
+               var value = this.value() || 0;
+
+               if ( !this.counter ) {
+                       this.counter = 1;
+               }
+
+               value = this._adjustValue( value + step * this._increment( this.counter ) );
+
+               if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false) {
+                       this._value( value );
+                       this.counter++;
+               }
+       },
+
+       _increment: function( i ) {
+               var incremental = this.options.incremental;
+
+               if ( incremental ) {
+                       return $.isFunction( incremental ) ?
+                               incremental( i ) :
+                               Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
+               }
+
+               return 1;
+       },
+
+       _precision: function() {
+               var precision = this._precisionOf( this.options.step );
+               if ( this.options.min !== null ) {
+                       precision = Math.max( precision, this._precisionOf( this.options.min ) );
+               }
+               return precision;
+       },
+
+       _precisionOf: function( num ) {
+               var str = num.toString(),
+                       decimal = str.indexOf( "." );
+               return decimal === -1 ? 0 : str.length - decimal - 1;
+       },
+
+       _adjustValue: function( value ) {
+               var base, aboveMin,
+                       options = this.options;
+
+               // make sure we're at a valid step
+               // - find out where we are relative to the base (min or 0)
+               base = options.min !== null ? options.min : 0;
+               aboveMin = value - base;
+               // - round to the nearest step
+               aboveMin = Math.round(aboveMin / options.step) * options.step;
+               // - rounding is based on 0, so adjust back to our base
+               value = base + aboveMin;
+
+               // fix precision from bad JS floating point math
+               value = parseFloat( value.toFixed( this._precision() ) );
+
+               // clamp the value
+               if ( options.max !== null && value > options.max) {
+                       return options.max;
+               }
+               if ( options.min !== null && value < options.min ) {
+                       return options.min;
+               }
+
+               return value;
+       },
+
+       _stop: function( event ) {
+               if ( !this.spinning ) {
+                       return;
+               }
+
+               clearTimeout( this.timer );
+               clearTimeout( this.mousewheelTimer );
+               this.counter = 0;
+               this.spinning = false;
+               this._trigger( "stop", event );
+       },
+
+       _setOption: function( key, value ) {
+               if ( key === "culture" || key === "numberFormat" ) {
+                       var prevValue = this._parse( this.element.val() );
+                       this.options[ key ] = value;
+                       this.element.val( this._format( prevValue ) );
+                       return;
+               }
+
+               if ( key === "max" || key === "min" || key === "step" ) {
+                       if ( typeof value === "string" ) {
+                               value = this._parse( value );
+                       }
+               }
+               if ( key === "icons" ) {
+                       this.buttons.first().find( ".ui-icon" )
+                               .removeClass( this.options.icons.up )
+                               .addClass( value.up );
+                       this.buttons.last().find( ".ui-icon" )
+                               .removeClass( this.options.icons.down )
+                               .addClass( value.down );
+               }
+
+               this._super( key, value );
+
+               if ( key === "disabled" ) {
+                       this.widget().toggleClass( "ui-state-disabled", !!value );
+                       this.element.prop( "disabled", !!value );
+                       this.buttons.button( value ? "disable" : "enable" );
+               }
+       },
+
+       _setOptions: spinner_modifier(function( options ) {
+               this._super( options );
+       }),
+
+       _parse: function( val ) {
+               if ( typeof val === "string" && val !== "" ) {
+                       val = window.Globalize && this.options.numberFormat ?
+                               Globalize.parseFloat( val, 10, this.options.culture ) : +val;
+               }
+               return val === "" || isNaN( val ) ? null : val;
+       },
+
+       _format: function( value ) {
+               if ( value === "" ) {
+                       return "";
+               }
+               return window.Globalize && this.options.numberFormat ?
+                       Globalize.format( value, this.options.numberFormat, this.options.culture ) :
+                       value;
+       },
+
+       _refresh: function() {
+               this.element.attr({
+                       "aria-valuemin": this.options.min,
+                       "aria-valuemax": this.options.max,
+                       // TODO: what should we do with values that can't be parsed?
+                       "aria-valuenow": this._parse( this.element.val() )
+               });
+       },
+
+       isValid: function() {
+               var value = this.value();
+
+               // null is invalid
+               if ( value === null ) {
+                       return false;
+               }
+
+               // if value gets adjusted, it's invalid
+               return value === this._adjustValue( value );
+       },
+
+       // update the value without triggering change
+       _value: function( value, allowAny ) {
+               var parsed;
+               if ( value !== "" ) {
+                       parsed = this._parse( value );
+                       if ( parsed !== null ) {
+                               if ( !allowAny ) {
+                                       parsed = this._adjustValue( parsed );
+                               }
+                               value = this._format( parsed );
+                       }
+               }
+               this.element.val( value );
+               this._refresh();
+       },
+
+       _destroy: function() {
+               this.element
+                       .removeClass( "ui-spinner-input" )
+                       .prop( "disabled", false )
+                       .removeAttr( "autocomplete" )
+                       .removeAttr( "role" )
+                       .removeAttr( "aria-valuemin" )
+                       .removeAttr( "aria-valuemax" )
+                       .removeAttr( "aria-valuenow" );
+               this.uiSpinner.replaceWith( this.element );
+       },
+
+       stepUp: spinner_modifier(function( steps ) {
+               this._stepUp( steps );
+       }),
+       _stepUp: function( steps ) {
+               if ( this._start() ) {
+                       this._spin( (steps || 1) * this.options.step );
+                       this._stop();
+               }
+       },
+
+       stepDown: spinner_modifier(function( steps ) {
+               this._stepDown( steps );
+       }),
+       _stepDown: function( steps ) {
+               if ( this._start() ) {
+                       this._spin( (steps || 1) * -this.options.step );
+                       this._stop();
+               }
+       },
+
+       pageUp: spinner_modifier(function( pages ) {
+               this._stepUp( (pages || 1) * this.options.page );
+       }),
+
+       pageDown: spinner_modifier(function( pages ) {
+               this._stepDown( (pages || 1) * this.options.page );
+       }),
+
+       value: function( newVal ) {
+               if ( !arguments.length ) {
+                       return this._parse( this.element.val() );
+               }
+               spinner_modifier( this._value ).call( this, newVal );
+       },
+
+       widget: function() {
+               return this.uiSpinner;
+       }
+});
+
+
+/*!
+ * jQuery UI Tabs 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/tabs/
+ */
+
+
+var tabs = $.widget( "ui.tabs", {
+       version: "1.11.2",
+       delay: 300,
+       options: {
+               active: null,
+               collapsible: false,
+               event: "click",
+               heightStyle: "content",
+               hide: null,
+               show: null,
+
+               // callbacks
+               activate: null,
+               beforeActivate: null,
+               beforeLoad: null,
+               load: null
+       },
+
+       _isLocal: (function() {
+               var rhash = /#.*$/;
+
+               return function( anchor ) {
+                       var anchorUrl, locationUrl;
+
+                       // support: IE7
+                       // IE7 doesn't normalize the href property when set via script (#9317)
+                       anchor = anchor.cloneNode( false );
+
+                       anchorUrl = anchor.href.replace( rhash, "" );
+                       locationUrl = location.href.replace( rhash, "" );
+
+                       // decoding may throw an error if the URL isn't UTF-8 (#9518)
+                       try {
+                               anchorUrl = decodeURIComponent( anchorUrl );
+                       } catch ( error ) {}
+                       try {
+                               locationUrl = decodeURIComponent( locationUrl );
+                       } catch ( error ) {}
+
+                       return anchor.hash.length > 1 && anchorUrl === locationUrl;
+               };
+       })(),
+
+       _create: function() {
+               var that = this,
+                       options = this.options;
+
+               this.running = false;
+
+               this.element
+                       .addClass( "ui-tabs ui-widget ui-widget-content ui-corner-all" )
+                       .toggleClass( "ui-tabs-collapsible", options.collapsible );
+
+               this._processTabs();
+               options.active = this._initialActive();
+
+               // Take disabling tabs via class attribute from HTML
+               // into account and update option properly.
+               if ( $.isArray( options.disabled ) ) {
+                       options.disabled = $.unique( options.disabled.concat(
+                               $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
+                                       return that.tabs.index( li );
+                               })
+                       ) ).sort();
+               }
+
+               // check for length avoids error when initializing empty list
+               if ( this.options.active !== false && this.anchors.length ) {
+                       this.active = this._findActive( options.active );
+               } else {
+                       this.active = $();
+               }
+
+               this._refresh();
+
+               if ( this.active.length ) {
+                       this.load( options.active );
+               }
+       },
+
+       _initialActive: function() {
+               var active = this.options.active,
+                       collapsible = this.options.collapsible,
+                       locationHash = location.hash.substring( 1 );
+
+               if ( active === null ) {
+                       // check the fragment identifier in the URL
+                       if ( locationHash ) {
+                               this.tabs.each(function( i, tab ) {
+                                       if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
+                                               active = i;
+                                               return false;
+                                       }
+                               });
+                       }
+
+                       // check for a tab marked active via a class
+                       if ( active === null ) {
+                               active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
+                       }
+
+                       // no active tab, set to false
+                       if ( active === null || active === -1 ) {
+                               active = this.tabs.length ? 0 : false;
+                       }
+               }
+
+               // handle numbers: negative, out of range
+               if ( active !== false ) {
+                       active = this.tabs.index( this.tabs.eq( active ) );
+                       if ( active === -1 ) {
+                               active = collapsible ? false : 0;
+                       }
+               }
+
+               // don't allow collapsible: false and active: false
+               if ( !collapsible && active === false && this.anchors.length ) {
+                       active = 0;
+               }
+
+               return active;
+       },
+
+       _getCreateEventData: function() {
+               return {
+                       tab: this.active,
+                       panel: !this.active.length ? $() : this._getPanelForTab( this.active )
+               };
+       },
+
+       _tabKeydown: function( event ) {
+               var focusedTab = $( this.document[0].activeElement ).closest( "li" ),
+                       selectedIndex = this.tabs.index( focusedTab ),
+                       goingForward = true;
+
+               if ( this._handlePageNav( event ) ) {
+                       return;
+               }
+
+               switch ( event.keyCode ) {
+                       case $.ui.keyCode.RIGHT:
+                       case $.ui.keyCode.DOWN:
+                               selectedIndex++;
+                               break;
+                       case $.ui.keyCode.UP:
+                       case $.ui.keyCode.LEFT:
+                               goingForward = false;
+                               selectedIndex--;
+                               break;
+                       case $.ui.keyCode.END:
+                               selectedIndex = this.anchors.length - 1;
+                               break;
+                       case $.ui.keyCode.HOME:
+                               selectedIndex = 0;
+                               break;
+                       case $.ui.keyCode.SPACE:
+                               // Activate only, no collapsing
+                               event.preventDefault();
+                               clearTimeout( this.activating );
+                               this._activate( selectedIndex );
+                               return;
+                       case $.ui.keyCode.ENTER:
+                               // Toggle (cancel delayed activation, allow collapsing)
+                               event.preventDefault();
+                               clearTimeout( this.activating );
+                               // Determine if we should collapse or activate
+                               this._activate( selectedIndex === this.options.active ? false : selectedIndex );
+                               return;
+                       default:
+                               return;
+               }
+
+               // Focus the appropriate tab, based on which key was pressed
+               event.preventDefault();
+               clearTimeout( this.activating );
+               selectedIndex = this._focusNextTab( selectedIndex, goingForward );
+
+               // Navigating with control key will prevent automatic activation
+               if ( !event.ctrlKey ) {
+                       // Update aria-selected immediately so that AT think the tab is already selected.
+                       // Otherwise AT may confuse the user by stating that they need to activate the tab,
+                       // but the tab will already be activated by the time the announcement finishes.
+                       focusedTab.attr( "aria-selected", "false" );
+                       this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
+
+                       this.activating = this._delay(function() {
+                               this.option( "active", selectedIndex );
+                       }, this.delay );
+               }
+       },
+
+       _panelKeydown: function( event ) {
+               if ( this._handlePageNav( event ) ) {
+                       return;
+               }
+
+               // Ctrl+up moves focus to the current tab
+               if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
+                       event.preventDefault();
+                       this.active.focus();
+               }
+       },
+
+       // Alt+page up/down moves focus to the previous/next tab (and activates)
+       _handlePageNav: function( event ) {
+               if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
+                       this._activate( this._focusNextTab( this.options.active - 1, false ) );
+                       return true;
+               }
+               if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
+                       this._activate( this._focusNextTab( this.options.active + 1, true ) );
+                       return true;
+               }
+       },
+
+       _findNextTab: function( index, goingForward ) {
+               var lastTabIndex = this.tabs.length - 1;
+
+               function constrain() {
+                       if ( index > lastTabIndex ) {
+                               index = 0;
+                       }
+                       if ( index < 0 ) {
+                               index = lastTabIndex;
+                       }
+                       return index;
+               }
+
+               while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
+                       index = goingForward ? index + 1 : index - 1;
+               }
+
+               return index;
+       },
+
+       _focusNextTab: function( index, goingForward ) {
+               index = this._findNextTab( index, goingForward );
+               this.tabs.eq( index ).focus();
+               return index;
+       },
+
+       _setOption: function( key, value ) {
+               if ( key === "active" ) {
+                       // _activate() will handle invalid values and update this.options
+                       this._activate( value );
+                       return;
+               }
+
+               if ( key === "disabled" ) {
+                       // don't use the widget factory's disabled handling
+                       this._setupDisabled( value );
+                       return;
+               }
+
+               this._super( key, value);
+
+               if ( key === "collapsible" ) {
+                       this.element.toggleClass( "ui-tabs-collapsible", value );
+                       // Setting collapsible: false while collapsed; open first panel
+                       if ( !value && this.options.active === false ) {
+                               this._activate( 0 );
+                       }
+               }
+
+               if ( key === "event" ) {
+                       this._setupEvents( value );
+               }
+
+               if ( key === "heightStyle" ) {
+                       this._setupHeightStyle( value );
+               }
+       },
+
+       _sanitizeSelector: function( hash ) {
+               return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
+       },
+
+       refresh: function() {
+               var options = this.options,
+                       lis = this.tablist.children( ":has(a[href])" );
+
+               // get disabled tabs from class attribute from HTML
+               // this will get converted to a boolean if needed in _refresh()
+               options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
+                       return lis.index( tab );
+               });
+
+               this._processTabs();
+
+               // was collapsed or no tabs
+               if ( options.active === false || !this.anchors.length ) {
+                       options.active = false;
+                       this.active = $();
+               // was active, but active tab is gone
+               } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
+                       // all remaining tabs are disabled
+                       if ( this.tabs.length === options.disabled.length ) {
+                               options.active = false;
+                               this.active = $();
+                       // activate previous tab
+                       } else {
+                               this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
+                       }
+               // was active, active tab still exists
+               } else {
+                       // make sure active index is correct
+                       options.active = this.tabs.index( this.active );
+               }
+
+               this._refresh();
+       },
+
+       _refresh: function() {
+               this._setupDisabled( this.options.disabled );
+               this._setupEvents( this.options.event );
+               this._setupHeightStyle( this.options.heightStyle );
+
+               this.tabs.not( this.active ).attr({
+                       "aria-selected": "false",
+                       "aria-expanded": "false",
+                       tabIndex: -1
+               });
+               this.panels.not( this._getPanelForTab( this.active ) )
+                       .hide()
+                       .attr({
+                               "aria-hidden": "true"
+                       });
+
+               // Make sure one tab is in the tab order
+               if ( !this.active.length ) {
+                       this.tabs.eq( 0 ).attr( "tabIndex", 0 );
+               } else {
+                       this.active
+                               .addClass( "ui-tabs-active ui-state-active" )
+                               .attr({
+                                       "aria-selected": "true",
+                                       "aria-expanded": "true",
+                                       tabIndex: 0
+                               });
+                       this._getPanelForTab( this.active )
+                               .show()
+                               .attr({
+                                       "aria-hidden": "false"
+                               });
+               }
+       },
+
+       _processTabs: function() {
+               var that = this,
+                       prevTabs = this.tabs,
+                       prevAnchors = this.anchors,
+                       prevPanels = this.panels;
+
+               this.tablist = this._getList()
+                       .addClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+                       .attr( "role", "tablist" )
+
+                       // Prevent users from focusing disabled tabs via click
+                       .delegate( "> li", "mousedown" + this.eventNamespace, function( event ) {
+                               if ( $( this ).is( ".ui-state-disabled" ) ) {
+                                       event.preventDefault();
+                               }
+                       })
+
+                       // support: IE <9
+                       // Preventing the default action in mousedown doesn't prevent IE
+                       // from focusing the element, so if the anchor gets focused, blur.
+                       // We don't have to worry about focusing the previously focused
+                       // element since clicking on a non-focusable element should focus
+                       // the body anyway.
+                       .delegate( ".ui-tabs-anchor", "focus" + this.eventNamespace, function() {
+                               if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
+                                       this.blur();
+                               }
+                       });
+
+               this.tabs = this.tablist.find( "> li:has(a[href])" )
+                       .addClass( "ui-state-default ui-corner-top" )
+                       .attr({
+                               role: "tab",
+                               tabIndex: -1
+                       });
+
+               this.anchors = this.tabs.map(function() {
+                               return $( "a", this )[ 0 ];
+                       })
+                       .addClass( "ui-tabs-anchor" )
+                       .attr({
+                               role: "presentation",
+                               tabIndex: -1
+                       });
+
+               this.panels = $();
+
+               this.anchors.each(function( i, anchor ) {
+                       var selector, panel, panelId,
+                               anchorId = $( anchor ).uniqueId().attr( "id" ),
+                               tab = $( anchor ).closest( "li" ),
+                               originalAriaControls = tab.attr( "aria-controls" );
+
+                       // inline tab
+                       if ( that._isLocal( anchor ) ) {
+                               selector = anchor.hash;
+                               panelId = selector.substring( 1 );
+                               panel = that.element.find( that._sanitizeSelector( selector ) );
+                       // remote tab
+                       } else {
+                               // If the tab doesn't already have aria-controls,
+                               // generate an id by using a throw-away element
+                               panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
+                               selector = "#" + panelId;
+                               panel = that.element.find( selector );
+                               if ( !panel.length ) {
+                                       panel = that._createPanel( panelId );
+                                       panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
+                               }
+                               panel.attr( "aria-live", "polite" );
+                       }
+
+                       if ( panel.length) {
+                               that.panels = that.panels.add( panel );
+                       }
+                       if ( originalAriaControls ) {
+                               tab.data( "ui-tabs-aria-controls", originalAriaControls );
+                       }
+                       tab.attr({
+                               "aria-controls": panelId,
+                               "aria-labelledby": anchorId
+                       });
+                       panel.attr( "aria-labelledby", anchorId );
+               });
+
+               this.panels
+                       .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+                       .attr( "role", "tabpanel" );
+
+               // Avoid memory leaks (#10056)
+               if ( prevTabs ) {
+                       this._off( prevTabs.not( this.tabs ) );
+                       this._off( prevAnchors.not( this.anchors ) );
+                       this._off( prevPanels.not( this.panels ) );
+               }
+       },
+
+       // allow overriding how to find the list for rare usage scenarios (#7715)
+       _getList: function() {
+               return this.tablist || this.element.find( "ol,ul" ).eq( 0 );
+       },
+
+       _createPanel: function( id ) {
+               return $( "<div>" )
+                       .attr( "id", id )
+                       .addClass( "ui-tabs-panel ui-widget-content ui-corner-bottom" )
+                       .data( "ui-tabs-destroy", true );
+       },
+
+       _setupDisabled: function( disabled ) {
+               if ( $.isArray( disabled ) ) {
+                       if ( !disabled.length ) {
+                               disabled = false;
+                       } else if ( disabled.length === this.anchors.length ) {
+                               disabled = true;
+                       }
+               }
+
+               // disable tabs
+               for ( var i = 0, li; ( li = this.tabs[ i ] ); i++ ) {
+                       if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
+                               $( li )
+                                       .addClass( "ui-state-disabled" )
+                                       .attr( "aria-disabled", "true" );
+                       } else {
+                               $( li )
+                                       .removeClass( "ui-state-disabled" )
+                                       .removeAttr( "aria-disabled" );
+                       }
+               }
+
+               this.options.disabled = disabled;
+       },
+
+       _setupEvents: function( event ) {
+               var events = {};
+               if ( event ) {
+                       $.each( event.split(" "), function( index, eventName ) {
+                               events[ eventName ] = "_eventHandler";
+                       });
+               }
+
+               this._off( this.anchors.add( this.tabs ).add( this.panels ) );
+               // Always prevent the default action, even when disabled
+               this._on( true, this.anchors, {
+                       click: function( event ) {
+                               event.preventDefault();
+                       }
+               });
+               this._on( this.anchors, events );
+               this._on( this.tabs, { keydown: "_tabKeydown" } );
+               this._on( this.panels, { keydown: "_panelKeydown" } );
+
+               this._focusable( this.tabs );
+               this._hoverable( this.tabs );
+       },
+
+       _setupHeightStyle: function( heightStyle ) {
+               var maxHeight,
+                       parent = this.element.parent();
+
+               if ( heightStyle === "fill" ) {
+                       maxHeight = parent.height();
+                       maxHeight -= this.element.outerHeight() - this.element.height();
+
+                       this.element.siblings( ":visible" ).each(function() {
+                               var elem = $( this ),
+                                       position = elem.css( "position" );
+
+                               if ( position === "absolute" || position === "fixed" ) {
+                                       return;
+                               }
+                               maxHeight -= elem.outerHeight( true );
+                       });
+
+                       this.element.children().not( this.panels ).each(function() {
+                               maxHeight -= $( this ).outerHeight( true );
+                       });
+
+                       this.panels.each(function() {
+                               $( this ).height( Math.max( 0, maxHeight -
+                                       $( this ).innerHeight() + $( this ).height() ) );
+                       })
+                       .css( "overflow", "auto" );
+               } else if ( heightStyle === "auto" ) {
+                       maxHeight = 0;
+                       this.panels.each(function() {
+                               maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
+                       }).height( maxHeight );
+               }
+       },
+
+       _eventHandler: function( event ) {
+               var options = this.options,
+                       active = this.active,
+                       anchor = $( event.currentTarget ),
+                       tab = anchor.closest( "li" ),
+                       clickedIsActive = tab[ 0 ] === active[ 0 ],
+                       collapsing = clickedIsActive && options.collapsible,
+                       toShow = collapsing ? $() : this._getPanelForTab( tab ),
+                       toHide = !active.length ? $() : this._getPanelForTab( active ),
+                       eventData = {
+                               oldTab: active,
+                               oldPanel: toHide,
+                               newTab: collapsing ? $() : tab,
+                               newPanel: toShow
+                       };
+
+               event.preventDefault();
+
+               if ( tab.hasClass( "ui-state-disabled" ) ||
+                               // tab is already loading
+                               tab.hasClass( "ui-tabs-loading" ) ||
+                               // can't switch durning an animation
+                               this.running ||
+                               // click on active header, but not collapsible
+                               ( clickedIsActive && !options.collapsible ) ||
+                               // allow canceling activation
+                               ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
+                       return;
+               }
+
+               options.active = collapsing ? false : this.tabs.index( tab );
+
+               this.active = clickedIsActive ? $() : tab;
+               if ( this.xhr ) {
+                       this.xhr.abort();
+               }
+
+               if ( !toHide.length && !toShow.length ) {
+                       $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
+               }
+
+               if ( toShow.length ) {
+                       this.load( this.tabs.index( tab ), event );
+               }
+               this._toggle( event, eventData );
+       },
+
+       // handles show/hide for selecting tabs
+       _toggle: function( event, eventData ) {
+               var that = this,
+                       toShow = eventData.newPanel,
+                       toHide = eventData.oldPanel;
+
+               this.running = true;
+
+               function complete() {
+                       that.running = false;
+                       that._trigger( "activate", event, eventData );
+               }
+
+               function show() {
+                       eventData.newTab.closest( "li" ).addClass( "ui-tabs-active ui-state-active" );
+
+                       if ( toShow.length && that.options.show ) {
+                               that._show( toShow, that.options.show, complete );
+                       } else {
+                               toShow.show();
+                               complete();
+                       }
+               }
+
+               // start out by hiding, then showing, then completing
+               if ( toHide.length && this.options.hide ) {
+                       this._hide( toHide, this.options.hide, function() {
+                               eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+                               show();
+                       });
+               } else {
+                       eventData.oldTab.closest( "li" ).removeClass( "ui-tabs-active ui-state-active" );
+                       toHide.hide();
+                       show();
+               }
+
+               toHide.attr( "aria-hidden", "true" );
+               eventData.oldTab.attr({
+                       "aria-selected": "false",
+                       "aria-expanded": "false"
+               });
+               // If we're switching tabs, remove the old tab from the tab order.
+               // If we're opening from collapsed state, remove the previous tab from the tab order.
+               // If we're collapsing, then keep the collapsing tab in the tab order.
+               if ( toShow.length && toHide.length ) {
+                       eventData.oldTab.attr( "tabIndex", -1 );
+               } else if ( toShow.length ) {
+                       this.tabs.filter(function() {
+                               return $( this ).attr( "tabIndex" ) === 0;
+                       })
+                       .attr( "tabIndex", -1 );
+               }
+
+               toShow.attr( "aria-hidden", "false" );
+               eventData.newTab.attr({
+                       "aria-selected": "true",
+                       "aria-expanded": "true",
+                       tabIndex: 0
+               });
+       },
+
+       _activate: function( index ) {
+               var anchor,
+                       active = this._findActive( index );
+
+               // trying to activate the already active panel
+               if ( active[ 0 ] === this.active[ 0 ] ) {
+                       return;
+               }
+
+               // trying to collapse, simulate a click on the current active header
+               if ( !active.length ) {
+                       active = this.active;
+               }
+
+               anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
+               this._eventHandler({
+                       target: anchor,
+                       currentTarget: anchor,
+                       preventDefault: $.noop
+               });
+       },
+
+       _findActive: function( index ) {
+               return index === false ? $() : this.tabs.eq( index );
+       },
+
+       _getIndex: function( index ) {
+               // meta-function to give users option to provide a href string instead of a numerical index.
+               if ( typeof index === "string" ) {
+                       index = this.anchors.index( this.anchors.filter( "[href$='" + index + "']" ) );
+               }
+
+               return index;
+       },
+
+       _destroy: function() {
+               if ( this.xhr ) {
+                       this.xhr.abort();
+               }
+
+               this.element.removeClass( "ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible" );
+
+               this.tablist
+                       .removeClass( "ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all" )
+                       .removeAttr( "role" );
+
+               this.anchors
+                       .removeClass( "ui-tabs-anchor" )
+                       .removeAttr( "role" )
+                       .removeAttr( "tabIndex" )
+                       .removeUniqueId();
+
+               this.tablist.unbind( this.eventNamespace );
+
+               this.tabs.add( this.panels ).each(function() {
+                       if ( $.data( this, "ui-tabs-destroy" ) ) {
+                               $( this ).remove();
+                       } else {
+                               $( this )
+                                       .removeClass( "ui-state-default ui-state-active ui-state-disabled " +
+                                               "ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel" )
+                                       .removeAttr( "tabIndex" )
+                                       .removeAttr( "aria-live" )
+                                       .removeAttr( "aria-busy" )
+                                       .removeAttr( "aria-selected" )
+                                       .removeAttr( "aria-labelledby" )
+                                       .removeAttr( "aria-hidden" )
+                                       .removeAttr( "aria-expanded" )
+                                       .removeAttr( "role" );
+                       }
+               });
+
+               this.tabs.each(function() {
+                       var li = $( this ),
+                               prev = li.data( "ui-tabs-aria-controls" );
+                       if ( prev ) {
+                               li
+                                       .attr( "aria-controls", prev )
+                                       .removeData( "ui-tabs-aria-controls" );
+                       } else {
+                               li.removeAttr( "aria-controls" );
+                       }
+               });
+
+               this.panels.show();
+
+               if ( this.options.heightStyle !== "content" ) {
+                       this.panels.css( "height", "" );
+               }
+       },
+
+       enable: function( index ) {
+               var disabled = this.options.disabled;
+               if ( disabled === false ) {
+                       return;
+               }
+
+               if ( index === undefined ) {
+                       disabled = false;
+               } else {
+                       index = this._getIndex( index );
+                       if ( $.isArray( disabled ) ) {
+                               disabled = $.map( disabled, function( num ) {
+                                       return num !== index ? num : null;
+                               });
+                       } else {
+                               disabled = $.map( this.tabs, function( li, num ) {
+                                       return num !== index ? num : null;
+                               });
+                       }
+               }
+               this._setupDisabled( disabled );
+       },
+
+       disable: function( index ) {
+               var disabled = this.options.disabled;
+               if ( disabled === true ) {
+                       return;
+               }
+
+               if ( index === undefined ) {
+                       disabled = true;
+               } else {
+                       index = this._getIndex( index );
+                       if ( $.inArray( index, disabled ) !== -1 ) {
+                               return;
+                       }
+                       if ( $.isArray( disabled ) ) {
+                               disabled = $.merge( [ index ], disabled ).sort();
+                       } else {
+                               disabled = [ index ];
+                       }
+               }
+               this._setupDisabled( disabled );
+       },
+
+       load: function( index, event ) {
+               index = this._getIndex( index );
+               var that = this,
+                       tab = this.tabs.eq( index ),
+                       anchor = tab.find( ".ui-tabs-anchor" ),
+                       panel = this._getPanelForTab( tab ),
+                       eventData = {
+                               tab: tab,
+                               panel: panel
+                       };
+
+               // not remote
+               if ( this._isLocal( anchor[ 0 ] ) ) {
+                       return;
+               }
+
+               this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
+
+               // support: jQuery <1.8
+               // jQuery <1.8 returns false if the request is canceled in beforeSend,
+               // but as of 1.8, $.ajax() always returns a jqXHR object.
+               if ( this.xhr && this.xhr.statusText !== "canceled" ) {
+                       tab.addClass( "ui-tabs-loading" );
+                       panel.attr( "aria-busy", "true" );
+
+                       this.xhr
+                               .success(function( response ) {
+                                       // support: jQuery <1.8
+                                       // http://bugs.jquery.com/ticket/11778
+                                       setTimeout(function() {
+                                               panel.html( response );
+                                               that._trigger( "load", event, eventData );
+                                       }, 1 );
+                               })
+                               .complete(function( jqXHR, status ) {
+                                       // support: jQuery <1.8
+                                       // http://bugs.jquery.com/ticket/11778
+                                       setTimeout(function() {
+                                               if ( status === "abort" ) {
+                                                       that.panels.stop( false, true );
+                                               }
+
+                                               tab.removeClass( "ui-tabs-loading" );
+                                               panel.removeAttr( "aria-busy" );
+
+                                               if ( jqXHR === that.xhr ) {
+                                                       delete that.xhr;
+                                               }
+                                       }, 1 );
+                               });
+               }
+       },
+
+       _ajaxSettings: function( anchor, event, eventData ) {
+               var that = this;
+               return {
+                       url: anchor.attr( "href" ),
+                       beforeSend: function( jqXHR, settings ) {
+                               return that._trigger( "beforeLoad", event,
+                                       $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
+                       }
+               };
+       },
+
+       _getPanelForTab: function( tab ) {
+               var id = $( tab ).attr( "aria-controls" );
+               return this.element.find( this._sanitizeSelector( "#" + id ) );
+       }
+});
+
+
+/*!
+ * jQuery UI Tooltip 1.11.2
+ * http://jqueryui.com
+ *
+ * Copyright 2014 jQuery Foundation and other contributors
+ * Released under the MIT license.
+ * http://jquery.org/license
+ *
+ * http://api.jqueryui.com/tooltip/
+ */
+
+
+var tooltip = $.widget( "ui.tooltip", {
+       version: "1.11.2",
+       options: {
+               content: function() {
+                       // support: IE<9, Opera in jQuery <1.7
+                       // .text() can't accept undefined, so coerce to a string
+                       var title = $( this ).attr( "title" ) || "";
+                       // Escape title, since we're going from an attribute to raw HTML
+                       return $( "<a>" ).text( title ).html();
+               },
+               hide: true,
+               // Disabled elements have inconsistent behavior across browsers (#8661)
+               items: "[title]:not([disabled])",
+               position: {
+                       my: "left top+15",
+                       at: "left bottom",
+                       collision: "flipfit flip"
+               },
+               show: true,
+               tooltipClass: null,
+               track: false,
+
+               // callbacks
+               close: null,
+               open: null
+       },
+
+       _addDescribedBy: function( elem, id ) {
+               var describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ );
+               describedby.push( id );
+               elem
+                       .data( "ui-tooltip-id", id )
+                       .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
+       },
+
+       _removeDescribedBy: function( elem ) {
+               var id = elem.data( "ui-tooltip-id" ),
+                       describedby = (elem.attr( "aria-describedby" ) || "").split( /\s+/ ),
+                       index = $.inArray( id, describedby );
+
+               if ( index !== -1 ) {
+                       describedby.splice( index, 1 );
+               }
+
+               elem.removeData( "ui-tooltip-id" );
+               describedby = $.trim( describedby.join( " " ) );
+               if ( describedby ) {
+                       elem.attr( "aria-describedby", describedby );
+               } else {
+                       elem.removeAttr( "aria-describedby" );
+               }
+       },
+
+       _create: function() {
+               this._on({
+                       mouseover: "open",
+                       focusin: "open"
+               });
+
+               // IDs of generated tooltips, needed for destroy
+               this.tooltips = {};
+
+               // IDs of parent tooltips where we removed the title attribute
+               this.parents = {};
+
+               if ( this.options.disabled ) {
+                       this._disable();
+               }
+
+               // Append the aria-live region so tooltips announce correctly
+               this.liveRegion = $( "<div>" )
+                       .attr({
+                               role: "log",
+                               "aria-live": "assertive",
+                               "aria-relevant": "additions"
+                       })
+                       .addClass( "ui-helper-hidden-accessible" )
+                       .appendTo( this.document[ 0 ].body );
+       },
+
+       _setOption: function( key, value ) {
+               var that = this;
+
+               if ( key === "disabled" ) {
+                       this[ value ? "_disable" : "_enable" ]();
+                       this.options[ key ] = value;
+                       // disable element style changes
+                       return;
+               }
+
+               this._super( key, value );
+
+               if ( key === "content" ) {
+                       $.each( this.tooltips, function( id, tooltipData ) {
+                               that._updateContent( tooltipData.element );
+                       });
+               }
+       },
+
+       _disable: function() {
+               var that = this;
+
+               // close open tooltips
+               $.each( this.tooltips, function( id, tooltipData ) {
+                       var event = $.Event( "blur" );
+                       event.target = event.currentTarget = tooltipData.element[ 0 ];
+                       that.close( event, true );
+               });
+
+               // remove title attributes to prevent native tooltips
+               this.element.find( this.options.items ).addBack().each(function() {
+                       var element = $( this );
+                       if ( element.is( "[title]" ) ) {
+                               element
+                                       .data( "ui-tooltip-title", element.attr( "title" ) )
+                                       .removeAttr( "title" );
+                       }
+               });
+       },
+
+       _enable: function() {
+               // restore title attributes
+               this.element.find( this.options.items ).addBack().each(function() {
+                       var element = $( this );
+                       if ( element.data( "ui-tooltip-title" ) ) {
+                               element.attr( "title", element.data( "ui-tooltip-title" ) );
+                       }
+               });
+       },
+
+       open: function( event ) {
+               var that = this,
+                       target = $( event ? event.target : this.element )
+                               // we need closest here due to mouseover bubbling,
+                               // but always pointing at the same event target
+                               .closest( this.options.items );
+
+               // No element to show a tooltip for or the tooltip is already open
+               if ( !target.length || target.data( "ui-tooltip-id" ) ) {
+                       return;
+               }
+
+               if ( target.attr( "title" ) ) {
+                       target.data( "ui-tooltip-title", target.attr( "title" ) );
+               }
+
+               target.data( "ui-tooltip-open", true );
+
+               // kill parent tooltips, custom or native, for hover
+               if ( event && event.type === "mouseover" ) {
+                       target.parents().each(function() {
+                               var parent = $( this ),
+                                       blurEvent;
+                               if ( parent.data( "ui-tooltip-open" ) ) {
+                                       blurEvent = $.Event( "blur" );
+                                       blurEvent.target = blurEvent.currentTarget = this;
+                                       that.close( blurEvent, true );
+                               }
+                               if ( parent.attr( "title" ) ) {
+                                       parent.uniqueId();
+                                       that.parents[ this.id ] = {
+                                               element: this,
+                                               title: parent.attr( "title" )
+                                       };
+                                       parent.attr( "title", "" );
+                               }
+                       });
+               }
+
+               this._updateContent( target, event );
+       },
+
+       _updateContent: function( target, event ) {
+               var content,
+                       contentOption = this.options.content,
+                       that = this,
+                       eventType = event ? event.type : null;
+
+               if ( typeof contentOption === "string" ) {
+                       return this._open( event, target, contentOption );
+               }
+
+               content = contentOption.call( target[0], function( response ) {
+                       // ignore async response if tooltip was closed already
+                       if ( !target.data( "ui-tooltip-open" ) ) {
+                               return;
+                       }
+                       // IE may instantly serve a cached response for ajax requests
+                       // delay this call to _open so the other call to _open runs first
+                       that._delay(function() {
+                               // jQuery creates a special event for focusin when it doesn't
+                               // exist natively. To improve performance, the native event
+                               // object is reused and the type is changed. Therefore, we can't
+                               // rely on the type being correct after the event finished
+                               // bubbling, so we set it back to the previous value. (#8740)
+                               if ( event ) {
+                                       event.type = eventType;
+                               }
+                               this._open( event, target, response );
+                       });
+               });
+               if ( content ) {
+                       this._open( event, target, content );
+               }
+       },
+
+       _open: function( event, target, content ) {
+               var tooltipData, tooltip, events, delayedShow, a11yContent,
+                       positionOption = $.extend( {}, this.options.position );
+
+               if ( !content ) {
+                       return;
+               }
+
+               // Content can be updated multiple times. If the tooltip already
+               // exists, then just update the content and bail.
+               tooltipData = this._find( target );
+               if ( tooltipData ) {
+                       tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
+                       return;
+               }
+
+               // if we have a title, clear it to prevent the native tooltip
+               // we have to check first to avoid defining a title if none exists
+               // (we don't want to cause an element to start matching [title])
+               //
+               // We use removeAttr only for key events, to allow IE to export the correct
+               // accessible attributes. For mouse events, set to empty string to avoid
+               // native tooltip showing up (happens only when removing inside mouseover).
+               if ( target.is( "[title]" ) ) {
+                       if ( event && event.type === "mouseover" ) {
+                               target.attr( "title", "" );
+                       } else {
+                               target.removeAttr( "title" );
+                       }
+               }
+
+               tooltipData = this._tooltip( target );
+               tooltip = tooltipData.tooltip;
+               this._addDescribedBy( target, tooltip.attr( "id" ) );
+               tooltip.find( ".ui-tooltip-content" ).html( content );
+
+               // Support: Voiceover on OS X, JAWS on IE <= 9
+               // JAWS announces deletions even when aria-relevant="additions"
+               // Voiceover will sometimes re-read the entire log region's contents from the beginning
+               this.liveRegion.children().hide();
+               if ( content.clone ) {
+                       a11yContent = content.clone();
+                       a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
+               } else {
+                       a11yContent = content;
+               }
+               $( "<div>" ).html( a11yContent ).appendTo( this.liveRegion );
+
+               function position( event ) {
+                       positionOption.of = event;
+                       if ( tooltip.is( ":hidden" ) ) {
+                               return;
+                       }
+                       tooltip.position( positionOption );
+               }
+               if ( this.options.track && event && /^mouse/.test( event.type ) ) {
+                       this._on( this.document, {
+                               mousemove: position
+                       });
+                       // trigger once to override element-relative positioning
+                       position( event );
+               } else {
+                       tooltip.position( $.extend({
+                               of: target
+                       }, this.options.position ) );
+               }
+
+               tooltip.hide();
+
+               this._show( tooltip, this.options.show );
+               // Handle tracking tooltips that are shown with a delay (#8644). As soon
+               // as the tooltip is visible, position the tooltip using the most recent
+               // event.
+               if ( this.options.show && this.options.show.delay ) {
+                       delayedShow = this.delayedShow = setInterval(function() {
+                               if ( tooltip.is( ":visible" ) ) {
+                                       position( positionOption.of );
+                                       clearInterval( delayedShow );
+                               }
+                       }, $.fx.interval );
+               }
+
+               this._trigger( "open", event, { tooltip: tooltip } );
+
+               events = {
+                       keyup: function( event ) {
+                               if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
+                                       var fakeEvent = $.Event(event);
+                                       fakeEvent.currentTarget = target[0];
+                                       this.close( fakeEvent, true );
+                               }
+                       }
+               };
+
+               // Only bind remove handler for delegated targets. Non-delegated
+               // tooltips will handle this in destroy.
+               if ( target[ 0 ] !== this.element[ 0 ] ) {
+                       events.remove = function() {
+                               this._removeTooltip( tooltip );
+                       };
+               }
+
+               if ( !event || event.type === "mouseover" ) {
+                       events.mouseleave = "close";
+               }
+               if ( !event || event.type === "focusin" ) {
+                       events.focusout = "close";
+               }
+               this._on( true, target, events );
+       },
+
+       close: function( event ) {
+               var tooltip,
+                       that = this,
+                       target = $( event ? event.currentTarget : this.element ),
+                       tooltipData = this._find( target );
+
+               // The tooltip may already be closed
+               if ( !tooltipData ) {
+                       return;
+               }
+
+               tooltip = tooltipData.tooltip;
+
+               // disabling closes the tooltip, so we need to track when we're closing
+               // to avoid an infinite loop in case the tooltip becomes disabled on close
+               if ( tooltipData.closing ) {
+                       return;
+               }
+
+               // Clear the interval for delayed tracking tooltips
+               clearInterval( this.delayedShow );
+
+               // only set title if we had one before (see comment in _open())
+               // If the title attribute has changed since open(), don't restore
+               if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
+                       target.attr( "title", target.data( "ui-tooltip-title" ) );
+               }
+
+               this._removeDescribedBy( target );
+
+               tooltipData.hiding = true;
+               tooltip.stop( true );
+               this._hide( tooltip, this.options.hide, function() {
+                       that._removeTooltip( $( this ) );
+               });
+
+               target.removeData( "ui-tooltip-open" );
+               this._off( target, "mouseleave focusout keyup" );
+
+               // Remove 'remove' binding only on delegated targets
+               if ( target[ 0 ] !== this.element[ 0 ] ) {
+                       this._off( target, "remove" );
+               }
+               this._off( this.document, "mousemove" );
+
+               if ( event && event.type === "mouseleave" ) {
+                       $.each( this.parents, function( id, parent ) {
+                               $( parent.element ).attr( "title", parent.title );
+                               delete that.parents[ id ];
+                       });
+               }
+
+               tooltipData.closing = true;
+               this._trigger( "close", event, { tooltip: tooltip } );
+               if ( !tooltipData.hiding ) {
+                       tooltipData.closing = false;
+               }
+       },
+
+       _tooltip: function( element ) {
+               var tooltip = $( "<div>" )
+                               .attr( "role", "tooltip" )
+                               .addClass( "ui-tooltip ui-widget ui-corner-all ui-widget-content " +
+                                       ( this.options.tooltipClass || "" ) ),
+                       id = tooltip.uniqueId().attr( "id" );
+
+               $( "<div>" )
+                       .addClass( "ui-tooltip-content" )
+                       .appendTo( tooltip );
+
+               tooltip.appendTo( this.document[0].body );
+
+               return this.tooltips[ id ] = {
+                       element: element,
+                       tooltip: tooltip
+               };
+       },
+
+       _find: function( target ) {
+               var id = target.data( "ui-tooltip-id" );
+               return id ? this.tooltips[ id ] : null;
+       },
+
+       _removeTooltip: function( tooltip ) {
+               tooltip.remove();
+               delete this.tooltips[ tooltip.attr( "id" ) ];
+       },
+
+       _destroy: function() {
+               var that = this;
+
+               // close open tooltips
+               $.each( this.tooltips, function( id, tooltipData ) {
+                       // Delegate to close method to handle common cleanup
+                       var event = $.Event( "blur" ),
+                               element = tooltipData.element;
+                       event.target = event.currentTarget = element[ 0 ];
+                       that.close( event, true );
+
+                       // Remove immediately; destroying an open tooltip doesn't use the
+                       // hide animation
+                       $( "#" + id ).remove();
+
+                       // Restore the title
+                       if ( element.data( "ui-tooltip-title" ) ) {
+                               // If the title attribute has changed since open(), don't restore
+                               if ( !element.attr( "title" ) ) {
+                                       element.attr( "title", element.data( "ui-tooltip-title" ) );
+                               }
+                               element.removeData( "ui-tooltip-title" );
+                       }
+               });
+               this.liveRegion.remove();
+       }
+});
+
+
+
+}));
\ No newline at end of file
diff --git a/HldRec/js/jquery.flot.js b/HldRec/js/jquery.flot.js
new file mode 100644 (file)
index 0000000..39f3e4c
--- /dev/null
@@ -0,0 +1,3168 @@
+/* Javascript plotting library for jQuery, version 0.8.3.
+
+Copyright (c) 2007-2014 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+*/
+
+// first an inline dependency, jquery.colorhelpers.js, we inline it here
+// for convenience
+
+/* Plugin for jQuery for working with colors.
+ *
+ * Version 1.1.
+ *
+ * Inspiration from jQuery color animation plugin by John Resig.
+ *
+ * Released under the MIT license by Ole Laursen, October 2009.
+ *
+ * Examples:
+ *
+ *   $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString()
+ *   var c = $.color.extract($("#mydiv"), 'background-color');
+ *   console.log(c.r, c.g, c.b, c.a);
+ *   $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)"
+ *
+ * Note that .scale() and .add() return the same modified object
+ * instead of making a new one.
+ *
+ * V. 1.1: Fix error handling so e.g. parsing an empty string does
+ * produce a color rather than just crashing.
+ */
+(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i<c.length;++i)o[c.charAt(i)]+=d;return o.normalize()};o.scale=function(c,f){for(var i=0;i<c.length;++i)o[c.charAt(i)]*=f;return o.normalize()};o.toString=function(){if(o.a>=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return value<min?min:value>max?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/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(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/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(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={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]}})(jQuery);
+
+// the actual Flot code
+(function($) {
+
+       // Cache the prototype hasOwnProperty for faster access
+
+       var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+    // A shim to provide 'detach' to jQuery versions prior to 1.4.  Using a DOM
+    // operation produces the same effect as detach, i.e. removing the element
+    // without touching its jQuery data.
+
+    // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+.
+
+    if (!$.fn.detach) {
+        $.fn.detach = function() {
+            return this.each(function() {
+                if (this.parentNode) {
+                    this.parentNode.removeChild( this );
+                }
+            });
+        };
+    }
+
+       ///////////////////////////////////////////////////////////////////////////
+       // The Canvas object is a wrapper around an HTML5 <canvas> tag.
+       //
+       // @constructor
+       // @param {string} cls List of classes to apply to the canvas.
+       // @param {element} container Element onto which to append the canvas.
+       //
+       // Requiring a container is a little iffy, but unfortunately canvas
+       // operations don't work unless the canvas is attached to the DOM.
+
+       function Canvas(cls, container) {
+
+               var element = container.children("." + cls)[0];
+
+               if (element == null) {
+
+                       element = document.createElement("canvas");
+                       element.className = cls;
+
+                       $(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 })
+                               .appendTo(container);
+
+                       // If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas
+
+                       if (!element.getContext) {
+                               if (window.G_vmlCanvasManager) {
+                                       element = window.G_vmlCanvasManager.initElement(element);
+                               } else {
+                                       throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode.");
+                               }
+                       }
+               }
+
+               this.element = element;
+
+               var context = this.context = element.getContext("2d");
+
+               // Determine the screen's ratio of physical to device-independent
+               // pixels.  This is the ratio between the canvas width that the browser
+               // advertises and the number of pixels actually present in that space.
+
+               // The iPhone 4, for example, has a device-independent width of 320px,
+               // but its screen is actually 640px wide.  It therefore has a pixel
+               // ratio of 2, while most normal devices have a ratio of 1.
+
+               var devicePixelRatio = window.devicePixelRatio || 1,
+                       backingStoreRatio =
+                               context.webkitBackingStorePixelRatio ||
+                               context.mozBackingStorePixelRatio ||
+                               context.msBackingStorePixelRatio ||
+                               context.oBackingStorePixelRatio ||
+                               context.backingStorePixelRatio || 1;
+
+               this.pixelRatio = devicePixelRatio / backingStoreRatio;
+
+               // Size the canvas to match the internal dimensions of its container
+
+               this.resize(container.width(), container.height());
+
+               // Collection of HTML div layers for text overlaid onto the canvas
+
+               this.textContainer = null;
+               this.text = {};
+
+               // Cache of text fragments and metrics, so we can avoid expensively
+               // re-calculating them when the plot is re-rendered in a loop.
+
+               this._textCache = {};
+       }
+
+       // Resizes the canvas to the given dimensions.
+       //
+       // @param {number} width New width of the canvas, in pixels.
+       // @param {number} width New height of the canvas, in pixels.
+
+       Canvas.prototype.resize = function(width, height) {
+
+               if (width <= 0 || height <= 0) {
+                       throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height);
+               }
+
+               var element = this.element,
+                       context = this.context,
+                       pixelRatio = this.pixelRatio;
+
+               // Resize the canvas, increasing its density based on the display's
+               // pixel ratio; basically giving it more pixels without increasing the
+               // size of its element, to take advantage of the fact that retina
+               // displays have that many more pixels in the same advertised space.
+
+               // Resizing should reset the state (excanvas seems to be buggy though)
+
+               if (this.width != width) {
+                       element.width = width * pixelRatio;
+                       element.style.width = width + "px";
+                       this.width = width;
+               }
+
+               if (this.height != height) {
+                       element.height = height * pixelRatio;
+                       element.style.height = height + "px";
+                       this.height = height;
+               }
+
+               // Save the context, so we can reset in case we get replotted.  The
+               // restore ensure that we're really back at the initial state, and
+               // should be safe even if we haven't saved the initial state yet.
+
+               context.restore();
+               context.save();
+
+               // Scale the coordinate space to match the display density; so even though we
+               // may have twice as many pixels, we still want lines and other drawing to
+               // appear at the same size; the extra pixels will just make them crisper.
+
+               context.scale(pixelRatio, pixelRatio);
+       };
+
+       // Clears the entire canvas area, not including any overlaid HTML text
+
+       Canvas.prototype.clear = function() {
+               this.context.clearRect(0, 0, this.width, this.height);
+       };
+
+       // Finishes rendering the canvas, including managing the text overlay.
+
+       Canvas.prototype.render = function() {
+
+               var cache = this._textCache;
+
+               // For each text layer, add elements marked as active that haven't
+               // already been rendered, and remove those that are no longer active.
+
+               for (var layerKey in cache) {
+                       if (hasOwnProperty.call(cache, layerKey)) {
+
+                               var layer = this.getTextLayer(layerKey),
+                                       layerCache = cache[layerKey];
+
+                               layer.hide();
+
+                               for (var styleKey in layerCache) {
+                                       if (hasOwnProperty.call(layerCache, styleKey)) {
+                                               var styleCache = layerCache[styleKey];
+                                               for (var key in styleCache) {
+                                                       if (hasOwnProperty.call(styleCache, key)) {
+
+                                                               var positions = styleCache[key].positions;
+
+                                                               for (var i = 0, position; position = positions[i]; i++) {
+                                                                       if (position.active) {
+                                                                               if (!position.rendered) {
+                                                                                       layer.append(position.element);
+                                                                                       position.rendered = true;
+                                                                               }
+                                                                       } else {
+                                                                               positions.splice(i--, 1);
+                                                                               if (position.rendered) {
+                                                                                       position.element.detach();
+                                                                               }
+                                                                       }
+                                                               }
+
+                                                               if (positions.length == 0) {
+                                                                       delete styleCache[key];
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               layer.show();
+                       }
+               }
+       };
+
+       // Creates (if necessary) and returns the text overlay container.
+       //
+       // @param {string} classes String of space-separated CSS classes used to
+       //     uniquely identify the text layer.
+       // @return {object} The jQuery-wrapped text-layer div.
+
+       Canvas.prototype.getTextLayer = function(classes) {
+
+               var layer = this.text[classes];
+
+               // Create the text layer if it doesn't exist
+
+               if (layer == null) {
+
+                       // Create the text layer container, if it doesn't exist
+
+                       if (this.textContainer == null) {
+                               this.textContainer = $("<div class='flot-text'></div>")
+                                       .css({
+                                               position: "absolute",
+                                               top: 0,
+                                               left: 0,
+                                               bottom: 0,
+                                               right: 0,
+                                               'font-size': "smaller",
+                                               color: "#545454"
+                                       })
+                                       .insertAfter(this.element);
+                       }
+
+                       layer = this.text[classes] = $("<div></div>")
+                               .addClass(classes)
+                               .css({
+                                       position: "absolute",
+                                       top: 0,
+                                       left: 0,
+                                       bottom: 0,
+                                       right: 0
+                               })
+                               .appendTo(this.textContainer);
+               }
+
+               return layer;
+       };
+
+       // Creates (if necessary) and returns a text info object.
+       //
+       // The object looks like this:
+       //
+       // {
+       //     width: Width of the text's wrapper div.
+       //     height: Height of the text's wrapper div.
+       //     element: The jQuery-wrapped HTML div containing the text.
+       //     positions: Array of positions at which this text is drawn.
+       // }
+       //
+       // The positions array contains objects that look like this:
+       //
+       // {
+       //     active: Flag indicating whether the text should be visible.
+       //     rendered: Flag indicating whether the text is currently visible.
+       //     element: The jQuery-wrapped HTML div containing the text.
+       //     x: X coordinate at which to draw the text.
+       //     y: Y coordinate at which to draw the text.
+       // }
+       //
+       // Each position after the first receives a clone of the original element.
+       //
+       // The idea is that that the width, height, and general 'identity' of the
+       // text is constant no matter where it is placed; the placements are a
+       // secondary property.
+       //
+       // Canvas maintains a cache of recently-used text info objects; getTextInfo
+       // either returns the cached element or creates a new entry.
+       //
+       // @param {string} layer A string of space-separated CSS classes uniquely
+       //     identifying the layer containing this text.
+       // @param {string} text Text string to retrieve info for.
+       // @param {(string|object)=} font Either a string of space-separated CSS
+       //     classes or a font-spec object, defining the text's font and style.
+       // @param {number=} angle Angle at which to rotate the text, in degrees.
+       //     Angle is currently unused, it will be implemented in the future.
+       // @param {number=} width Maximum width of the text before it wraps.
+       // @return {object} a text info object.
+
+       Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) {
+
+               var textStyle, layerCache, styleCache, info;
+
+               // Cast the value to a string, in case we were given a number or such
+
+               text = "" + text;
+
+               // If the font is a font-spec object, generate a CSS font definition
+
+               if (typeof font === "object") {
+                       textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family;
+               } else {
+                       textStyle = font;
+               }
+
+               // Retrieve (or create) the cache for the text's layer and styles
+
+               layerCache = this._textCache[layer];
+
+               if (layerCache == null) {
+                       layerCache = this._textCache[layer] = {};
+               }
+
+               styleCache = layerCache[textStyle];
+
+               if (styleCache == null) {
+                       styleCache = layerCache[textStyle] = {};
+               }
+
+               info = styleCache[text];
+
+               // If we can't find a matching element in our cache, create a new one
+
+               if (info == null) {
+
+                       var element = $("<div></div>").html(text)
+                               .css({
+                                       position: "absolute",
+                                       'max-width': width,
+                                       top: -9999
+                               })
+                               .appendTo(this.getTextLayer(layer));
+
+                       if (typeof font === "object") {
+                               element.css({
+                                       font: textStyle,
+                                       color: font.color
+                               });
+                       } else if (typeof font === "string") {
+                               element.addClass(font);
+                       }
+
+                       info = styleCache[text] = {
+                               width: element.outerWidth(true),
+                               height: element.outerHeight(true),
+                               element: element,
+                               positions: []
+                       };
+
+                       element.detach();
+               }
+
+               return info;
+       };
+
+       // Adds a text string to the canvas text overlay.
+       //
+       // The text isn't drawn immediately; it is marked as rendering, which will
+       // result in its addition to the canvas on the next render pass.
+       //
+       // @param {string} layer A string of space-separated CSS classes uniquely
+       //     identifying the layer containing this text.
+       // @param {number} x X coordinate at which to draw the text.
+       // @param {number} y Y coordinate at which to draw the text.
+       // @param {string} text Text string to draw.
+       // @param {(string|object)=} font Either a string of space-separated CSS
+       //     classes or a font-spec object, defining the text's font and style.
+       // @param {number=} angle Angle at which to rotate the text, in degrees.
+       //     Angle is currently unused, it will be implemented in the future.
+       // @param {number=} width Maximum width of the text before it wraps.
+       // @param {string=} halign Horizontal alignment of the text; either "left",
+       //     "center" or "right".
+       // @param {string=} valign Vertical alignment of the text; either "top",
+       //     "middle" or "bottom".
+
+       Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) {
+
+               var info = this.getTextInfo(layer, text, font, angle, width),
+                       positions = info.positions;
+
+               // Tweak the div's position to match the text's alignment
+
+               if (halign == "center") {
+                       x -= info.width / 2;
+               } else if (halign == "right") {
+                       x -= info.width;
+               }
+
+               if (valign == "middle") {
+                       y -= info.height / 2;
+               } else if (valign == "bottom") {
+                       y -= info.height;
+               }
+
+               // Determine whether this text already exists at this position.
+               // If so, mark it for inclusion in the next render pass.
+
+               for (var i = 0, position; position = positions[i]; i++) {
+                       if (position.x == x && position.y == y) {
+                               position.active = true;
+                               return;
+                       }
+               }
+
+               // If the text doesn't exist at this position, create a new entry
+
+               // For the very first position we'll re-use the original element,
+               // while for subsequent ones we'll clone it.
+
+               position = {
+                       active: true,
+                       rendered: false,
+                       element: positions.length ? info.element.clone() : info.element,
+                       x: x,
+                       y: y
+               };
+
+               positions.push(position);
+
+               // Move the element to its final position within the container
+
+               position.element.css({
+                       top: Math.round(y),
+                       left: Math.round(x),
+                       'text-align': halign    // In case the text wraps
+               });
+       };
+
+       // Removes one or more text strings from the canvas text overlay.
+       //
+       // If no parameters are given, all text within the layer is removed.
+       //
+       // Note that the text is not immediately removed; it is simply marked as
+       // inactive, which will result in its removal on the next render pass.
+       // This avoids the performance penalty for 'clear and redraw' behavior,
+       // where we potentially get rid of all text on a layer, but will likely
+       // add back most or all of it later, as when redrawing axes, for example.
+       //
+       // @param {string} layer A string of space-separated CSS classes uniquely
+       //     identifying the layer containing this text.
+       // @param {number=} x X coordinate of the text.
+       // @param {number=} y Y coordinate of the text.
+       // @param {string=} text Text string to remove.
+       // @param {(string|object)=} font Either a string of space-separated CSS
+       //     classes or a font-spec object, defining the text's font and style.
+       // @param {number=} angle Angle at which the text is rotated, in degrees.
+       //     Angle is currently unused, it will be implemented in the future.
+
+       Canvas.prototype.removeText = function(layer, x, y, text, font, angle) {
+               if (text == null) {
+                       var layerCache = this._textCache[layer];
+                       if (layerCache != null) {
+                               for (var styleKey in layerCache) {
+                                       if (hasOwnProperty.call(layerCache, styleKey)) {
+                                               var styleCache = layerCache[styleKey];
+                                               for (var key in styleCache) {
+                                                       if (hasOwnProperty.call(styleCache, key)) {
+                                                               var positions = styleCache[key].positions;
+                                                               for (var i = 0, position; position = positions[i]; i++) {
+                                                                       position.active = false;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               } else {
+                       var positions = this.getTextInfo(layer, text, font, angle).positions;
+                       for (var i = 0, position; position = positions[i]; i++) {
+                               if (position.x == x && position.y == y) {
+                                       position.active = false;
+                               }
+                       }
+               }
+       };
+
+       ///////////////////////////////////////////////////////////////////////////
+       // The top-level container for the entire plot.
+
+    function Plot(placeholder, data_, options_, plugins) {
+        // data is on the form:
+        //   [ series1, series2 ... ]
+        // where series is either just the data as [ [x1, y1], [x2, y2], ... ]
+        // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... }
+
+        var series = [],
+            options = {
+                // the color theme used for graphs
+                colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"],
+                legend: {
+                    show: true,
+                    noColumns: 1, // number of colums in legend table
+                    labelFormatter: null, // fn: string -> string
+                    labelBoxBorderColor: "#ccc", // border color for the little label boxes
+                    container: null, // container (as jQuery object) to put legend in, null means default on top of graph
+                    position: "ne", // position of default legend container within plot
+                    margin: 5, // distance from grid edge to default legend container within plot
+                    backgroundColor: null, // null means auto-detect
+                    backgroundOpacity: 0.85, // set to 0 to avoid background
+                    sorted: null    // default to no legend sorting
+                },
+                xaxis: {
+                    show: null, // null = auto-detect, true = always, false = never
+                    position: "bottom", // or "top"
+                    mode: null, // null or "time"
+                    font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" }
+                    color: null, // base color, labels, ticks
+                    tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)"
+                    transform: null, // null or f: number -> number to transform axis
+                    inverseTransform: null, // if transform is set, this should be the inverse function
+                    min: null, // min. value to show, null means set automatically
+                    max: null, // max. value to show, null means set automatically
+                    autoscaleMargin: null, // margin in % to add if auto-setting min/max
+                    ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks
+                    tickFormatter: null, // fn: number -> string
+                    labelWidth: null, // size of tick labels in pixels
+                    labelHeight: null,
+                    reserveSpace: null, // whether to reserve space even if axis isn't shown
+                    tickLength: null, // size in pixels of ticks, or "full" for whole line
+                    alignTicksWithAxis: null, // axis number or null for no sync
+                    tickDecimals: null, // no. of decimals, null means auto
+                    tickSize: null, // number or [number, "unit"]
+                    minTickSize: null // number or [number, "unit"]
+                },
+                yaxis: {
+                    autoscaleMargin: 0.02,
+                    position: "left" // or "right"
+                },
+                xaxes: [],
+                yaxes: [],
+                series: {
+                    points: {
+                        show: false,
+                        radius: 3,
+                        lineWidth: 2, // in pixels
+                        fill: true,
+                        fillColor: "#ffffff",
+                        symbol: "circle" // or callback
+                    },
+                    lines: {
+                        // we don't put in show: false so we can see
+                        // whether lines were actively disabled
+                        lineWidth: 2, // in pixels
+                        fill: false,
+                        fillColor: null,
+                        steps: false
+                        // Omit 'zero', so we can later default its value to
+                        // match that of the 'fill' option.
+                    },
+                    bars: {
+                        show: false,
+                        lineWidth: 2, // in pixels
+                        barWidth: 1, // in units of the x axis
+                        fill: true,
+                        fillColor: null,
+                        align: "left", // "left", "right", or "center"
+                        horizontal: false,
+                        zero: true
+                    },
+                    shadowSize: 3,
+                    highlightColor: null
+                },
+                grid: {
+                    show: true,
+                    aboveData: false,
+                    color: "#545454", // primary color used for outline and labels
+                    backgroundColor: null, // null for transparent, else color
+                    borderColor: null, // set if different from the grid color
+                    tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)"
+                    margin: 0, // distance from the canvas edge to the grid
+                    labelMargin: 5, // in pixels
+                    axisMargin: 8, // in pixels
+                    borderWidth: 2, // in pixels
+                    minBorderMargin: null, // in pixels, null means taken from points radius
+                    markings: null, // array of ranges or fn: axes -> array of ranges
+                    markingsColor: "#f4f4f4",
+                    markingsLineWidth: 2,
+                    // interactive stuff
+                    clickable: false,
+                    hoverable: false,
+                    autoHighlight: true, // highlight in case mouse is near
+                    mouseActiveRadius: 10 // how far the mouse can be away to activate an item
+                },
+                interaction: {
+                    redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow
+                },
+                hooks: {}
+            },
+        surface = null,     // the canvas for the plot itself
+        overlay = null,     // canvas for interactive stuff on top of plot
+        eventHolder = null, // jQuery object that events should be bound to
+        ctx = null, octx = null,
+        xaxes = [], yaxes = [],
+        plotOffset = { left: 0, right: 0, top: 0, bottom: 0},
+        plotWidth = 0, plotHeight = 0,
+        hooks = {
+            processOptions: [],
+            processRawData: [],
+            processDatapoints: [],
+            processOffset: [],
+            drawBackground: [],
+            drawSeries: [],
+            draw: [],
+            bindEvents: [],
+            drawOverlay: [],
+            shutdown: []
+        },
+        plot = this;
+
+        // public functions
+        plot.setData = setData;
+        plot.setupGrid = setupGrid;
+        plot.draw = draw;
+        plot.getPlaceholder = function() { return placeholder; };
+        plot.getCanvas = function() { return surface.element; };
+        plot.getPlotOffset = function() { return plotOffset; };
+        plot.width = function () { return plotWidth; };
+        plot.height = function () { return plotHeight; };
+        plot.offset = function () {
+            var o = eventHolder.offset();
+            o.left += plotOffset.left;
+            o.top += plotOffset.top;
+            return o;
+        };
+        plot.getData = function () { return series; };
+        plot.getAxes = function () {
+            var res = {}, i;
+            $.each(xaxes.concat(yaxes), function (_, axis) {
+                if (axis)
+                    res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis;
+            });
+            return res;
+        };
+        plot.getXAxes = function () { return xaxes; };
+        plot.getYAxes = function () { return yaxes; };
+        plot.c2p = canvasToAxisCoords;
+        plot.p2c = axisToCanvasCoords;
+        plot.getOptions = function () { return options; };
+        plot.highlight = highlight;
+        plot.unhighlight = unhighlight;
+        plot.triggerRedrawOverlay = triggerRedrawOverlay;
+        plot.pointOffset = function(point) {
+            return {
+                left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10),
+                top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10)
+            };
+        };
+        plot.shutdown = shutdown;
+        plot.destroy = function () {
+            shutdown();
+            placeholder.removeData("plot").empty();
+
+            series = [];
+            options = null;
+            surface = null;
+            overlay = null;
+            eventHolder = null;
+            ctx = null;
+            octx = null;
+            xaxes = [];
+            yaxes = [];
+            hooks = null;
+            highlights = [];
+            plot = null;
+        };
+        plot.resize = function () {
+               var width = placeholder.width(),
+                       height = placeholder.height();
+            surface.resize(width, height);
+            overlay.resize(width, height);
+        };
+
+        // public attributes
+        plot.hooks = hooks;
+
+        // initialize
+        initPlugins(plot);
+        parseOptions(options_);
+        setupCanvases();
+        setData(data_);
+        setupGrid();
+        draw();
+        bindEvents();
+
+
+        function executeHooks(hook, args) {
+            args = [plot].concat(args);
+            for (var i = 0; i < hook.length; ++i)
+                hook[i].apply(this, args);
+        }
+
+        function initPlugins() {
+
+            // References to key classes, allowing plugins to modify them
+
+            var classes = {
+                Canvas: Canvas
+            };
+
+            for (var i = 0; i < plugins.length; ++i) {
+                var p = plugins[i];
+                p.init(plot, classes);
+                if (p.options)
+                    $.extend(true, options, p.options);
+            }
+        }
+
+        function parseOptions(opts) {
+
+            $.extend(true, options, opts);
+
+            // $.extend merges arrays, rather than replacing them.  When less
+            // colors are provided than the size of the default palette, we
+            // end up with those colors plus the remaining defaults, which is
+            // not expected behavior; avoid it by replacing them here.
+
+            if (opts && opts.colors) {
+               options.colors = opts.colors;
+            }
+
+            if (options.xaxis.color == null)
+                options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();
+            if (options.yaxis.color == null)
+                options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString();
+
+            if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility
+                options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color;
+            if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility
+                options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color;
+
+            if (options.grid.borderColor == null)
+                options.grid.borderColor = options.grid.color;
+            if (options.grid.tickColor == null)
+                options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString();
+
+            // Fill in defaults for axis options, including any unspecified
+            // font-spec fields, if a font-spec was provided.
+
+            // If no x/y axis options were provided, create one of each anyway,
+            // since the rest of the code assumes that they exist.
+
+            var i, axisOptions, axisCount,
+                fontSize = placeholder.css("font-size"),
+                fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13,
+                fontDefaults = {
+                    style: placeholder.css("font-style"),
+                    size: Math.round(0.8 * fontSizeDefault),
+                    variant: placeholder.css("font-variant"),
+                    weight: placeholder.css("font-weight"),
+                    family: placeholder.css("font-family")
+                };
+
+            axisCount = options.xaxes.length || 1;
+            for (i = 0; i < axisCount; ++i) {
+
+                axisOptions = options.xaxes[i];
+                if (axisOptions && !axisOptions.tickColor) {
+                    axisOptions.tickColor = axisOptions.color;
+                }
+
+                axisOptions = $.extend(true, {}, options.xaxis, axisOptions);
+                options.xaxes[i] = axisOptions;
+
+                if (axisOptions.font) {
+                    axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);
+                    if (!axisOptions.font.color) {
+                        axisOptions.font.color = axisOptions.color;
+                    }
+                    if (!axisOptions.font.lineHeight) {
+                        axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
+                    }
+                }
+            }
+
+            axisCount = options.yaxes.length || 1;
+            for (i = 0; i < axisCount; ++i) {
+
+                axisOptions = options.yaxes[i];
+                if (axisOptions && !axisOptions.tickColor) {
+                    axisOptions.tickColor = axisOptions.color;
+                }
+
+                axisOptions = $.extend(true, {}, options.yaxis, axisOptions);
+                options.yaxes[i] = axisOptions;
+
+                if (axisOptions.font) {
+                    axisOptions.font = $.extend({}, fontDefaults, axisOptions.font);
+                    if (!axisOptions.font.color) {
+                        axisOptions.font.color = axisOptions.color;
+                    }
+                    if (!axisOptions.font.lineHeight) {
+                        axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15);
+                    }
+                }
+            }
+
+            // backwards compatibility, to be removed in future
+            if (options.xaxis.noTicks && options.xaxis.ticks == null)
+                options.xaxis.ticks = options.xaxis.noTicks;
+            if (options.yaxis.noTicks && options.yaxis.ticks == null)
+                options.yaxis.ticks = options.yaxis.noTicks;
+            if (options.x2axis) {
+                options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis);
+                options.xaxes[1].position = "top";
+                // Override the inherit to allow the axis to auto-scale
+                if (options.x2axis.min == null) {
+                    options.xaxes[1].min = null;
+                }
+                if (options.x2axis.max == null) {
+                    options.xaxes[1].max = null;
+                }
+            }
+            if (options.y2axis) {
+                options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis);
+                options.yaxes[1].position = "right";
+                // Override the inherit to allow the axis to auto-scale
+                if (options.y2axis.min == null) {
+                    options.yaxes[1].min = null;
+                }
+                if (options.y2axis.max == null) {
+                    options.yaxes[1].max = null;
+                }
+            }
+            if (options.grid.coloredAreas)
+                options.grid.markings = options.grid.coloredAreas;
+            if (options.grid.coloredAreasColor)
+                options.grid.markingsColor = options.grid.coloredAreasColor;
+            if (options.lines)
+                $.extend(true, options.series.lines, options.lines);
+            if (options.points)
+                $.extend(true, options.series.points, options.points);
+            if (options.bars)
+                $.extend(true, options.series.bars, options.bars);
+            if (options.shadowSize != null)
+                options.series.shadowSize = options.shadowSize;
+            if (options.highlightColor != null)
+                options.series.highlightColor = options.highlightColor;
+
+            // save options on axes for future reference
+            for (i = 0; i < options.xaxes.length; ++i)
+                getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i];
+            for (i = 0; i < options.yaxes.length; ++i)
+                getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i];
+
+            // add hooks from options
+            for (var n in hooks)
+                if (options.hooks[n] && options.hooks[n].length)
+                    hooks[n] = hooks[n].concat(options.hooks[n]);
+
+            executeHooks(hooks.processOptions, [options]);
+        }
+
+        function setData(d) {
+            series = parseData(d);
+            fillInSeriesOptions();
+            processData();
+        }
+
+        function parseData(d) {
+            var res = [];
+            for (var i = 0; i < d.length; ++i) {
+                var s = $.extend(true, {}, options.series);
+
+                if (d[i].data != null) {
+                    s.data = d[i].data; // move the data instead of deep-copy
+                    delete d[i].data;
+
+                    $.extend(true, s, d[i]);
+
+                    d[i].data = s.data;
+                }
+                else
+                    s.data = d[i];
+                res.push(s);
+            }
+
+            return res;
+        }
+
+        function axisNumber(obj, coord) {
+            var a = obj[coord + "axis"];
+            if (typeof a == "object") // if we got a real axis, extract number
+                a = a.n;
+            if (typeof a != "number")
+                a = 1; // default to first axis
+            return a;
+        }
+
+        function allAxes() {
+            // return flat array without annoying null entries
+            return $.grep(xaxes.concat(yaxes), function (a) { return a; });
+        }
+
+        function canvasToAxisCoords(pos) {
+            // return an object with x/y corresponding to all used axes
+            var res = {}, i, axis;
+            for (i = 0; i < xaxes.length; ++i) {
+                axis = xaxes[i];
+                if (axis && axis.used)
+                    res["x" + axis.n] = axis.c2p(pos.left);
+            }
+
+            for (i = 0; i < yaxes.length; ++i) {
+                axis = yaxes[i];
+                if (axis && axis.used)
+                    res["y" + axis.n] = axis.c2p(pos.top);
+            }
+
+            if (res.x1 !== undefined)
+                res.x = res.x1;
+            if (res.y1 !== undefined)
+                res.y = res.y1;
+
+            return res;
+        }
+
+        function axisToCanvasCoords(pos) {
+            // get canvas coords from the first pair of x/y found in pos
+            var res = {}, i, axis, key;
+
+            for (i = 0; i < xaxes.length; ++i) {
+                axis = xaxes[i];
+                if (axis && axis.used) {
+                    key = "x" + axis.n;
+                    if (pos[key] == null && axis.n == 1)
+                        key = "x";
+
+                    if (pos[key] != null) {
+                        res.left = axis.p2c(pos[key]);
+                        break;
+                    }
+                }
+            }
+
+            for (i = 0; i < yaxes.length; ++i) {
+                axis = yaxes[i];
+                if (axis && axis.used) {
+                    key = "y" + axis.n;
+                    if (pos[key] == null && axis.n == 1)
+                        key = "y";
+
+                    if (pos[key] != null) {
+                        res.top = axis.p2c(pos[key]);
+                        break;
+                    }
+                }
+            }
+
+            return res;
+        }
+
+        function getOrCreateAxis(axes, number) {
+            if (!axes[number - 1])
+                axes[number - 1] = {
+                    n: number, // save the number for future reference
+                    direction: axes == xaxes ? "x" : "y",
+                    options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis)
+                };
+
+            return axes[number - 1];
+        }
+
+        function fillInSeriesOptions() {
+
+            var neededColors = series.length, maxIndex = -1, i;
+
+            // Subtract the number of series that already have fixed colors or
+            // color indexes from the number that we still need to generate.
+
+            for (i = 0; i < series.length; ++i) {
+                var sc = series[i].color;
+                if (sc != null) {
+                    neededColors--;
+                    if (typeof sc == "number" && sc > maxIndex) {
+                        maxIndex = sc;
+                    }
+                }
+            }
+
+            // If any of the series have fixed color indexes, then we need to
+            // generate at least as many colors as the highest index.
+
+            if (neededColors <= maxIndex) {
+                neededColors = maxIndex + 1;
+            }
+
+            // Generate all the colors, using first the option colors and then
+            // variations on those colors once they're exhausted.
+
+            var c, colors = [], colorPool = options.colors,
+                colorPoolSize = colorPool.length, variation = 0;
+
+            for (i = 0; i < neededColors; i++) {
+
+                c = $.color.parse(colorPool[i % colorPoolSize] || "#666");
+
+                // Each time we exhaust the colors in the pool we adjust
+                // a scaling factor used to produce more variations on
+                // those colors. The factor alternates negative/positive
+                // to produce lighter/darker colors.
+
+                // Reset the variation after every few cycles, or else
+                // it will end up producing only white or black colors.
+
+                if (i % colorPoolSize == 0 && i) {
+                    if (variation >= 0) {
+                        if (variation < 0.5) {
+                            variation = -variation - 0.2;
+                        } else variation = 0;
+                    } else variation = -variation;
+                }
+
+                colors[i] = c.scale('rgb', 1 + variation);
+            }
+
+            // Finalize the series options, filling in their colors
+
+            var colori = 0, s;
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+
+                // assign colors
+                if (s.color == null) {
+                    s.color = colors[colori].toString();
+                    ++colori;
+                }
+                else if (typeof s.color == "number")
+                    s.color = colors[s.color].toString();
+
+                // turn on lines automatically in case nothing is set
+                if (s.lines.show == null) {
+                    var v, show = true;
+                    for (v in s)
+                        if (s[v] && s[v].show) {
+                            show = false;
+                            break;
+                        }
+                    if (show)
+                        s.lines.show = true;
+                }
+
+                // If nothing was provided for lines.zero, default it to match
+                // lines.fill, since areas by default should extend to zero.
+
+                if (s.lines.zero == null) {
+                    s.lines.zero = !!s.lines.fill;
+                }
+
+                // setup axes
+                s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x"));
+                s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y"));
+            }
+        }
+
+        function processData() {
+            var topSentry = Number.POSITIVE_INFINITY,
+                bottomSentry = Number.NEGATIVE_INFINITY,
+                fakeInfinity = Number.MAX_VALUE,
+                i, j, k, m, length,
+                s, points, ps, x, y, axis, val, f, p,
+                data, format;
+
+            function updateAxis(axis, min, max) {
+                if (min < axis.datamin && min != -fakeInfinity)
+                    axis.datamin = min;
+                if (max > axis.datamax && max != fakeInfinity)
+                    axis.datamax = max;
+            }
+
+            $.each(allAxes(), function (_, axis) {
+                // init axis
+                axis.datamin = topSentry;
+                axis.datamax = bottomSentry;
+                axis.used = false;
+            });
+
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+                s.datapoints = { points: [] };
+
+                executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]);
+            }
+
+            // first pass: clean and copy data
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+
+                data = s.data;
+                format = s.datapoints.format;
+
+                if (!format) {
+                    format = [];
+                    // find out how to copy
+                    format.push({ x: true, number: true, required: true });
+                    format.push({ y: true, number: true, required: true });
+
+                    if (s.bars.show || (s.lines.show && s.lines.fill)) {
+                        var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero));
+                        format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale });
+                        if (s.bars.horizontal) {
+                            delete format[format.length - 1].y;
+                            format[format.length - 1].x = true;
+                        }
+                    }
+
+                    s.datapoints.format = format;
+                }
+
+                if (s.datapoints.pointsize != null)
+                    continue; // already filled in
+
+                s.datapoints.pointsize = format.length;
+
+                ps = s.datapoints.pointsize;
+                points = s.datapoints.points;
+
+                var insertSteps = s.lines.show && s.lines.steps;
+                s.xaxis.used = s.yaxis.used = true;
+
+                for (j = k = 0; j < data.length; ++j, k += ps) {
+                    p = data[j];
+
+                    var nullify = p == null;
+                    if (!nullify) {
+                        for (m = 0; m < ps; ++m) {
+                            val = p[m];
+                            f = format[m];
+
+                            if (f) {
+                                if (f.number && val != null) {
+                                    val = +val; // convert to number
+                                    if (isNaN(val))
+                                        val = null;
+                                    else if (val == Infinity)
+                                        val = fakeInfinity;
+                                    else if (val == -Infinity)
+                                        val = -fakeInfinity;
+                                }
+
+                                if (val == null) {
+                                    if (f.required)
+                                        nullify = true;
+
+                                    if (f.defaultValue != null)
+                                        val = f.defaultValue;
+                                }
+                            }
+
+                            points[k + m] = val;
+                        }
+                    }
+
+                    if (nullify) {
+                        for (m = 0; m < ps; ++m) {
+                            val = points[k + m];
+                            if (val != null) {
+                                f = format[m];
+                                // extract min/max info
+                                if (f.autoscale !== false) {
+                                    if (f.x) {
+                                        updateAxis(s.xaxis, val, val);
+                                    }
+                                    if (f.y) {
+                                        updateAxis(s.yaxis, val, val);
+                                    }
+                                }
+                            }
+                            points[k + m] = null;
+                        }
+                    }
+                    else {
+                        // a little bit of line specific stuff that
+                        // perhaps shouldn't be here, but lacking
+                        // better means...
+                        if (insertSteps && k > 0
+                            && points[k - ps] != null
+                            && points[k - ps] != points[k]
+                            && points[k - ps + 1] != points[k + 1]) {
+                            // copy the point to make room for a middle point
+                            for (m = 0; m < ps; ++m)
+                                points[k + ps + m] = points[k + m];
+
+                            // middle point has same y
+                            points[k + 1] = points[k - ps + 1];
+
+                            // we've added a point, better reflect that
+                            k += ps;
+                        }
+                    }
+                }
+            }
+
+            // give the hooks a chance to run
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+
+                executeHooks(hooks.processDatapoints, [ s, s.datapoints]);
+            }
+
+            // second pass: find datamax/datamin for auto-scaling
+            for (i = 0; i < series.length; ++i) {
+                s = series[i];
+                points = s.datapoints.points;
+                ps = s.datapoints.pointsize;
+                format = s.datapoints.format;
+
+                var xmin = topSentry, ymin = topSentry,
+                    xmax = bottomSentry, ymax = bottomSentry;
+
+                for (j = 0; j < points.length; j += ps) {
+                    if (points[j] == null)
+                        continue;
+
+                    for (m = 0; m < ps; ++m) {
+                        val = points[j + m];
+                        f = format[m];
+                        if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity)
+                            continue;
+
+                        if (f.x) {
+                            if (val < xmin)
+                                xmin = val;
+                            if (val > xmax)
+                                xmax = val;
+                        }
+                        if (f.y) {
+                            if (val < ymin)
+                                ymin = val;
+                            if (val > ymax)
+                                ymax = val;
+                        }
+                    }
+                }
+
+                if (s.bars.show) {
+                    // make sure we got room for the bar on the dancing floor
+                    var delta;
+
+                    switch (s.bars.align) {
+                        case "left":
+                            delta = 0;
+                            break;
+                        case "right":
+                            delta = -s.bars.barWidth;
+                            break;
+                        default:
+                            delta = -s.bars.barWidth / 2;
+                    }
+
+                    if (s.bars.horizontal) {
+                        ymin += delta;
+                        ymax += delta + s.bars.barWidth;
+                    }
+                    else {
+                        xmin += delta;
+                        xmax += delta + s.bars.barWidth;
+                    }
+                }
+
+                updateAxis(s.xaxis, xmin, xmax);
+                updateAxis(s.yaxis, ymin, ymax);
+            }
+
+            $.each(allAxes(), function (_, axis) {
+                if (axis.datamin == topSentry)
+                    axis.datamin = null;
+                if (axis.datamax == bottomSentry)
+                    axis.datamax = null;
+            });
+        }
+
+        function setupCanvases() {
+
+            // Make sure the placeholder is clear of everything except canvases
+            // from a previous plot in this container that we'll try to re-use.
+
+            placeholder.css("padding", 0) // padding messes up the positioning
+                .children().filter(function(){
+                    return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base');
+                }).remove();
+
+            if (placeholder.css("position") == 'static')
+                placeholder.css("position", "relative"); // for positioning labels and overlay
+
+            surface = new Canvas("flot-base", placeholder);
+            overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features
+
+            ctx = surface.context;
+            octx = overlay.context;
+
+            // define which element we're listening for events on
+            eventHolder = $(overlay.element).unbind();
+
+            // If we're re-using a plot object, shut down the old one
+
+            var existing = placeholder.data("plot");
+
+            if (existing) {
+                existing.shutdown();
+                overlay.clear();
+            }
+
+            // save in case we get replotted
+            placeholder.data("plot", plot);
+        }
+
+        function bindEvents() {
+            // bind events
+            if (options.grid.hoverable) {
+                eventHolder.mousemove(onMouseMove);
+
+                // Use bind, rather than .mouseleave, because we officially
+                // still support jQuery 1.2.6, which doesn't define a shortcut
+                // for mouseenter or mouseleave.  This was a bug/oversight that
+                // was fixed somewhere around 1.3.x.  We can return to using
+                // .mouseleave when we drop support for 1.2.6.
+
+                eventHolder.bind("mouseleave", onMouseLeave);
+            }
+
+            if (options.grid.clickable)
+                eventHolder.click(onClick);
+
+            executeHooks(hooks.bindEvents, [eventHolder]);
+        }
+
+        function shutdown() {
+            if (redrawTimeout)
+                clearTimeout(redrawTimeout);
+
+            eventHolder.unbind("mousemove", onMouseMove);
+            eventHolder.unbind("mouseleave", onMouseLeave);
+            eventHolder.unbind("click", onClick);
+
+            executeHooks(hooks.shutdown, [eventHolder]);
+        }
+
+        function setTransformationHelpers(axis) {
+            // set helper functions on the axis, assumes plot area
+            // has been computed already
+
+            function identity(x) { return x; }
+
+            var s, m, t = axis.options.transform || identity,
+                it = axis.options.inverseTransform;
+
+            // precompute how much the axis is scaling a point
+            // in canvas space
+            if (axis.direction == "x") {
+                s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min));
+                m = Math.min(t(axis.max), t(axis.min));
+            }
+            else {
+                s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min));
+                s = -s;
+                m = Math.max(t(axis.max), t(axis.min));
+            }
+
+            // data point to canvas coordinate
+            if (t == identity) // slight optimization
+                axis.p2c = function (p) { return (p - m) * s; };
+            else
+                axis.p2c = function (p) { return (t(p) - m) * s; };
+            // canvas coordinate to data point
+            if (!it)
+                axis.c2p = function (c) { return m + c / s; };
+            else
+                axis.c2p = function (c) { return it(m + c / s); };
+        }
+
+        function measureTickLabels(axis) {
+
+            var opts = axis.options,
+                ticks = axis.ticks || [],
+                labelWidth = opts.labelWidth || 0,
+                labelHeight = opts.labelHeight || 0,
+                maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null),
+                legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
+                layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
+                font = opts.font || "flot-tick-label tickLabel";
+
+            for (var i = 0; i < ticks.length; ++i) {
+
+                var t = ticks[i];
+
+                if (!t.label)
+                    continue;
+
+                var info = surface.getTextInfo(layer, t.label, font, null, maxWidth);
+
+                labelWidth = Math.max(labelWidth, info.width);
+                labelHeight = Math.max(labelHeight, info.height);
+            }
+
+            axis.labelWidth = opts.labelWidth || labelWidth;
+            axis.labelHeight = opts.labelHeight || labelHeight;
+        }
+
+        function allocateAxisBoxFirstPhase(axis) {
+            // find the bounding box of the axis by looking at label
+            // widths/heights and ticks, make room by diminishing the
+            // plotOffset; this first phase only looks at one
+            // dimension per axis, the other dimension depends on the
+            // other axes so will have to wait
+
+            var lw = axis.labelWidth,
+                lh = axis.labelHeight,
+                pos = axis.options.position,
+                isXAxis = axis.direction === "x",
+                tickLength = axis.options.tickLength,
+                axisMargin = options.grid.axisMargin,
+                padding = options.grid.labelMargin,
+                innermost = true,
+                outermost = true,
+                first = true,
+                found = false;
+
+            // Determine the axis's position in its direction and on its side
+
+            $.each(isXAxis ? xaxes : yaxes, function(i, a) {
+                if (a && (a.show || a.reserveSpace)) {
+                    if (a === axis) {
+                        found = true;
+                    } else if (a.options.position === pos) {
+                        if (found) {
+                            outermost = false;
+                        } else {
+                            innermost = false;
+                        }
+                    }
+                    if (!found) {
+                        first = false;
+                    }
+                }
+            });
+
+            // The outermost axis on each side has no margin
+
+            if (outermost) {
+                axisMargin = 0;
+            }
+
+            // The ticks for the first axis in each direction stretch across
+
+            if (tickLength == null) {
+                tickLength = first ? "full" : 5;
+            }
+
+            if (!isNaN(+tickLength))
+                padding += +tickLength;
+
+            if (isXAxis) {
+                lh += padding;
+
+                if (pos == "bottom") {
+                    plotOffset.bottom += lh + axisMargin;
+                    axis.box = { top: surface.height - plotOffset.bottom, height: lh };
+                }
+                else {
+                    axis.box = { top: plotOffset.top + axisMargin, height: lh };
+                    plotOffset.top += lh + axisMargin;
+                }
+            }
+            else {
+                lw += padding;
+
+                if (pos == "left") {
+                    axis.box = { left: plotOffset.left + axisMargin, width: lw };
+                    plotOffset.left += lw + axisMargin;
+                }
+                else {
+                    plotOffset.right += lw + axisMargin;
+                    axis.box = { left: surface.width - plotOffset.right, width: lw };
+                }
+            }
+
+             // save for future reference
+            axis.position = pos;
+            axis.tickLength = tickLength;
+            axis.box.padding = padding;
+            axis.innermost = innermost;
+        }
+
+        function allocateAxisBoxSecondPhase(axis) {
+            // now that all axis boxes have been placed in one
+            // dimension, we can set the remaining dimension coordinates
+            if (axis.direction == "x") {
+                axis.box.left = plotOffset.left - axis.labelWidth / 2;
+                axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth;
+            }
+            else {
+                axis.box.top = plotOffset.top - axis.labelHeight / 2;
+                axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight;
+            }
+        }
+
+        function adjustLayoutForThingsStickingOut() {
+            // possibly adjust plot offset to ensure everything stays
+            // inside the canvas and isn't clipped off
+
+            var minMargin = options.grid.minBorderMargin,
+                axis, i;
+
+            // check stuff from the plot (FIXME: this should just read
+            // a value from the series, otherwise it's impossible to
+            // customize)
+            if (minMargin == null) {
+                minMargin = 0;
+                for (i = 0; i < series.length; ++i)
+                    minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2));
+            }
+
+            var margins = {
+                left: minMargin,
+                right: minMargin,
+                top: minMargin,
+                bottom: minMargin
+            };
+
+            // check axis labels, note we don't check the actual
+            // labels but instead use the overall width/height to not
+            // jump as much around with replots
+            $.each(allAxes(), function (_, axis) {
+                if (axis.reserveSpace && axis.ticks && axis.ticks.length) {
+                    if (axis.direction === "x") {
+                        margins.left = Math.max(margins.left, axis.labelWidth / 2);
+                        margins.right = Math.max(margins.right, axis.labelWidth / 2);
+                    } else {
+                        margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2);
+                        margins.top = Math.max(margins.top, axis.labelHeight / 2);
+                    }
+                }
+            });
+
+            plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left));
+            plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right));
+            plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top));
+            plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom));
+        }
+
+        function setupGrid() {
+            var i, axes = allAxes(), showGrid = options.grid.show;
+
+            // Initialize the plot's offset from the edge of the canvas
+
+            for (var a in plotOffset) {
+                var margin = options.grid.margin || 0;
+                plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0;
+            }
+
+            executeHooks(hooks.processOffset, [plotOffset]);
+
+            // If the grid is visible, add its border width to the offset
+
+            for (var a in plotOffset) {
+                if(typeof(options.grid.borderWidth) == "object") {
+                    plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0;
+                }
+                else {
+                    plotOffset[a] += showGrid ? options.grid.borderWidth : 0;
+                }
+            }
+
+            $.each(axes, function (_, axis) {
+                var axisOpts = axis.options;
+                axis.show = axisOpts.show == null ? axis.used : axisOpts.show;
+                axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace;
+                setRange(axis);
+            });
+
+            if (showGrid) {
+
+                var allocatedAxes = $.grep(axes, function (axis) {
+                    return axis.show || axis.reserveSpace;
+                });
+
+                $.each(allocatedAxes, function (_, axis) {
+                    // make the ticks
+                    setupTickGeneration(axis);
+                    setTicks(axis);
+                    snapRangeToTicks(axis, axis.ticks);
+                    // find labelWidth/Height for axis
+                    measureTickLabels(axis);
+                });
+
+                // with all dimensions calculated, we can compute the
+                // axis bounding boxes, start from the outside
+                // (reverse order)
+                for (i = allocatedAxes.length - 1; i >= 0; --i)
+                    allocateAxisBoxFirstPhase(allocatedAxes[i]);
+
+                // make sure we've got enough space for things that
+                // might stick out
+                adjustLayoutForThingsStickingOut();
+
+                $.each(allocatedAxes, function (_, axis) {
+                    allocateAxisBoxSecondPhase(axis);
+                });
+            }
+
+            plotWidth = surface.width - plotOffset.left - plotOffset.right;
+            plotHeight = surface.height - plotOffset.bottom - plotOffset.top;
+
+            // now we got the proper plot dimensions, we can compute the scaling
+            $.each(axes, function (_, axis) {
+                setTransformationHelpers(axis);
+            });
+
+            if (showGrid) {
+                drawAxisLabels();
+            }
+
+            insertLegend();
+        }
+
+        function setRange(axis) {
+            var opts = axis.options,
+                min = +(opts.min != null ? opts.min : axis.datamin),
+                max = +(opts.max != null ? opts.max : axis.datamax),
+                delta = max - min;
+
+            if (delta == 0.0) {
+                // degenerate case
+                var widen = max == 0 ? 1 : 0.01;
+
+                if (opts.min == null)
+                    min -= widen;
+                // always widen max if we couldn't widen min to ensure we
+                // don't fall into min == max which doesn't work
+                if (opts.max == null || opts.min != null)
+                    max += widen;
+            }
+            else {
+                // consider autoscaling
+                var margin = opts.autoscaleMargin;
+                if (margin != null) {
+                    if (opts.min == null) {
+                        min -= delta * margin;
+                        // make sure we don't go below zero if all values
+                        // are positive
+                        if (min < 0 && axis.datamin != null && axis.datamin >= 0)
+                            min = 0;
+                    }
+                    if (opts.max == null) {
+                        max += delta * margin;
+                        if (max > 0 && axis.datamax != null && axis.datamax <= 0)
+                            max = 0;
+                    }
+                }
+            }
+            axis.min = min;
+            axis.max = max;
+        }
+
+        function setupTickGeneration(axis) {
+            var opts = axis.options;
+
+            // estimate number of ticks
+            var noTicks;
+            if (typeof opts.ticks == "number" && opts.ticks > 0)
+                noTicks = opts.ticks;
+            else
+                // heuristic based on the model a*sqrt(x) fitted to
+                // some data points that seemed reasonable
+                noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height);
+
+            var delta = (axis.max - axis.min) / noTicks,
+                dec = -Math.floor(Math.log(delta) / Math.LN10),
+                maxDec = opts.tickDecimals;
+
+            if (maxDec != null && dec > maxDec) {
+                dec = maxDec;
+            }
+
+            var magn = Math.pow(10, -dec),
+                norm = delta / magn, // norm is between 1.0 and 10.0
+                size;
+
+            if (norm < 1.5) {
+                size = 1;
+            } else if (norm < 3) {
+                size = 2;
+                // special case for 2.5, requires an extra decimal
+                if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) {
+                    size = 2.5;
+                    ++dec;
+                }
+            } else if (norm < 7.5) {
+                size = 5;
+            } else {
+                size = 10;
+            }
+
+            size *= magn;
+
+            if (opts.minTickSize != null && size < opts.minTickSize) {
+                size = opts.minTickSize;
+            }
+
+            axis.delta = delta;
+            axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec);
+            axis.tickSize = opts.tickSize || size;
+
+            // Time mode was moved to a plug-in in 0.8, and since so many people use it
+            // we'll add an especially friendly reminder to make sure they included it.
+
+            if (opts.mode == "time" && !axis.tickGenerator) {
+                throw new Error("Time mode requires the flot.time plugin.");
+            }
+
+            // Flot supports base-10 axes; any other mode else is handled by a plug-in,
+            // like flot.time.js.
+
+            if (!axis.tickGenerator) {
+
+                axis.tickGenerator = function (axis) {
+
+                    var ticks = [],
+                        start = floorInBase(axis.min, axis.tickSize),
+                        i = 0,
+                        v = Number.NaN,
+                        prev;
+
+                    do {
+                        prev = v;
+                        v = start + i * axis.tickSize;
+                        ticks.push(v);
+                        ++i;
+                    } while (v < axis.max && v != prev);
+                    return ticks;
+                };
+
+                               axis.tickFormatter = function (value, axis) {
+
+                                       var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1;
+                                       var formatted = "" + Math.round(value * factor) / factor;
+
+                                       // If tickDecimals was specified, ensure that we have exactly that
+                                       // much precision; otherwise default to the value's own precision.
+
+                                       if (axis.tickDecimals != null) {
+                                               var decimal = formatted.indexOf(".");
+                                               var precision = decimal == -1 ? 0 : formatted.length - decimal - 1;
+                                               if (precision < axis.tickDecimals) {
+                                                       return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision);
+                                               }
+                                       }
+
+                    return formatted;
+                };
+            }
+
+            if ($.isFunction(opts.tickFormatter))
+                axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); };
+
+            if (opts.alignTicksWithAxis != null) {
+                var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1];
+                if (otherAxis && otherAxis.used && otherAxis != axis) {
+                    // consider snapping min/max to outermost nice ticks
+                    var niceTicks = axis.tickGenerator(axis);
+                    if (niceTicks.length > 0) {
+                        if (opts.min == null)
+                            axis.min = Math.min(axis.min, niceTicks[0]);
+                        if (opts.max == null && niceTicks.length > 1)
+                            axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]);
+                    }
+
+                    axis.tickGenerator = function (axis) {
+                        // copy ticks, scaled to this axis
+                        var ticks = [], v, i;
+                        for (i = 0; i < otherAxis.ticks.length; ++i) {
+                            v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min);
+                            v = axis.min + v * (axis.max - axis.min);
+                            ticks.push(v);
+                        }
+                        return ticks;
+                    };
+
+                    // we might need an extra decimal since forced
+                    // ticks don't necessarily fit naturally
+                    if (!axis.mode && opts.tickDecimals == null) {
+                        var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1),
+                            ts = axis.tickGenerator(axis);
+
+                        // only proceed if the tick interval rounded
+                        // with an extra decimal doesn't give us a
+                        // zero at end
+                        if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec))))
+                            axis.tickDecimals = extraDec;
+                    }
+                }
+            }
+        }
+
+        function setTicks(axis) {
+            var oticks = axis.options.ticks, ticks = [];
+            if (oticks == null || (typeof oticks == "number" && oticks > 0))
+                ticks = axis.tickGenerator(axis);
+            else if (oticks) {
+                if ($.isFunction(oticks))
+                    // generate the ticks
+                    ticks = oticks(axis);
+                else
+                    ticks = oticks;
+            }
+
+            // clean up/labelify the supplied ticks, copy them over
+            var i, v;
+            axis.ticks = [];
+            for (i = 0; i < ticks.length; ++i) {
+                var label = null;
+                var t = ticks[i];
+                if (typeof t == "object") {
+                    v = +t[0];
+                    if (t.length > 1)
+                        label = t[1];
+                }
+                else
+                    v = +t;
+                if (label == null)
+                    label = axis.tickFormatter(v, axis);
+                if (!isNaN(v))
+                    axis.ticks.push({ v: v, label: label });
+            }
+        }
+
+        function snapRangeToTicks(axis, ticks) {
+            if (axis.options.autoscaleMargin && ticks.length > 0) {
+                // snap to ticks
+                if (axis.options.min == null)
+                    axis.min = Math.min(axis.min, ticks[0].v);
+                if (axis.options.max == null && ticks.length > 1)
+                    axis.max = Math.max(axis.max, ticks[ticks.length - 1].v);
+            }
+        }
+
+        function draw() {
+
+            surface.clear();
+
+            executeHooks(hooks.drawBackground, [ctx]);
+
+            var grid = options.grid;
+
+            // draw background, if any
+            if (grid.show && grid.backgroundColor)
+                drawBackground();
+
+            if (grid.show && !grid.aboveData) {
+                drawGrid();
+            }
+
+            for (var i = 0; i < series.length; ++i) {
+                executeHooks(hooks.drawSeries, [ctx, series[i]]);
+                drawSeries(series[i]);
+            }
+
+            executeHooks(hooks.draw, [ctx]);
+
+            if (grid.show && grid.aboveData) {
+                drawGrid();
+            }
+
+            surface.render();
+
+            // A draw implies that either the axes or data have changed, so we
+            // should probably update the overlay highlights as well.
+
+            triggerRedrawOverlay();
+        }
+
+        function extractRange(ranges, coord) {
+            var axis, from, to, key, axes = allAxes();
+
+            for (var i = 0; i < axes.length; ++i) {
+                axis = axes[i];
+                if (axis.direction == coord) {
+                    key = coord + axis.n + "axis";
+                    if (!ranges[key] && axis.n == 1)
+                        key = coord + "axis"; // support x1axis as xaxis
+                    if (ranges[key]) {
+                        from = ranges[key].from;
+                        to = ranges[key].to;
+                        break;
+                    }
+                }
+            }
+
+            // backwards-compat stuff - to be removed in future
+            if (!ranges[key]) {
+                axis = coord == "x" ? xaxes[0] : yaxes[0];
+                from = ranges[coord + "1"];
+                to = ranges[coord + "2"];
+            }
+
+            // auto-reverse as an added bonus
+            if (from != null && to != null && from > to) {
+                var tmp = from;
+                from = to;
+                to = tmp;
+            }
+
+            return { from: from, to: to, axis: axis };
+        }
+
+        function drawBackground() {
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+
+            ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)");
+            ctx.fillRect(0, 0, plotWidth, plotHeight);
+            ctx.restore();
+        }
+
+        function drawGrid() {
+            var i, axes, bw, bc;
+
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+
+            // draw markings
+            var markings = options.grid.markings;
+            if (markings) {
+                if ($.isFunction(markings)) {
+                    axes = plot.getAxes();
+                    // xmin etc. is backwards compatibility, to be
+                    // removed in the future
+                    axes.xmin = axes.xaxis.min;
+                    axes.xmax = axes.xaxis.max;
+                    axes.ymin = axes.yaxis.min;
+                    axes.ymax = axes.yaxis.max;
+
+                    markings = markings(axes);
+                }
+
+                for (i = 0; i < markings.length; ++i) {
+                    var m = markings[i],
+                        xrange = extractRange(m, "x"),
+                        yrange = extractRange(m, "y");
+
+                    // fill in missing
+                    if (xrange.from == null)
+                        xrange.from = xrange.axis.min;
+                    if (xrange.to == null)
+                        xrange.to = xrange.axis.max;
+                    if (yrange.from == null)
+                        yrange.from = yrange.axis.min;
+                    if (yrange.to == null)
+                        yrange.to = yrange.axis.max;
+
+                    // clip
+                    if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max ||
+                        yrange.to < yrange.axis.min || yrange.from > yrange.axis.max)
+                        continue;
+
+                    xrange.from = Math.max(xrange.from, xrange.axis.min);
+                    xrange.to = Math.min(xrange.to, xrange.axis.max);
+                    yrange.from = Math.max(yrange.from, yrange.axis.min);
+                    yrange.to = Math.min(yrange.to, yrange.axis.max);
+
+                    var xequal = xrange.from === xrange.to,
+                        yequal = yrange.from === yrange.to;
+
+                    if (xequal && yequal) {
+                        continue;
+                    }
+
+                    // then draw
+                    xrange.from = Math.floor(xrange.axis.p2c(xrange.from));
+                    xrange.to = Math.floor(xrange.axis.p2c(xrange.to));
+                    yrange.from = Math.floor(yrange.axis.p2c(yrange.from));
+                    yrange.to = Math.floor(yrange.axis.p2c(yrange.to));
+
+                    if (xequal || yequal) {
+                        var lineWidth = m.lineWidth || options.grid.markingsLineWidth,
+                            subPixel = lineWidth % 2 ? 0.5 : 0;
+                        ctx.beginPath();
+                        ctx.strokeStyle = m.color || options.grid.markingsColor;
+                        ctx.lineWidth = lineWidth;
+                        if (xequal) {
+                            ctx.moveTo(xrange.to + subPixel, yrange.from);
+                            ctx.lineTo(xrange.to + subPixel, yrange.to);
+                        } else {
+                            ctx.moveTo(xrange.from, yrange.to + subPixel);
+                            ctx.lineTo(xrange.to, yrange.to + subPixel);                            
+                        }
+                        ctx.stroke();
+                    } else {
+                        ctx.fillStyle = m.color || options.grid.markingsColor;
+                        ctx.fillRect(xrange.from, yrange.to,
+                                     xrange.to - xrange.from,
+                                     yrange.from - yrange.to);
+                    }
+                }
+            }
+
+            // draw the ticks
+            axes = allAxes();
+            bw = options.grid.borderWidth;
+
+            for (var j = 0; j < axes.length; ++j) {
+                var axis = axes[j], box = axis.box,
+                    t = axis.tickLength, x, y, xoff, yoff;
+                if (!axis.show || axis.ticks.length == 0)
+                    continue;
+
+                ctx.lineWidth = 1;
+
+                // find the edges
+                if (axis.direction == "x") {
+                    x = 0;
+                    if (t == "full")
+                        y = (axis.position == "top" ? 0 : plotHeight);
+                    else
+                        y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0);
+                }
+                else {
+                    y = 0;
+                    if (t == "full")
+                        x = (axis.position == "left" ? 0 : plotWidth);
+                    else
+                        x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0);
+                }
+
+                // draw tick bar
+                if (!axis.innermost) {
+                    ctx.strokeStyle = axis.options.color;
+                    ctx.beginPath();
+                    xoff = yoff = 0;
+                    if (axis.direction == "x")
+                        xoff = plotWidth + 1;
+                    else
+                        yoff = plotHeight + 1;
+
+                    if (ctx.lineWidth == 1) {
+                        if (axis.direction == "x") {
+                            y = Math.floor(y) + 0.5;
+                        } else {
+                            x = Math.floor(x) + 0.5;
+                        }
+                    }
+
+                    ctx.moveTo(x, y);
+                    ctx.lineTo(x + xoff, y + yoff);
+                    ctx.stroke();
+                }
+
+                // draw ticks
+
+                ctx.strokeStyle = axis.options.tickColor;
+
+                ctx.beginPath();
+                for (i = 0; i < axis.ticks.length; ++i) {
+                    var v = axis.ticks[i].v;
+
+                    xoff = yoff = 0;
+
+                    if (isNaN(v) || v < axis.min || v > axis.max
+                        // skip those lying on the axes if we got a border
+                        || (t == "full"
+                            && ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0)
+                            && (v == axis.min || v == axis.max)))
+                        continue;
+
+                    if (axis.direction == "x") {
+                        x = axis.p2c(v);
+                        yoff = t == "full" ? -plotHeight : t;
+
+                        if (axis.position == "top")
+                            yoff = -yoff;
+                    }
+                    else {
+                        y = axis.p2c(v);
+                        xoff = t == "full" ? -plotWidth : t;
+
+                        if (axis.position == "left")
+                            xoff = -xoff;
+                    }
+
+                    if (ctx.lineWidth == 1) {
+                        if (axis.direction == "x")
+                            x = Math.floor(x) + 0.5;
+                        else
+                            y = Math.floor(y) + 0.5;
+                    }
+
+                    ctx.moveTo(x, y);
+                    ctx.lineTo(x + xoff, y + yoff);
+                }
+
+                ctx.stroke();
+            }
+
+
+            // draw border
+            if (bw) {
+                // If either borderWidth or borderColor is an object, then draw the border
+                // line by line instead of as one rectangle
+                bc = options.grid.borderColor;
+                if(typeof bw == "object" || typeof bc == "object") {
+                    if (typeof bw !== "object") {
+                        bw = {top: bw, right: bw, bottom: bw, left: bw};
+                    }
+                    if (typeof bc !== "object") {
+                        bc = {top: bc, right: bc, bottom: bc, left: bc};
+                    }
+
+                    if (bw.top > 0) {
+                        ctx.strokeStyle = bc.top;
+                        ctx.lineWidth = bw.top;
+                        ctx.beginPath();
+                        ctx.moveTo(0 - bw.left, 0 - bw.top/2);
+                        ctx.lineTo(plotWidth, 0 - bw.top/2);
+                        ctx.stroke();
+                    }
+
+                    if (bw.right > 0) {
+                        ctx.strokeStyle = bc.right;
+                        ctx.lineWidth = bw.right;
+                        ctx.beginPath();
+                        ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top);
+                        ctx.lineTo(plotWidth + bw.right / 2, plotHeight);
+                        ctx.stroke();
+                    }
+
+                    if (bw.bottom > 0) {
+                        ctx.strokeStyle = bc.bottom;
+                        ctx.lineWidth = bw.bottom;
+                        ctx.beginPath();
+                        ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2);
+                        ctx.lineTo(0, plotHeight + bw.bottom / 2);
+                        ctx.stroke();
+                    }
+
+                    if (bw.left > 0) {
+                        ctx.strokeStyle = bc.left;
+                        ctx.lineWidth = bw.left;
+                        ctx.beginPath();
+                        ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom);
+                        ctx.lineTo(0- bw.left/2, 0);
+                        ctx.stroke();
+                    }
+                }
+                else {
+                    ctx.lineWidth = bw;
+                    ctx.strokeStyle = options.grid.borderColor;
+                    ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw);
+                }
+            }
+
+            ctx.restore();
+        }
+
+        function drawAxisLabels() {
+
+            $.each(allAxes(), function (_, axis) {
+                var box = axis.box,
+                    legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis",
+                    layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles,
+                    font = axis.options.font || "flot-tick-label tickLabel",
+                    tick, x, y, halign, valign;
+
+                // Remove text before checking for axis.show and ticks.length;
+                // otherwise plugins, like flot-tickrotor, that draw their own
+                // tick labels will end up with both theirs and the defaults.
+
+                surface.removeText(layer);
+
+                if (!axis.show || axis.ticks.length == 0)
+                    return;
+
+                for (var i = 0; i < axis.ticks.length; ++i) {
+
+                    tick = axis.ticks[i];
+                    if (!tick.label || tick.v < axis.min || tick.v > axis.max)
+                        continue;
+
+                    if (axis.direction == "x") {
+                        halign = "center";
+                        x = plotOffset.left + axis.p2c(tick.v);
+                        if (axis.position == "bottom") {
+                            y = box.top + box.padding;
+                        } else {
+                            y = box.top + box.height - box.padding;
+                            valign = "bottom";
+                        }
+                    } else {
+                        valign = "middle";
+                        y = plotOffset.top + axis.p2c(tick.v);
+                        if (axis.position == "left") {
+                            x = box.left + box.width - box.padding;
+                            halign = "right";
+                        } else {
+                            x = box.left + box.padding;
+                        }
+                    }
+
+                    surface.addText(layer, x, y, tick.label, font, null, null, halign, valign);
+                }
+            });
+        }
+
+        function drawSeries(series) {
+            if (series.lines.show)
+                drawSeriesLines(series);
+            if (series.bars.show)
+                drawSeriesBars(series);
+            if (series.points.show)
+                drawSeriesPoints(series);
+        }
+
+        function drawSeriesLines(series) {
+            function plotLine(datapoints, xoffset, yoffset, axisx, axisy) {
+                var points = datapoints.points,
+                    ps = datapoints.pointsize,
+                    prevx = null, prevy = null;
+
+                ctx.beginPath();
+                for (var i = ps; i < points.length; i += ps) {
+                    var x1 = points[i - ps], y1 = points[i - ps + 1],
+                        x2 = points[i], y2 = points[i + 1];
+
+                    if (x1 == null || x2 == null)
+                        continue;
+
+                    // clip with ymin
+                    if (y1 <= y2 && y1 < axisy.min) {
+                        if (y2 < axisy.min)
+                            continue;   // line segment is outside
+                        // compute new intersection point
+                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y1 = axisy.min;
+                    }
+                    else if (y2 <= y1 && y2 < axisy.min) {
+                        if (y1 < axisy.min)
+                            continue;
+                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y2 = axisy.min;
+                    }
+
+                    // clip with ymax
+                    if (y1 >= y2 && y1 > axisy.max) {
+                        if (y2 > axisy.max)
+                            continue;
+                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y1 = axisy.max;
+                    }
+                    else if (y2 >= y1 && y2 > axisy.max) {
+                        if (y1 > axisy.max)
+                            continue;
+                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y2 = axisy.max;
+                    }
+
+                    // clip with xmin
+                    if (x1 <= x2 && x1 < axisx.min) {
+                        if (x2 < axisx.min)
+                            continue;
+                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x1 = axisx.min;
+                    }
+                    else if (x2 <= x1 && x2 < axisx.min) {
+                        if (x1 < axisx.min)
+                            continue;
+                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x2 = axisx.min;
+                    }
+
+                    // clip with xmax
+                    if (x1 >= x2 && x1 > axisx.max) {
+                        if (x2 > axisx.max)
+                            continue;
+                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x1 = axisx.max;
+                    }
+                    else if (x2 >= x1 && x2 > axisx.max) {
+                        if (x1 > axisx.max)
+                            continue;
+                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x2 = axisx.max;
+                    }
+
+                    if (x1 != prevx || y1 != prevy)
+                        ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset);
+
+                    prevx = x2;
+                    prevy = y2;
+                    ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset);
+                }
+                ctx.stroke();
+            }
+
+            function plotLineArea(datapoints, axisx, axisy) {
+                var points = datapoints.points,
+                    ps = datapoints.pointsize,
+                    bottom = Math.min(Math.max(0, axisy.min), axisy.max),
+                    i = 0, top, areaOpen = false,
+                    ypos = 1, segmentStart = 0, segmentEnd = 0;
+
+                // we process each segment in two turns, first forward
+                // direction to sketch out top, then once we hit the
+                // end we go backwards to sketch the bottom
+                while (true) {
+                    if (ps > 0 && i > points.length + ps)
+                        break;
+
+                    i += ps; // ps is negative if going backwards
+
+                    var x1 = points[i - ps],
+                        y1 = points[i - ps + ypos],
+                        x2 = points[i], y2 = points[i + ypos];
+
+                    if (areaOpen) {
+                        if (ps > 0 && x1 != null && x2 == null) {
+                            // at turning point
+                            segmentEnd = i;
+                            ps = -ps;
+                            ypos = 2;
+                            continue;
+                        }
+
+                        if (ps < 0 && i == segmentStart + ps) {
+                            // done with the reverse sweep
+                            ctx.fill();
+                            areaOpen = false;
+                            ps = -ps;
+                            ypos = 1;
+                            i = segmentStart = segmentEnd + ps;
+                            continue;
+                        }
+                    }
+
+                    if (x1 == null || x2 == null)
+                        continue;
+
+                    // clip x values
+
+                    // clip with xmin
+                    if (x1 <= x2 && x1 < axisx.min) {
+                        if (x2 < axisx.min)
+                            continue;
+                        y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x1 = axisx.min;
+                    }
+                    else if (x2 <= x1 && x2 < axisx.min) {
+                        if (x1 < axisx.min)
+                            continue;
+                        y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x2 = axisx.min;
+                    }
+
+                    // clip with xmax
+                    if (x1 >= x2 && x1 > axisx.max) {
+                        if (x2 > axisx.max)
+                            continue;
+                        y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x1 = axisx.max;
+                    }
+                    else if (x2 >= x1 && x2 > axisx.max) {
+                        if (x1 > axisx.max)
+                            continue;
+                        y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1;
+                        x2 = axisx.max;
+                    }
+
+                    if (!areaOpen) {
+                        // open area
+                        ctx.beginPath();
+                        ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom));
+                        areaOpen = true;
+                    }
+
+                    // now first check the case where both is outside
+                    if (y1 >= axisy.max && y2 >= axisy.max) {
+                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max));
+                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max));
+                        continue;
+                    }
+                    else if (y1 <= axisy.min && y2 <= axisy.min) {
+                        ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min));
+                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min));
+                        continue;
+                    }
+
+                    // else it's a bit more complicated, there might
+                    // be a flat maxed out rectangle first, then a
+                    // triangular cutout or reverse; to find these
+                    // keep track of the current x values
+                    var x1old = x1, x2old = x2;
+
+                    // clip the y values, without shortcutting, we
+                    // go through all cases in turn
+
+                    // clip with ymin
+                    if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) {
+                        x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y1 = axisy.min;
+                    }
+                    else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) {
+                        x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y2 = axisy.min;
+                    }
+
+                    // clip with ymax
+                    if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) {
+                        x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y1 = axisy.max;
+                    }
+                    else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) {
+                        x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1;
+                        y2 = axisy.max;
+                    }
+
+                    // if the x value was changed we got a rectangle
+                    // to fill
+                    if (x1 != x1old) {
+                        ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1));
+                        // it goes to (x1, y1), but we fill that below
+                    }
+
+                    // fill triangular section, this sometimes result
+                    // in redundant points if (x1, y1) hasn't changed
+                    // from previous line to, but we just ignore that
+                    ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1));
+                    ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
+
+                    // fill the other rectangle if it's there
+                    if (x2 != x2old) {
+                        ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2));
+                        ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2));
+                    }
+                }
+            }
+
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+            ctx.lineJoin = "round";
+
+            var lw = series.lines.lineWidth,
+                sw = series.shadowSize;
+            // FIXME: consider another form of shadow when filling is turned on
+            if (lw > 0 && sw > 0) {
+                // draw shadow as a thick and thin line with transparency
+                ctx.lineWidth = sw;
+                ctx.strokeStyle = "rgba(0,0,0,0.1)";
+                // position shadow at angle from the mid of line
+                var angle = Math.PI/18;
+                plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis);
+                ctx.lineWidth = sw/2;
+                plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis);
+            }
+
+            ctx.lineWidth = lw;
+            ctx.strokeStyle = series.color;
+            var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight);
+            if (fillStyle) {
+                ctx.fillStyle = fillStyle;
+                plotLineArea(series.datapoints, series.xaxis, series.yaxis);
+            }
+
+            if (lw > 0)
+                plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis);
+            ctx.restore();
+        }
+
+        function drawSeriesPoints(series) {
+            function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) {
+                var points = datapoints.points, ps = datapoints.pointsize;
+
+                for (var i = 0; i < points.length; i += ps) {
+                    var x = points[i], y = points[i + 1];
+                    if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
+                        continue;
+
+                    ctx.beginPath();
+                    x = axisx.p2c(x);
+                    y = axisy.p2c(y) + offset;
+                    if (symbol == "circle")
+                        ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false);
+                    else
+                        symbol(ctx, x, y, radius, shadow);
+                    ctx.closePath();
+
+                    if (fillStyle) {
+                        ctx.fillStyle = fillStyle;
+                        ctx.fill();
+                    }
+                    ctx.stroke();
+                }
+            }
+
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+
+            var lw = series.points.lineWidth,
+                sw = series.shadowSize,
+                radius = series.points.radius,
+                symbol = series.points.symbol;
+
+            // If the user sets the line width to 0, we change it to a very 
+            // small value. A line width of 0 seems to force the default of 1.
+            // Doing the conditional here allows the shadow setting to still be 
+            // optional even with a lineWidth of 0.
+
+            if( lw == 0 )
+                lw = 0.0001;
+
+            if (lw > 0 && sw > 0) {
+                // draw shadow in two steps
+                var w = sw / 2;
+                ctx.lineWidth = w;
+                ctx.strokeStyle = "rgba(0,0,0,0.1)";
+                plotPoints(series.datapoints, radius, null, w + w/2, true,
+                           series.xaxis, series.yaxis, symbol);
+
+                ctx.strokeStyle = "rgba(0,0,0,0.2)";
+                plotPoints(series.datapoints, radius, null, w/2, true,
+                           series.xaxis, series.yaxis, symbol);
+            }
+
+            ctx.lineWidth = lw;
+            ctx.strokeStyle = series.color;
+            plotPoints(series.datapoints, radius,
+                       getFillStyle(series.points, series.color), 0, false,
+                       series.xaxis, series.yaxis, symbol);
+            ctx.restore();
+        }
+
+        function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) {
+            var left, right, bottom, top,
+                drawLeft, drawRight, drawTop, drawBottom,
+                tmp;
+
+            // in horizontal mode, we start the bar from the left
+            // instead of from the bottom so it appears to be
+            // horizontal rather than vertical
+            if (horizontal) {
+                drawBottom = drawRight = drawTop = true;
+                drawLeft = false;
+                left = b;
+                right = x;
+                top = y + barLeft;
+                bottom = y + barRight;
+
+                // account for negative bars
+                if (right < left) {
+                    tmp = right;
+                    right = left;
+                    left = tmp;
+                    drawLeft = true;
+                    drawRight = false;
+                }
+            }
+            else {
+                drawLeft = drawRight = drawTop = true;
+                drawBottom = false;
+                left = x + barLeft;
+                right = x + barRight;
+                bottom = b;
+                top = y;
+
+                // account for negative bars
+                if (top < bottom) {
+                    tmp = top;
+                    top = bottom;
+                    bottom = tmp;
+                    drawBottom = true;
+                    drawTop = false;
+                }
+            }
+
+            // clip
+            if (right < axisx.min || left > axisx.max ||
+                top < axisy.min || bottom > axisy.max)
+                return;
+
+            if (left < axisx.min) {
+                left = axisx.min;
+                drawLeft = false;
+            }
+
+            if (right > axisx.max) {
+                right = axisx.max;
+                drawRight = false;
+            }
+
+            if (bottom < axisy.min) {
+                bottom = axisy.min;
+                drawBottom = false;
+            }
+
+            if (top > axisy.max) {
+                top = axisy.max;
+                drawTop = false;
+            }
+
+            left = axisx.p2c(left);
+            bottom = axisy.p2c(bottom);
+            right = axisx.p2c(right);
+            top = axisy.p2c(top);
+
+            // fill the bar
+            if (fillStyleCallback) {
+                c.fillStyle = fillStyleCallback(bottom, top);
+                c.fillRect(left, top, right - left, bottom - top)
+            }
+
+            // draw outline
+            if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) {
+                c.beginPath();
+
+                // FIXME: inline moveTo is buggy with excanvas
+                c.moveTo(left, bottom);
+                if (drawLeft)
+                    c.lineTo(left, top);
+                else
+                    c.moveTo(left, top);
+                if (drawTop)
+                    c.lineTo(right, top);
+                else
+                    c.moveTo(right, top);
+                if (drawRight)
+                    c.lineTo(right, bottom);
+                else
+                    c.moveTo(right, bottom);
+                if (drawBottom)
+                    c.lineTo(left, bottom);
+                else
+                    c.moveTo(left, bottom);
+                c.stroke();
+            }
+        }
+
+        function drawSeriesBars(series) {
+            function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) {
+                var points = datapoints.points, ps = datapoints.pointsize;
+
+                for (var i = 0; i < points.length; i += ps) {
+                    if (points[i] == null)
+                        continue;
+                    drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth);
+                }
+            }
+
+            ctx.save();
+            ctx.translate(plotOffset.left, plotOffset.top);
+
+            // FIXME: figure out a way to add shadows (for instance along the right edge)
+            ctx.lineWidth = series.bars.lineWidth;
+            ctx.strokeStyle = series.color;
+
+            var barLeft;
+
+            switch (series.bars.align) {
+                case "left":
+                    barLeft = 0;
+                    break;
+                case "right":
+                    barLeft = -series.bars.barWidth;
+                    break;
+                default:
+                    barLeft = -series.bars.barWidth / 2;
+            }
+
+            var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null;
+            plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis);
+            ctx.restore();
+        }
+
+        function getFillStyle(filloptions, seriesColor, bottom, top) {
+            var fill = filloptions.fill;
+            if (!fill)
+                return null;
+
+            if (filloptions.fillColor)
+                return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor);
+
+            var c = $.color.parse(seriesColor);
+            c.a = typeof fill == "number" ? fill : 0.4;
+            c.normalize();
+            return c.toString();
+        }
+
+        function insertLegend() {
+
+            if (options.legend.container != null) {
+                $(options.legend.container).html("");
+            } else {
+                placeholder.find(".legend").remove();
+            }
+
+            if (!options.legend.show) {
+                return;
+            }
+
+            var fragments = [], entries = [], rowStarted = false,
+                lf = options.legend.labelFormatter, s, label;
+
+            // Build a list of legend entries, with each having a label and a color
+
+            for (var i = 0; i < series.length; ++i) {
+                s = series[i];
+                if (s.label) {
+                    label = lf ? lf(s.label, s) : s.label;
+                    if (label) {
+                        entries.push({
+                            label: label,
+                            color: s.color
+                        });
+                    }
+                }
+            }
+
+            // Sort the legend using either the default or a custom comparator
+
+            if (options.legend.sorted) {
+                if ($.isFunction(options.legend.sorted)) {
+                    entries.sort(options.legend.sorted);
+                } else if (options.legend.sorted == "reverse") {
+                       entries.reverse();
+                } else {
+                    var ascending = options.legend.sorted != "descending";
+                    entries.sort(function(a, b) {
+                        return a.label == b.label ? 0 : (
+                            (a.label < b.label) != ascending ? 1 : -1   // Logical XOR
+                        );
+                    });
+                }
+            }
+
+            // Generate markup for the list of entries, in their final order
+
+            for (var i = 0; i < entries.length; ++i) {
+
+                var entry = entries[i];
+
+                if (i % options.legend.noColumns == 0) {
+                    if (rowStarted)
+                        fragments.push('</tr>');
+                    fragments.push('<tr>');
+                    rowStarted = true;
+                }
+
+                fragments.push(
+                    '<td class="legendColorBox"><div style="border:1px solid ' + options.legend.labelBoxBorderColor + ';padding:1px"><div style="width:4px;height:0;border:5px solid ' + entry.color + ';overflow:hidden"></div></div></td>' +
+                    '<td class="legendLabel">' + entry.label + '</td>'
+                );
+            }
+
+            if (rowStarted)
+                fragments.push('</tr>');
+
+            if (fragments.length == 0)
+                return;
+
+            var table = '<table style="font-size:smaller;color:' + options.grid.color + '">' + fragments.join("") + '</table>';
+            if (options.legend.container != null)
+                $(options.legend.container).html(table);
+            else {
+                var pos = "",
+                    p = options.legend.position,
+                    m = options.legend.margin;
+                if (m[0] == null)
+                    m = [m, m];
+                if (p.charAt(0) == "n")
+                    pos += 'top:' + (m[1] + plotOffset.top) + 'px;';
+                else if (p.charAt(0) == "s")
+                    pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;';
+                if (p.charAt(1) == "e")
+                    pos += 'right:' + (m[0] + plotOffset.right) + 'px;';
+                else if (p.charAt(1) == "w")
+                    pos += 'left:' + (m[0] + plotOffset.left) + 'px;';
+                var legend = $('<div class="legend">' + table.replace('style="', 'style="position:absolute;' + pos +';') + '</div>').appendTo(placeholder);
+                if (options.legend.backgroundOpacity != 0.0) {
+                    // put in the transparent background
+                    // separately to avoid blended labels and
+                    // label boxes
+                    var c = options.legend.backgroundColor;
+                    if (c == null) {
+                        c = options.grid.backgroundColor;
+                        if (c && typeof c == "string")
+                            c = $.color.parse(c);
+                        else
+                            c = $.color.extract(legend, 'background-color');
+                        c.a = 1;
+                        c = c.toString();
+                    }
+                    var div = legend.children();
+                    $('<div style="position:absolute;width:' + div.width() + 'px;height:' + div.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').prependTo(legend).css('opacity', options.legend.backgroundOpacity);
+                }
+            }
+        }
+
+
+        // interactive features
+
+        var highlights = [],
+            redrawTimeout = null;
+
+        // returns the data item the mouse is over, or null if none is found
+        function findNearbyItem(mouseX, mouseY, seriesFilter) {
+            var maxDistance = options.grid.mouseActiveRadius,
+                smallestDistance = maxDistance * maxDistance + 1,
+                item = null, foundPoint = false, i, j, ps;
+
+            for (i = series.length - 1; i >= 0; --i) {
+                if (!seriesFilter(series[i]))
+                    continue;
+
+                var s = series[i],
+                    axisx = s.xaxis,
+                    axisy = s.yaxis,
+                    points = s.datapoints.points,
+                    mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster
+                    my = axisy.c2p(mouseY),
+                    maxx = maxDistance / axisx.scale,
+                    maxy = maxDistance / axisy.scale;
+
+                ps = s.datapoints.pointsize;
+                // with inverse transforms, we can't use the maxx/maxy
+                // optimization, sadly
+                if (axisx.options.inverseTransform)
+                    maxx = Number.MAX_VALUE;
+                if (axisy.options.inverseTransform)
+                    maxy = Number.MAX_VALUE;
+
+                if (s.lines.show || s.points.show) {
+                    for (j = 0; j < points.length; j += ps) {
+                        var x = points[j], y = points[j + 1];
+                        if (x == null)
+                            continue;
+
+                        // For points and lines, the cursor must be within a
+                        // certain distance to the data point
+                        if (x - mx > maxx || x - mx < -maxx ||
+                            y - my > maxy || y - my < -maxy)
+                            continue;
+
+                        // We have to calculate distances in pixels, not in
+                        // data units, because the scales of the axes may be different
+                        var dx = Math.abs(axisx.p2c(x) - mouseX),
+                            dy = Math.abs(axisy.p2c(y) - mouseY),
+                            dist = dx * dx + dy * dy; // we save the sqrt
+
+                        // use <= to ensure last point takes precedence
+                        // (last generally means on top of)
+                        if (dist < smallestDistance) {
+                            smallestDistance = dist;
+                            item = [i, j / ps];
+                        }
+                    }
+                }
+
+                if (s.bars.show && !item) { // no other point can be nearby
+
+                    var barLeft, barRight;
+
+                    switch (s.bars.align) {
+                        case "left":
+                            barLeft = 0;
+                            break;
+                        case "right":
+                            barLeft = -s.bars.barWidth;
+                            break;
+                        default:
+                            barLeft = -s.bars.barWidth / 2;
+                    }
+
+                    barRight = barLeft + s.bars.barWidth;
+
+                    for (j = 0; j < points.length; j += ps) {
+                        var x = points[j], y = points[j + 1], b = points[j + 2];
+                        if (x == null)
+                            continue;
+
+                        // for a bar graph, the cursor must be inside the bar
+                        if (series[i].bars.horizontal ?
+                            (mx <= Math.max(b, x) && mx >= Math.min(b, x) &&
+                             my >= y + barLeft && my <= y + barRight) :
+                            (mx >= x + barLeft && mx <= x + barRight &&
+                             my >= Math.min(b, y) && my <= Math.max(b, y)))
+                                item = [i, j / ps];
+                    }
+                }
+            }
+
+            if (item) {
+                i = item[0];
+                j = item[1];
+                ps = series[i].datapoints.pointsize;
+
+                return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps),
+                         dataIndex: j,
+                         series: series[i],
+                         seriesIndex: i };
+            }
+
+            return null;
+        }
+
+        function onMouseMove(e) {
+            if (options.grid.hoverable)
+                triggerClickHoverEvent("plothover", e,
+                                       function (s) { return s["hoverable"] != false; });
+        }
+
+        function onMouseLeave(e) {
+            if (options.grid.hoverable)
+                triggerClickHoverEvent("plothover", e,
+                                       function (s) { return false; });
+        }
+
+        function onClick(e) {
+            triggerClickHoverEvent("plotclick", e,
+                                   function (s) { return s["clickable"] != false; });
+        }
+
+        // trigger click or hover event (they send the same parameters
+        // so we share their code)
+        function triggerClickHoverEvent(eventname, event, seriesFilter) {
+            var offset = eventHolder.offset(),
+                canvasX = event.pageX - offset.left - plotOffset.left,
+                canvasY = event.pageY - offset.top - plotOffset.top,
+            pos = canvasToAxisCoords({ left: canvasX, top: canvasY });
+
+            pos.pageX = event.pageX;
+            pos.pageY = event.pageY;
+
+            var item = findNearbyItem(canvasX, canvasY, seriesFilter);
+
+            if (item) {
+                // fill in mouse pos for any listeners out there
+                item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10);
+                item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10);
+            }
+
+            if (options.grid.autoHighlight) {
+                // clear auto-highlights
+                for (var i = 0; i < highlights.length; ++i) {
+                    var h = highlights[i];
+                    if (h.auto == eventname &&
+                        !(item && h.series == item.series &&
+                          h.point[0] == item.datapoint[0] &&
+                          h.point[1] == item.datapoint[1]))
+                        unhighlight(h.series, h.point);
+                }
+
+                if (item)
+                    highlight(item.series, item.datapoint, eventname);
+            }
+
+            placeholder.trigger(eventname, [ pos, item ]);
+        }
+
+        function triggerRedrawOverlay() {
+            var t = options.interaction.redrawOverlayInterval;
+            if (t == -1) {      // skip event queue
+                drawOverlay();
+                return;
+            }
+
+            if (!redrawTimeout)
+                redrawTimeout = setTimeout(drawOverlay, t);
+        }
+
+        function drawOverlay() {
+            redrawTimeout = null;
+
+            // draw highlights
+            octx.save();
+            overlay.clear();
+            octx.translate(plotOffset.left, plotOffset.top);
+
+            var i, hi;
+            for (i = 0; i < highlights.length; ++i) {
+                hi = highlights[i];
+
+                if (hi.series.bars.show)
+                    drawBarHighlight(hi.series, hi.point);
+                else
+                    drawPointHighlight(hi.series, hi.point);
+            }
+            octx.restore();
+
+            executeHooks(hooks.drawOverlay, [octx]);
+        }
+
+        function highlight(s, point, auto) {
+            if (typeof s == "number")
+                s = series[s];
+
+            if (typeof point == "number") {
+                var ps = s.datapoints.pointsize;
+                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
+            }
+
+            var i = indexOfHighlight(s, point);
+            if (i == -1) {
+                highlights.push({ series: s, point: point, auto: auto });
+
+                triggerRedrawOverlay();
+            }
+            else if (!auto)
+                highlights[i].auto = false;
+        }
+
+        function unhighlight(s, point) {
+            if (s == null && point == null) {
+                highlights = [];
+                triggerRedrawOverlay();
+                return;
+            }
+
+            if (typeof s == "number")
+                s = series[s];
+
+            if (typeof point == "number") {
+                var ps = s.datapoints.pointsize;
+                point = s.datapoints.points.slice(ps * point, ps * (point + 1));
+            }
+
+            var i = indexOfHighlight(s, point);
+            if (i != -1) {
+                highlights.splice(i, 1);
+
+                triggerRedrawOverlay();
+            }
+        }
+
+        function indexOfHighlight(s, p) {
+            for (var i = 0; i < highlights.length; ++i) {
+                var h = highlights[i];
+                if (h.series == s && h.point[0] == p[0]
+                    && h.point[1] == p[1])
+                    return i;
+            }
+            return -1;
+        }
+
+        function drawPointHighlight(series, point) {
+            var x = point[0], y = point[1],
+                axisx = series.xaxis, axisy = series.yaxis,
+                highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString();
+
+            if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max)
+                return;
+
+            var pointRadius = series.points.radius + series.points.lineWidth / 2;
+            octx.lineWidth = pointRadius;
+            octx.strokeStyle = highlightColor;
+            var radius = 1.5 * pointRadius;
+            x = axisx.p2c(x);
+            y = axisy.p2c(y);
+
+            octx.beginPath();
+            if (series.points.symbol == "circle")
+                octx.arc(x, y, radius, 0, 2 * Math.PI, false);
+            else
+                series.points.symbol(octx, x, y, radius, false);
+            octx.closePath();
+            octx.stroke();
+        }
+
+        function drawBarHighlight(series, point) {
+            var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(),
+                fillStyle = highlightColor,
+                barLeft;
+
+            switch (series.bars.align) {
+                case "left":
+                    barLeft = 0;
+                    break;
+                case "right":
+                    barLeft = -series.bars.barWidth;
+                    break;
+                default:
+                    barLeft = -series.bars.barWidth / 2;
+            }
+
+            octx.lineWidth = series.bars.lineWidth;
+            octx.strokeStyle = highlightColor;
+
+            drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth,
+                    function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth);
+        }
+
+        function getColorOrGradient(spec, bottom, top, defaultColor) {
+            if (typeof spec == "string")
+                return spec;
+            else {
+                // assume this is a gradient spec; IE currently only
+                // supports a simple vertical gradient properly, so that's
+                // what we support too
+                var gradient = ctx.createLinearGradient(0, top, 0, bottom);
+
+                for (var i = 0, l = spec.colors.length; i < l; ++i) {
+                    var c = spec.colors[i];
+                    if (typeof c != "string") {
+                        var co = $.color.parse(defaultColor);
+                        if (c.brightness != null)
+                            co = co.scale('rgb', c.brightness);
+                        if (c.opacity != null)
+                            co.a *= c.opacity;
+                        c = co.toString();
+                    }
+                    gradient.addColorStop(i / (l - 1), c);
+                }
+
+                return gradient;
+            }
+        }
+    }
+
+    // Add the plot function to the top level of the jQuery object
+
+    $.plot = function(placeholder, data, options) {
+        //var t0 = new Date();
+        var plot = new Plot($(placeholder), data, options, $.plot.plugins);
+        //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime()));
+        return plot;
+    };
+
+    $.plot.version = "0.8.3";
+
+    $.plot.plugins = [];
+
+    // Also add the plot function as a chainable property
+
+    $.fn.plot = function(data, options) {
+        return this.each(function() {
+            $.plot(this, data, options);
+        });
+    };
+
+    // round to nearby lower multiple of base
+    function floorInBase(n, base) {
+        return base * Math.floor(n / base);
+    }
+
+})(jQuery);
diff --git a/HldRec/js/jquery.flot.selection.js b/HldRec/js/jquery.flot.selection.js
new file mode 100644 (file)
index 0000000..d3c20fa
--- /dev/null
@@ -0,0 +1,360 @@
+/* Flot plugin for selecting regions of a plot.
+
+Copyright (c) 2007-2014 IOLA and Ole Laursen.
+Licensed under the MIT license.
+
+The plugin supports these options:
+
+selection: {
+       mode: null or "x" or "y" or "xy",
+       color: color,
+       shape: "round" or "miter" or "bevel",
+       minSize: number of pixels
+}
+
+Selection support is enabled by setting the mode to one of "x", "y" or "xy".
+In "x" mode, the user will only be able to specify the x range, similarly for
+"y" mode. For "xy", the selection becomes a rectangle where both ranges can be
+specified. "color" is color of the selection (if you need to change the color
+later on, you can get to it with plot.getOptions().selection.color). "shape"
+is the shape of the corners of the selection.
+
+"minSize" is the minimum size a selection can be in pixels. This value can
+be customized to determine the smallest size a selection can be and still
+have the selection rectangle be displayed. When customizing this value, the
+fact that it refers to pixels, not axis units must be taken into account.
+Thus, for example, if there is a bar graph in time mode with BarWidth set to 1
+minute, setting "minSize" to 1 will not make the minimum selection size 1
+minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent
+"plotunselected" events from being fired when the user clicks the mouse without
+dragging.
+
+When selection support is enabled, a "plotselected" event will be emitted on
+the DOM element you passed into the plot function. The event handler gets a
+parameter with the ranges selected on the axes, like this:
+
+       placeholder.bind( "plotselected", function( event, ranges ) {
+               alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to)
+               // similar for yaxis - with multiple axes, the extra ones are in
+               // x2axis, x3axis, ...
+       });
+
+The "plotselected" event is only fired when the user has finished making the
+selection. A "plotselecting" event is fired during the process with the same
+parameters as the "plotselected" event, in case you want to know what's
+happening while it's happening,
+
+A "plotunselected" event with no arguments is emitted when the user clicks the
+mouse to remove the selection. As stated above, setting "minSize" to 0 will
+destroy this behavior.
+
+The plugin allso adds the following methods to the plot object:
+
+- setSelection( ranges, preventEvent )
+
+  Set the selection rectangle. The passed in ranges is on the same form as
+  returned in the "plotselected" event. If the selection mode is "x", you
+  should put in either an xaxis range, if the mode is "y" you need to put in
+  an yaxis range and both xaxis and yaxis if the selection mode is "xy", like
+  this:
+
+       setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } });
+
+  setSelection will trigger the "plotselected" event when called. If you don't
+  want that to happen, e.g. if you're inside a "plotselected" handler, pass
+  true as the second parameter. If you are using multiple axes, you can
+  specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of
+  xaxis, the plugin picks the first one it sees.
+
+- clearSelection( preventEvent )
+
+  Clear the selection rectangle. Pass in true to avoid getting a
+  "plotunselected" event.
+
+- getSelection()
+
+  Returns the current selection in the same format as the "plotselected"
+  event. If there's currently no selection, the function returns null.
+
+*/
+
+(function ($) {
+    function init(plot) {
+        var selection = {
+                first: { x: -1, y: -1}, second: { x: -1, y: -1},
+                show: false,
+                active: false
+            };
+
+        // FIXME: The drag handling implemented here should be
+        // abstracted out, there's some similar code from a library in
+        // the navigation plugin, this should be massaged a bit to fit
+        // the Flot cases here better and reused. Doing this would
+        // make this plugin much slimmer.
+        var savedhandlers = {};
+
+        var mouseUpHandler = null;
+        
+        function onMouseMove(e) {
+            if (selection.active) {
+                updateSelection(e);
+                
+                plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]);
+            }
+        }
+
+        function onMouseDown(e) {
+            if (e.which != 1)  // only accept left-click
+                return;
+            
+            // cancel out any text selections
+            document.body.focus();
+
+            // prevent text selection and drag in old-school browsers
+            if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) {
+                savedhandlers.onselectstart = document.onselectstart;
+                document.onselectstart = function () { return false; };
+            }
+            if (document.ondrag !== undefined && savedhandlers.ondrag == null) {
+                savedhandlers.ondrag = document.ondrag;
+                document.ondrag = function () { return false; };
+            }
+
+            setSelectionPos(selection.first, e);
+
+            selection.active = true;
+
+            // this is a bit silly, but we have to use a closure to be
+            // able to whack the same handler again
+            mouseUpHandler = function (e) { onMouseUp(e); };
+            
+            $(document).one("mouseup", mouseUpHandler);
+        }
+
+        function onMouseUp(e) {
+            mouseUpHandler = null;
+            
+            // revert drag stuff for old-school browsers
+            if (document.onselectstart !== undefined)
+                document.onselectstart = savedhandlers.onselectstart;
+            if (document.ondrag !== undefined)
+                document.ondrag = savedhandlers.ondrag;
+
+            // no more dragging
+            selection.active = false;
+            updateSelection(e);
+
+            if (selectionIsSane())
+                triggerSelectedEvent();
+            else {
+                // this counts as a clear
+                plot.getPlaceholder().trigger("plotunselected", [ ]);
+                plot.getPlaceholder().trigger("plotselecting", [ null ]);
+            }
+
+            return false;
+        }
+
+        function getSelection() {
+            if (!selectionIsSane())
+                return null;
+            
+            if (!selection.show) return null;
+
+            var r = {}, c1 = selection.first, c2 = selection.second;
+            $.each(plot.getAxes(), function (name, axis) {
+                if (axis.used) {
+                    var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]); 
+                    r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) };
+                }
+            });
+            return r;
+        }
+
+        function triggerSelectedEvent() {
+            var r = getSelection();
+
+            plot.getPlaceholder().trigger("plotselected", [ r ]);
+
+            // backwards-compat stuff, to be removed in future
+            if (r.xaxis && r.yaxis)
+                plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]);
+        }
+
+        function clamp(min, value, max) {
+            return value < min ? min: (value > max ? max: value);
+        }
+
+        function setSelectionPos(pos, e) {
+            var o = plot.getOptions();
+            var offset = plot.getPlaceholder().offset();
+            var plotOffset = plot.getPlotOffset();
+            pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width());
+            pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height());
+
+            if (o.selection.mode == "y")
+                pos.x = pos == selection.first ? 0 : plot.width();
+
+            if (o.selection.mode == "x")
+                pos.y = pos == selection.first ? 0 : plot.height();
+        }
+
+        function updateSelection(pos) {
+            if (pos.pageX == null)
+                return;
+
+            setSelectionPos(selection.second, pos);
+            if (selectionIsSane()) {
+                selection.show = true;
+                plot.triggerRedrawOverlay();
+            }
+            else
+                clearSelection(true);
+        }
+
+        function clearSelection(preventEvent) {
+            if (selection.show) {
+                selection.show = false;
+                plot.triggerRedrawOverlay();
+                if (!preventEvent)
+                    plot.getPlaceholder().trigger("plotunselected", [ ]);
+            }
+        }
+
+        // function taken from markings support in Flot
+        function extractRange(ranges, coord) {
+            var axis, from, to, key, axes = plot.getAxes();
+
+            for (var k in axes) {
+                axis = axes[k];
+                if (axis.direction == coord) {
+                    key = coord + axis.n + "axis";
+                    if (!ranges[key] && axis.n == 1)
+                        key = coord + "axis"; // support x1axis as xaxis
+                    if (ranges[key]) {
+                        from = ranges[key].from;
+                        to = ranges[key].to;
+                        break;
+                    }
+                }
+            }
+
+            // backwards-compat stuff - to be removed in future
+            if (!ranges[key]) {
+                axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0];
+                from = ranges[coord + "1"];
+                to = ranges[coord + "2"];
+            }
+
+            // auto-reverse as an added bonus
+            if (from != null && to != null && from > to) {
+                var tmp = from;
+                from = to;
+                to = tmp;
+            }
+            
+            return { from: from, to: to, axis: axis };
+        }
+        
+        function setSelection(ranges, preventEvent) {
+            var axis, range, o = plot.getOptions();
+
+            if (o.selection.mode == "y") {
+                selection.first.x = 0;
+                selection.second.x = plot.width();
+            }
+            else {
+                range = extractRange(ranges, "x");
+
+                selection.first.x = range.axis.p2c(range.from);
+                selection.second.x = range.axis.p2c(range.to);
+            }
+
+            if (o.selection.mode == "x") {
+                selection.first.y = 0;
+                selection.second.y = plot.height();
+            }
+            else {
+                range = extractRange(ranges, "y");
+
+                selection.first.y = range.axis.p2c(range.from);
+                selection.second.y = range.axis.p2c(range.to);
+            }
+
+            selection.show = true;
+            plot.triggerRedrawOverlay();
+            if (!preventEvent && selectionIsSane())
+                triggerSelectedEvent();
+        }
+
+        function selectionIsSane() {
+            var minSize = plot.getOptions().selection.minSize;
+            return Math.abs(selection.second.x - selection.first.x) >= minSize &&
+                Math.abs(selection.second.y - selection.first.y) >= minSize;
+        }
+
+        plot.clearSelection = clearSelection;
+        plot.setSelection = setSelection;
+        plot.getSelection = getSelection;
+
+        plot.hooks.bindEvents.push(function(plot, eventHolder) {
+            var o = plot.getOptions();
+            if (o.selection.mode != null) {
+                eventHolder.mousemove(onMouseMove);
+                eventHolder.mousedown(onMouseDown);
+            }
+        });
+
+
+        plot.hooks.drawOverlay.push(function (plot, ctx) {
+            // draw selection
+            if (selection.show && selectionIsSane()) {
+                var plotOffset = plot.getPlotOffset();
+                var o = plot.getOptions();
+
+                ctx.save();
+                ctx.translate(plotOffset.left, plotOffset.top);
+
+                var c = $.color.parse(o.selection.color);
+
+                ctx.strokeStyle = c.scale('a', 0.8).toString();
+                ctx.lineWidth = 1;
+                ctx.lineJoin = o.selection.shape;
+                ctx.fillStyle = c.scale('a', 0.4).toString();
+
+                var x = Math.min(selection.first.x, selection.second.x) + 0.5,
+                    y = Math.min(selection.first.y, selection.second.y) + 0.5,
+                    w = Math.abs(selection.second.x - selection.first.x) - 1,
+                    h = Math.abs(selection.second.y - selection.first.y) - 1;
+
+                ctx.fillRect(x, y, w, h);
+                ctx.strokeRect(x, y, w, h);
+
+                ctx.restore();
+            }
+        });
+        
+        plot.hooks.shutdown.push(function (plot, eventHolder) {
+            eventHolder.unbind("mousemove", onMouseMove);
+            eventHolder.unbind("mousedown", onMouseDown);
+            
+            if (mouseUpHandler)
+                $(document).unbind("mouseup", mouseUpHandler);
+        });
+
+    }
+
+    $.plot.plugins.push({
+        init: init,
+        options: {
+            selection: {
+                mode: null, // one of null, "x", "y" or "xy"
+                color: "#e8cfac",
+                shape: "round", // one of "round", "miter", or "bevel"
+                minSize: 5 // minimum number of pixels
+            }
+        },
+        name: 'selection',
+        version: '1.1'
+    });
+})(jQuery);
diff --git a/HldRec/js/jquery.min.js b/HldRec/js/jquery.min.js
new file mode 100644 (file)
index 0000000..29b3a2c
--- /dev/null
@@ -0,0 +1,6 @@
+/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery.min.map
+*/
+(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav></:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t
+}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Ct=/^(?:checkbox|radio)$/i,Nt=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle);
+u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=un(e,t),Pt.detach()),Gt[e]=n),n}function un(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,n){x.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(x.css(e,"display"))?x.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x.support.opacity||(x.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=x.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===x.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,n){return n?x.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,n){x.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?x(e).position()[n]+"px":r):t}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!x.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||x.css(e,"display"))},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(x.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Ct.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),x.param=function(e,n){var r,i=[],o=function(e,t){t=x.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var mn,yn,vn=x.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Cn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Nn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=x.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=o.href}catch(Ln){yn=a.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(T)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(l){var u;return o[l]=!0,x.each(e[l]||[],function(e,l){var c=l(n,r,i);return"string"!=typeof c||a||o[c]?a?!(u=c):t:(n.dataTypes.unshift(c),s(c),!1)}),u}return s(n.dataTypes[0])||!o["*"]&&s("*")}function _n(e,n){var r,i,o=x.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,l=e.indexOf(" ");return l>=0&&(i=e.slice(l,e.length),e=e.slice(0,l)),x.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&x.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?x("<div>").append(x.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Cn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_n(_n(e,x.ajaxSettings),t):_n(x.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,l,u,c,p=x.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),g=x.Callbacks("once memory"),m=p.statusCode||{},y={},v={},b=0,w="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>b)for(t in e)m[t]=[m[t],e[t]];else C.always(e[C.status]);return this},abort:function(e){var t=e||w;return u&&u.abort(t),k(0,t),this}};if(h.promise(C).complete=g.add,C.success=C.done,C.error=C.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=x.trim(p.dataType||"*").toLowerCase().match(T)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?"80":"443"))===(mn[3]||("http:"===mn[1]?"80":"443")))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=x.param(p.data,p.traditional)),qn(An,p,n,C),2===b)return C;l=p.global,l&&0===x.active++&&x.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Nn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(x.lastModified[o]&&C.setRequestHeader("If-Modified-Since",x.lastModified[o]),x.etag[o]&&C.setRequestHeader("If-None-Match",x.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",p.contentType),C.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)C.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,C,p)===!1||2===b))return C.abort();w="abort";for(i in{success:1,error:1,complete:1})C[i](p[i]);if(u=qn(jn,p,n,C)){C.readyState=1,l&&d.trigger("ajaxSend",[C,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){C.abort("timeout")},p.timeout));try{b=1,u.send(y,k)}catch(N){if(!(2>b))throw N;k(-1,N)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,N=n;2!==b&&(b=2,s&&clearTimeout(s),u=t,a=i||"",C.readyState=e>0?4:0,c=e>=200&&300>e||304===e,r&&(w=Mn(p,C,r)),w=On(p,w,C,c),c?(p.ifModified&&(T=C.getResponseHeader("Last-Modified"),T&&(x.lastModified[o]=T),T=C.getResponseHeader("etag"),T&&(x.etag[o]=T)),204===e||"HEAD"===p.type?N="nocontent":304===e?N="notmodified":(N=w.state,y=w.data,v=w.error,c=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),C.status=e,C.statusText=(n||N)+"",c?h.resolveWith(f,[y,N,C]):h.rejectWith(f,[C,N,v]),C.statusCode(m),m=t,l&&d.trigger(c?"ajaxSuccess":"ajaxError",[C,p,c?y:v]),g.fireWith(f,[C,N]),l&&(d.trigger("ajaxComplete",[C,p]),--x.active||x.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,n){return x.get(e,t,n,"script")}}),x.each(["get","post"],function(e,n){x[n]=function(e,r,i,o){return x.isFunction(r)&&(o=o||i,i=r,r=t),x.ajax({url:e,type:n,dataType:o,data:r,success:i})}});function Mn(e,n,r){var i,o,a,s,l=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in l)if(l[s]&&l[s].test(o)){u.unshift(s);break}if(u[0]in r)a=u[0];else{for(s in r){if(!u[0]||e.converters[s+" "+u[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==u[0]&&u.unshift(a),r[a]):t}function On(e,t,n,r){var i,o,a,s,l,u={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)u[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=c.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(a=u[l+" "+o]||u["* "+o],!a)for(i in u)if(s=i.split(" "),s[1]===o&&(a=u[l+" "+s[0]]||u["* "+s[0]])){a===!0?a=u[i]:u[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(p){return{state:"parsererror",error:a?p:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),x.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=a.head||x("head")[0]||a.documentElement;return{send:function(t,i){n=a.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Fn=[],Bn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Fn.pop()||x.expando+"_"+vn++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,l=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return l||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=x.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,l?n[l]=n[l].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||x.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Fn.push(o)),s&&x.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}x.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=x.ajaxSettings.xhr(),x.support.cors=!!Rn&&"withCredentials"in Rn,Rn=x.support.ajax=!!Rn,Rn&&x.ajaxTransport(function(n){if(!n.crossDomain||x.support.cors){var r;return{send:function(i,o){var a,s,l=n.xhr();if(n.username?l.open(n.type,n.url,n.async,n.username,n.password):l.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)l[s]=n.xhrFields[s];n.mimeType&&l.overrideMimeType&&l.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)l.setRequestHeader(s,i[s])}catch(u){}l.send(n.hasContent&&n.data||null),r=function(e,i){var s,u,c,p;try{if(r&&(i||4===l.readyState))if(r=t,a&&(l.onreadystatechange=x.noop,$n&&delete Pn[a]),i)4!==l.readyState&&l.abort();else{p={},s=l.status,u=l.getAllResponseHeaders(),"string"==typeof l.responseText&&(p.text=l.responseText);try{c=l.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,u)},n.async?4===l.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},x(e).unload($n)),Pn[a]=r),l.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+w+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Yn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),a=(x.cssNumber[e]||"px"!==o&&+r)&&Yn.exec(x.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],i=i||[],a=+r||1;do s=s||".5",a/=s,x.style(n.elem,e,a+o);while(s!==(s=n.cur()/r)&&1!==s&&--l)}return i&&(a=n.start=+a||+r||0,n.unit=o,n.end=i[1]?a+(i[1]+1)*i[2]:+i[2]),n}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=x.now()}function Zn(e,t,n){var r,i=(Qn[t]||[]).concat(Qn["*"]),o=0,a=i.length;for(;a>o;o++)if(r=i[o].call(n,t,e))return r}function er(e,t,n){var r,i,o=0,a=Gn.length,s=x.Deferred().always(function(){delete l.elem}),l=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,u.startTime+u.duration-t),r=n/u.duration||0,o=1-r,a=0,l=u.tweens.length;for(;l>a;a++)u.tweens[a].run(o);return s.notifyWith(e,[u,o,n]),1>o&&l?n:(s.resolveWith(e,[u]),!1)},u=s.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,u.opts,t,n,u.opts.specialEasing[t]||u.opts.easing);return u.tweens.push(r),r},stop:function(t){var n=0,r=t?u.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)u.tweens[n].run(1);return t?s.resolveWith(e,[u,t]):s.rejectWith(e,[u,t]),this}}),c=u.props;for(tr(c,u.opts.specialEasing);a>o;o++)if(r=Gn[o].call(u,e,c,u.opts))return r;return x.map(c,Zn,u),x.isFunction(u.opts.start)&&u.opts.start.call(e,u),x.fx.timer(x.extend(l,{elem:e,anim:u,queue:u.opts.queue})),u.progress(u.opts.progress).done(u.opts.done,u.opts.complete).fail(u.opts.fail).always(u.opts.always)}function tr(e,t){var n,r,i,o,a;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=x.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(er,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,l,u=this,c={},p=e.style,f=e.nodeType&&nn(e),d=x._data(e,"fxshow");n.queue||(s=x._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,x.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(x.support.inlineBlockNeedsLayout&&"inline"!==ln(e.nodeName)?p.zoom=1:p.display="inline-block")),n.overflow&&(p.overflow="hidden",x.support.shrinkWrapBlocks||u.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Vn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show"))continue;c[r]=d&&d[r]||x.style(e,r)}if(!x.isEmptyObject(c)){d?"hidden"in d&&(f=d.hidden):d=x._data(e,"fxshow",{}),o&&(d.hidden=!f),f?x(e).show():u.done(function(){x(e).hide()}),u.done(function(){var t;x._removeData(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)a=Zn(f?d[r]:0,r,u),r in d||(d[r]=a.start,f&&(a.end=a.start,a.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}x.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),a=function(){var t=er(this,x.extend({},e),o);(i||x._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=x.timers,a=x._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=x._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,a=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=rr.prototype.init,x.fx.tick=function(){var e,n=x.timers,r=0;for(Xn=x.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||x.fx.stop(),Xn=t},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){Un||(Un=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(Un),Un=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){x.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,x.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},x.offset={setOffset:function(e,t,n){var r=x.css(e,"position");"static"===r&&(e.style.position="relative");var i=x(e),o=i.offset(),a=x.css(e,"top"),s=x.css(e,"left"),l=("absolute"===r||"fixed"===r)&&x.inArray("auto",[a,s])>-1,u={},c={},p,f;l?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),x.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(u.top=t.top-o.top+p),null!=t.left&&(u.left=t.left-o.left+f),"using"in t?t.using.call(e,u):i.css(u)}},x.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===x.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(n=e.offset()),n.top+=x.css(e[0],"borderTopWidth",!0),n.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-x.css(r,"marginTop",!0),left:t.left-n.left-x.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);x.fn[e]=function(i){return x.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?x(a).scrollLeft():o,r?o:x(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return x.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}x.each({Height:"height",Width:"width"},function(e,n){x.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){x.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return x.access(this,function(n,r,i){var o;return x.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?x.css(n,r,s):x.style(n,r,i,s)},n,a?i:t,a,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:(e.jQuery=e.$=x,"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}))})(window);
diff --git a/HldRec/js/jquery.mwiebusch.js b/HldRec/js/jquery.mwiebusch.js
new file mode 100644 (file)
index 0000000..342d622
--- /dev/null
@@ -0,0 +1,43 @@
+
+
+function flot_w_selectZoom(id,data,options) {
+  $.plot(id, data, options);
+  
+  $(id).bind("plotselected", function (event, ranges) {
+    // clamp the zooming to prevent eternal zoom
+    if (ranges.xaxis.to - ranges.xaxis.from < 0.00001) {
+      ranges.xaxis.to = ranges.xaxis.from + 0.00001;
+    }
+    if (ranges.yaxis.to - ranges.yaxis.from < 0.00001) {
+      ranges.yaxis.to = ranges.yaxis.from + 0.00001;
+    }
+    // do the zooming
+    plot = $.plot(id, data,
+      $.extend(true, {}, options, {
+        xaxis: { min: ranges.xaxis.from, max: ranges.xaxis.to },
+        yaxis: { min: ranges.yaxis.from, max: ranges.yaxis.to }
+      })
+    );
+  });
+}
+
+
+
+function armAllAnything(selector) {
+  // all [selector] get the function with the same name attached to it
+  $(selector).each(function(){
+    var id = $(this).attr('id');
+    if(typeof id !== 'undefined'){
+      if(eval("typeof " + id + "_click") !== 'undefined') {
+        $(this).click(window[id + "_click"]);
+      }
+      if(eval("typeof " + id + "_change") !== 'undefined') {
+        $(this).change(window[id + "_change"]);
+      }
+    }
+  });
+}
+
+function epoch(){
+  return Math.floor((new Date).getTime()/1000);
+}
diff --git a/HldRec/js/jquery.timer.js b/HldRec/js/jquery.timer.js
new file mode 100644 (file)
index 0000000..959fef3
--- /dev/null
@@ -0,0 +1,111 @@
+/**
+ * jquery.timer.js
+ *
+ * Copyright (c) 2011 Jason Chavannes <jason.chavannes@gmail.com>
+ *
+ * http://jchavannes.com/jquery-timer
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+;(function($) {
+        $.timer = function(func, time, autostart) {    
+                this.set = function(func, time, autostart) {
+                        this.init = true;
+                        if(typeof func == 'object') {
+                                var paramList = ['autostart', 'time'];
+                                for(var arg in paramList) {if(func[paramList[arg]] != undefined) {eval(paramList[arg] + " = func[paramList[arg]]");}};
+                                func = func.action;
+                        }
+                        if(typeof func == 'function') {this.action = func;}
+                        if(!isNaN(time)) {this.intervalTime = time;}
+                        if(autostart && !this.isActive) {
+                                this.isActive = true;
+                                this.setTimer();
+                        }
+                        return this;
+                };
+                this.once = function(time) {
+                        var timer = this;
+                        if(isNaN(time)) {time = 0;}
+                        window.setTimeout(function() {timer.action();}, time);
+                        return this;
+                };
+                this.play = function(reset) {
+                        if(!this.isActive) {
+                                if(reset) {this.setTimer();}
+                                else {this.setTimer(this.remaining);}
+                                this.isActive = true;
+                        }
+                        return this;
+                };
+                this.pause = function() {
+                        if(this.isActive) {
+                                this.isActive = false;
+                                this.remaining -= new Date() - this.last;
+                                this.clearTimer();
+                        }
+                        return this;
+                };
+                this.stop = function() {
+                        this.isActive = false;
+                        this.remaining = this.intervalTime;
+                        this.clearTimer();
+                        return this;
+                };
+                this.toggle = function(reset) {
+                        if(this.isActive) {this.pause();}
+                        else if(reset) {this.play(true);}
+                        else {this.play();}
+                        return this;
+                };
+                this.reset = function() {
+                        this.isActive = false;
+                        this.play(true);
+                        return this;
+                };
+                this.clearTimer = function() {
+                        window.clearTimeout(this.timeoutObject);
+                };
+                this.setTimer = function(time) {
+                        var timer = this;
+                        if(typeof this.action != 'function') {return;}
+                        if(isNaN(time)) {time = this.intervalTime;}
+                        this.remaining = time;
+                        this.last = new Date();
+                        this.clearTimer();
+                        this.timeoutObject = window.setTimeout(function() {timer.go();}, time);
+                };
+                this.go = function() {
+                        if(this.isActive) {
+                                this.action();
+                                this.setTimer();
+                        }
+                };
+               
+                if(this.init) {
+                        return new $.timer(func, time, autostart);
+                } else {
+                        this.set(func, time, autostart);
+                        return this;
+                }
+        };
+})(jQuery);
diff --git a/HldRec/js/jquery.unfold.js b/HldRec/js/jquery.unfold.js
new file mode 100644 (file)
index 0000000..592500d
--- /dev/null
@@ -0,0 +1,51 @@
+// requires cookies.js
+
+function armUnfoldButtons(){
+  $('.unfoldBtn').each(function () {
+    var ContainerId = $(this).attr('data-ContainerId');
+    unfolds($(this),$("#"+ContainerId));
+  });
+}
+
+function unfold(button,container){
+  var button_text = button.html();
+  var new_button_text;
+  
+  if(container.is(':visible')){
+    new_button_text = button_text.replace("[-]","[+]");
+    createCookie(container.attr("id"),"hidden",10);
+  } else {
+    new_button_text = button_text.replace("[+]","[-]");
+    container.trigger('isVisible');
+    createCookie(container.attr("id"),"visible",10);
+  }
+  container.fadeToggle();
+//   $('html, body').animate({
+//       scrollTop: container.offset().top
+//   }, 1000);
+  button.html(new_button_text);
+}
+
+function unfolds(button,container){
+  button.click(function(){
+    unfold(button,container);
+  });
+  
+  var button_text = button.html();
+  var id=container.attr("id");
+  var status = readCookie(id);
+  if( status == "hidden" ) {
+    container.hide();
+  } else if ( status == "visible" ) {
+    container.trigger('isVisible');
+    container.show();
+  }
+  
+  if(container.is(':visible')){
+    button.html("[-] "+button_text);
+  } else {
+    button.html("[+] "+button_text);
+  }
+  
+}
+
diff --git a/HldRec/main_controls.html b/HldRec/main_controls.html
new file mode 100644 (file)
index 0000000..ddf19d8
--- /dev/null
@@ -0,0 +1,53 @@
+<p>
+<table><tr>
+
+<td align=right>bytesWritten:</td>
+<td id='bytesWritten'></td>
+</tr><tr>
+<td align=right>bytesReceived0:</td>
+<td id='bytesReceived0'></td>
+</tr><tr>
+<td align=right>bytesReceived0_s:</td>
+<td id='bytesReceived0_s'></td>
+</tr><tr>
+<td align=right>remaining time</td>
+<td id='remainingTime'></td>
+
+</tr></table>
+<table><tr>
+
+<td align=right >shm id:</td><td><input type='text' id='text_shm_id'></td>
+</tr><tr>
+
+<td align=right >dump file path:</td><td><input type='text' id='text_dump_path'></td>
+<!-- <td><input type='button' value='inc'></td> -->
+
+</tr><tr>
+
+<td align=right
+title="time constraint on recording. If empty -> record forever. Accepts values like 90 = 90s = 1m30s = 1.5m">
+acquisition time:</td><td><input type='text' id='text_acq_time'></td><td></td>
+
+</tr><tr>
+<td align=right >ports:</td><td><input type='text' id='text_ports'></td><td></td>
+</p>
+</tr></table>
+</p>
+<p>
+recorder <span id="backend_status">not running</span>
+</p>
+<p>
+<input type='button' value='record' id='btn_record'>
+<input type='button' value='stop'   id='btn_stop'>
+<input type='button' value='test'   id='btn_test'>
+</p>
+<p>
+<!--<input type='button' value='evtbuild log' id='btn_evtb_log'>
+<input type='button' value='netmem log'   id='btn_netm_log'>-->
+<!-- <input type='button' value='HldRec log'   id='btn_hldrec_log'> -->
+
+<a href='' target='_blank' id='a_evtb_log'>
+<input type='button' value='evtbuild log'></a>
+<a href='' target='_blank' id='a_netm_log'>
+<input type='button' value='netmem log'></a>
+</p>
\ No newline at end of file
diff --git a/HldRec/misc_subs.pm b/HldRec/misc_subs.pm
new file mode 100644 (file)
index 0000000..fe91d58
--- /dev/null
@@ -0,0 +1,223 @@
+package misc_subs;
+use POSIX;
+use Proc::Daemon;
+
+use IO::Handle;
+
+BEGIN {
+  require Exporter;
+  # set the version for version checking
+  our $VERSION = 1.02;
+  
+  # revision history
+  # v1.01
+  #     removed daemonize
+  #     added daemon_start/stop/status based on Proc::Daemon (debian packet "libproc-daemon-perl")
+  # v1.02
+  #     added kilomega()
+  
+  # Inherit from Exporter to export functions and variables
+  our @ISA = qw(Exporter);
+  # Functions and variables which are exported by default
+  our @EXPORT = qw(
+    printHeader
+    min
+    max
+    echo
+    require_run
+    test hms_string
+    false_color
+    daemon_start
+    daemon_stop
+    daemon_status
+    time_to_s
+    kilomega
+  );
+  # Functions and variables which can be optionally exported
+  #our @EXPORT_OK = qw($Var1 %Hashit func3);
+}
+
+sub test {
+  my $self = shift;
+  my %options = @_;
+  print "This is the test message!\n";
+  print "The test routine has received the following options:\n\n";
+  
+  for my $item ( keys %options ) {
+    print "key: $item\tvalue: ".$options{$item}."\n";
+  }
+  exit;
+  
+}
+
+sub require_run {
+  my $self    = shift;
+  my $subname = shift;
+  
+  unless($self->{has_run}->{$subname}){
+    $self->$subname();
+    $self->{has_run}->{$subname} = 1;
+  }
+}
+
+# simple subs
+
+sub echo {
+  print shift."\n";
+}
+
+sub max {
+  my ($x,$y) = @_;
+  return $x >= $y ? $x : $y;
+}
+sub min {
+  my ($x,$y) = @_;
+  return $x <= $y ? $x : $y;
+}
+
+sub printHeader {
+  my $type = shift @_;
+  if ($ENV{'SERVER_SOFTWARE'} =~ /HTTPi/i) {
+    print "HTTP/1.0 200 OK\n";
+    print "Content-type: $type\r\n\r\n";
+  }
+  else {
+    print "Content-type: $type\n\n";
+  }
+}
+
+sub hms_string {
+  my $s = shift;
+  
+  my $hours = floor($s/3600);
+  my $mins  = floor($s/60)-$hours*60;
+  my $secs  = floor($s)-$hours*3600-$mins*60;
+  
+  my $string = "";
+  $string .= $hours." h, " if $hours;
+  $string .= $mins." m, " if $mins;
+  $string .= $secs." s";
+  return $string;
+}
+
+
+
+sub false_color {
+  my $val = shift;
+  my $bot = shift;
+  my $top = shift;
+  
+  my $c = min(255,max(0,floor( ($val-$bot)/($top-$bot)*255)));
+  return ($c,$c,$c);
+
+}
+
+
+sub time_to_s {
+  my $time = shift;
+  return unless(defined($time));
+  my ($s) = $time =~ m/([\d\.]+[sS]?$)/ ;
+  my ($m) = $time =~ m/([\d\.]+[mM])/   ;
+  my ($h) = $time =~ m/([\d\.]+[hH])/   ;
+  
+  return (($h||0)*3600 + ($m||0)*60 + ($s||0));
+  
+}
+
+
+
+sub daemon_start{
+
+  my $self = shift;
+  
+  my %options = @_;
+  
+  my $pf  = $options{pf}  || $self->{settings}->{pid_file};
+  my $log = $options{log} || $self->{settings}->{log_file};
+  my $daemon = Proc::Daemon->new(
+      pid_file => $pf,
+      work_dir => "./",
+  );
+  
+  my $pid = $daemon->Status($pf);
+  
+  if ($pid) {
+      print STDOUT "Background service already running with pid $pid.\n";
+      return 0;
+  } else {
+      print STDOUT "Starting background service\n";
+      $daemon->Init;
+      open(LOG,"+>>$log");
+      *STDERR = *LOG;
+      *STDOUT = *LOG;
+      LOG->autoflush;
+      return 1;
+  }
+}
+
+sub daemon_stop {
+  my $self = shift;
+  my %options = @_;
+  my $pf  = $options{pf}  || $self->{settings}->{pid_file};
+  my $daemon = Proc::Daemon->new(
+      pid_file => $pf,
+      work_dir => "./",
+  );
+  my $pid = $daemon->Status($pf);
+
+  if ($pid) {
+      print STDOUT "Stopping pid $pid...\n";
+      if ($daemon->Kill_Daemon($pf)) {
+          print STDOUT "Successfully stopped.\n";
+          return 1;
+      } else {
+          print STDOUT "Could not find $pid.  Was it running?\n";
+          return 0;
+      }
+  } else {
+        print STDOUT "Not running, nothing to stop.\n";
+        return 1;
+  }
+  return 0;
+    
+}
+
+sub daemon_status {
+  my $self = shift;
+  my %options = @_;
+  my $pf  = $options{pf}  || $self->{settings}->{pid_file};
+  my $daemon = Proc::Daemon->new(
+      pid_file => $pf,
+      work_dir => "./",
+  );
+  my $pid = $daemon->Status($pf);
+
+    if ($pid) {
+        print "Running with pid $pid.\n";
+    } else {
+        print "Not running.\n";
+    }
+  return $pid;
+}
+
+sub kilomega {
+  my $val = $_[0];
+  my $num;
+  if($val/1e9 >= 1){
+    my $a = sprintf("%1.1fG",$val/1e9);
+#     $a =~ s/\.0//;
+    return $a;
+  } elsif ($val/1e6 >= 1){
+    my $a = sprintf("%1.1fM",$val/1e6);
+#     $a =~ s/\.0//;
+    return $a;
+  } elsif ($val/1e3 >= 1){
+    my $a = sprintf("%1.1fk",$val/1e3);
+#     $a =~ s/\.0//;
+    return $a;
+  } else {
+    return sprintf("%d",$val);
+  }
+}
+
+1;
\ No newline at end of file
diff --git a/HldRec/shm b/HldRec/shm
new file mode 120000 (symlink)
index 0000000..0d99fd7
--- /dev/null
@@ -0,0 +1 @@
+/dev/shm
\ No newline at end of file
diff --git a/HldRec/shm_manager.pm b/HldRec/shm_manager.pm
new file mode 100644 (file)
index 0000000..2be943d
--- /dev/null
@@ -0,0 +1,131 @@
+package shm_manager;
+
+
+use strict;
+use warnings;
+use POSIX;
+
+use Storable qw(lock_store lock_retrieve fd_retrieve nstore_fd);
+use Fcntl qw(:DEFAULT :flock);
+
+sub new {
+  my $class = shift;
+  my %options = @_;
+  my $self  = {
+    %options
+  };
+  
+  die "shm_manager must get an shmName" unless defined($self->{shmName});
+  if(defined($self->{shmPath})){
+    $self->{shmPath} =~ s/\/+$//; #remove trailing "/"
+    $self->{shmPath} .= "/";
+    $self->{shmFile} = $self->{shmPath}.$self->{shmName};
+  } else {
+    $self->{shmFile} = "/dev/shm/".$self->{shmName};
+  }
+#   $self->{dataDir} = $self->{shmFile}."_data";
+#   $self->{dataFile} = $self->{dataDir}."/data";
+  
+  $self->{shmFhLocked} = 0;
+  bless($self, $class);
+}
+
+
+sub initShm {
+  my $self = shift;
+  unless($self->existShm()){
+    $self->createShm();
+  }
+
+}
+
+sub existShm {
+  my $self = shift;
+  return 1 if( -e $self->{shmFile} );
+  return 0;
+}
+
+sub createShm {
+  my $self = shift;
+  die "shm ".$self->{shmFile}." already exists!\n" if( -e $self->{shmFile} );
+  
+  lock_store({},$self->{shmFile});
+#   die "data directory ".$self->{dataDir}." already exists!\n" if( -e $self->{dataDir} );
+#   mkdir $self->{dataDir};
+};
+
+
+sub deleteShm {
+  my $self = shift;
+  unlink $self->{shmFile};
+  system("rm -rf ".$self->{dataDir});
+}
+
+sub readShm {
+  my $self = shift;
+  
+  if ( -e $self->{shmFile} ){
+    return lock_retrieve($self->{shmFile});
+  } else {
+    die "shm does not exist!";
+  }
+}
+
+sub lockAndReadShm {
+  my $self = shift;
+  
+  if ( -e $self->{shmFile} ){
+    die "Shm file handle already open and locked!\n" if $self->{shmFhLocked};
+    sysopen(my $fh, $self->{shmFile}, O_RDWR|O_CREAT, 0666) 
+        or die "can't open shm file: $!";
+    flock($fh, LOCK_EX)           or die "can't lock shm file: $!";
+    $self->{shmFhLocked} = 1;
+    $self->{shmFh} = $fh; # store file handle in object
+    # attention! file handle is now still open!
+    return fd_retrieve(*$fh);
+  } else {
+    die "shm does not exist!";
+  }
+}
+
+
+sub writeShm { # closes and unlocks shm file if already open
+  my $self = shift;
+  my $shmHash = shift;
+  
+  if ( -e $self->{shmFile} ){
+    my $fh=$self->{shmFh};
+    #check if file handle still open and locked
+    unless($self->{shmFhLocked}){
+      print "found locked shm from previous lock-and-read\n";
+      sysopen($fh, $self->{shmFile}, O_RDWR|O_CREAT, 0666) 
+          or die "can't open shm file: $!";
+      flock($fh, LOCK_EX)           or die "can't lock shm file: $!";
+    }
+    #in any case, store your hash in shm file 
+    seek($fh,0,0);
+    nstore_fd($shmHash, *$fh)
+        or die "can't store hash\n";
+    truncate($fh, tell($fh));
+    close($fh);
+    $self->{shmFhLocked} = 0;# mark file handle as unlocked
+    return $shmHash; 
+  } else {
+    die "shm does not exist!";
+  }
+}
+
+
+
+sub updateShm {
+  my $self = shift;
+  my $shmHash = shift;
+  
+  my $oldShmHash = $self->lockAndReadShm();
+  my $compositeShmHash = {%$oldShmHash,%$shmHash};
+  $self->writeShm($compositeShmHash);
+  return $compositeShmHash;
+}
+
+
+1;
\ No newline at end of file
index a5807b6a1d8d93d8b62486c26afca87e696d445b..7db514b74b92659041ca6fce69f418fb9a57a0fd 100755 (executable)
@@ -76,8 +76,12 @@ my $name = $db->getDocumentElement->getAttribute('name');
 my $ccu = $dbsys->getDocumentElement->findnodes('ccu')->[0]->getAttribute('address');
 print STDERR "Loading setup $name from file $setupFile\n" if $verbose;
 
+print STDERR "Stop CTS trigger source\n" if $verbose;
 execute("trbcmd clearbit 0x$ccu 0xa101 0x1");
 
+
+
+
 foreach my $curctrl ($db->getDocumentElement->findnodes('controller')) {
   my $ctrlname = $curctrl->getAttribute('name');
   my $ctrlid   = $curctrl->getAttribute('id');
@@ -198,7 +202,7 @@ foreach my $ctrladdr (keys %$JtagCommands) {
     }
 }
 execute("trbcmd w 0xfe4d 0xb00b 1"); #Enable start sensors on next reference time
-execute("trbcmd setbit 0x$ccu 0xa101 0x1");
+execute("trbcmd setbit 0x$ccu 0xa101 0x1");# enable CTS trigger source
 execute("trbcmd w 0xfe4d 0xb00b 1"); #Enable start sensors on next reference time
 
   
index 6bc7e3ef5a1a84192f2870cff233f43916134348..1a54f7cf6d217fb36861ece1d06ea54e6eb8a68d 100755 (executable)
@@ -81,10 +81,6 @@ run(DAQTOOLSPATH."/tools/loadregisterdb.pl ".CONFIGPATH."/network/register_confi
 
 trb_write(0xfffe,0x00c5,0x20ff);   #Timeouts
 
-#Send arbiter start signal
-#trb_write($ccu,0xa000,0x00000001);
-
-
 
 # deactivate all peripheral FPGAs by default in the TrbNet hub
 # activate peripheral FPGAs only, when you find a <roc/> entry in system file
@@ -97,10 +93,30 @@ trb_write($ccu,0x00c1,0x00f0|$hub_active_mask);
 trb_write($ccu,0x00c3,0x00f0|$hub_active_mask);
 
 
-trb_write($_,0x8041,0x8d00) for @roc;
+trb_write($_,0x8041,0x8d00) for @roc; #set buffer delete time
+
+my $systems_w_ccu = {
+  ProbeStation_scurve   => 1,
+  ProbeStation_readout  => 1,
+  Vacuum_scurve         => 1,
+  Vacuum_readout        => 1,
+  ELab                  => 1,
+  PRESTO_readout        => 1,
+  PRESTO_scurve         => 1,
+};
+
+if($systems_w_ccu->{$system}) {
+  #ProbeStation continues to use the CCU
+  #Send arbiter start signal
+  print "System uses the old CCU\n";
+  trb_write($ccu,0xa000,0x00000001);
+} else {
+  #newer set-ups use the CTS
+  print "System uses the new CTS\n";
+  trb_write($ccu,0xa150,0x2cff);  #115.19us
+  trb_write($ccu,0xa101,0x00000001);
+}
 
-trb_write($ccu,0xa150,0x2cff);  #115.19us
-trb_write($ccu,0xa101,0x00000001);
 
 
 
index 35eb5edc60f21d921d0a1e80f7aa08bbec2dd0f8..599d83cb9657eee3d64645cccaea8129f60bd8f1 100755 (executable)
@@ -70,9 +70,9 @@ else {
 
 chdir($opt_path);
 
-$thr1 = threads->new(\&execute, "timeout -s SIGINT ".($time+1.5)." daq_evtbuild -m $c -q 32 -d file -x te -Se -S $opt_system");
+$thr1 = threads->new(\&execute, "timeout -k 2 -s SIGINT ".($time+1.5)." daq_evtbuild -m $c -q 32 -d file -x te -Se -S $opt_system");
 sleep 1;
-$thr2 = threads->new(\&execute, "timeout -s SIGINT ".$time." daq_netmem -m $c -q 32 $portoption -S $opt_system");
+$thr2 = threads->new(\&execute, "timeout -k 2 -s SIGINT ".$time." daq_netmem -m $c -q 32 $portoption -S $opt_system");
 
 $thr1->join();
 $thr2->join();
index ec91bb95f8f7f348f6d2013dfd934fe5ab6461ef..fbb06cfdfb8e8fd7201a4fabe111ec5cdef010e8 100755 (executable)
@@ -92,7 +92,7 @@ unless(-e $picPath) {
 
 my $dummy;
 print_exec "date";
-print_exec "./init_setup.pl $setupFile";
+print_exec "./init_setup.pl $setupFile $systemFile";
 
 
 unless($q->param('startupOnly') eq 'true'){
index a147aa37f369f15aea25b49627bcdd096fc60b19..112383bc3981b084815416317ba5b4d52d33f176 100755 (executable)
@@ -5,12 +5,12 @@
 
 ### ------------ Interpret the command line arguments ------------
 
-usage () { echo -e "\nUsage: ./scurve_control.sh [ELab/Vacuum] [Number of Runs] [Step Size]\n"; }
+usage () { echo -e "\nUsage: ./scurve_control.sh [ELab/Vacuum_scurve/ProbeStation_scurve PRESTO_scurve] [Number of Runs] [Step Size]\n"; }
 
 if [ -z "$1" ]  # check if first parameter is empty
 then
   usage
-  echo Error: Specify the system! Use Vacuum or ELab as first parameter.
+  echo Error: Specify the system! Use Vacuum, ELab, ProbeStation, or PRESTO_scurve as first parameter.
   exit -1
 fi
 
@@ -21,15 +21,29 @@ then
   export DAQOPSERVER=localhost:88
   JTAG_CONFIG_FILE=/local.1/htdocs/mvdconfig/config/sensorE0scurve2.xml
   SETUP_FILE=/local.1/htdocs/mvdconfig/setup/scurve2_setup_ELab2.xml
-elif [ $1 == 'Vacuum' ]
+elif [ $1 == 'PRESTO_scurve' ]
 then
-  PERIPH_ROC='0xd000'
-  CCU='0x8000'
+  PERIPH_ROC='0xd882'
+  CCU='0x8880'
+  export DAQOPSERVER=localhost:88
+  JTAG_CONFIG_FILE=/local.1/htdocs/mvdconfig/config/sensorE0scurve2.xml
+  SETUP_FILE=/local.1/htdocs/mvdconfig/setup/scurve2_setup_ELab2.xml
+elif [ $1 == 'Vacuum_scurve' ]
+then
+  PERIPH_ROC='0xd011'
+  CCU='0xc010'
+  export DAQOPSERVER=localhost:1
+  JTAG_CONFIG_FILE=/local.1/htdocs/mvdconfig/config/sensor_Vacuum_scurve.xml
+  SETUP_FILE=/local.1/htdocs/mvdconfig/setup/Vacuum_scurve.xml
+elif [ $1 == 'ProbeStation_scurve' ]
+then
+  PERIPH_ROC='0xd072'
+  CCU='0xc070'
   export DAQOPSERVER=localhost:7
-  JTAG_CONFIG_FILE=/local.1/htdocs/mvdconfig/config/sensorE0scurve.xml
-  SETUP_FILE=/local.1/htdocs/mvdconfig/setup/scurve2_setup.xml
+  JTAG_CONFIG_FILE=/local.1/htdocs/mvdconfig/config/sensorE0scurve2.xml
+  SETUP_FILE=/local.1/htdocs/mvdconfig/setup/ProbeStation_scurve.xml
 else
-  echo Error: system unspecified! Use ELab or Vacuum as the first parameter.
+  echo Error: system unspecified! Use ELab, Vacuum, ProbeStation, or PRESTO_scurve as the first parameter.
   exit -1
 fi
 
@@ -83,10 +97,11 @@ trbcmd w $PERIPH_ROC 0x8001 0x1 # set testmode   was 8006
 
 for BANK in 0 1 2 3
 do
-echo -e "\nBank $BANK"
-for i in $(seq 101 $stepsize 255)
+echo -e "\nNow scanning bank $BANK"
+ for i in $(seq 0 $stepsize 255)
+# for i in 0 255
 do
-  echo Threshold $i
+  echo "Setting threshold $i"
 
   printf -v threshhex '%02x' $i
 
@@ -111,7 +126,7 @@ do
   # Start taking data and cycle through runs:
   for j in $(seq 1 1 $numruns) # for all runs, to gather statistics
   do
-    echo "run $j"
+    echo "Bank $BANK Threshold $i run $j"
 
     printf -v runhex '%05x' $j
     check="0"
@@ -119,7 +134,7 @@ do
       trbcmd w $PERIPH_ROC 0x8002 0x1 # reset the FPGA buffers   was 8005
      # result=$(trbcmd r $PERIPH_ROC 0x8005)
      # check=${result:17:1}
-      echo "attempting soft-reset..."
+      #echo "attempting soft-reset..."
     #done
     trbcmd w $PERIPH_ROC 0x8002 0x0 # clear the previous reset   was 8005
     trbcmd w $PERIPH_ROC 0x8003 0x$threshhex$BANK$runhex # write current scan parameters to ROC-FPGA (later in data) was 8007
diff --git a/tools/test.txt b/tools/test.txt
deleted file mode 100644 (file)
index e69de29..0000000
index 6acec154cd5462b933e9aa1c19075f4a4e83403d..01b063dd8b2989c1a6adff2f4e8b987c240ca763 100755 (executable)
@@ -26,13 +26,16 @@ use Environment;
 
 
 our $setupDir = SETUPDIR;
+our $systemDir = SYSTEMDIR;
 our $confDir  = CONFDIR;
 our $specDir  = SPECDIR;
 my $picPath= PICTUREPATHREL;
 # my $picPath   = PICTUREPATH;
 # my $setupFile = SETUPFILE;
 my $setupFile;
+my $setupName;
 my $setupFileName;
+my $systemFile;
 my $systemName;
 
 # the file that tells me what fields should be printed in the quick edit area
@@ -46,8 +49,11 @@ setQuickEditMaskFile($confDir."/".$quickEditMaskFileName);
 
 my $quickEditMaskTree;
 my $setupTree;
+my $systemTree;
 my $sensorAreaId;
 my $quickEditAreaId;
+my $daqopserver;
+my $gbe_port;
 
 my %previewAreaIdHash;
 
@@ -126,6 +132,14 @@ sub parse_setupFile {
   }
   $setupTree = $parser->parse_file($setupFile);
 }
+sub parse_systemFile {
+  my $parser = XML::LibXML->new();
+  $systemFile = $systemDir.$systemName.".xml";
+  unless( -e $systemFile ) { 
+    die "system file $systemFile does not exist!\n";
+  }
+  $systemTree = $parser->parse_file($systemFile);
+}
 
 sub init_html{
 
@@ -221,7 +235,7 @@ sub init_html{
  
  
   print "<p id='show_advanced_options' class='quasibutton' >advanced options</p>";
-  print "<div id='advancedOptionsContainer' class='stylishBox hidden_by_default'>";
+  print "<div id='advancedOptionsContainer' class='stylishBox'>";
   print "<div class='header'>advanced options</div>";
   print "<div id='advancedOptions'>";
   
@@ -231,13 +245,17 @@ sub init_html{
 #   print "</td><td>";
   print q%<input type='button' id='button_init_system' value='init system'
   title="initialize the readout system (resets the TRB3)">%;
+  print "</td><td>";
+  print q%<a href="../HldRec/HldRec.pl?ports=%.$gbe_port.q%&shm_id=%.$setupName.q%" target=_blank><input type='button' id='button_take_data' value='take data'
+  title="record large amounts of data"></a>%;
+#   print "setupName: $setupName, gbe port: $gbe_port";
   print "</td></tr></table>"; 
   print "</div>";
   print "</div>";
   
   
   print "<p id='show_theConsole' class='quasibutton' >show debug output</p>";
-  print "<div id='theConsoleContainer' class='stylishBox hidden_by_default'>";
+  print "<div id='theConsoleContainer' class='stylishBox'>";
   print "<div class='header'>debug output</div>";
   print "<div id='theConsole'>[the \"console\"]</div>";
   print "</div>";
@@ -257,11 +275,20 @@ sub print_setupStructure {
   my $setup = $setupTree->findnodes("/setup")->shift();
   unless(defined($setup)) { die "did not find setup node in setup file!\n";}
   my $setupDesc = $setup->findvalue("./description");
-  my $setupName = $setup->findvalue("./\@name");
+     $setupName = $setup->findvalue("./\@name");
      $systemName = $setup->findvalue("/setup/system/\@name");
+  unless(defined($systemTree)) {
+    parse_systemFile();
+  }
   print h2("Setup: $setupName");
+  $daqopserver = $systemTree->findvalue("//daqopserver");
+  $gbe_port    = $systemTree->findvalue("//gbe/\@port");
+  print "<p>DAQOPSERVER=".$daqopserver."</p>";
+  
   print "<p>description: $setupDesc</p>";
   
+  
+  
   my @controllers = $setup->findnodes("./controller");
   unless(scalar(@controllers) > 0) { die "no controllers in setup file!\n";}
   for my $controller (@controllers) {
@@ -283,7 +310,7 @@ sub print_setupStructure {
       for my $sensor (@sensors) {
         
 
-        print_sensorArea($controller,$sensor);
+        print_sensorArea($controller,$chain,$sensor);
       }
       
     }
@@ -300,7 +327,8 @@ sub print_setupStructure {
 sub print_sensorArea {
   
   my $controller = $_[0];
-  my $sensor = $_[1];
+  my $chain = $_[1];
+  my $sensor = $_[2];
   # this is an xml object that contains the sensor node
   # from the setup file
   
@@ -314,6 +342,13 @@ sub print_sensorArea {
   my $sensorPosition = $sensor->findnodes("./position")->shift();
   my $sensorDescription = $sensor->findvalue("./description");
   
+  my $adcmon_info = {
+    FPGA        => $controllerAddress,
+    DAQOPSERVER => $daqopserver,
+    CB          => $chain->findvalue("./\@id"),
+    chip        => $sensor->findvalue("./\@id")
+  };
+  
   
   $sensorAreaId = $sensorId;
   print "<div class='sensorAreaDiv' id='".$sensorAreaId."'>";
@@ -324,11 +359,10 @@ sub print_sensorArea {
   print "<td class='previewArea stylishBox'>";
   print "<div class='header' title='$sensorDescription'>$sensorName (id=$sensorId)</div>";
   print "<div id='".$previewAreaId."' class='prevImgContainer'><div>[not run yet]</div></div>";
-  
   print "</td>";
   $quickEditAreaId = "quickEdit_".$sensorId;
   print "<td id='".$quickEditAreaId."' class='quickEditArea stylishBox'>";
-  print_quickEditArea($sensorConfig);
+  print_quickEditArea($sensorConfig,$adcmon_info);
   print "</td>";
   print "</tr>";
 
@@ -344,7 +378,7 @@ sub print_sensorArea {
 sub print_quickEditArea {
 
   my $argumentConfigFile = $_[0];
-
+  my $adcmon_info = $_[1];
 
   
   parseConfigAndSpec($argumentConfigFile);
@@ -353,8 +387,28 @@ sub print_quickEditArea {
   print "<div align=center><a title='open config file with the full featured JTAG editor' href='jtageditor.pl?edit=".getConfigFileName()."'>".getConfigFileName()."</a></div>";
   setEditorRefreshCommand("reloadQuickEditArea(\"".getConfigFileName()."\",\"$quickEditAreaId\")"); 
   print_registers(getConfigFile());
-
-
+  print "<hr>";
+#   print "<p> DAQOPSERVER: ".
+#   $adcmon_info->{DAQOPSERVER}
+#   ."</p>";
+#   print "<p> FPGA: ".
+#   $adcmon_info->{FPGA}
+#   ."</p>";
+#   print "<p> CB: ".
+#   $adcmon_info->{CB}
+#   ."</p>";
+#   print "<p> CHIP: ".
+#   $adcmon_info->{chip}
+#   ."</p>";
+  
+  print "<div align=center><a title='open ADC monitor for this chip'
+  href='adcmon.pl?DAQOPSERVER=".$adcmon_info->{DAQOPSERVER}
+  ."&FPGA=0x".$adcmon_info->{FPGA}
+  ."&CB=".$adcmon_info->{CB}
+  ."&chip=".($adcmon_info->{chip}&0xF)
+  ."&channel=CurrentDigital,CurrentAnalog'>ADC monitor</a>";
+  print q% - <input type='button' onClick='run(document.getElementById("runtime").value)' value='run'>%;
+  print "</div>";
 }
 
 
index 6bd2d94dcfe563f38087a35bfe2a2751c782ee1f..fb7fda42a5d85cdf2750c5b784adb814f36259f6 100644 (file)
@@ -14,6 +14,7 @@ unsigned pixelMap[MAX_SENSORS][576][1152] = {{0}};
 unsigned pixelcount[MAX_SENSORS][1153] = {{0}};
 unsigned statistics[MAX_SENSORS][4] = {{0}};
 unsigned numSensors = 0;
+unsigned long numSubevents = 0;
 unsigned countMarkedFrames = 0;
 unsigned sensors[MAX_SENSORS];
 
@@ -61,9 +62,11 @@ unsigned getSensor(unsigned sensorId) {
 void readSubEvents(hadaq::RawEvent* evnt) {
        hadaq::RawSubevent* sub = 0;
        while ((sub=evnt->NextSubevent(sub))!=0) {
+               numSubevents++;
                unsigned trbSubEvSize = sub->GetSize() / 4 - 4;
-#if DEBUG>=2
-               printf("Subevent Size\t%08x\n",
+#if DEBUG>=1
+               printf("Subevent  no. %d  Size\t%08x\n",
+                               numSubevents,
                                trbSubEvSize);
 #endif
                unsigned pos = 0;
@@ -186,13 +189,15 @@ signed analyzeSubEvent(hadaq::RawSubevent* sub, unsigned pos, unsigned datalen,
 #endif
 
                if (sub->Data(pdata) != 0x55555555) {
+#if DEBUG>=1
                        printf("ERROR: Sensor Header (0x55555555) Not Found! (got: %08x)\n",sub->Data(pdata));
+#endif
                        continue;
                        }
 
                unsigned sensorIsValid = 0;
                if (v1 == 1){
-                       if(frame_status == 0xf000000f) {
+                       if((frame_status & 0xf000000f) == 0xf000000f) {
                                sensorIsValid = 1;
                        }
                        else{
@@ -210,13 +215,13 @@ signed analyzeSubEvent(hadaq::RawSubevent* sub, unsigned pos, unsigned datalen,
                                }
                        }
                else if (v3 == 1){
-                       if (frame_status == 0x0) {
-                               sensorIsValid = 1;
-                               }
-                       else{
+                       if (frame_status & ((1<<14) | (1<<1) | (1<<2) | (1<<3) | (1<<4))) {
                                sensorIsValid = 0;
                                statistics[mySensor][FRBROKEN]++;
                                }
+                       else{
+                               sensorIsValid = 1;
+                               }
                        }
 
                if(sensorIsValid && frame_length>0x0){
@@ -268,7 +273,7 @@ signed analyzeSubEvent(hadaq::RawSubevent* sub, unsigned pos, unsigned datalen,
                                                        }
                                                }
 
-                                       #if DEBUG>=2
+                                       #if DEBUG>=3
                                        printf("\tdx >>> %04x\n",d);
                                        #endif
 
@@ -281,7 +286,7 @@ signed analyzeSubEvent(hadaq::RawSubevent* sub, unsigned pos, unsigned datalen,
                                        else {
                                                pixels = (d & 0x3);
                                                column = (d >> 2) & 0x7FF;
-                                               #if DEBUG>=2
+                                               #if DEBUG>=3
                                                printf("\t%d, %d x %d\n",line,column,pixels+1);
                                                #endif
                                                pixelcount[mySensor][column] += pixels+1;
@@ -373,7 +378,7 @@ signed analyzeData(hadaq::RawSubevent* sub, unsigned ix, unsigned datalen, unsig
                //Something is really wrong with data. Skip SubEvent!
                printf("Broken Sensor Header\n");
                statistics[mySensor][FRREALBROKEN]++;
-               #if DEBUG==0
+               #if DEBUG>=0
                printf("Head\t%08x\tID\t%08x\tStatus\t%08x\tError\t%08x\tDebug\t%08x\n",
                                        sensorHead, sensorId, sensorStatus, sensorError, sensorDebug);
                #endif