[Phpmyadmin-git] [SCM] phpMyAdmin branch, master, updated. RELEASE_3_4_3_1-11900-gf34dfda

Michal Čihař nijel at users.sourceforge.net
Mon Jul 25 11:31:41 CEST 2011


The branch, master has been updated
       via  f34dfda0fe22e24deeb012701cb481f9e4af579c (commit)
       via  ace73f25bbec0da26c97ef4e97583c3655c83c42 (commit)
       via  9ee8ff38c3388dce4cbee016c278f0602601dc27 (commit)
       via  2689428b3866725a8de292ad3039efc78c86ea19 (commit)
       via  bf20f06683000cb7a2f31184a61c6f57161924c7 (commit)
       via  9f343e6ead652e4cfa0224a120aa74505cab42ca (commit)
       via  0530016f381c52f683b5a6a2d40e313ae7c427ed (commit)
       via  def2df01f303d17250f1854f079f0c0c95eee30c (commit)
       via  64d2cb7e5ede1a62bfb66d1f32e9804c0fbed147 (commit)
       via  c30d209146d9d7c2f840cb8fb14de8840dccd54e (commit)
       via  5022829ae64d9f72726a9d73ba2f2e51de2b2837 (commit)
      from  5e72ef35781881d791b337d5ac19b5311c65e953 (commit)


- Log -----------------------------------------------------------------
commit f34dfda0fe22e24deeb012701cb481f9e4af579c
Merge: 5e72ef35781881d791b337d5ac19b5311c65e953 ace73f25bbec0da26c97ef4e97583c3655c83c42
Author: Michal Čihař <mcihar at suse.cz>
Date:   Mon Jul 25 11:29:17 2011 +0200

    Merge remote-tracking branch 'tyron/master'
    
    Conflicts:
    	js/functions.js
    	js/server_status.js
    	js/sql.js
    	libraries/common.lib.php
    	server_status.php
    	themes/pmahomme/css/theme_left.css.php

commit ace73f25bbec0da26c97ef4e97583c3655c83c42
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Sat Jul 23 09:23:18 2011 +0300

    - Added missing CSS Sprites, Icon sprites now also for PMA_linkOrButton()
    - Rewrote PMA_linkOrButton() to rely on Javascript, making the code way less complicated
    - Removed legacy support of Javascript 1.1 or lower
    - Fixed a bug in cases where PMA_linkOrButton() creates a form, which when clicked required a js confirm, the confirm is being displayed a second time after the form is submitted.

commit 9ee8ff38c3388dce4cbee016c278f0602601dc27
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Fri Jul 22 11:41:13 2011 +0300

    Replaced qtTip js library with non-minified version.

commit 2689428b3866725a8de292ad3039efc78c86ea19
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Fri Jul 22 11:39:59 2011 +0300

    debug logging for linux cpu chart

commit bf20f06683000cb7a2f31184a61c6f57161924c7
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Thu Jul 21 17:46:03 2011 +0300

    Adjusted some places to adjust to current master changes, plus IE8 fix for Status page

commit 9f343e6ead652e4cfa0224a120aa74505cab42ca
Merge: 0530016f381c52f683b5a6a2d40e313ae7c427ed ce3f3087414ebb87acf75346c17a69962e699e62
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Thu Jul 21 17:41:06 2011 +0300

    Merge remote-tracking branch 'origin/master'
    
    Conflicts:
    	js/functions.js
    	libraries/common.lib.php
    	libraries/header.inc.php
    	server_status.php

commit 0530016f381c52f683b5a6a2d40e313ae7c427ed
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Thu Jul 21 15:45:41 2011 +0300

    With backgroundColor: 'transparent' Opera and IE draw black background on all charts.
    Using 'none' seems to work well on all major browsers

commit def2df01f303d17250f1854f079f0c0c95eee30c
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Thu Jul 21 15:26:30 2011 +0300

    Fix: undefined index php notice
    Fix: INSERT queries not being grouped

commit 64d2cb7e5ede1a62bfb66d1f32e9804c0fbed147
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Thu Jul 21 13:43:21 2011 +0300

    Removed debug code

commit c30d209146d9d7c2f840cb8fb14de8840dccd54e
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Thu Jul 21 13:38:51 2011 +0300

    Query Analyzer Dialog v0.1

commit 5022829ae64d9f72726a9d73ba2f2e51de2b2837
Author: Tyron Madlener <tyronx at gmail.com>
Date:   Wed Jul 20 12:08:05 2011 +0300

    Monitor Logs Feature: Grouping of Queries, ignoring variable data in WHERE Statements

-----------------------------------------------------------------------

Summary of changes:
 js/functions.js                                    |  258 ++--
 js/jquery/jquery.qtip-1.0.0-rc3.js                 | 2149 ++++++++++++++++++++
 js/jquery/jquery.qtip-1.0.0.min.js                 |   15 -
 js/jquery/jquery.sortableTable.js                  |   32 +-
 js/messages.php                                    |   13 +-
 js/server_status.js                                | 1140 ++++++-----
 js/sql.js                                          |   53 +-
 libraries/common.lib.php                           |   66 +-
 libraries/header_scripts.inc.php                   |    2 +-
 server_status.php                                  |  166 +-
 sql.php                                            |    2 +-
 themes/original/css/theme_left.css.php             |    2 +
 themes/original/img/s_sortable.png                 |  Bin 0 -> 258 bytes
 themes/pmahomme/css/theme_left.css.php             |    4 +
 themes/pmahomme/css/theme_right.css.php            |   29 +
 themes/pmahomme/img/pause.png                      |  Bin 0 -> 329 bytes
 .../img/b_nextpage.png => pmahomme/img/play.png}   |  Bin 395 -> 395 bytes
 17 files changed, 3178 insertions(+), 753 deletions(-)
 create mode 100644 js/jquery/jquery.qtip-1.0.0-rc3.js
 delete mode 100644 js/jquery/jquery.qtip-1.0.0.min.js
 create mode 100644 themes/original/img/s_sortable.png
 create mode 100644 themes/pmahomme/img/pause.png
 copy themes/{original/img/b_nextpage.png => pmahomme/img/play.png} (100%)

diff --git a/js/functions.js b/js/functions.js
index 7b36e51..d7694f4 100644
--- a/js/functions.js
+++ b/js/functions.js
@@ -210,7 +210,13 @@ function confirmLink(theLink, theSqlQuery)
 
     var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + theSqlQuery);
     if (is_confirmed) {
-        if ( typeof(theLink.href) != 'undefined' ) {
+        if ( $(theLink).hasClass('formLinkSubmit') ) {
+			var name = 'is_js_confirmed';
+            if($(theLink).attr('href').indexOf('usesubform') != -1)
+				name = 'subform[' + $(theLink).attr('href').substr('#').match(/usesubform\[(\d+)\]/i)[1] + '][is_js_confirmed]';
+
+            $(theLink).parents('form').append('<input type="hidden" name="' + name + '" value="1" />');
+        } else if ( typeof(theLink.href) != 'undefined' ) {
             theLink.href += '&is_js_confirmed=1';
         } else if ( typeof(theLink.form) != 'undefined' ) {
             theLink.form.action += '?is_js_confirmed=1';
@@ -265,59 +271,51 @@ function confirmQuery(theForm1, sqlQuery1)
         return true;
     }
 
-    // The replace function (js1.2) isn't supported
-    else if (typeof(sqlQuery1.value.replace) == 'undefined') {
-        return true;
-    }
-
-    // js1.2+ -> validation with regular expressions
-    else {
-        // "DROP DATABASE" statement isn't allowed
-        if (PMA_messages['strNoDropDatabases'] != '') {
-            var drop_re = new RegExp('(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s', 'i');
-            if (drop_re.test(sqlQuery1.value)) {
-                alert(PMA_messages['strNoDropDatabases']);
-                theForm1.reset();
-                sqlQuery1.focus();
-                return false;
-            } // end if
+    // "DROP DATABASE" statement isn't allowed
+    if (PMA_messages['strNoDropDatabases'] != '') {
+        var drop_re = new RegExp('(^|;)\\s*DROP\\s+(IF EXISTS\\s+)?DATABASE\\s', 'i');
+        if (drop_re.test(sqlQuery1.value)) {
+            alert(PMA_messages['strNoDropDatabases']);
+            theForm1.reset();
+            sqlQuery1.focus();
+            return false;
         } // end if
+    } // end if
 
-        // Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement
-        //
-        // TODO: find a way (if possible) to use the parser-analyser
-        // for this kind of verification
-        // For now, I just added a ^ to check for the statement at
-        // beginning of expression
-
-        var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s', 'i');
-        var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i');
-        var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i');
-        var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i');
-
-        if (do_confirm_re_0.test(sqlQuery1.value)
-            || do_confirm_re_1.test(sqlQuery1.value)
-            || do_confirm_re_2.test(sqlQuery1.value)
-            || do_confirm_re_3.test(sqlQuery1.value)) {
-            var message      = (sqlQuery1.value.length > 100)
-                             ? sqlQuery1.value.substr(0, 100) + '\n    ...'
-                             : sqlQuery1.value;
-            var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + message);
-            // statement is confirmed -> update the
-            // "is_js_confirmed" form field so the confirm test won't be
-            // run on the server side and allows to submit the form
-            if (is_confirmed) {
-                theForm1.elements['is_js_confirmed'].value = 1;
-                return true;
-            }
-            // statement is rejected -> do not submit the form
-            else {
-                window.focus();
-                sqlQuery1.focus();
-                return false;
-            } // end if (handle confirm box result)
-        } // end if (display confirm box)
-    } // end confirmation stuff
+    // Confirms a "DROP/DELETE/ALTER/TRUNCATE" statement
+    //
+    // TODO: find a way (if possible) to use the parser-analyser
+    // for this kind of verification
+    // For now, I just added a ^ to check for the statement at
+    // beginning of expression
+
+    var do_confirm_re_0 = new RegExp('^\\s*DROP\\s+(IF EXISTS\\s+)?(TABLE|DATABASE|PROCEDURE)\\s', 'i');
+    var do_confirm_re_1 = new RegExp('^\\s*ALTER\\s+TABLE\\s+((`[^`]+`)|([A-Za-z0-9_$]+))\\s+DROP\\s', 'i');
+    var do_confirm_re_2 = new RegExp('^\\s*DELETE\\s+FROM\\s', 'i');
+    var do_confirm_re_3 = new RegExp('^\\s*TRUNCATE\\s', 'i');
+
+    if (do_confirm_re_0.test(sqlQuery1.value)
+        || do_confirm_re_1.test(sqlQuery1.value)
+        || do_confirm_re_2.test(sqlQuery1.value)
+        || do_confirm_re_3.test(sqlQuery1.value)) {
+        var message      = (sqlQuery1.value.length > 100)
+                         ? sqlQuery1.value.substr(0, 100) + '\n    ...'
+                         : sqlQuery1.value;
+        var is_confirmed = confirm(PMA_messages['strDoYouReally'] + ' :\n' + message);
+        // statement is confirmed -> update the
+        // "is_js_confirmed" form field so the confirm test won't be
+        // run on the server side and allows to submit the form
+        if (is_confirmed) {
+            theForm1.elements['is_js_confirmed'].value = 1;
+            return true;
+        }
+        // statement is rejected -> do not submit the form
+        else {
+            window.focus();
+            sqlQuery1.focus();
+            return false;
+        } // end if (handle confirm box result)
+    } // end if (display confirm box)
 
     return true;
 } // end of the 'confirmQuery()' function
@@ -360,47 +358,31 @@ function checkSqlQuery(theForm)
     var sqlQuery = theForm.elements['sql_query'];
     var isEmpty  = 1;
 
-    // The replace function (js1.2) isn't supported -> basic tests
-    if (typeof(sqlQuery.value.replace) == 'undefined') {
-        isEmpty      = (sqlQuery.value == '') ? 1 : 0;
-        if (isEmpty && typeof(theForm.elements['sql_file']) != 'undefined') {
-            isEmpty  = (theForm.elements['sql_file'].value == '') ? 1 : 0;
-        }
-        if (isEmpty && typeof(theForm.elements['sql_localfile']) != 'undefined') {
-            isEmpty  = (theForm.elements['sql_localfile'].value == '') ? 1 : 0;
-        }
-        if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined') {
-            isEmpty  = (theForm.elements['id_bookmark'].value == null || theForm.elements['id_bookmark'].value == '');
-        }
+    var space_re = new RegExp('\\s+');
+    if (typeof(theForm.elements['sql_file']) != 'undefined' &&
+            theForm.elements['sql_file'].value.replace(space_re, '') != '') {
+        return true;
     }
-    // js1.2+ -> validation with regular expressions
-    else {
-        var space_re = new RegExp('\\s+');
-        if (typeof(theForm.elements['sql_file']) != 'undefined' &&
-                theForm.elements['sql_file'].value.replace(space_re, '') != '') {
-            return true;
-        }
-        if (typeof(theForm.elements['sql_localfile']) != 'undefined' &&
-                theForm.elements['sql_localfile'].value.replace(space_re, '') != '') {
-            return true;
-        }
-        if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined' &&
-                (theForm.elements['id_bookmark'].value != null || theForm.elements['id_bookmark'].value != '') &&
-                theForm.elements['id_bookmark'].selectedIndex != 0
-                ) {
+    if (typeof(theForm.elements['sql_localfile']) != 'undefined' &&
+            theForm.elements['sql_localfile'].value.replace(space_re, '') != '') {
+        return true;
+    }
+    if (isEmpty && typeof(theForm.elements['id_bookmark']) != 'undefined' &&
+            (theForm.elements['id_bookmark'].value != null || theForm.elements['id_bookmark'].value != '') &&
+            theForm.elements['id_bookmark'].selectedIndex != 0
+            ) {
+        return true;
+    }
+    // Checks for "DROP/DELETE/ALTER" statements
+    if (sqlQuery.value.replace(space_re, '') != '') {
+        if (confirmQuery(theForm, sqlQuery)) {
             return true;
+        } else {
+            return false;
         }
-        // Checks for "DROP/DELETE/ALTER" statements
-        if (sqlQuery.value.replace(space_re, '') != '') {
-            if (confirmQuery(theForm, sqlQuery)) {
-                return true;
-            } else {
-                return false;
-            }
-        }
-        theForm.reset();
-        isEmpty = 1;
     }
+    theForm.reset();
+    isEmpty = 1;
 
     if (isEmpty) {
         sqlQuery.select();
@@ -423,19 +405,9 @@ function checkSqlQuery(theForm)
  */
 function emptyCheckTheField(theForm, theFieldName)
 {
-    var isEmpty  = 1;
     var theField = theForm.elements[theFieldName];
-    // Whether the replace function (js1.2) is supported or not
-    var isRegExp = (typeof(theField.value.replace) != 'undefined');
-
-    if (!isRegExp) {
-        isEmpty      = (theField.value == '') ? 1 : 0;
-    } else {
-        var space_re = new RegExp('\\s+');
-        isEmpty      = (theField.value.replace(space_re, '') == '') ? 1 : 0;
-    }
-
-    return isEmpty;
+    var space_re = new RegExp('\\s+');
+    return (theField.value.replace(space_re, '') == '') ? 1 : 0;
 } // end of the 'emptyCheckTheField()' function
 
 
@@ -1457,6 +1429,8 @@ function PMA_createTableDialog( div, url , target) {
  *                                      - the current response value of the GET request, JSON parsed
  *                                      - the previous response value of the GET request, JSON parsed
  *                                      - the number of added points
+ *                                  error: Callback function when the get request fails. TODO: Apply callback on timeouts aswell
+ *                              }
  *
  * @return  object   The created highcharts instance
  */
@@ -1467,7 +1441,7 @@ function PMA_createChart(passedSettings) {
         chart: {
             type: 'spline',
             marginRight: 10,
-            backgroundColor: 'transparent',
+            backgroundColor: 'none',
             events: {
                 /* Live charting support */
                 load: function() {
@@ -1488,7 +1462,13 @@ function PMA_createChart(passedSettings) {
                             thisChart.options.realtime.url,
                             thisChart.options.realtime.postData,
                             function(data) {
-                                curValue = jQuery.parseJSON(data);
+                                try {
+                                    curValue = jQuery.parseJSON(data);
+                                } catch (err) {
+                                    if(thisChart.options.realtime.error)
+                                        thisChart.options.realtime.error(err);
+                                    return;
+                                }
 
                                 if(lastValue==null) diff = curValue.x - thisChart.xAxis[0].getExtremes().max;
                                 else diff = parseInt(curValue.x - lastValue.x);
@@ -1578,6 +1558,53 @@ function PMA_createChart(passedSettings) {
     return new Highcharts.Chart(settings);
 }
 
+
+/*
+ * Creates a Profiling Chart. Used in sql.php and server_status.js
+ */
+function PMA_createProfilingChart(data, options) {
+    return PMA_createChart($.extend(true, {
+        chart: {
+            renderTo: 'profilingchart',
+            type: 'pie'
+        },
+        title: { text:'', margin:0 },
+        series: [{
+            type: 'pie',
+            name: PMA_messages['strQueryExecutionTime'],
+            data: data
+        }],
+        plotOptions: {
+            pie: {
+                allowPointSelect: true,
+                cursor: 'pointer',
+                dataLabels: {
+                    enabled: true,
+                    distance: 35,
+                    formatter: function() {
+                        return '<b>'+ this.point.name +'</b><br/>'+ Highcharts.numberFormat(this.percentage, 2) +' %';
+                   }
+                }
+            }
+        },
+        tooltip: {
+            formatter: function() {
+                return '<b>'+ this.point.name +'</b><br/>'+PMA_prettyProfilingNum(this.y)+'<br/>('+Highcharts.numberFormat(this.percentage, 2) +' %)';
+            }
+        }
+    },options));
+}
+
+// Formats a profiling duration nicely. Used in PMA_createProfilingChart() and server_status.js
+function PMA_prettyProfilingNum(num, acc) {
+    if(!acc) acc = 1;
+    acc = Math.pow(10,acc);
+    if(num*1000 < 0.1) num = Math.round(acc*(num*1000*1000))/acc + 'µ'
+    else if(num < 0.1) num = Math.round(acc*(num*1000))/acc + 'm'
+
+    return num + 's';
+}
+
 /**
  * jQuery function that uses jQueryUI's dialogs to confirm with user. Does not
  *  return a jQuery object yet and hence cannot be chained
@@ -2710,22 +2737,15 @@ $(document).ready(function() {
     /**
      * Enables the text generated by PMA_linkOrButton() to be clickable
      */
-    $('.clickprevimage')
-        .css('color', function(index) {
-            return $('a').css('color');
-        })
-        .css('cursor', function(index) {
-            return $('a').css('cursor');
-        }) //todo: hover effect
-        .live('click',function(e) {
-            $this_span = $(this);
-            if ($this_span.closest('td').is('.inline_edit_anchor')) {
-            // this would bind a second click event to the inline edit
-            // anchor and would disturb its behavior
-            } else {
-                $this_span.parent().find('input:image').click();
-            }
-        });
+    $('a[class~="formLinkSubmit"]').live('click',function(e) {
+
+        if($(this).attr('href').indexOf('=') != -1) {
+            var data = $(this).attr('href').substr($(this).attr('href').indexOf('#')+1).split('=',2);
+            $(this).parents('form').append('<input type="hidden" name="' + data[0] + '" value="' + data[1] + '"/>');
+        }
+        $(this).parents('form').submit();
+        return false;
+    });
 
     $('#update_recent_tables').ready(function() {
         if (window.parent.frame_navigation != undefined
diff --git a/js/jquery/jquery.qtip-1.0.0-rc3.js b/js/jquery/jquery.qtip-1.0.0-rc3.js
new file mode 100644
index 0000000..5b9c7e3
--- /dev/null
+++ b/js/jquery/jquery.qtip-1.0.0-rc3.js
@@ -0,0 +1,2149 @@
+/*!
+ * jquery.qtip. The jQuery tooltip plugin
+ *
+ * Copyright (c) 2009 Craig Thompson
+ * http://craigsworks.com
+ *
+ * Licensed under MIT
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Launch  : February 2009
+ * Version : 1.0.0-rc3
+ * Released: Tuesday 12th May, 2009 - 00:00
+ * Debug: jquery.qtip.debug.js
+ */
+(function($)
+{
+   // Implementation
+   $.fn.qtip = function(options, blanket)
+   {
+      var i, id, interfaces, opts, obj, command, config, api;
+
+      // Return API / Interfaces if requested
+      if(typeof options == 'string')
+      {
+         // Make sure API data exists if requested
+         if(typeof $(this).data('qtip') !== 'object')
+            $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_TOOLTIP_PRESENT, false);
+
+         // Return requested object
+         if(options == 'api')
+            return $(this).data('qtip').interfaces[ $(this).data('qtip').current ];
+         else if(options == 'interfaces')
+            return $(this).data('qtip').interfaces;
+      }
+
+      // Validate provided options
+      else
+      {
+         // Set null options object if no options are provided
+         if(!options) options = {};
+
+         // Sanitize option data
+         if(typeof options.content !== 'object' || (options.content.jquery && options.content.length > 0)) options.content = { text: options.content };
+         if(typeof options.content.title !== 'object') options.content.title = { text: options.content.title };
+         if(typeof options.position !== 'object') options.position = { corner: options.position };
+         if(typeof options.position.corner !== 'object') options.position.corner = { target: options.position.corner, tooltip: options.position.corner };
+         if(typeof options.show !== 'object') options.show = { when: options.show };
+         if(typeof options.show.when !== 'object') options.show.when = { event: options.show.when };
+         if(typeof options.show.effect !== 'object') options.show.effect = { type: options.show.effect };
+         if(typeof options.hide !== 'object') options.hide = { when: options.hide };
+         if(typeof options.hide.when !== 'object') options.hide.when = { event: options.hide.when };
+         if(typeof options.hide.effect !== 'object') options.hide.effect = { type: options.hide.effect };
+         if(typeof options.style !== 'object') options.style = { name: options.style };
+         options.style = sanitizeStyle(options.style);
+
+         // Build main options object
+         opts = $.extend(true, {}, $.fn.qtip.defaults, options);
+
+         // Inherit all style properties into one syle object and include original options
+         opts.style = buildStyle.call({ options: opts }, opts.style);
+         opts.user = $.extend(true, {}, options);
+      };
+
+      // Iterate each matched element
+      return $(this).each(function() // Return original elements as per jQuery guidelines
+      {
+         // Check for API commands
+         if(typeof options == 'string')
+         {
+            command = options.toLowerCase();
+            interfaces = $(this).qtip('interfaces');
+
+            // Make sure API data exists$('.qtip').qtip('destroy')
+            if(typeof interfaces == 'object')
+            {
+               // Check if API call is a BLANKET DESTROY command
+               if(blanket === true && command == 'destroy')
+                  while(interfaces.length > 0) interfaces[interfaces.length-1].destroy();
+
+               // API call is not a BLANKET DESTROY command
+               else
+               {
+                  // Check if supplied command effects this tooltip only (NOT BLANKET)
+                  if(blanket !== true) interfaces = [ $(this).qtip('api') ];
+
+                  // Execute command on chosen qTips
+                  for(i = 0; i < interfaces.length; i++)
+                  {
+                     // Destroy command doesn't require tooltip to be rendered
+                     if(command == 'destroy') interfaces[i].destroy();
+
+                     // Only call API if tooltip is rendered and it wasn't a destroy call
+                     else if(interfaces[i].status.rendered === true)
+                     {
+                        if(command == 'show') interfaces[i].show();
+                        else if(command == 'hide') interfaces[i].hide();
+                        else if(command == 'focus') interfaces[i].focus();
+                        else if(command == 'disable') interfaces[i].disable(true);
+                        else if(command == 'enable') interfaces[i].disable(false);
+                     };
+                  };
+               };
+            };
+         }
+
+         // No API commands, continue with qTip creation
+         else
+         {
+            // Create unique configuration object
+            config = $.extend(true, {}, opts);
+            config.hide.effect.length = opts.hide.effect.length;
+            config.show.effect.length = opts.show.effect.length;
+
+            // Sanitize target options
+            if(config.position.container === false) config.position.container = $(document.body);
+            if(config.position.target === false) config.position.target = $(this);
+            if(config.show.when.target === false) config.show.when.target = $(this);
+            if(config.hide.when.target === false) config.hide.when.target = $(this);
+
+            // Determine tooltip ID (Reuse array slots if possible)
+            id = $.fn.qtip.interfaces.length;
+            for(i = 0; i < id; i++)
+            {
+               if(typeof $.fn.qtip.interfaces[i] == 'undefined'){ id = i; break; };
+            };
+
+            // Instantiate the tooltip
+            obj = new qTip($(this), config, id);
+
+            // Add API references
+            $.fn.qtip.interfaces[id] = obj;
+
+            // Check if element already has qTip data assigned
+            if(typeof $(this).data('qtip') == 'object')
+            {
+               // Set new current interface id
+               if(typeof $(this).attr('qtip') === 'undefined')
+                  $(this).data('qtip').current = $(this).data('qtip').interfaces.length;
+
+               // Push new API interface onto interfaces array
+               $(this).data('qtip').interfaces.push(obj);
+            }
+
+            // No qTip data is present, create now
+            else $(this).data('qtip', { current: 0, interfaces: [obj] });
+
+            // If prerendering is disabled, create tooltip on showEvent
+            if(config.content.prerender === false && config.show.when.event !== false && config.show.ready !== true)
+            {
+               config.show.when.target.bind(config.show.when.event+'.qtip-'+id+'-create', { qtip: id }, function(event)
+               {
+                  // Retrieve API interface via passed qTip Id
+                  api = $.fn.qtip.interfaces[ event.data.qtip ];
+
+                  // Unbind show event and cache mouse coords
+                  api.options.show.when.target.unbind(api.options.show.when.event+'.qtip-'+event.data.qtip+'-create');
+                  api.cache.mouse = { x: event.pageX, y: event.pageY };
+
+                  // Render tooltip and start the event sequence
+                  construct.call( api );
+                  api.options.show.when.target.trigger(api.options.show.when.event);
+               });
+            }
+
+            // Prerendering is enabled, create tooltip now
+            else
+            {
+               // Set mouse position cache to top left of the element
+               obj.cache.mouse = {
+                  x: config.show.when.target.offset().left,
+                  y: config.show.when.target.offset().top
+               };
+
+               // Construct the tooltip
+               construct.call(obj);
+            }
+         };
+      });
+   };
+
+   // Instantiator
+   function qTip(target, options, id)
+   {
+      // Declare this reference
+      var self = this;
+
+      // Setup class attributes
+      self.id = id;
+      self.options = options;
+      self.status = {
+         animated: false,
+         rendered: false,
+         disabled: false,
+         focused: false
+      };
+      self.elements = {
+         target: target.addClass(self.options.style.classes.target),
+         tooltip: null,
+         wrapper: null,
+         content: null,
+         contentWrapper: null,
+         title: null,
+         button: null,
+         tip: null,
+         bgiframe: null
+      };
+      self.cache = {
+         mouse: {},
+         position: {},
+         toggle: 0
+      };
+      self.timers = {};
+
+      // Define exposed API methods
+      $.extend(self, self.options.api,
+      {
+         show: function(event)
+         {
+            var returned, solo;
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'show');
+
+            // Only continue if element is visible
+            if(self.elements.tooltip.css('display') !== 'none') return self;
+
+            // Clear animation queue
+            self.elements.tooltip.stop(true, false);
+
+            // Call API method and if return value is false, halt
+            returned = self.beforeShow.call(self, event);
+            if(returned === false) return self;
+
+            // Define afterShow callback method
+            function afterShow()
+            {
+               // Call API method and focus if it isn't static
+               if(self.options.position.type !== 'static') self.focus();
+               self.onShow.call(self, event);
+
+               // Prevent antialias from disappearing in IE7 by removing filter attribute
+               if($.browser.msie) self.elements.tooltip.get(0).style.removeAttribute('filter');
+            };
+
+            // Maintain toggle functionality if enabled
+            self.cache.toggle = 1;
+
+            // Update tooltip position if it isn't static
+            if(self.options.position.type !== 'static')
+               self.updatePosition(event, (self.options.show.effect.length > 0));
+
+            // Hide other tooltips if tooltip is solo
+            if(typeof self.options.show.solo == 'object') solo = $(self.options.show.solo);
+            else if(self.options.show.solo === true) solo = $('div.qtip').not(self.elements.tooltip);
+            if(solo) solo.each(function(){ if($(this).qtip('api').status.rendered === true) $(this).qtip('api').hide(); });
+
+            // Show tooltip
+            if(typeof self.options.show.effect.type == 'function')
+            {
+               self.options.show.effect.type.call(self.elements.tooltip, self.options.show.effect.length);
+               self.elements.tooltip.queue(function(){ afterShow(); $(this).dequeue(); });
+            }
+            else
+            {
+               switch(self.options.show.effect.type.toLowerCase())
+               {
+                  case 'fade':
+                     self.elements.tooltip.fadeIn(self.options.show.effect.length, afterShow);
+                     break;
+                  case 'slide':
+                     self.elements.tooltip.slideDown(self.options.show.effect.length, function()
+                     {
+                        afterShow();
+                        if(self.options.position.type !== 'static') self.updatePosition(event, true);
+                     });
+                     break;
+                  case 'grow':
+                     self.elements.tooltip.show(self.options.show.effect.length, afterShow);
+                     break;
+                  default:
+                     self.elements.tooltip.show(null, afterShow);
+                     break;
+               };
+
+               // Add active class to tooltip
+               self.elements.tooltip.addClass(self.options.style.classes.active);
+            };
+
+            // Log event and return
+            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_SHOWN, 'show');
+         },
+
+         hide: function(event)
+         {
+            var returned;
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'hide');
+
+            // Only continue if element is visible
+            else if(self.elements.tooltip.css('display') === 'none') return self;
+
+            // Stop show timer and animation queue
+            clearTimeout(self.timers.show);
+            self.elements.tooltip.stop(true, false);
+
+            // Call API method and if return value is false, halt
+            returned = self.beforeHide.call(self, event);
+            if(returned === false) return self;
+
+            // Define afterHide callback method
+            function afterHide(){ self.onHide.call(self, event); };
+
+            // Maintain toggle functionality if enabled
+            self.cache.toggle = 0;
+
+            // Hide tooltip
+            if(typeof self.options.hide.effect.type == 'function')
+            {
+               self.options.hide.effect.type.call(self.elements.tooltip, self.options.hide.effect.length);
+               self.elements.tooltip.queue(function(){ afterHide(); $(this).dequeue(); });
+            }
+            else
+            {
+               switch(self.options.hide.effect.type.toLowerCase())
+               {
+                  case 'fade':
+                     self.elements.tooltip.fadeOut(self.options.hide.effect.length, afterHide);
+                     break;
+                  case 'slide':
+                     self.elements.tooltip.slideUp(self.options.hide.effect.length, afterHide);
+                     break;
+                  case 'grow':
+                     self.elements.tooltip.hide(self.options.hide.effect.length, afterHide);
+                     break;
+                  default:
+                     self.elements.tooltip.hide(null, afterHide);
+                     break;
+               };
+
+               // Remove active class to tooltip
+               self.elements.tooltip.removeClass(self.options.style.classes.active);
+            };
+
+            // Log event and return
+            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_HIDDEN, 'hide');
+         },
+
+         updatePosition: function(event, animate)
+         {
+            var i, target, tooltip, coords, mapName, imagePos, newPosition, ieAdjust, ie6Adjust, borderAdjust, mouseAdjust, offset, curPosition, returned
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updatePosition');
+
+            // If tooltip is static, return
+            else if(self.options.position.type == 'static')
+               return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_POSITION_STATIC, 'updatePosition');
+
+            // Define property objects
+            target = {
+               position: { left: 0, top: 0 },
+               dimensions: { height: 0, width: 0 },
+               corner: self.options.position.corner.target
+            };
+            tooltip = {
+               position: self.getPosition(),
+               dimensions: self.getDimensions(),
+               corner: self.options.position.corner.tooltip
+            };
+
+            // Target is an HTML element
+            if(self.options.position.target !== 'mouse')
+            {
+               // If the HTML element is AREA, calculate position manually
+               if(self.options.position.target.get(0).nodeName.toLowerCase() == 'area')
+               {
+                  // Retrieve coordinates from coords attribute and parse into integers
+                  coords = self.options.position.target.attr('coords').split(',');
+                  for(i = 0; i < coords.length; i++) coords[i] = parseInt(coords[i]);
+
+                  // Setup target position object
+                  mapName = self.options.position.target.parent('map').attr('name');
+                  imagePos = $('img[usemap="#'+mapName+'"]:first').offset();
+                  target.position = {
+                     left: Math.floor(imagePos.left + coords[0]),
+                     top: Math.floor(imagePos.top + coords[1])
+                  };
+
+                  // Determine width and height of the area
+                  switch(self.options.position.target.attr('shape').toLowerCase())
+                  {
+                     case 'rect':
+                        target.dimensions = {
+                           width: Math.ceil(Math.abs(coords[2] - coords[0])),
+                           height: Math.ceil(Math.abs(coords[3] - coords[1]))
+                        };
+                        break;
+
+                     case 'circle':
+                        target.dimensions = {
+                           width: coords[2] + 1,
+                           height: coords[2] + 1
+                        };
+                        break;
+
+                     case 'poly':
+                        target.dimensions = {
+                           width: coords[0],
+                           height: coords[1]
+                        };
+
+                        for(i = 0; i < coords.length; i++)
+                        {
+                           if(i % 2 == 0)
+                           {
+                              if(coords[i] > target.dimensions.width)
+                                 target.dimensions.width = coords[i];
+                              if(coords[i] < coords[0])
+                                 target.position.left = Math.floor(imagePos.left + coords[i]);
+                           }
+                           else
+                           {
+                              if(coords[i] > target.dimensions.height)
+                                 target.dimensions.height = coords[i];
+                              if(coords[i] < coords[1])
+                                 target.position.top = Math.floor(imagePos.top + coords[i]);
+                           };
+                        };
+
+                        target.dimensions.width = target.dimensions.width - (target.position.left - imagePos.left);
+                        target.dimensions.height = target.dimensions.height - (target.position.top - imagePos.top);
+                        break;
+
+                     default:
+                        return $.fn.qtip.log.error.call(self, 4, $.fn.qtip.constants.INVALID_AREA_SHAPE, 'updatePosition');
+                        break;
+                  };
+
+                  // Adjust position by 2 pixels (Positioning bug?)
+                  target.dimensions.width -= 2; target.dimensions.height -= 2;
+               }
+
+               // Target is the document
+               else if(self.options.position.target.add(document.body).length === 1)
+               {
+                  target.position = { left: $(document).scrollLeft(), top: $(document).scrollTop() };
+                  target.dimensions = { height: $(window).height(), width: $(window).width() };
+               }
+
+               // Target is a regular HTML element, find position normally
+               else
+               {
+                  // Check if the target is another tooltip. If its animated, retrieve position from newPosition data
+                  if(typeof self.options.position.target.attr('qtip') !== 'undefined')
+                     target.position = self.options.position.target.qtip('api').cache.position;
+                  else
+                     target.position = self.options.position.target.offset();
+
+                  // Setup dimensions objects
+                  target.dimensions = {
+                     height: self.options.position.target.outerHeight(),
+                     width: self.options.position.target.outerWidth()
+                  };
+               };
+
+               // Calculate correct target corner position
+               newPosition = $.extend({}, target.position);
+               if(target.corner.search(/right/i) !== -1)
+                  newPosition.left += target.dimensions.width;
+
+               if(target.corner.search(/bottom/i) !== -1)
+                  newPosition.top += target.dimensions.height;
+
+               if(target.corner.search(/((top|bottom)Middle)|center/) !== -1)
+                  newPosition.left += (target.dimensions.width / 2);
+
+               if(target.corner.search(/((left|right)Middle)|center/) !== -1)
+                  newPosition.top += (target.dimensions.height / 2);
+            }
+
+            // Mouse is the target, set position to current mouse coordinates
+            else
+            {
+               // Setup target position and dimensions objects
+               target.position = newPosition = { left: self.cache.mouse.x, top: self.cache.mouse.y };
+               target.dimensions = { height: 1, width: 1 };
+            };
+
+            // Calculate correct target corner position
+            if(tooltip.corner.search(/right/i) !== -1)
+               newPosition.left -= tooltip.dimensions.width;
+
+            if(tooltip.corner.search(/bottom/i) !== -1)
+               newPosition.top -= tooltip.dimensions.height;
+
+            if(tooltip.corner.search(/((top|bottom)Middle)|center/) !== -1)
+               newPosition.left -= (tooltip.dimensions.width / 2);
+
+            if(tooltip.corner.search(/((left|right)Middle)|center/) !== -1)
+               newPosition.top -= (tooltip.dimensions.height / 2);
+
+            // Setup IE adjustment variables (Pixel gap bugs)
+            ieAdjust = ($.browser.msie) ? 1 : 0; // And this is why I hate IE...
+            ie6Adjust = ($.browser.msie && parseInt($.browser.version.charAt(0)) === 6) ? 1 : 0; // ...and even more so IE6!
+
+            // Adjust for border radius
+            if(self.options.style.border.radius > 0)
+            {
+               if(tooltip.corner.search(/Left/) !== -1)
+                  newPosition.left -= self.options.style.border.radius;
+               else if(tooltip.corner.search(/Right/) !== -1)
+                  newPosition.left += self.options.style.border.radius;
+
+               if(tooltip.corner.search(/Top/) !== -1)
+                  newPosition.top -= self.options.style.border.radius;
+               else if(tooltip.corner.search(/Bottom/) !== -1)
+                  newPosition.top += self.options.style.border.radius;
+            };
+
+            // IE only adjustments (Pixel perfect!)
+            if(ieAdjust)
+            {
+               if(tooltip.corner.search(/top/) !== -1)
+                  newPosition.top -= ieAdjust
+               else if(tooltip.corner.search(/bottom/) !== -1)
+                  newPosition.top += ieAdjust
+
+               if(tooltip.corner.search(/left/) !== -1)
+                  newPosition.left -= ieAdjust
+               else if(tooltip.corner.search(/right/) !== -1)
+                  newPosition.left += ieAdjust
+
+               if(tooltip.corner.search(/leftMiddle|rightMiddle/) !== -1)
+                  newPosition.top -= 1
+            };
+
+            // If screen adjustment is enabled, apply adjustments
+            if(self.options.position.adjust.screen === true)
+               newPosition = screenAdjust.call(self, newPosition, target, tooltip);
+
+            // If mouse is the target, prevent tooltip appearing directly under the mouse
+            if(self.options.position.target === 'mouse' && self.options.position.adjust.mouse === true)
+            {
+               if(self.options.position.adjust.screen === true && self.elements.tip)
+                  mouseAdjust = self.elements.tip.attr('rel');
+               else
+                  mouseAdjust = self.options.position.corner.tooltip;
+
+               newPosition.left += (mouseAdjust.search(/right/i) !== -1) ? -6 : 6;
+               newPosition.top += (mouseAdjust.search(/bottom/i) !== -1) ? -6 : 6;
+            }
+
+            // Initiate bgiframe plugin in IE6 if tooltip overlaps a select box or object element
+            if(!self.elements.bgiframe && $.browser.msie && parseInt($.browser.version.charAt(0)) == 6)
+            {
+               $('select, object').each(function()
+               {
+                  offset = $(this).offset();
+                  offset.bottom = offset.top + $(this).height();
+                  offset.right = offset.left + $(this).width();
+
+                  if(newPosition.top + tooltip.dimensions.height >= offset.top
+                  && newPosition.left + tooltip.dimensions.width >= offset.left)
+                     bgiframe.call(self);
+               });
+            };
+
+            // Add user xy adjustments
+            newPosition.left += self.options.position.adjust.x;
+            newPosition.top += self.options.position.adjust.y;
+
+            // Set new tooltip position if its moved, animate if enabled
+            curPosition = self.getPosition();
+            if(newPosition.left != curPosition.left || newPosition.top != curPosition.top)
+            {
+               // Call API method and if return value is false, halt
+               returned = self.beforePositionUpdate.call(self, event);
+               if(returned === false) return self;
+
+               // Cache new position
+               self.cache.position = newPosition;
+
+               // Check if animation is enabled
+               if(animate === true)
+               {
+                  // Set animated status
+                  self.status.animated = true;
+
+                  // Animate and reset animated status on animation end
+                  self.elements.tooltip.animate(newPosition, 200, 'swing', function(){ self.status.animated = false });
+               }
+
+               // Set new position via CSS
+               else self.elements.tooltip.css(newPosition);
+
+               // Call API method and log event if its not a mouse move
+               self.onPositionUpdate.call(self, event);
+               if(typeof event !== 'undefined' && event.type && event.type !== 'mousemove')
+                  $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_POSITION_UPDATED, 'updatePosition');
+            };
+
+            return self;
+         },
+
+         updateWidth: function(newWidth)
+         {
+            var hidden;
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateWidth');
+
+            // Make sure supplied width is a number and if not, return
+            else if(newWidth && typeof newWidth !== 'number')
+               return $.fn.qtip.log.error.call(self, 2, 'newWidth must be of type number', 'updateWidth');
+
+            // Setup elements which must be hidden during width update
+            hidden = self.elements.contentWrapper.siblings().add(self.elements.tip).add(self.elements.button);
+
+            // Calculate the new width if one is not supplied
+            if(!newWidth)
+            {
+               // Explicit width is set
+               if(typeof self.options.style.width.value == 'number')
+                  newWidth = self.options.style.width.value;
+
+               // No width is set, proceed with auto detection
+               else
+               {
+                  // Set width to auto initally to determine new width and hide other elements
+                  self.elements.tooltip.css({ width: 'auto' });
+                  hidden.hide();
+
+                  // Set position and zoom to defaults to prevent IE hasLayout bug
+                  if($.browser.msie)
+                     self.elements.wrapper.add(self.elements.contentWrapper.children()).css({ zoom: 'normal' });
+
+                  // Set the new width
+                  newWidth = self.getDimensions().width + 1;
+
+                  // Make sure its within the maximum and minimum width boundries
+                  if(!self.options.style.width.value)
+                  {
+                     if(newWidth > self.options.style.width.max) newWidth = self.options.style.width.max
+                     if(newWidth < self.options.style.width.min) newWidth = self.options.style.width.min
+                  };
+               };
+            };
+
+            // Adjust newWidth by 1px if width is odd (IE6 rounding bug fix)
+            if(newWidth % 2 !== 0) newWidth -= 1;
+
+            // Set the new calculated width and unhide other elements
+            self.elements.tooltip.width(newWidth);
+            hidden.show();
+
+            // Set the border width, if enabled
+            if(self.options.style.border.radius)
+            {
+               self.elements.tooltip.find('.qtip-betweenCorners').each(function(i)
+               {
+                  $(this).width(newWidth - (self.options.style.border.radius * 2));
+               })
+            };
+
+            // IE only adjustments
+            if($.browser.msie)
+            {
+               // Reset position and zoom to give the wrapper layout (IE hasLayout bug)
+               self.elements.wrapper.add(self.elements.contentWrapper.children()).css({ zoom: '1' });
+
+               // Set the new width
+               self.elements.wrapper.width(newWidth);
+
+               // Adjust BGIframe height and width if enabled
+               if(self.elements.bgiframe) self.elements.bgiframe.width(newWidth).height(self.getDimensions.height);
+            };
+
+            // Log event and return
+            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_WIDTH_UPDATED, 'updateWidth');
+         },
+
+         updateStyle: function(name)
+         {
+            var tip, borders, context, corner, coordinates;
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateStyle');
+
+            // Return if style is not defined or name is not a string
+            else if(typeof name !== 'string' || !$.fn.qtip.styles[name])
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.STYLE_NOT_DEFINED, 'updateStyle');
+
+            // Set the new style object
+            self.options.style = buildStyle.call(self, $.fn.qtip.styles[name], self.options.user.style);
+
+            // Update initial styles of content and title elements
+            self.elements.content.css( jQueryStyle(self.options.style) );
+            if(self.options.content.title.text !== false)
+               self.elements.title.css( jQueryStyle(self.options.style.title, true) );
+
+            // Update CSS border colour
+            self.elements.contentWrapper.css({ borderColor: self.options.style.border.color });
+
+            // Update tip color if enabled
+            if(self.options.style.tip.corner !== false)
+            {
+               if($('<canvas>').get(0).getContext)
+               {
+                  // Retrieve canvas context and clear
+                  tip = self.elements.tooltip.find('.qtip-tip canvas:first');
+                  context = tip.get(0).getContext('2d');
+                  context.clearRect(0,0,300,300);
+
+                  // Draw new tip
+                  corner = tip.parent('div[rel]:first').attr('rel');
+                  coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height);
+                  drawTip.call(self, tip, coordinates, self.options.style.tip.color || self.options.style.border.color);
+               }
+               else if($.browser.msie)
+               {
+                  // Set new fillcolor attribute
+                  tip = self.elements.tooltip.find('.qtip-tip [nodeName="shape"]');
+                  tip.attr('fillcolor', self.options.style.tip.color || self.options.style.border.color);
+               };
+            };
+
+            // Update border colors if enabled
+            if(self.options.style.border.radius > 0)
+            {
+               self.elements.tooltip.find('.qtip-betweenCorners').css({ backgroundColor: self.options.style.border.color });
+
+               if($('<canvas>').get(0).getContext)
+               {
+                  borders = calculateBorders(self.options.style.border.radius)
+                  self.elements.tooltip.find('.qtip-wrapper canvas').each(function()
+                  {
+                     // Retrieve canvas context and clear
+                     context = $(this).get(0).getContext('2d');
+                     context.clearRect(0,0,300,300);
+
+                     // Draw new border
+                     corner = $(this).parent('div[rel]:first').attr('rel')
+                     drawBorder.call(self, $(this), borders[corner],
+                        self.options.style.border.radius, self.options.style.border.color);
+                  });
+               }
+               else if($.browser.msie)
+               {
+                  // Set new fillcolor attribute on each border corner
+                  self.elements.tooltip.find('.qtip-wrapper [nodeName="arc"]').each(function()
+                  {
+                     $(this).attr('fillcolor', self.options.style.border.color)
+                  });
+               };
+            };
+
+            // Log event and return
+            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_STYLE_UPDATED, 'updateStyle');
+         },
+
+         updateContent: function(content, reposition)
+         {
+            var parsedContent, images, loadedImages;
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateContent');
+
+            // Make sure content is defined before update
+            else if(!content)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.NO_CONTENT_PROVIDED, 'updateContent');
+
+            // Call API method and set new content if a string is returned
+            parsedContent = self.beforeContentUpdate.call(self, content);
+            if(typeof parsedContent == 'string') content = parsedContent;
+            else if(parsedContent === false) return;
+
+            // Set position and zoom to defaults to prevent IE hasLayout bug
+            if($.browser.msie) self.elements.contentWrapper.children().css({ zoom: 'normal' });
+
+            // Append new content if its a DOM array and show it if hidden
+            if(content.jquery && content.length > 0)
+               content.clone(true).appendTo(self.elements.content).show();
+
+            // Content is a regular string, insert the new content
+            else self.elements.content.html(content);
+
+            // Check if images need to be loaded before position is updated to prevent mis-positioning
+            images = self.elements.content.find('img[complete=false]');
+            if(images.length > 0)
+            {
+               loadedImages = 0;
+               images.each(function(i)
+               {
+                  $('<img src="'+ $(this).attr('src') +'" />')
+                     .load(function(){ if(++loadedImages == images.length) afterLoad(); });
+               });
+            }
+            else afterLoad();
+
+            function afterLoad()
+            {
+               // Update the tooltip width
+               self.updateWidth();
+
+               // If repositioning is enabled, update positions
+               if(reposition !== false)
+               {
+                  // Update position if tooltip isn't static
+                  if(self.options.position.type !== 'static')
+                     self.updatePosition(self.elements.tooltip.is(':visible'), true);
+
+                  // Reposition the tip if enabled
+                  if(self.options.style.tip.corner !== false)
+                     positionTip.call(self);
+               };
+            };
+
+            // Call API method and log event
+            self.onContentUpdate.call(self);
+            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_CONTENT_UPDATED, 'loadContent');
+         },
+
+         loadContent: function(url, data, method)
+         {
+            var returned;
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'loadContent');
+
+            // Call API method and if return value is false, halt
+            returned = self.beforeContentLoad.call(self);
+            if(returned === false) return self;
+
+            // Load content using specified request type
+            if(method == 'post')
+               $.post(url, data, setupContent);
+            else
+               $.get(url, data, setupContent);
+
+            function setupContent(content)
+            {
+               // Call API method and log event
+               self.onContentLoad.call(self);
+               $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_CONTENT_LOADED, 'loadContent');
+
+               // Update the content
+               self.updateContent(content);
+            };
+
+            return self;
+         },
+
+         updateTitle: function(content)
+         {
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'updateTitle');
+
+            // Make sure content is defined before update
+            else if(!content)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.NO_CONTENT_PROVIDED, 'updateTitle');
+
+            // Call API method and if return value is false, halt
+            returned = self.beforeTitleUpdate.call(self);
+            if(returned === false) return self;
+
+            // Set the new content and reappend the button if enabled
+            if(self.elements.button) self.elements.button = self.elements.button.clone(true);
+            self.elements.title.html(content)
+            if(self.elements.button) self.elements.title.prepend(self.elements.button);
+
+            // Call API method and log event
+            self.onTitleUpdate.call(self);
+            return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_TITLE_UPDATED, 'updateTitle');
+         },
+
+         focus: function(event)
+         {
+            var curIndex, newIndex, elemIndex, returned;
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'focus');
+
+            else if(self.options.position.type == 'static')
+               return $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.CANNOT_FOCUS_STATIC, 'focus');
+
+            // Set z-index variables
+            curIndex = parseInt( self.elements.tooltip.css('z-index') );
+            newIndex = 6000 + $('div.qtip[qtip]').length - 1;
+
+            // Only update the z-index if it has changed and tooltip is not already focused
+            if(!self.status.focused && curIndex !== newIndex)
+            {
+               // Call API method and if return value is false, halt
+               returned = self.beforeFocus.call(self, event);
+               if(returned === false) return self;
+
+               // Loop through all other tooltips
+               $('div.qtip[qtip]').not(self.elements.tooltip).each(function()
+               {
+                  if($(this).qtip('api').status.rendered === true)
+                  {
+                     elemIndex = parseInt($(this).css('z-index'));
+
+                     // Reduce all other tooltip z-index by 1
+                     if(typeof elemIndex == 'number' && elemIndex > -1)
+                        $(this).css({ zIndex: parseInt( $(this).css('z-index') ) - 1 });
+
+                     // Set focused status to false
+                     $(this).qtip('api').status.focused = false;
+                  }
+               })
+
+               // Set the new z-index and set focus status to true
+               self.elements.tooltip.css({ zIndex: newIndex });
+               self.status.focused = true;
+
+               // Call API method and log event
+               self.onFocus.call(self, event);
+               $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_FOCUSED, 'focus');
+            };
+
+            return self;
+         },
+
+         disable: function(state)
+         {
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'disable');
+
+            if(state)
+            {
+               // Tooltip is not already disabled, proceed
+               if(!self.status.disabled)
+               {
+                  // Set the disabled flag and log event
+                  self.status.disabled = true;
+                  $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DISABLED, 'disable');
+               }
+
+               // Tooltip is already disabled, inform user via log
+               else  $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_DISABLED, 'disable');
+            }
+            else
+            {
+               // Tooltip is not already enabled, proceed
+               if(self.status.disabled)
+               {
+                  // Reassign events, set disable status and log
+                  self.status.disabled = false;
+                  $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_ENABLED, 'disable');
+               }
+
+               // Tooltip is already enabled, inform the user via log
+               else $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.TOOLTIP_ALREADY_ENABLED, 'disable');
+            };
+
+            return self;
+         },
+
+         destroy: function()
+         {
+            var i, returned, interfaces;
+
+            // Call API method and if return value is false, halt
+            returned = self.beforeDestroy.call(self);
+            if(returned === false) return self;
+
+            // Check if tooltip is rendered
+            if(self.status.rendered)
+            {
+               // Remove event handlers and remove element
+               self.options.show.when.target.unbind('mousemove.qtip', self.updatePosition);
+               self.options.show.when.target.unbind('mouseout.qtip', self.hide);
+               self.options.show.when.target.unbind(self.options.show.when.event + '.qtip');
+               self.options.hide.when.target.unbind(self.options.hide.when.event + '.qtip');
+               self.elements.tooltip.unbind(self.options.hide.when.event + '.qtip');
+               self.elements.tooltip.unbind('mouseover.qtip', self.focus);
+               self.elements.tooltip.remove();
+            }
+
+            // Tooltip isn't yet rendered, remove render event
+            else self.options.show.when.target.unbind(self.options.show.when.event+'.qtip-create');
+
+            // Check to make sure qTip data is present on target element
+            if(typeof self.elements.target.data('qtip') == 'object')
+            {
+               // Remove API references from interfaces object
+               interfaces = self.elements.target.data('qtip').interfaces;
+               if(typeof interfaces == 'object' && interfaces.length > 0)
+               {
+                  // Remove API from interfaces array
+                  for(i = 0; i < interfaces.length - 1; i++)
+                     if(interfaces[i].id == self.id) interfaces.splice(i, 1)
+               }
+            }
+            delete $.fn.qtip.interfaces[self.id];
+
+            // Set qTip current id to previous tooltips API if available
+            if(typeof interfaces == 'object' && interfaces.length > 0)
+               self.elements.target.data('qtip').current = interfaces.length -1;
+            else
+               self.elements.target.removeData('qtip');
+
+            // Call API method and log destroy
+            self.onDestroy.call(self);
+            $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_DESTROYED, 'destroy');
+
+            return self.elements.target
+         },
+
+         getPosition: function()
+         {
+            var show, offset;
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getPosition');
+
+            show = (self.elements.tooltip.css('display') !== 'none') ? false : true;
+
+            // Show and hide tooltip to make sure coordinates are returned
+            if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
+            offset = self.elements.tooltip.offset();
+            if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();
+
+            return offset;
+         },
+
+         getDimensions: function()
+         {
+            var show, dimensions;
+
+            // Make sure tooltip is rendered and if not, return
+            if(!self.status.rendered)
+               return $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.TOOLTIP_NOT_RENDERED, 'getDimensions');
+
+            show = (!self.elements.tooltip.is(':visible')) ? true : false;
+
+            // Show and hide tooltip to make sure dimensions are returned
+            if(show) self.elements.tooltip.css({ visiblity: 'hidden' }).show();
+            dimensions = {
+               height: self.elements.tooltip.outerHeight(),
+               width: self.elements.tooltip.outerWidth()
+            };
+            if(show) self.elements.tooltip.css({ visiblity: 'visible' }).hide();
+
+            return dimensions;
+         }
+      });
+   };
+
+   // Define priamry construct function
+   function construct()
+   {
+      var self, adjust, content, url, data, method, tempLength;
+      self = this;
+
+      // Call API method
+      self.beforeRender.call(self);
+
+      // Set rendered status to true
+      self.status.rendered = true;
+
+      // Create initial tooltip elements
+      self.elements.tooltip =  '<div qtip="'+self.id+'" ' +
+         'class="qtip '+(self.options.style.classes.tooltip || self.options.style)+'"' +
+         'style="display:none; -moz-border-radius:0; -webkit-border-radius:0; border-radius:0;' +
+         'position:'+self.options.position.type+';">' +
+         '  <div class="qtip-wrapper" style="position:relative; overflow:hidden; text-align:left;">' +
+         '    <div class="qtip-contentWrapper" style="overflow:hidden;">' +
+         '       <div class="qtip-content '+self.options.style.classes.content+'"></div>' +
+         '</div></div></div>';
+
+      // Append to container element
+      self.elements.tooltip = $(self.elements.tooltip);
+      self.elements.tooltip.appendTo(self.options.position.container)
+
+      // Setup tooltip qTip data
+      self.elements.tooltip.data('qtip', { current: 0, interfaces: [self] });
+
+      // Setup element references
+      self.elements.wrapper = self.elements.tooltip.children('div:first');
+      self.elements.contentWrapper = self.elements.wrapper.children('div:first').css({ background: self.options.style.background });
+      self.elements.content = self.elements.contentWrapper.children('div:first').css( jQueryStyle(self.options.style) );
+
+      // Apply IE hasLayout fix to wrapper and content elements
+      if($.browser.msie) self.elements.wrapper.add(self.elements.content).css({ zoom: 1 });
+
+      // Setup tooltip attributes
+      if(self.options.hide.when.event == 'unfocus') self.elements.tooltip.attr('unfocus', true);
+
+      // If an explicit width is set, updateWidth prior to setting content to prevent dirty rendering
+      if(typeof self.options.style.width.value == 'number') self.updateWidth();
+
+      // Create borders and tips if supported by the browser
+      if($('<canvas>').get(0).getContext || $.browser.msie)
+      {
+         // Create border
+         if(self.options.style.border.radius > 0)
+            createBorder.call(self);
+         else
+            self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color  });
+
+         // Create tip if enabled
+         if(self.options.style.tip.corner !== false)
+            createTip.call(self);
+      }
+
+      // Neither canvas or VML is supported, tips and borders cannot be drawn!
+      else
+      {
+         // Set defined border width
+         self.elements.contentWrapper.css({ border: self.options.style.border.width+'px solid '+self.options.style.border.color  });
+
+         // Reset border radius and tip
+         self.options.style.border.radius = 0;
+         self.options.style.tip.corner = false;
+
+         // Inform via log
+         $.fn.qtip.log.error.call(self, 2, $.fn.qtip.constants.CANVAS_VML_NOT_SUPPORTED, 'render');
+      };
+
+      // Use the provided content string or DOM array
+      if((typeof self.options.content.text == 'string' && self.options.content.text.length > 0)
+      || (self.options.content.text.jquery && self.options.content.text.length > 0))
+         content = self.options.content.text;
+
+      // Use title string for content if present
+      else if(typeof self.elements.target.attr('title') == 'string' && self.elements.target.attr('title').length > 0)
+      {
+         content = self.elements.target.attr('title').replace("\\n", '<br />');
+         self.elements.target.attr('title', ''); // Remove title attribute to prevent default tooltip showing
+      }
+
+      // No title is present, use alt attribute instead
+      else if(typeof self.elements.target.attr('alt') == 'string' && self.elements.target.attr('alt').length > 0)
+      {
+         content = self.elements.target.attr('alt').replace("\\n", '<br />');
+         self.elements.target.attr('alt', ''); // Remove alt attribute to prevent default tooltip showing
+      }
+
+      // No valid content was provided, inform via log
+      else
+      {
+         content = ' ';
+         $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.NO_VALID_CONTENT, 'render');
+      };
+
+      // Set the tooltips content and create title if enabled
+      if(self.options.content.title.text !== false) createTitle.call(self);
+      self.updateContent(content);
+
+      // Assign events and toggle tooltip with focus
+      assignEvents.call(self);
+      if(self.options.show.ready === true) self.show();
+
+      // Retrieve ajax content if provided
+      if(self.options.content.url !== false)
+      {
+         url = self.options.content.url;
+         data = self.options.content.data;
+         method = self.options.content.method || 'get';
+         self.loadContent(url, data, method);
+      };
+
+      // Call API method and log event
+      self.onRender.call(self);
+      $.fn.qtip.log.error.call(self, 1, $.fn.qtip.constants.EVENT_RENDERED, 'render');
+   };
+
+   // Create borders using canvas and VML
+   function createBorder()
+   {
+      var self, i, width, radius, color, coordinates, containers, size, betweenWidth, betweenCorners, borderTop, borderBottom, borderCoord, sideWidth, vertWidth;
+      self = this;
+
+      // Destroy previous border elements, if present
+      self.elements.wrapper.find('.qtip-borderBottom, .qtip-borderTop').remove();
+
+      // Setup local variables
+      width = self.options.style.border.width;
+      radius = self.options.style.border.radius;
+      color = self.options.style.border.color || self.options.style.tip.color;
+
+      // Calculate border coordinates
+      coordinates = calculateBorders(radius);
+
+      // Create containers for the border shapes
+      containers = {};
+      for(i in coordinates)
+      {
+         // Create shape container
+         containers[i] = '<div rel="'+i+'" style="'+((i.search(/Left/) !== -1) ? 'left' : 'right') + ':0; ' +
+            'position:absolute; height:'+radius+'px; width:'+radius+'px; overflow:hidden; line-height:0.1px; font-size:1px">';
+
+         // Canvas is supported
+         if($('<canvas>').get(0).getContext)
+            containers[i] += '<canvas height="'+radius+'" width="'+radius+'" style="vertical-align: top"></canvas>';
+
+         // No canvas, but if it's IE use VML
+         else if($.browser.msie)
+         {
+            size = radius * 2 + 3;
+            containers[i] += '<v:arc stroked="false" fillcolor="'+color+'" startangle="'+coordinates[i][0]+'" endangle="'+coordinates[i][1]+'" ' +
+               'style="width:'+size+'px; height:'+size+'px; margin-top:'+((i.search(/bottom/) !== -1) ? -2 : -1)+'px; ' +
+               'margin-left:'+((i.search(/Right/) !== -1) ? coordinates[i][2] - 3.5 : -1)+'px; ' +
+               'vertical-align:top; display:inline-block; behavior:url(#default#VML)"></v:arc>';
+
+         };
+
+         containers[i] += '</div>';
+      };
+
+      // Create between corners elements
+      betweenWidth = self.getDimensions().width - (Math.max(width, radius) * 2);
+      betweenCorners = '<div class="qtip-betweenCorners" style="height:'+radius+'px; width:'+betweenWidth+'px; ' +
+         'overflow:hidden; background-color:'+color+'; line-height:0.1px; font-size:1px;">';
+
+      // Create top border container
+      borderTop = '<div class="qtip-borderTop" dir="ltr" style="height:'+radius+'px; ' +
+         'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
+         containers['topLeft'] + containers['topRight'] + betweenCorners;
+      self.elements.wrapper.prepend(borderTop);
+
+      // Create bottom border container
+      borderBottom = '<div class="qtip-borderBottom" dir="ltr" style="height:'+radius+'px; ' +
+         'margin-left:'+radius+'px; line-height:0.1px; font-size:1px; padding:0;">' +
+         containers['bottomLeft'] + containers['bottomRight'] + betweenCorners;
+      self.elements.wrapper.append(borderBottom);
+
+      // Draw the borders if canvas were used (Delayed til after DOM creation)
+      if($('<canvas>').get(0).getContext)
+      {
+         self.elements.wrapper.find('canvas').each(function()
+         {
+            borderCoord = coordinates[ $(this).parent('[rel]:first').attr('rel') ];
+            drawBorder.call(self, $(this), borderCoord, radius, color);
+         })
+      }
+
+      // Create a phantom VML element (IE won't show the last created VML element otherwise)
+      else if($.browser.msie) self.elements.tooltip.append('<v:image style="behavior:url(#default#VML);"></v:image>');
+
+      // Setup contentWrapper border
+      sideWidth = Math.max(radius, (radius + (width - radius)) )
+      vertWidth = Math.max(width - radius, 0);
+      self.elements.contentWrapper.css({
+         border: '0px solid ' + color,
+         borderWidth: vertWidth + 'px ' + sideWidth + 'px'
+      })
+   };
+
+   // Border canvas draw method
+   function drawBorder(canvas, coordinates, radius, color)
+   {
+      // Create corner
+      var context = canvas.get(0).getContext('2d');
+      context.fillStyle = color;
+      context.beginPath();
+      context.arc(coordinates[0], coordinates[1], radius, 0, Math.PI * 2, false);
+      context.fill();
+   };
+
+   // Create tip using canvas and VML
+   function createTip(corner)
+   {
+      var self, color, coordinates, coordsize, path;
+      self = this;
+
+      // Destroy previous tip, if there is one
+      if(self.elements.tip !== null) self.elements.tip.remove();
+
+      // Setup color and corner values
+      color = self.options.style.tip.color || self.options.style.border.color;
+      if(self.options.style.tip.corner === false) return;
+      else if(!corner) corner = self.options.style.tip.corner;
+
+      // Calculate tip coordinates
+      coordinates = calculateTip(corner, self.options.style.tip.size.width, self.options.style.tip.size.height);
+
+      // Create tip element
+      self.elements.tip =  '<div class="'+self.options.style.classes.tip+'" dir="ltr" rel="'+corner+'" style="position:absolute; ' +
+         'height:'+self.options.style.tip.size.height+'px; width:'+self.options.style.tip.size.width+'px; ' +
+         'margin:0 auto; line-height:0.1px; font-size:1px;">';
+
+      // Use canvas element if supported
+      if($('<canvas>').get(0).getContext)
+          self.elements.tip += '<canvas height="'+self.options.style.tip.size.height+'" width="'+self.options.style.tip.size.width+'"></canvas>';
+
+      // Canvas not supported - Use VML (IE)
+      else if($.browser.msie)
+      {
+         // Create coordize and tip path using tip coordinates
+         coordsize = self.options.style.tip.size.width + ',' + self.options.style.tip.size.height;
+         path = 'm' + coordinates[0][0] + ',' + coordinates[0][1];
+         path += ' l' + coordinates[1][0] + ',' + coordinates[1][1];
+         path += ' ' + coordinates[2][0] + ',' + coordinates[2][1];
+         path += ' xe';
+
+         // Create VML element
+         self.elements.tip += '<v:shape fillcolor="'+color+'" stroked="false" filled="true" path="'+path+'" coordsize="'+coordsize+'" ' +
+            'style="width:'+self.options.style.tip.size.width+'px; height:'+self.options.style.tip.size.height+'px; ' +
+            'line-height:0.1px; display:inline-block; behavior:url(#default#VML); ' +
+            'vertical-align:'+((corner.search(/top/) !== -1) ? 'bottom' : 'top')+'"></v:shape>';
+
+         // Create a phantom VML element (IE won't show the last created VML element otherwise)
+         self.elements.tip += '<v:image style="behavior:url(#default#VML);"></v:image>';
+
+         // Prevent tooltip appearing above the content (IE z-index bug)
+         self.elements.contentWrapper.css('position', 'relative');
+      };
+
+      // Attach new tip to tooltip element
+      self.elements.tooltip.prepend(self.elements.tip + '</div>');
+
+      // Create element reference and draw the canvas tip (Delayed til after DOM creation)
+      self.elements.tip = self.elements.tooltip.find('.'+self.options.style.classes.tip).eq(0);
+      if($('<canvas>').get(0).getContext)
+         drawTip.call(self, self.elements.tip.find('canvas:first'), coordinates, color);
+
+      // Fix IE small tip bug
+      if(corner.search(/top/) !== -1 && $.browser.msie && parseInt($.browser.version.charAt(0)) === 6)
+         self.elements.tip.css({ marginTop: -4 });
+
+      // Set the tip position
+      positionTip.call(self, corner);
+   };
+
+   // Canvas tip drawing method
+   function drawTip(canvas, coordinates, color)
+   {
+      // Setup properties
+      var context = canvas.get(0).getContext('2d');
+      context.fillStyle = color;
+
+      // Create tip
+      context.beginPath();
+      context.moveTo(coordinates[0][0], coordinates[0][1]);
+      context.lineTo(coordinates[1][0], coordinates[1][1]);
+      context.lineTo(coordinates[2][0], coordinates[2][1]);
+      context.fill();
+   };
+
+   function positionTip(corner)
+   {
+      var self, ieAdjust, paddingCorner, paddingSize, newMargin;
+      self = this;
+
+      // Return if tips are disabled or tip is not yet rendered
+      if(self.options.style.tip.corner === false || !self.elements.tip) return;
+      if(!corner) corner = self.elements.tip.attr('rel');
+
+      // Setup adjustment variables
+      ieAdjust = positionAdjust = ($.browser.msie) ? 1 : 0;
+
+      // Set initial position
+      self.elements.tip.css(corner.match(/left|right|top|bottom/)[0], 0);
+
+      // Set position of tip to correct side
+      if(corner.search(/top|bottom/) !== -1)
+      {
+         // Adjustments for IE6 - 0.5px border gap bug
+         if($.browser.msie)
+         {
+            if(parseInt($.browser.version.charAt(0)) === 6)
+               positionAdjust = (corner.search(/top/) !== -1) ? -3 : 1;
+            else
+               positionAdjust = (corner.search(/top/) !== -1) ? 1 : 2;
+         };
+
+         if(corner.search(/Middle/) !== -1)
+            self.elements.tip.css({ left: '50%', marginLeft: -(self.options.style.tip.size.width / 2) });
+
+         else if(corner.search(/Left/) !== -1)
+            self.elements.tip.css({ left: self.options.style.border.radius - ieAdjust });
+
+         else if(corner.search(/Right/) !== -1)
+            self.elements.tip.css({ right: self.options.style.border.radius + ieAdjust });
+
+         if(corner.search(/top/) !== -1)
+            self.elements.tip.css({ top: -positionAdjust });
+         else
+            self.elements.tip.css({ bottom: positionAdjust });
+
+      }
+      else if(corner.search(/left|right/) !== -1)
+      {
+         // Adjustments for IE6 - 0.5px border gap bug
+         if($.browser.msie)
+            positionAdjust = (parseInt($.browser.version.charAt(0)) === 6) ? 1 : ((corner.search(/left/) !== -1) ? 1 : 2);
+
+         if(corner.search(/Middle/) !== -1)
+            self.elements.tip.css({ top: '50%', marginTop: -(self.options.style.tip.size.height / 2) });
+
+         else if(corner.search(/Top/) !== -1)
+            self.elements.tip.css({ top: self.options.style.border.radius - ieAdjust });
+
+         else if(corner.search(/Bottom/) !== -1)
+            self.elements.tip.css({ bottom: self.options.style.border.radius + ieAdjust });
+
+         if(corner.search(/left/) !== -1)
+            self.elements.tip.css({ left: -positionAdjust });
+         else
+            self.elements.tip.css({ right: positionAdjust });
+      };
+
+      // Adjust tooltip padding to compensate for tip
+      paddingCorner = 'padding-' + corner.match(/left|right|top|bottom/)[0];
+      paddingSize = self.options.style.tip.size[ (paddingCorner.search(/left|right/) !== -1) ? 'width' : 'height' ];
+      self.elements.tooltip.css('padding', 0);
+      self.elements.tooltip.css(paddingCorner, paddingSize);
+
+      // Match content margin to prevent gap bug in IE6 ONLY
+      if($.browser.msie && parseInt($.browser.version.charAt(0)) == 6)
+      {
+         newMargin = parseInt(self.elements.tip.css('margin-top')) || 0;
+         newMargin += parseInt(self.elements.content.css('margin-top')) || 0;
+
+         self.elements.tip.css({ marginTop: newMargin });
+      };
+   };
+
+   // Create title bar for content
+   function createTitle()
+   {
+      var self = this;
+
+      // Destroy previous title element, if present
+      if(self.elements.title !== null) self.elements.title.remove();
+
+      // Create title element
+      self.elements.title = $('<div class="'+self.options.style.classes.title+'">')
+         .css( jQueryStyle(self.options.style.title, true) )
+         .css({ zoom: ($.browser.msie) ? 1 : 0 })
+         .prependTo(self.elements.contentWrapper);
+
+      // Update title with contents if enabled
+      if(self.options.content.title.text) self.updateTitle.call(self, self.options.content.title.text);
+
+      // Create title close buttons if enabled
+      if(self.options.content.title.button !== false
+      && typeof self.options.content.title.button == 'string')
+      {
+         self.elements.button = $('<a class="'+self.options.style.classes.button+'" style="float:right; position: relative"></a>')
+            .css( jQueryStyle(self.options.style.button, true) )
+            .html(self.options.content.title.button)
+            .prependTo(self.elements.title)
+            .click(function(event){ if(!self.status.disabled) self.hide(event) });
+      };
+   };
+
+   // Assign hide and show events
+   function assignEvents()
+   {
+      var self, showTarget, hideTarget, inactiveEvents;
+      self = this;
+
+      // Setup event target variables
+      showTarget = self.options.show.when.target;
+      hideTarget = self.options.hide.when.target;
+
+      // Add tooltip as a hideTarget is its fixed
+      if(self.options.hide.fixed) hideTarget = hideTarget.add(self.elements.tooltip);
+
+      // Check if the hide event is special 'inactive' type
+      if(self.options.hide.when.event == 'inactive')
+      {
+         // Define events which reset the 'inactive' event handler
+         inactiveEvents = ['click', 'dblclick', 'mousedown', 'mouseup', 'mousemove',
+         'mouseout', 'mouseenter', 'mouseleave', 'mouseover' ];
+
+         // Define 'inactive' event timer method
+         function inactiveMethod(event)
+         {
+            if(self.status.disabled === true) return;
+
+            //Clear and reset the timer
+            clearTimeout(self.timers.inactive);
+            self.timers.inactive = setTimeout(function()
+            {
+               // Unassign 'inactive' events
+               $(inactiveEvents).each(function()
+               {
+                  hideTarget.unbind(this+'.qtip-inactive');
+                  self.elements.content.unbind(this+'.qtip-inactive');
+               });
+
+               // Hide the tooltip
+               self.hide(event);
+            }
+            , self.options.hide.delay);
+         };
+      }
+
+      // Check if the tooltip is 'fixed'
+      else if(self.options.hide.fixed === true)
+      {
+         self.elements.tooltip.bind('mouseover.qtip', function()
+         {
+            if(self.status.disabled === true) return;
+
+            // Reset the hide timer
+            clearTimeout(self.timers.hide);
+         });
+      };
+
+      // Define show event method
+      function showMethod(event)
+      {
+         if(self.status.disabled === true) return;
+
+         // If set, hide tooltip when inactive for delay period
+         if(self.options.hide.when.event == 'inactive')
+         {
+            // Assign each reset event
+            $(inactiveEvents).each(function()
+            {
+               hideTarget.bind(this+'.qtip-inactive', inactiveMethod);
+               self.elements.content.bind(this+'.qtip-inactive', inactiveMethod);
+            });
+
+            // Start the inactive timer
+            inactiveMethod();
+         };
+
+         // Clear hide timers
+         clearTimeout(self.timers.show);
+         clearTimeout(self.timers.hide);
+
+         // Start show timer
+         self.timers.show = setTimeout(function(){ self.show(event); }, self.options.show.delay);
+      };
+
+      // Define hide event method
+      function hideMethod(event)
+      {
+         if(self.status.disabled === true) return;
+
+         // Prevent hiding if tooltip is fixed and event target is the tooltip
+         if(self.options.hide.fixed === true
+         && self.options.hide.when.event.search(/mouse(out|leave)/i) !== -1
+         && $(event.relatedTarget).parents('div.qtip[qtip]').length > 0)
+         {
+            // Prevent default and popagation
+            event.stopPropagation();
+            event.preventDefault();
+
+            // Reset the hide timer
+            clearTimeout(self.timers.hide);
+            return false;
+         };
+
+         // Clear timers and stop animation queue
+         clearTimeout(self.timers.show);
+         clearTimeout(self.timers.hide);
+         self.elements.tooltip.stop(true, true);
+
+         // If tooltip has displayed, start hide timer
+         self.timers.hide = setTimeout(function(){ self.hide(event); }, self.options.hide.delay);
+      };
+
+      // Both events and targets are identical, apply events using a toggle
+      if((self.options.show.when.target.add(self.options.hide.when.target).length === 1
+      && self.options.show.when.event == self.options.hide.when.event
+      && self.options.hide.when.event !== 'inactive')
+      || self.options.hide.when.event == 'unfocus')
+      {
+         self.cache.toggle = 0;
+         // Use a toggle to prevent hide/show conflicts
+         showTarget.bind(self.options.show.when.event + '.qtip', function(event)
+         {
+            if(self.cache.toggle == 0) showMethod(event);
+            else hideMethod(event);
+         });
+      }
+
+      // Events are not identical, bind normally
+      else
+      {
+         showTarget.bind(self.options.show.when.event + '.qtip', showMethod);
+
+         // If the hide event is not 'inactive', bind the hide method
+         if(self.options.hide.when.event !== 'inactive')
+            hideTarget.bind(self.options.hide.when.event + '.qtip', hideMethod);
+      };
+
+      // Focus the tooltip on mouseover
+      if(self.options.position.type.search(/(fixed|absolute)/) !== -1)
+         self.elements.tooltip.bind('mouseover.qtip', self.focus);
+
+      // If mouse is the target, update tooltip position on mousemove
+      if(self.options.position.target === 'mouse' && self.options.position.type !== 'static')
+      {
+         showTarget.bind('mousemove.qtip', function(event)
+         {
+            // Set the new mouse positions if adjustment is enabled
+            self.cache.mouse = { x: event.pageX, y: event.pageY };
+
+            // Update the tooltip position only if the tooltip is visible and adjustment is enabled
+            if(self.status.disabled === false
+            && self.options.position.adjust.mouse === true
+            && self.options.position.type !== 'static'
+            && self.elements.tooltip.css('display') !== 'none')
+               self.updatePosition(event);
+         });
+      };
+   };
+
+   // Screen position adjustment
+   function screenAdjust(position, target, tooltip)
+   {
+      var self, adjustedPosition, adjust, newCorner, overflow, corner;
+      self = this;
+
+      // Setup corner and adjustment variable
+      if(tooltip.corner == 'center') return target.position // TODO: 'center' corner adjustment
+      adjustedPosition = $.extend({}, position);
+      newCorner = { x: false, y: false };
+
+      // Define overflow properties
+      overflow = {
+         left: (adjustedPosition.left < $.fn.qtip.cache.screen.scroll.left),
+         right: (adjustedPosition.left + tooltip.dimensions.width + 2 >= $.fn.qtip.cache.screen.width + $.fn.qtip.cache.screen.scroll.left),
+         top: (adjustedPosition.top < $.fn.qtip.cache.screen.scroll.top),
+         bottom: (adjustedPosition.top + tooltip.dimensions.height + 2 >= $.fn.qtip.cache.screen.height + $.fn.qtip.cache.screen.scroll.top)
+      };
+
+      // Determine new positioning properties
+      adjust = {
+         left: (overflow.left && (tooltip.corner.search(/right/i) != -1 || (tooltip.corner.search(/right/i) == -1 && !overflow.right))),
+         right: (overflow.right && (tooltip.corner.search(/left/i) != -1 || (tooltip.corner.search(/left/i) == -1 && !overflow.left))),
+         top: (overflow.top && tooltip.corner.search(/top/i) == -1),
+         bottom: (overflow.bottom && tooltip.corner.search(/bottom/i) == -1)
+      };
+
+      // Tooltip overflows off the left side of the screen
+      if(adjust.left)
+      {
+         if(self.options.position.target !== 'mouse')
+            adjustedPosition.left = target.position.left + target.dimensions.width;
+         else
+            adjustedPosition.left = self.cache.mouse.x
+
+         newCorner.x = 'Left';
+      }
+
+      // Tooltip overflows off the right side of the screen
+      else if(adjust.right)
+      {
+         if(self.options.position.target !== 'mouse')
+            adjustedPosition.left = target.position.left - tooltip.dimensions.width;
+         else
+            adjustedPosition.left = self.cache.mouse.x - tooltip.dimensions.width;
+
+         newCorner.x = 'Right';
+      };
+
+      // Tooltip overflows off the top of the screen
+      if(adjust.top)
+      {
+         if(self.options.position.target !== 'mouse')
+            adjustedPosition.top = target.position.top + target.dimensions.height;
+         else
+            adjustedPosition.top = self.cache.mouse.y
+
+         newCorner.y = 'top';
+      }
+
+      // Tooltip overflows off the bottom of the screen
+      else if(adjust.bottom)
+      {
+         if(self.options.position.target !== 'mouse')
+            adjustedPosition.top = target.position.top - tooltip.dimensions.height;
+         else
+            adjustedPosition.top = self.cache.mouse.y - tooltip.dimensions.height;
+
+         newCorner.y = 'bottom';
+      };
+
+      // Don't adjust if resulting position is negative
+      if(adjustedPosition.left < 0)
+      {
+         adjustedPosition.left = position.left;
+         newCorner.x = false;
+      };
+      if(adjustedPosition.top < 0)
+      {
+         adjustedPosition.top = position.top;
+         newCorner.y = false;
+      };
+
+      // Change tip corner if positioning has changed and tips are enabled
+      if(self.options.style.tip.corner !== false)
+      {
+         // Determine new corner properties
+         adjustedPosition.corner = new String(tooltip.corner);
+         if(newCorner.x !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/Left|Right|Middle/, newCorner.x);
+         if(newCorner.y !== false) adjustedPosition.corner = adjustedPosition.corner.replace(/top|bottom/, newCorner.y);
+
+         // Adjust tip if position has changed and tips are enabled
+         if(adjustedPosition.corner !== self.elements.tip.attr('rel'))
+            createTip.call(self, adjustedPosition.corner);
+      };
+
+      return adjustedPosition;
+   };
+
+   // Build a jQuery style object from supplied style object
+   function jQueryStyle(style, sub)
+   {
+      var styleObj, i;
+
+      styleObj = $.extend(true, {}, style);
+      for(i in styleObj)
+      {
+         if(sub === true && i.search(/(tip|classes)/i) !== -1)
+            delete styleObj[i];
+         else if(!sub && i.search(/(width|border|tip|title|classes|user)/i) !== -1)
+            delete styleObj[i];
+      };
+
+      return styleObj;
+   };
+
+   // Sanitize styles
+   function sanitizeStyle(style)
+   {
+      if(typeof style.tip !== 'object') style.tip = { corner: style.tip };
+      if(typeof style.tip.size !== 'object') style.tip.size = { width: style.tip.size, height: style.tip.size };
+      if(typeof style.border !== 'object') style.border = { width: style.border };
+      if(typeof style.width !== 'object') style.width = { value: style.width };
+      if(typeof style.width.max == 'string') style.width.max = parseInt(style.width.max.replace(/([0-9]+)/i, "$1"));
+      if(typeof style.width.min == 'string') style.width.min = parseInt(style.width.min.replace(/([0-9]+)/i, "$1"));
+
+      // Convert deprecated x and y tip values to width/height
+      if(typeof style.tip.size.x == 'number')
+      {
+         style.tip.size.width = style.tip.size.x;
+         delete style.tip.size.x;
+      };
+      if(typeof style.tip.size.y == 'number')
+      {
+         style.tip.size.height = style.tip.size.y;
+         delete style.tip.size.y;
+      };
+
+      return style;
+   };
+
+   // Build styles recursively with inheritance
+   function buildStyle()
+   {
+      var self, i, styleArray, styleExtend, finalStyle, ieAdjust;
+      self = this;
+
+      // Build style options from supplied arguments
+      styleArray = [true, {}];
+      for(i = 0; i < arguments.length; i++)
+         styleArray.push(arguments[i]);
+      styleExtend = [ $.extend.apply($, styleArray) ];
+
+      // Loop through each named style inheritance
+      while(typeof styleExtend[0].name == 'string')
+      {
+         // Sanitize style data and append to extend array
+         styleExtend.unshift( sanitizeStyle($.fn.qtip.styles[ styleExtend[0].name ]) );
+      };
+
+      // Make sure resulting tooltip className represents final style
+      styleExtend.unshift(true, {classes:{ tooltip: 'qtip-' + (arguments[0].name || 'defaults') }}, $.fn.qtip.styles.defaults);
+
+      // Extend into a single style object
+      finalStyle = $.extend.apply($, styleExtend);
+
+      // Adjust tip size if needed (IE 1px adjustment bug fix)
+      ieAdjust = ($.browser.msie) ? 1 : 0;
+      finalStyle.tip.size.width += ieAdjust;
+      finalStyle.tip.size.height += ieAdjust;
+
+      // Force even numbers for pixel precision
+      if(finalStyle.tip.size.width % 2 > 0) finalStyle.tip.size.width += 1;
+      if(finalStyle.tip.size.height % 2 > 0) finalStyle.tip.size.height += 1;
+
+      // Sanitize final styles tip corner value
+      if(finalStyle.tip.corner === true)
+         finalStyle.tip.corner = (self.options.position.corner.tooltip === 'center') ? false : self.options.position.corner.tooltip;
+
+      return finalStyle;
+   };
+
+   // Tip coordinates calculator
+   function calculateTip(corner, width, height)
+   {
+      // Define tip coordinates in terms of height and width values
+      var tips = {
+         bottomRight:   [[0,0],              [width,height],      [width,0]],
+         bottomLeft:    [[0,0],              [width,0],           [0,height]],
+         topRight:      [[0,height],         [width,0],           [width,height]],
+         topLeft:       [[0,0],              [0,height],          [width,height]],
+         topMiddle:     [[0,height],         [width / 2,0],       [width,height]],
+         bottomMiddle:  [[0,0],              [width,0],           [width / 2,height]],
+         rightMiddle:   [[0,0],              [width,height / 2],  [0,height]],
+         leftMiddle:    [[width,0],          [width,height],      [0,height / 2]]
+      };
+      tips.leftTop = tips.bottomRight;
+      tips.rightTop = tips.bottomLeft;
+      tips.leftBottom = tips.topRight;
+      tips.rightBottom = tips.topLeft;
+
+      return tips[corner];
+   };
+
+   // Border coordinates calculator
+   function calculateBorders(radius)
+   {
+      var borders;
+
+      // Use canvas element if supported
+      if($('<canvas>').get(0).getContext)
+      {
+         borders = {
+            topLeft: [radius,radius], topRight: [0,radius],
+            bottomLeft: [radius,0], bottomRight: [0,0]
+         };
+      }
+
+      // Canvas not supported - Use VML (IE)
+      else if($.browser.msie)
+      {
+         borders = {
+            topLeft: [-90,90,0], topRight: [-90,90,-radius],
+            bottomLeft: [90,270,0], bottomRight: [90, 270,-radius]
+         };
+      };
+
+      return borders;
+   };
+
+   // BGIFRAME JQUERY PLUGIN ADAPTION
+   //   Special thanks to Brandon Aaron for this plugin
+   //   http://plugins.jquery.com/project/bgiframe
+   function bgiframe()
+   {
+      var self, html, dimensions;
+      self = this;
+      dimensions = self.getDimensions();
+
+      // Setup iframe HTML string
+      html = '<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:false" '+
+         'style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=\'0\'); border: 1px solid red; ' +
+         'height:'+dimensions.height+'px; width:'+dimensions.width+'px" />';
+
+      // Append the new HTML and setup element reference
+      self.elements.bgiframe = self.elements.wrapper.prepend(html).children('.qtip-bgiframe:first');
+   };
+
+   // Assign cache and event initialisation on document load
+   $(document).ready(function()
+   {
+      // Setup library cache with window scroll and dimensions of document
+      $.fn.qtip.cache = {
+         screen: {
+            scroll: { left: $(window).scrollLeft(), top: $(window).scrollTop() },
+            width: $(window).width(),
+            height: $(window).height()
+         }
+      };
+
+      // Adjust positions of the tooltips on window resize or scroll if enabled
+      var adjustTimer;
+      $(window).bind('resize scroll', function(event)
+      {
+         clearTimeout(adjustTimer);
+         adjustTimer = setTimeout(function()
+         {
+            // Readjust cached screen values
+            if(event.type === 'scroll')
+               $.fn.qtip.cache.screen.scroll = { left: $(window).scrollLeft(), top: $(window).scrollTop() };
+            else
+            {
+               $.fn.qtip.cache.screen.width = $(window).width();
+               $.fn.qtip.cache.screen.height = $(window).height();
+            };
+
+            for(i = 0; i < $.fn.qtip.interfaces.length; i++)
+            {
+               // Access current elements API
+               var api = $.fn.qtip.interfaces[i];
+
+               // Update position if resize or scroll adjustments are enabled
+               if(api.status.rendered === true
+               && (api.options.position.type !== 'static'
+               || api.options.position.adjust.scroll && event.type === 'scroll'
+               || api.options.position.adjust.resize && event.type === 'resize'))
+               {
+                  // Queue the animation so positions are updated correctly
+                  api.updatePosition(event, true);
+               }
+            };
+         }
+         , 100);
+      })
+
+      // Hide unfocus toolipts on document mousedown
+      $(document).bind('mousedown.qtip', function(event)
+      {
+         if($(event.target).parents('div.qtip').length === 0)
+         {
+            $('.qtip[unfocus]').each(function()
+            {
+               var api = $(this).qtip("api");
+
+               // Only hide if its visible and not the tooltips target
+               if($(this).is(':visible') && !api.status.disabled
+               && $(event.target).add(api.elements.target).length > 1)
+                  api.hide(event);
+            })
+         };
+      })
+   });
+
+   // Define qTip API interfaces array
+   $.fn.qtip.interfaces = []
+
+   // Define log and constant place holders
+   $.fn.qtip.log = { error: function(){ return this; } };
+   $.fn.qtip.constants = {};
+
+   // Define configuration defaults
+   $.fn.qtip.defaults = {
+      // Content
+      content: {
+         prerender: false,
+         text: false,
+         url: false,
+         data: null,
+         title: {
+            text: false,
+            button: false
+         }
+      },
+      // Position
+      position: {
+         target: false,
+         corner: {
+            target: 'bottomRight',
+            tooltip: 'topLeft'
+         },
+         adjust: {
+            x: 0, y: 0,
+            mouse: true,
+            screen: false,
+            scroll: true,
+            resize: true
+         },
+         type: 'absolute',
+         container: false
+      },
+      // Effects
+      show: {
+         when: {
+            target: false,
+            event: 'mouseover'
+         },
+         effect: {
+            type: 'fade',
+            length: 100
+         },
+         delay: 140,
+         solo: false,
+         ready: false
+      },
+      hide: {
+         when: {
+            target: false,
+            event: 'mouseout'
+         },
+         effect: {
+            type: 'fade',
+            length: 100
+         },
+         delay: 0,
+         fixed: false
+      },
+      // Callbacks
+      api: {
+         beforeRender: function(){},
+         onRender: function(){},
+         beforePositionUpdate: function(){},
+         onPositionUpdate: function(){},
+         beforeShow: function(){},
+         onShow: function(){},
+         beforeHide: function(){},
+         onHide: function(){},
+         beforeContentUpdate: function(){},
+         onContentUpdate: function(){},
+         beforeContentLoad: function(){},
+         onContentLoad: function(){},
+         beforeTitleUpdate: function(){},
+         onTitleUpdate: function(){},
+         beforeDestroy: function(){},
+         onDestroy: function(){},
+         beforeFocus: function(){},
+         onFocus: function(){}
+      }
+   };
+
+   $.fn.qtip.styles = {
+      defaults: {
+         background: 'white',
+         color: '#111',
+         overflow: 'hidden',
+         textAlign: 'left',
+         width: {
+            min: 0,
+            max: 250
+         },
+         padding: '5px 9px',
+         border: {
+            width: 1,
+            radius: 0,
+            color: '#d3d3d3'
+         },
+         tip: {
+            corner: false,
+            color: false,
+            size: { width: 13, height: 13 },
+            opacity: 1
+         },
+         title: {
+            background: '#e1e1e1',
+            fontWeight: 'bold',
+            padding: '7px 12px'
+         },
+         button: {
+            cursor: 'pointer'
+         },
+         classes: {
+            target: '',
+            tip: 'qtip-tip',
+            title: 'qtip-title',
+            button: 'qtip-button',
+            content: 'qtip-content',
+            active: 'qtip-active'
+         }
+      },
+      cream: {
+         border: {
+            width: 3,
+            radius: 0,
+            color: '#F9E98E'
+         },
+         title: {
+            background: '#F0DE7D',
+            color: '#A27D35'
+         },
+         background: '#FBF7AA',
+         color: '#A27D35',
+
+         classes: { tooltip: 'qtip-cream' }
+      },
+      light: {
+         border: {
+            width: 3,
+            radius: 0,
+            color: '#E2E2E2'
+         },
+         title: {
+            background: '#f1f1f1',
+            color: '#454545'
+         },
+         background: 'white',
+         color: '#454545',
+
+         classes: { tooltip: 'qtip-light' }
+      },
+      dark: {
+         border: {
+            width: 3,
+            radius: 0,
+            color: '#303030'
+         },
+         title: {
+            background: '#404040',
+            color: '#f3f3f3'
+         },
+         background: '#505050',
+         color: '#f3f3f3',
+
+         classes: { tooltip: 'qtip-dark' }
+      },
+      red: {
+         border: {
+            width: 3,
+            radius: 0,
+            color: '#CE6F6F'
+         },
+         title: {
+            background: '#f28279',
+            color: '#9C2F2F'
+         },
+         background: '#F79992',
+         color: '#9C2F2F',
+
+         classes: { tooltip: 'qtip-red' }
+      },
+      green: {
+         border: {
+            width: 3,
+            radius: 0,
+            color: '#A9DB66'
+         },
+         title: {
+            background: '#b9db8c',
+            color: '#58792E'
+         },
+         background: '#CDE6AC',
+         color: '#58792E',
+
+         classes: { tooltip: 'qtip-green' }
+      },
+      blue: {
+         border: {
+            width: 3,
+            radius: 0,
+            color: '#ADD9ED'
+         },
+         title: {
+            background: '#D0E9F5',
+            color: '#5E99BD'
+         },
+         background: '#E5F6FE',
+         color: '#4D9FBF',
+
+         classes: { tooltip: 'qtip-blue' }
+      }
+   };
+})(jQuery);
\ No newline at end of file
diff --git a/js/jquery/jquery.qtip-1.0.0.min.js b/js/jquery/jquery.qtip-1.0.0.min.js
deleted file mode 100644
index 208a6d1..0000000
--- a/js/jquery/jquery.qtip-1.0.0.min.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * jquery.qtip. The jQuery tooltip plugin
- *
- * Copyright (c) 2009 Craig Thompson
- * http://craigsworks.com
- *
- * Licensed under MIT
- * http://www.opensource.org/licenses/mit-license.php
- *
- * Launch  : February 2009
- * Version : 1.0.0-rc3
- * Released: Tuesday 12th May, 2009 - 00:00
- * Debug: jquery.qtip.debug.js
- */
-(function(f){f.fn.qtip=function(B,u){var y,t,A,s,x,w,v,z;if(typeof B=="string"){if(typeof f(this).data("qtip")!=="object"){f.fn.qtip.log.error.call(self,1,f.fn.qtip.constants.NO_TOOLTIP_PRESENT,false)}if(B=="api"){return f(this).data("qtip").interfaces[f(this).data("qtip").current]}else{if(B=="interfaces"){return f(this).data("qtip").interfaces}}}else{if(!B){B={}}if(typeof B.content!=="object"||(B.content.jquery&&B.content.length>0)){B.content={text:B.content}}if(typeof B.content.title!=="object"){B.content.title={text:B.content.title}}if(typeof B.position!=="object"){B.position={corner:B.position}}if(typeof B.position.corner!=="object"){B.position.corner={target:B.position.corner,tooltip:B.position.corner}}if(typeof B.show!=="object"){B.show={when:B.show}}if(typeof B.show.when!=="object"){B.show.when={event:B.show.when}}if(typeof B.show.effect!=="object"){B.show.effect={type:B.show.effect}}if(typeof B.hide!=="object"){B.hide={when:B.hide}}if(typeof B.hide.when!=="object"){B.hide.when={event:B.hide.when}}if(typeof B.hide.effect!=="object"){B.hide.effect={type:B.hide.effect}}if(typeof B.style!=="object"){B.style={name:B.style}}B.style=c(B.style);s=f.extend(true,{},f.fn.qtip.defaults,B);s.style=a.call({options:s},s.style);s.user=f.extend(true,{},B)}return f(this).each(function(){if(typeof B=="string"){w=B.toLowerCase();A=f(this).qtip("interfaces");if(typeof A=="object"){if(u===true&&w=="destroy"){while(A.length>0){A[A.length-1].destroy()}}else{if(u!==true){A=[f(this).qtip("api")]}for(y=0;y<A.length;y++){if(w=="destroy"){A[y].destroy()}else{if(A[y].status.rendered===true){if(w=="show"){A[y].show()}else{if(w=="hide"){A[y].hide()}else{if(w=="focus"){A[y].focus()}else{if(w=="disable"){A[y].disable(true)}else{if(w=="enable"){A[y].disable(false)}}}}}}}}}}}else{v=f.extend(true,{},s);v.hide.effect.length=s.hide.effect.length;v.show.effect.length=s.show.effect.length;if(v.position.container===false){v.position.container=f(document.body)}if(v.position.target===false){v.position.target=f(this)}if(v.show.when.target===false){ v.show.when.target=f(this)}if(v.hide.when.target===false){v.hide.when.target=f(this)}t=f.fn.qtip.interfaces.length;for(y=0;y<t;y++){if(typeof f.fn.qtip.interfaces[y]=="undefined"){t=y;break}}x=new d(f(this),v,t);f.fn.qtip.interfaces[t]=x;if(typeof f(this).data("qtip")=="object"&&f(this).data('qtip')!==null){if(typeof f(this).attr("qtip")==="undefined"){f(this).data("qtip").current=f(this).data("qtip").interfaces.length}f(this).data("qtip").interfaces.push(x)}else{f(this).data("qtip",{current:0,interfaces:[x]})}if(v.content.prerender===false&&v.show.when.event!==false&&v.show.ready!==true){v.show.when.target.bind(v.show.when.event+".qtip-"+t+"-create",{qtip:t},function(C){z=f.fn.qtip.interfaces[C.data.qtip];z.options.show.when.target.unbind(z.options.show.when.event+".qtip-"+C.data.qtip+"-create");z.cache.mouse={x:C.pageX,y:C.pageY};p.call(z);z.options.show.when.target.trigger(z.options.show.when.event)})}else{x.cache.mouse={x:v.show.when.target.offset().left,y:v.show.when.target.offset().top};p.call(x)}}})};function d(u,t,v){var s=this;s.id=v;s.options=t;s.status={animated:false,rendered:false,disabled:false,focused:false};s.elements={target:u.addClass(s.options.style.classes.target),tooltip:null,wrapper:null,content:null,contentWrapper:null,title:null,button:null,tip:null,bgiframe:null};s.cache={mouse:{},position:{},toggle:0};s.timers={};f.extend(s,s.options.api,{show:function(y){var x,z;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"show")}if(s.elements.tooltip.css("display")!=="none"){return s}s.elements.tooltip.stop(true,false);x=s.beforeShow.call(s,y);if(x===false){return s}function w(){if(s.options.position.type!=="static"){s.focus()}s.onShow.call(s,y);if(f.browser.msie){s.elements.tooltip.get(0).style.removeAttribute("filter")}}s.cache.toggle=1;if(s.options.position.type!=="static"){s.updatePosition(y,(s.options.show.effect.length>0))}if(typeof s.options.show.solo=="object"){z=f(s.options.show.solo)}else{if(s.options.show.solo===true){z=f("div.qtip").no t(s.elements.tooltip)}}if(z){z.each(function(){if(f(this).qtip("api").status.rendered===true){f(this).qtip("api").hide()}})}if(typeof s.options.show.effect.type=="function"){s.options.show.effect.type.call(s.elements.tooltip,s.options.show.effect.length);s.elements.tooltip.queue(function(){w();f(this).dequeue()})}else{switch(s.options.show.effect.type.toLowerCase()){case"fade":s.elements.tooltip.fadeIn(s.options.show.effect.length,w);break;case"slide":s.elements.tooltip.slideDown(s.options.show.effect.length,function(){w();if(s.options.position.type!=="static"){s.updatePosition(y,true)}});break;case"grow":s.elements.tooltip.show(s.options.show.effect.length,w);break;default:s.elements.tooltip.show(null,w);break}s.elements.tooltip.addClass(s.options.style.classes.active)}return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_SHOWN,"show")},hide:function(y){var x;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"hide")}else{if(s.elements.tooltip.css("display")==="none"){return s}}clearTimeout(s.timers.show);s.elements.tooltip.stop(true,false);x=s.beforeHide.call(s,y);if(x===false){return s}function w(){s.onHide.call(s,y)}s.cache.toggle=0;if(typeof s.options.hide.effect.type=="function"){s.options.hide.effect.type.call(s.elements.tooltip,s.options.hide.effect.length);s.elements.tooltip.queue(function(){w();f(this).dequeue()})}else{switch(s.options.hide.effect.type.toLowerCase()){case"fade":s.elements.tooltip.fadeOut(s.options.hide.effect.length,w);break;case"slide":s.elements.tooltip.slideUp(s.options.hide.effect.length,w);break;case"grow":s.elements.tooltip.hide(s.options.hide.effect.length,w);break;default:s.elements.tooltip.hide(null,w);break}s.elements.tooltip.removeClass(s.options.style.classes.active)}return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_HIDDEN,"hide")},updatePosition:function(w,x){var C,G,L,J,H,E,y,I,B,D,K,A,F,z;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updatePosition") }else{if(s.options.position.type=="static"){return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.CANNOT_POSITION_STATIC,"updatePosition")}}G={position:{left:0,top:0},dimensions:{height:0,width:0},corner:s.options.position.corner.target};L={position:s.getPosition(),dimensions:s.getDimensions(),corner:s.options.position.corner.tooltip};if(s.options.position.target!=="mouse"){if(s.options.position.target.get(0).nodeName.toLowerCase()=="area"){J=s.options.position.target.attr("coords").split(",");for(C=0;C<J.length;C++){J[C]=parseInt(J[C])}H=s.options.position.target.parent("map").attr("name");E=f('img[usemap="#'+H+'"]:first').offset();G.position={left:Math.floor(E.left+J[0]),top:Math.floor(E.top+J[1])};switch(s.options.position.target.attr("shape").toLowerCase()){case"rect":G.dimensions={width:Math.ceil(Math.abs(J[2]-J[0])),height:Math.ceil(Math.abs(J[3]-J[1]))};break;case"circle":G.dimensions={width:J[2]+1,height:J[2]+1};break;case"poly":G.dimensions={width:J[0],height:J[1]};for(C=0;C<J.length;C++){if(C%2==0){if(J[C]>G.dimensions.width){G.dimensions.width=J[C]}if(J[C]<J[0]){G.position.left=Math.floor(E.left+J[C])}}else{if(J[C]>G.dimensions.height){G.dimensions.height=J[C]}if(J[C]<J[1]){G.position.top=Math.floor(E.top+J[C])}}}G.dimensions.width=G.dimensions.width-(G.position.left-E.left);G.dimensions.height=G.dimensions.height-(G.position.top-E.top);break;default:return f.fn.qtip.log.error.call(s,4,f.fn.qtip.constants.INVALID_AREA_SHAPE,"updatePosition");break}G.dimensions.width-=2;G.dimensions.height-=2}else{if(s.options.position.target.add(document.body).length===1){G.position={left:f(document).scrollLeft(),top:f(document).scrollTop()};G.dimensions={height:f(window).height(),width:f(window).width()}}else{if(typeof s.options.position.target.attr("qtip")!=="undefined"){G.position=s.options.position.target.qtip("api").cache.position}else{G.position=s.options.position.target.offset()}G.dimensions={height:s.options.position.target.outerHeight(),width:s.options.position.target.outerWidth()}}}y=f.extend({},G.position) ;if(G.corner.search(/right/i)!==-1){y.left+=G.dimensions.width}if(G.corner.search(/bottom/i)!==-1){y.top+=G.dimensions.height}if(G.corner.search(/((top|bottom)Middle)|center/)!==-1){y.left+=(G.dimensions.width/2)}if(G.corner.search(/((left|right)Middle)|center/)!==-1){y.top+=(G.dimensions.height/2)}}else{G.position=y={left:s.cache.mouse.x,top:s.cache.mouse.y};G.dimensions={height:1,width:1}}if(L.corner.search(/right/i)!==-1){y.left-=L.dimensions.width}if(L.corner.search(/bottom/i)!==-1){y.top-=L.dimensions.height}if(L.corner.search(/((top|bottom)Middle)|center/)!==-1){y.left-=(L.dimensions.width/2)}if(L.corner.search(/((left|right)Middle)|center/)!==-1){y.top-=(L.dimensions.height/2)}I=(f.browser.msie)?1:0;B=(f.browser.msie&&parseInt(f.browser.version.charAt(0))===6)?1:0;if(s.options.style.border.radius>0){if(L.corner.search(/Left/)!==-1){y.left-=s.options.style.border.radius}else{if(L.corner.search(/Right/)!==-1){y.left+=s.options.style.border.radius}}if(L.corner.search(/Top/)!==-1){y.top-=s.options.style.border.radius}else{if(L.corner.search(/Bottom/)!==-1){y.top+=s.options.style.border.radius}}}if(I){if(L.corner.search(/top/)!==-1){y.top-=I}else{if(L.corner.search(/bottom/)!==-1){y.top+=I}}if(L.corner.search(/left/)!==-1){y.left-=I}else{if(L.corner.search(/right/)!==-1){y.left+=I}}if(L.corner.search(/leftMiddle|rightMiddle/)!==-1){y.top-=1}}if(s.options.position.adjust.screen===true){y=o.call(s,y,G,L)}if(s.options.position.target==="mouse"&&s.options.position.adjust.mouse===true){if(s.options.position.adjust.screen===true&&s.elements.tip){K=s.elements.tip.attr("rel")}else{K=s.options.position.corner.tooltip}y.left+=(K.search(/right/i)!==-1)?-6:6;y.top+=(K.search(/bottom/i)!==-1)?-6:6}if(!s.elements.bgiframe&&f.browser.msie&&parseInt(f.browser.version.charAt(0))==6){f("select, object").each(function(){A=f(this).offset();A.bottom=A.top+f(this).height();A.right=A.left+f(this).width();if(y.top+L.dimensions.height>=A.top&&y.left+L.dimensions.width>=A.left){k.call(s)}})}y.left+=s.options.position.adjust.x;y.top+=s.o ptions.position.adjust.y;F=s.getPosition();if(y.left!=F.left||y.top!=F.top){z=s.beforePositionUpdate.call(s,w);if(z===false){return s}s.cache.position=y;if(x===true){s.status.animated=true;s.elements.tooltip.animate(y,200,"swing",function(){s.status.animated=false})}else{s.elements.tooltip.css(y)}s.onPositionUpdate.call(s,w);if(typeof w!=="undefined"&&w.type&&w.type!=="mousemove"){f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_POSITION_UPDATED,"updatePosition")}}return s},updateWidth:function(w){var x;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updateWidth")}else{if(w&&typeof w!=="number"){return f.fn.qtip.log.error.call(s,2,"newWidth must be of type number","updateWidth")}}x=s.elements.contentWrapper.siblings().add(s.elements.tip).add(s.elements.button);if(!w){if(typeof s.options.style.width.value=="number"){w=s.options.style.width.value}else{s.elements.tooltip.css({width:"auto"});x.hide();if(f.browser.msie){s.elements.wrapper.css({width:"auto"});s.elements.wrapper.add(s.elements.contentWrapper.children()).css({zoom:"normal"});}w=s.getDimensions().width+1;if(!s.options.style.width.value){if(w>s.options.style.width.max){w=s.options.style.width.max}if(w<s.options.style.width.min){w=s.options.style.width.min}}}}if(w%2!==0){w-=1}s.elements.tooltip.width(w);x.show();if(s.options.style.border.radius){s.elements.tooltip.find(".qtip-betweenCorners").each(function(y){f(this).width(w-(s.options.style.border.radius*2))})}if(f.browser.msie){s.elements.wrapper.add(s.elements.contentWrapper.children()).css({zoom:"1"});s.elements.wrapper.width(w);if(s.elements.bgiframe){s.elements.bgiframe.width(w).height(s.getDimensions.height)}}return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_WIDTH_UPDATED,"updateWidth")},updateStyle:function(w){var z,A,x,y,B;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updateStyle")}else{if(typeof w!=="string"||!f.fn.qtip.styles[w]){return f.fn.qtip.log.error.call(s,2,f.fn.qt ip.constants.STYLE_NOT_DEFINED,"updateStyle")}}s.options.style=a.call(s,f.fn.qtip.styles[w],s.options.user.style);s.elements.content.css(q(s.options.style));if(s.options.content.title.text!==false){s.elements.title.css(q(s.options.style.title,true))}s.elements.contentWrapper.css({borderColor:s.options.style.border.color});if(s.options.style.tip.corner!==false){if(f("<canvas>").get(0).getContext){z=s.elements.tooltip.find(".qtip-tip canvas:first");x=z.get(0).getContext("2d");x.clearRect(0,0,300,300);y=z.parent("div[rel]:first").attr("rel");B=b(y,s.options.style.tip.size.width,s.options.style.tip.size.height);h.call(s,z,B,s.options.style.tip.color||s.options.style.border.color)}else{if(f.browser.msie){z=s.elements.tooltip.find('.qtip-tip [nodeName="shape"]');z.attr("fillcolor",s.options.style.tip.color||s.options.style.border.color)}}}if(s.options.style.border.radius>0){s.elements.tooltip.find(".qtip-betweenCorners").css({backgroundColor:s.options.style.border.color});if(f("<canvas>").get(0).getContext){A=g(s.options.style.border.radius);s.elements.tooltip.find(".qtip-wrapper canvas").each(function(){x=f(this).get(0).getContext("2d");x.clearRect(0,0,300,300);y=f(this).parent("div[rel]:first").attr("rel");r.call(s,f(this),A[y],s.options.style.border.radius,s.options.style.border.color)})}else{if(f.browser.msie){s.elements.tooltip.find('.qtip-wrapper [nodeName="arc"]').each(function(){f(this).attr("fillcolor",s.options.style.border.color)})}}}return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_STYLE_UPDATED,"updateStyle")},updateContent:function(A,y){var z,x,w;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updateContent")}else{if(!A){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.NO_CONTENT_PROVIDED,"updateContent")}}z=s.beforeContentUpdate.call(s,A);if(typeof z=="string"){A=z}else{if(z===false){return}}if(f.browser.msie){s.elements.contentWrapper.children().css({zoom:"normal"})}if(A.jquery&&A.length>0){A.clone(true).appendTo(s.elements.content) .show()}else{s.elements.content.html(A)}x=s.elements.content.find("img[complete=false]");if(x.length>0){w=0;x.each(function(C){f('<img src="'+f(this).attr("src")+'" />').load(function(){if(++w==x.length){B()}})})}else{B()}function B(){s.updateWidth();if(y!==false){if(s.options.position.type!=="static"){s.updatePosition(s.elements.tooltip.is(":visible"),true)}if(s.options.style.tip.corner!==false){n.call(s)}}}s.onContentUpdate.call(s);return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_CONTENT_UPDATED,"loadContent")},loadContent:function(w,z,A){var y;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"loadContent")}y=s.beforeContentLoad.call(s);if(y===false){return s}if(A=="post"){f.post(w,z,x)}else{f.get(w,z,x)}function x(B){s.onContentLoad.call(s);f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_CONTENT_LOADED,"loadContent");s.updateContent(B)}return s},updateTitle:function(w){if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"updateTitle")}else{if(!w){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.NO_CONTENT_PROVIDED,"updateTitle")}}returned=s.beforeTitleUpdate.call(s);if(returned===false){return s}if(s.elements.button){s.elements.button=s.elements.button.clone(true)}s.elements.title.html(w);if(s.elements.button){s.elements.title.prepend(s.elements.button)}s.onTitleUpdate.call(s);return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_TITLE_UPDATED,"updateTitle")},focus:function(A){var y,x,w,z;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"focus")}else{if(s.options.position.type=="static"){return f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.CANNOT_FOCUS_STATIC,"focus")}}y=parseInt(s.elements.tooltip.css("z-index"));x=6000+f("div.qtip[qtip]").length-1;if(!s.status.focused&&y!==x){z=s.beforeFocus.call(s,A);if(z===false){return s}f("div.qtip[qtip]").not(s.elements.tooltip).each(function(){if(f(this).qtip("api").status.rendered=== true){w=parseInt(f(this).css("z-index"));if(typeof w=="number"&&w>-1){f(this).css({zIndex:parseInt(f(this).css("z-index"))-1})}f(this).qtip("api").status.focused=false}});s.elements.tooltip.css({zIndex:x});s.status.focused=true;s.onFocus.call(s,A);f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_FOCUSED,"focus")}return s},disable:function(w){if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"disable")}if(w){if(!s.status.disabled){s.status.disabled=true;f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_DISABLED,"disable")}else{f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.TOOLTIP_ALREADY_DISABLED,"disable")}}else{if(s.status.disabled){s.status.disabled=false;f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_ENABLED,"disable")}else{f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.TOOLTIP_ALREADY_ENABLED,"disable")}}return s},destroy:function(){var w,x,y;x=s.beforeDestroy.call(s);if(x===false){return s}if(s.status.rendered){s.options.show.when.target.unbind("mousemove.qtip",s.updatePosition);s.options.show.when.target.unbind("mouseout.qtip",s.hide);s.options.show.when.target.unbind(s.options.show.when.event+".qtip");s.options.hide.when.target.unbind(s.options.hide.when.event+".qtip");s.elements.tooltip.unbind(s.options.hide.when.event+".qtip");s.elements.tooltip.unbind("mouseover.qtip",s.focus);s.elements.tooltip.remove()}else{s.options.show.when.target.unbind(s.options.show.when.event+".qtip-create")}if(typeof s.elements.target.data("qtip")=="object"){y=s.elements.target.data("qtip").interfaces;if(typeof y=="object"&&y.length>0){for(w=0;w<y.length-1;w++){if(y[w].id==s.id){y.splice(w,1)}}}}delete f.fn.qtip.interfaces[s.id];if(typeof y=="object"&&y.length>0){s.elements.target.data("qtip").current=y.length-1}else{s.elements.target.removeData("qtip")}s.onDestroy.call(s);f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_DESTROYED,"destroy");return s.elements.target},getPosition:function(){var w,x;if(!s.status.rendered){return f.fn.qtip.log.error.c all(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"getPosition")}w=(s.elements.tooltip.css("display")!=="none")?false:true;if(w){s.elements.tooltip.css({visiblity:"hidden"}).show()}x=s.elements.tooltip.offset();if(w){s.elements.tooltip.css({visiblity:"visible"}).hide()}return x},getDimensions:function(){var w,x;if(!s.status.rendered){return f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.TOOLTIP_NOT_RENDERED,"getDimensions")}w=(!s.elements.tooltip.is(":visible"))?true:false;if(w){s.elements.tooltip.css({visiblity:"hidden"}).show()}x={height:s.elements.tooltip.outerHeight(),width:s.elements.tooltip.outerWidth()};if(w){s.elements.tooltip.css({visiblity:"visible"}).hide()}return x}})}function p(){var s,w,u,t,v,y,x;s=this;s.beforeRender.call(s);s.status.rendered=true;s.elements.tooltip='<div qtip="'+s.id+'" class="qtip '+(s.options.style.classes.tooltip||s.options.style)+'"style="display:none; -moz-border-radius:0; -webkit-border-radius:0; border-radius:0;position:'+s.options.position.type+';">  <div class="qtip-wrapper" style="position:relative; overflow:hidden; text-align:left;">    <div class="qtip-contentWrapper" style="overflow:hidden;">       <div class="qtip-content '+s.options.style.classes.content+'"></div></div></div></div>';s.elements.tooltip=f(s.elements.tooltip);s.elements.tooltip.appendTo(s.options.position.container);s.elements.tooltip.data("qtip",{current:0,interfaces:[s]});s.elements.wrapper=s.elements.tooltip.children("div:first");s.elements.contentWrapper=s.elements.wrapper.children("div:first").css({background:s.options.style.background});s.elements.content=s.elements.contentWrapper.children("div:first").css(q(s.options.style));if(f.browser.msie){s.elements.wrapper.add(s.elements.content).css({zoom:1})}if(s.options.hide.when.event=="unfocus"){s.elements.tooltip.attr("unfocus",true)}if(typeof s.options.style.width.value=="number"){s.updateWidth()}if(f("<canvas>").get(0).getContext||f.browser.msie){if(s.options.style.border.radius>0){m.call(s)}else{s.elements.contentWrapper.css({border:s.options.sty le.border.width+"px solid "+s.options.style.border.color})}if(s.options.style.tip.corner!==false){e.call(s)}}else{s.elements.contentWrapper.css({border:s.options.style.border.width+"px solid "+s.options.style.border.color});s.options.style.border.radius=0;s.options.style.tip.corner=false;f.fn.qtip.log.error.call(s,2,f.fn.qtip.constants.CANVAS_VML_NOT_SUPPORTED,"render")}if((typeof s.options.content.text=="string"&&s.options.content.text.length>0)||(s.options.content.text.jquery&&s.options.content.text.length>0)){u=s.options.content.text}else{if(typeof s.elements.target.attr("title")=="string"&&s.elements.target.attr("title").length>0){u=s.elements.target.attr("title").replace("\\n","<br />");s.elements.target.attr("title","")}else{if(typeof s.elements.target.attr("alt")=="string"&&s.elements.target.attr("alt").length>0){u=s.elements.target.attr("alt").replace("\\n","<br />");s.elements.target.attr("alt","")}else{u=" ";f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.NO_VALID_CONTENT,"render")}}}if(s.options.content.title.text!==false){j.call(s)}s.updateContent(u);l.call(s);if(s.options.show.ready===true){s.show()}if(s.options.content.url!==false){t=s.options.content.url;v=s.options.content.data;y=s.options.content.method||"get";s.loadContent(t,v,y)}s.onRender.call(s);f.fn.qtip.log.error.call(s,1,f.fn.qtip.constants.EVENT_RENDERED,"render")}function m(){var F,z,t,B,x,E,u,G,D,y,w,C,A,s,v;F=this;F.elements.wrapper.find(".qtip-borderBottom, .qtip-borderTop").remove();t=F.options.style.border.width;B=F.options.style.border.radius;x=F.options.style.border.color||F.options.style.tip.color;E=g(B);u={};for(z in E){u[z]='<div rel="'+z+'" style="'+((z.search(/Left/)!==-1)?"left":"right")+":0; position:absolute; height:"+B+"px; width:"+B+'px; overflow:hidden; line-height:0.1px; font-size:1px">';if(f("<canvas>").get(0).getContext){u[z]+='<canvas height="'+B+'" width="'+B+'" style="vertical-align: top"></canvas>'}else{if(f.browser.msie){G=B*2+3;u[z]+='<v:arc stroked="false" fillcolor="'+x+'" startangle="'+E[z][0]+'" endangle=" '+E[z][1]+'" style="width:'+G+"px; height:"+G+"px; margin-top:"+((z.search(/bottom/)!==-1)?-2:-1)+"px; margin-left:"+((z.search(/Right/)!==-1)?E[z][2]-3.5:-1)+'px; vertical-align:top; display:inline-block; behavior:url(#default#VML)"></v:arc>'}}u[z]+="</div>"}D=F.getDimensions().width-(Math.max(t,B)*2);y='<div class="qtip-betweenCorners" style="height:'+B+"px; width:"+D+"px; overflow:hidden; background-color:"+x+'; line-height:0.1px; font-size:1px;">';w='<div class="qtip-borderTop" dir="ltr" style="height:'+B+"px; margin-left:"+B+'px; line-height:0.1px; font-size:1px; padding:0;">'+u.topLeft+u.topRight+y;F.elements.wrapper.prepend(w);C='<div class="qtip-borderBottom" dir="ltr" style="height:'+B+"px; margin-left:"+B+'px; line-height:0.1px; font-size:1px; padding:0;">'+u.bottomLeft+u.bottomRight+y;F.elements.wrapper.append(C);if(f("<canvas>").get(0).getContext){F.elements.wrapper.find("canvas").each(function(){A=E[f(this).parent("[rel]:first").attr("rel")];r.call(F,f(this),A,B,x)})}else{if(f.browser.msie){F.elements.tooltip.append('<v:image style="behavior:url(#default#VML);"></v:image>')}}s=Math.max(B,(B+(t-B)));v=Math.max(t-B,0);F.elements.contentWrapper.css({border:"0px solid "+x,borderWidth:v+"px "+s+"px"})}function r(u,w,s,t){var v=u.get(0).getContext("2d");v.fillStyle=t;v.beginPath();v.arc(w[0],w[1],s,0,Math.PI*2,false);v.fill()}function e(v){var t,s,x,u,w;t=this;if(t.elements.tip!==null){t.elements.tip.remove()}s=t.options.style.tip.color||t.options.style.border.color;if(t.options.style.tip.corner===false){return}else{if(!v){v=t.options.style.tip.corner}}x=b(v,t.options.style.tip.size.width,t.options.style.tip.size.height);t.elements.tip='<div class="'+t.options.style.classes.tip+'" dir="ltr" rel="'+v+'" style="position:absolute; height:'+t.options.style.tip.size.height+"px; width:"+t.options.style.tip.size.width+'px; margin:0 auto; line-height:0.1px; font-size:1px;">';if(f("<canvas>").get(0).getContext){t.elements.tip+='<canvas height="'+t.options.style.tip.size.height+'" width="'+t.options.style.tip.size.w idth+'"></canvas>'}else{if(f.browser.msie){u=t.options.style.tip.size.width+","+t.options.style.tip.size.height;w="m"+x[0][0]+","+x[0][1];w+=" l"+x[1][0]+","+x[1][1];w+=" "+x[2][0]+","+x[2][1];w+=" xe";t.elements.tip+='<v:shape fillcolor="'+s+'" stroked="false" filled="true" path="'+w+'" coordsize="'+u+'" style="width:'+t.options.style.tip.size.width+"px; height:"+t.options.style.tip.size.height+"px; line-height:0.1px; display:inline-block; behavior:url(#default#VML); vertical-align:"+((v.search(/top/)!==-1)?"bottom":"top")+'"></v:shape>';t.elements.tip+='<v:image style="behavior:url(#default#VML);"></v:image>';t.elements.contentWrapper.css("position","relative")}}t.elements.tooltip.prepend(t.elements.tip+"</div>");t.elements.tip=t.elements.tooltip.find("."+t.options.style.classes.tip).eq(0);if(f("<canvas>").get(0).getContext){h.call(t,t.elements.tip.find("canvas:first"),x,s)}if(v.search(/top/)!==-1&&f.browser.msie&&parseInt(f.browser.version.charAt(0))===6){t.elements.tip.css({marginTop:-4})}n.call(t,v)}function h(t,v,s){var u=t.get(0).getContext("2d");u.fillStyle=s;u.beginPath();u.moveTo(v[0][0],v[0][1]);u.lineTo(v[1][0],v[1][1]);u.lineTo(v[2][0],v[2][1]);u.fill()}function n(u){var t,w,s,x,v;t=this;if(t.options.style.tip.corner===false||!t.elements.tip){return}if(!u){u=t.elements.tip.attr("rel")}w=positionAdjust=(f.browser.msie)?1:0;t.elements.tip.css(u.match(/left|right|top|bottom/)[0],0);if(u.search(/top|bottom/)!==-1){if(f.browser.msie){if(parseInt(f.browser.version.charAt(0))===6){positionAdjust=(u.search(/top/)!==-1)?-3:1}else{positionAdjust=(u.search(/top/)!==-1)?1:2}}if(u.search(/Middle/)!==-1){t.elements.tip.css({left:"50%",marginLeft:-(t.options.style.tip.size.width/2)})}else{if(u.search(/Left/)!==-1){t.elements.tip.css({left:t.options.style.border.radius-w})}else{if(u.search(/Right/)!==-1){t.elements.tip.css({right:t.options.style.border.radius+w})}}}if(u.search(/top/)!==-1){t.elements.tip.css({top:-positionAdjust})}else{t.elements.tip.css({bottom:positionAdjust})}}else{if(u.search(/left|right/)!==-1) {if(f.browser.msie){positionAdjust=(parseInt(f.browser.version.charAt(0))===6)?1:((u.search(/left/)!==-1)?1:2)}if(u.search(/Middle/)!==-1){t.elements.tip.css({top:"50%",marginTop:-(t.options.style.tip.size.height/2)})}else{if(u.search(/Top/)!==-1){t.elements.tip.css({top:t.options.style.border.radius-w})}else{if(u.search(/Bottom/)!==-1){t.elements.tip.css({bottom:t.options.style.border.radius+w})}}}if(u.search(/left/)!==-1){t.elements.tip.css({left:-positionAdjust})}else{t.elements.tip.css({right:positionAdjust})}}}s="padding-"+u.match(/left|right|top|bottom/)[0];x=t.options.style.tip.size[(s.search(/left|right/)!==-1)?"width":"height"];t.elements.tooltip.css("padding",0);t.elements.tooltip.css(s,x);if(f.browser.msie&&parseInt(f.browser.version.charAt(0))==6){v=parseInt(t.elements.tip.css("margin-top"))||0;v+=parseInt(t.elements.content.css("margin-top"))||0;t.elements.tip.css({marginTop:v})}}function j(){var s=this;if(s.elements.title!==null){s.elements.title.remove()}s.elements.title=f('<div class="'+s.options.style.classes.title+'">').css(q(s.options.style.title,true)).css({zoom:(f.browser.msie)?1:0}).prependTo(s.elements.contentWrapper);if(s.options.content.title.text){s.updateTitle.call(s,s.options.content.title.text)}if(s.options.content.title.button!==false&&typeof s.options.content.title.button=="string"){s.elements.button=f('<a class="'+s.options.style.classes.button+'" style="float:right; position: relative"></a>').css(q(s.options.style.button,true)).html(s.options.content.title.button).prependTo(s.elements.title).click(function(t){if(!s.status.disabled){s.hide(t)}})}}function l(){var t,v,u,s;t=this;v=t.options.show.when.target;u=t.options.hide.when.target;if(t.options.hide.fixed){u=u.add(t.elements.tooltip)}if(t.options.hide.when.event=="inactive"){s=["click","dblclick","mousedown","mouseup","mousemove","mouseout","mouseenter","mouseleave","mouseover"];function y(z){if(t.status.disabled===true){return}clearTimeout(t.timers.inactive);t.timers.inactive=setTimeout(function(){f(s).each(function(){u.unbind( this+".qtip-inactive");t.elements.content.unbind(this+".qtip-inactive")});t.hide(z)},t.options.hide.delay)}}else{if(t.options.hide.fixed===true){t.elements.tooltip.bind("mouseover.qtip",function(){if(t.status.disabled===true){return}clearTimeout(t.timers.hide)})}}function x(z){if(t.status.disabled===true){return}if(t.options.hide.when.event=="inactive"){f(s).each(function(){u.bind(this+".qtip-inactive",y);t.elements.content.bind(this+".qtip-inactive",y)});y()}clearTimeout(t.timers.show);clearTimeout(t.timers.hide);t.timers.show=setTimeout(function(){t.show(z)},t.options.show.delay)}function w(z){if(t.status.disabled===true){return}if(t.options.hide.fixed===true&&t.options.hide.when.event.search(/mouse(out|leave)/i)!==-1&&f(z.relatedTarget).parents("div.qtip[qtip]").length>0){z.stopPropagation();z.preventDefault();clearTimeout(t.timers.hide);return false}clearTimeout(t.timers.show);clearTimeout(t.timers.hide);t.elements.tooltip.stop(true,true);t.timers.hide=setTimeout(function(){t.hide(z)},t.options.hide.delay)}if((t.options.show.when.target.add(t.options.hide.when.target).length===1&&t.options.show.when.event==t.options.hide.when.event&&t.options.hide.when.event!=="inactive")||t.options.hide.when.event=="unfocus"){t.cache.toggle=0;v.bind(t.options.show.when.event+".qtip",function(z){if(t.cache.toggle==0){x(z)}else{w(z)}})}else{v.bind(t.options.show.when.event+".qtip",x);if(t.options.hide.when.event!=="inactive"){u.bind(t.options.hide.when.event+".qtip",w)}}if(t.options.position.type.search(/(fixed|absolute)/)!==-1){t.elements.tooltip.bind("mouseover.qtip",t.focus)}if(t.options.position.target==="mouse"&&t.options.position.type!=="static"){v.bind("mousemove.qtip",function(z){t.cache.mouse={x:z.pageX,y:z.pageY};if(t.status.disabled===false&&t.options.position.adjust.mouse===true&&t.options.position.type!=="static"&&t.elements.tooltip.css("display")!=="none"){t.updatePosition(z)}})}}function o(u,v,A){var z,s,x,y,t,w;z=this;if(A.corner=="center"){return v.position}s=f.extend({},u);y={x:false,y:false};t={left:(s.left< f.fn.qtip.cache.screen.scroll.left),right:(s.left+A.dimensions.width+2>=f.fn.qtip.cache.screen.width+f.fn.qtip.cache.screen.scroll.left),top:(s.top<f.fn.qtip.cache.screen.scroll.top),bottom:(s.top+A.dimensions.height+2>=f.fn.qtip.cache.screen.height+f.fn.qtip.cache.screen.scroll.top)};x={left:(t.left&&(A.corner.search(/right/i)!=-1||(A.corner.search(/right/i)==-1&&!t.right))),right:(t.right&&(A.corner.search(/left/i)!=-1||(A.corner.search(/left/i)==-1&&!t.left))),top:(t.top&&A.corner.search(/top/i)==-1),bottom:(t.bottom&&A.corner.search(/bottom/i)==-1)};if(x.left){if(z.options.position.target!=="mouse"){s.left=v.position.left+v.dimensions.width}else{s.left=z.cache.mouse.x}y.x="Left"}else{if(x.right){if(z.options.position.target!=="mouse"){s.left=v.position.left-A.dimensions.width}else{s.left=z.cache.mouse.x-A.dimensions.width}y.x="Right"}}if(x.top){if(z.options.position.target!=="mouse"){s.top=v.position.top+v.dimensions.height}else{s.top=z.cache.mouse.y}y.y="top"}else{if(x.bottom){if(z.options.position.target!=="mouse"){s.top=v.position.top-A.dimensions.height}else{s.top=z.cache.mouse.y-A.dimensions.height}y.y="bottom"}}if(s.left<0){s.left=u.left;y.x=false}if(s.top<0){s.top=u.top;y.y=false}if(z.options.style.tip.corner!==false){s.corner=new String(A.corner);if(y.x!==false){s.corner=s.corner.replace(/Left|Right|Middle/,y.x)}if(y.y!==false){s.corner=s.corner.replace(/top|bottom/,y.y)}if(s.corner!==z.elements.tip.attr("rel")){e.call(z,s.corner)}}return s}function q(u,t){var v,s;v=f.extend(true,{},u);for(s in v){if(t===true&&s.search(/(tip|classes)/i)!==-1){delete v[s]}else{if(!t&&s.search(/(width|border|tip|title|classes|user)/i)!==-1){delete v[s]}}}return v}function c(s){if(typeof s.tip!=="object"){s.tip={corner:s.tip}}if(typeof s.tip.size!=="object"){s.tip.size={width:s.tip.size,height:s.tip.size}}if(typeof s.border!=="object"){s.border={width:s.border}}if(typeof s.width!=="object"){s.width={value:s.width}}if(typeof s.width.max=="string"){s.width.max=parseInt(s.width.max.replace(/([0-9]+)/i,"$1"))}if(typeof s.wid th.min=="string"){s.width.min=parseInt(s.width.min.replace(/([0-9]+)/i,"$1"))}if(typeof s.tip.size.x=="number"){s.tip.size.width=s.tip.size.x;delete s.tip.size.x}if(typeof s.tip.size.y=="number"){s.tip.size.height=s.tip.size.y;delete s.tip.size.y}return s}function a(){var s,t,u,x,v,w;s=this;u=[true,{}];for(t=0;t<arguments.length;t++){u.push(arguments[t])}x=[f.extend.apply(f,u)];while(typeof x[0].name=="string"){x.unshift(c(f.fn.qtip.styles[x[0].name]))}x.unshift(true,{classes:{tooltip:"qtip-"+(arguments[0].name||"defaults")}},f.fn.qtip.styles.defaults);v=f.extend.apply(f,x);w=(f.browser.msie)?1:0;v.tip.size.width+=w;v.tip.size.height+=w;if(v.tip.size.width%2>0){v.tip.size.width+=1}if(v.tip.size.height%2>0){v.tip.size.height+=1}if(v.tip.corner===true){v.tip.corner=(s.options.position.corner.tooltip==="center")?false:s.options.position.corner.tooltip}return v}function b(v,u,t){var s={bottomRight:[[0,0],[u,t],[u,0]],bottomLeft:[[0,0],[u,0],[0,t]],topRight:[[0,t],[u,0],[u,t]],topLeft:[[0,0],[0,t],[u,t]],topMiddle:[[0,t],[u/2,0],[u,t]],bottomMiddle:[[0,0],[u,0],[u/2,t]],rightMiddle:[[0,0],[u,t/2],[0,t]],leftMiddle:[[u,0],[u,t],[0,t/2]]};s.leftTop=s.bottomRight;s.rightTop=s.bottomLeft;s.leftBottom=s.topRight;s.rightBottom=s.topLeft;return s[v]}function g(s){var t;if(f("<canvas>").get(0).getContext){t={topLeft:[s,s],topRight:[0,s],bottomLeft:[s,0],bottomRight:[0,0]}}else{if(f.browser.msie){t={topLeft:[-90,90,0],topRight:[-90,90,-s],bottomLeft:[90,270,0],bottomRight:[90,270,-s]}}}return t}function k(){var s,t,u;s=this;u=s.getDimensions();t='<iframe class="qtip-bgiframe" frameborder="0" tabindex="-1" src="javascript:false" style="display:block; position:absolute; z-index:-1; filter:alpha(opacity=\'0\'); border: 1px solid red; height:'+u.height+"px; width:"+u.width+'px" />';s.elements.bgiframe=s.elements.wrapper.prepend(t).children(".qtip-bgiframe:first")}f(document).ready(function(){f.fn.qtip.cache={screen:{scroll:{left:f(window).scrollLeft(),top:f(window).scrollTop()},width:f(window).width(),height:f(window).height()}};v ar s;f(window).bind("resize scroll",function(t){clearTimeout(s);s=setTimeout(function(){if(t.type==="scroll"){f.fn.qtip.cache.screen.scroll={left:f(window).scrollLeft(),top:f(window).scrollTop()}}else{f.fn.qtip.cache.screen.width=f(window).width();f.fn.qtip.cache.screen.height=f(window).height()}for(i=0;i<f.fn.qtip.interfaces.length;i++){var u=f.fn.qtip.interfaces[i];if(u.status.rendered===true&&(u.options.position.type!=="static"||u.options.position.adjust.scroll&&t.type==="scroll"||u.options.position.adjust.resize&&t.type==="resize")){u.updatePosition(t,true)}}},100)});f(document).bind("mousedown.qtip",function(t){if(f(t.target).parents("div.qtip").length===0){f(".qtip[unfocus]").each(function(){var u=f(this).qtip("api");if(f(this).is(":visible")&&!u.status.disabled&&f(t.target).add(u.elements.target).length>1){u.hide(t)}})}})});f.fn.qtip.interfaces=[];f.fn.qtip.log={error:function(){return this}};f.fn.qtip.constants={};f.fn.qtip.defaults={content:{prerender:false,text:false,url:false,data:null,title:{text:false,button:false}},position:{target:false,corner:{target:"bottomRight",tooltip:"topLeft"},adjust:{x:0,y:0,mouse:true,screen:false,scroll:true,resize:true},type:"absolute",container:false},show:{when:{target:false,event:"mouseover"},effect:{type:"fade",length:100},delay:140,solo:false,ready:false},hide:{when:{target:false,event:"mouseout"},effect:{type:"fade",length:100},delay:0,fixed:false},api:{beforeRender:function(){},onRender:function(){},beforePositionUpdate:function(){},onPositionUpdate:function(){},beforeShow:function(){},onShow:function(){},beforeHide:function(){},onHide:function(){},beforeContentUpdate:function(){},onContentUpdate:function(){},beforeContentLoad:function(){},onContentLoad:function(){},beforeTitleUpdate:function(){},onTitleUpdate:function(){},beforeDestroy:function(){},onDestroy:function(){},beforeFocus:function(){},onFocus:function(){}}};f.fn.qtip.styles={defaults:{background:"white",color:"#111",overflow:"hidden",textAlign:"left",width:{min:0,max:250},padding:"5px 9px",border:{widt h:1,radius:0,color:"#d3d3d3"},tip:{corner:false,color:false,size:{width:13,height:13},opacity:1},title:{background:"#e1e1e1",fontWeight:"bold",padding:"7px 12px"},button:{cursor:"pointer"},classes:{target:"",tip:"qtip-tip",title:"qtip-title",button:"qtip-button",content:"qtip-content",active:"qtip-active"}},cream:{border:{width:3,radius:0,color:"#F9E98E"},title:{background:"#F0DE7D",color:"#A27D35"},background:"#FBF7AA",color:"#A27D35",classes:{tooltip:"qtip-cream"}},light:{border:{width:3,radius:0,color:"#E2E2E2"},title:{background:"#f1f1f1",color:"#454545"},background:"white",color:"#454545",classes:{tooltip:"qtip-light"}},dark:{border:{width:3,radius:0,color:"#303030"},title:{background:"#404040",color:"#f3f3f3"},background:"#505050",color:"#f3f3f3",classes:{tooltip:"qtip-dark"}},red:{border:{width:3,radius:0,color:"#CE6F6F"},title:{background:"#f28279",color:"#9C2F2F"},background:"#F79992",color:"#9C2F2F",classes:{tooltip:"qtip-red"}},green:{border:{width:3,radius:0,color:"#A9DB66"},title:{background:"#b9db8c",color:"#58792E"},background:"#CDE6AC",color:"#58792E",classes:{tooltip:"qtip-green"}},blue:{border:{width:3,radius:0,color:"#ADD9ED"},title:{background:"#D0E9F5",color:"#5E99BD"},background:"#E5F6FE",color:"#4D9FBF",classes:{tooltip:"qtip-blue"}}}})(jQuery);
diff --git a/js/jquery/jquery.sortableTable.js b/js/jquery/jquery.sortableTable.js
index 8fa6eb6..2dd1ede 100644
--- a/js/jquery/jquery.sortableTable.js
+++ b/js/jquery/jquery.sortableTable.js
@@ -10,21 +10,31 @@
  */
 
 /* Options:
-	$('table').sortableTable({
-		ignoreRect: { top, left, width, height }  - relative coordinates on each element. If the user clicks 
-												    in this area, it is not seen as a drag&drop request. Useful for toolbars etc.
-		events: {
-			start: callback function when the user starts dragging
-			drop: callback function after an element has been dropped
-		}
-	})
+
+$('table').sortableTable({
+    ignoreRect: { top, left, width, height }  - relative coordinates on each element. If the user clicks 
+                                               in this area, it is not seen as a drag&drop request. Useful for toolbars etc.
+    events: {
+       start: callback function when the user starts dragging
+       drop: callback function after an element has been dropped
+    }
+})
 */
 
 /* Commands:
-	$('table').sortableTable('init')  		- equivalent to $('table').sortableTable()
-	$('table').sortableTable('refresh')  	- if the table has been changed, refresh correctly assigns all events again
-	$('table').sortableTable('destroy')  	- removes all events from the table
+
+$('table').sortableTable('init')      - equivalent to $('table').sortableTable()
+$('table').sortableTable('refresh')   - if the table has been changed, refresh correctly assigns all events again
+$('table').sortableTable('destroy')   - removes all events from the table
+
 */ 
+
+/* Setup: 
+
+  Can be applied on any table, there is just one convention. 
+  Each cell (<td>) has to contain one and only one element (preferably div or span) 
+  which is the actually draggable element.
+*/
 (function($) {
 	jQuery.fn.sortableTable = function(method) {
 	
diff --git a/js/messages.php b/js/messages.php
index 3d41b87..17d0fad 100644
--- a/js/messages.php
+++ b/js/messages.php
@@ -137,9 +137,6 @@ $js_messages['strChartTitle'] = __('Chart Title');
 $js_messages['strDifferential'] = __('Differential');
 $js_messages['strDividedBy'] = __('Divided by %s:');
 
-$js_messages['strSelectedTimeRange'] = __('Selected time range:');
-$js_messages['strGroupInserts'] = __('Group together INSERTs into same table');
-$js_messages['strLogAnalyseInfo'] = __('<p>Choose from which log you want the statistics to be generated from.</p> Results are grouped by query text.');
 $js_messages['strFromSlowLog'] = __('From slow log');
 $js_messages['strFromGeneralLog'] = __('From general log');
 $js_messages['strAnalysingLogs'] = __('Analysing & loading logs. This may take a while.');
@@ -150,6 +147,15 @@ $js_messages['strLogDataLoaded'] = __('Log data loaded. Queries executed in this
 $js_messages['strJumpToTable'] = __('Jump to Log table');
 $js_messages['strNoDataFound'] = __('Log analysed, but not data found in this time span.');
 
+/* l10n: A collection of available filters */
+$js_messages['strFilters'] = __('Filters');
+/* l10n: Filter as in "Start Filtering" */
+$js_messages['strFilter'] = __('Filter');
+$js_messages['strFilterByWordRegexp'] = __('Filter queries by word/regexp:');
+$js_messages['strIgnoreWhereAndGroup'] = __('Group queries, ignoring variable data in WHERE statements');
+$js_messages['strSumRows'] = __('Sum of grouped rows:');
+$js_messages['strTotal'] = __('Total:');
+
 /* For inline query editing */
 $js_messages['strGo'] = __('Go');
 $js_messages['strCancel'] = __('Cancel');
@@ -199,6 +205,7 @@ $js_messages['strSave'] = __('Save');
 $js_messages['strHide'] = __('Hide');
 $js_messages['strNoRowSelected'] = __('No rows selected');
 $js_messages['strChangeTbl'] = __('Change');
+$js_messages['strQueryExecutionTime'] = __('Query execution time');
 
 /* For tbl_select.js */
 $js_messages['strHideSearchCriteria'] = __('Hide search criteria');
diff --git a/js/server_status.js b/js/server_status.js
index ed61204..d8f3788 100644
--- a/js/server_status.js
+++ b/js/server_status.js
@@ -21,11 +21,11 @@ $(function() {
             return /^[0-9]?[0-9,\.]*\s?(k|M|G|T|%)?$/.test(s);
         },
         format: function(s) {
-            var num = jQuery.tablesorter.formatFloat( 
+            var num = jQuery.tablesorter.formatFloat(
                 s.replace(PMA_messages['strThousandsSeperator'],'')
-                 .replace(PMA_messages['strDecimalSeperator'],'.') 
+                 .replace(PMA_messages['strDecimalSeperator'],'.')
             );
-            
+
             var factor = 1;
             switch (s.charAt(s.length - 1)) {
                 case '%': factor = -2; break;
@@ -35,37 +35,37 @@ $(function() {
                 case 'G': factor = 9; break;
                 case 'T': factor = 12; break;
             }
-            
+
             return num * Math.pow(10,factor);
         },
         type: "numeric"
     });
 
-    
+
     // Popup behaviour
     $('a[rel="popupLink"]').click( function() {
         var $link = $(this);
-        
+
         $('.' + $link.attr('href').substr(1))
             .show()
             .offset({ top: $link.offset().top + $link.height() + 5, left: $link.offset().left })
             .addClass('openedPopup');
-        
+
         return false;
     });
-    
+
     $(document).click( function(event) {
         $('.openedPopup').each(function() {
             var $cnt = $(this);
             var pos = $(this).offset();
-            
+
             // Hide if the mouseclick is outside the popupcontent
             if(event.pageX < pos.left || event.pageY < pos.top || event.pageX > pos.left + $cnt.outerWidth() || event.pageY > pos.top + $cnt.outerHeight())
                 $cnt.hide().removeClass('openedPopup');
         });
     });
 });
-    
+
 $(function() {
     // Filters for status variables
     var textFilter=null;
@@ -74,19 +74,19 @@ $(function() {
     var odd_row=false;
     var text=''; // Holds filter text
     var queryPieChart = null;
-    
+
     /* Chart configuration */
     // Defines what the tabs are currently displaying (realtime or data)
     var tabStatus = new Object();
     // Holds the current chart instances for each tab
     var tabChart = new Object();
-    
-    
+
+
     /*** Table sort tooltip ***/
-    
+
     var $tableSortHint = $('<div class="dHint" style="display:none;">' + 'Click to sort' + '</div>');
     $('body').append($tableSortHint);
-    
+
     $('table.sortable thead th').live('mouseover mouseout',function(e) {
         if(e.type == 'mouseover') {
             $tableSortHint
@@ -105,7 +105,7 @@ $(function() {
                 });
         }
     });
-    
+
     $(document).mousemove(function(e) {
         if($tableSortHint.data('shown') == true)
             $tableSortHint.css({
@@ -113,9 +113,9 @@ $(function() {
                 left: e.clientX + 15
             })
     });
-    
-    
-    // Tell highcarts not to use UTC dates (global setting)    
+
+
+    // Tell highcarts not to use UTC dates (global setting)
     Highcharts.setOptions({
         global: {
             useUTC: false
@@ -125,7 +125,7 @@ $(function() {
     $.ajaxSetup({
         cache:false
     });
-       
+
     // Add tabs
     $('#serverStatusTabs').tabs({
         // Tab persistence
@@ -133,19 +133,19 @@ $(function() {
         // Fixes line break in the menu bar when the page overflows and scrollbar appears
         show: function() { menuResize(); }
     });
-    
+
     // Fixes wrong tab height with floated elements. See also http://bugs.jqueryui.com/ticket/5601
     $(".ui-widget-content:not(.ui-tabs):not(.ui-helper-clearfix)").addClass("ui-helper-clearfix");
-    
+
     // Initialize each tab
-    $('div.ui-tabs-panel').each(function() { 
-        initTab($(this),null); 
+    $('div.ui-tabs-panel').each(function() {
+        initTab($(this),null);
         tabStatus[$(this).attr('id')] = 'static';
     });
-    
+
     // Display button links
     $('div.buttonlinks').show();
-    
+
     // Handles refresh rate changing
     $('.buttonlinks select').change(function() {
         var chart=tabChart[$(this).parents('div.ui-tabs-panel').attr('id')];
@@ -154,27 +154,27 @@ $(function() {
         clearTimeout(chart_activeTimeouts[chart.options.chart.renderTo]);
         if(chart.options.realtime.postRequest)
             chart.options.realtime.postRequest.abort();
-        
+
         chart.options.realtime.refreshRate = 1000*parseInt(this.value);
-        
+
         chart.xAxis[0].setExtremes(
             new Date().getTime() - server_time_diff - chart.options.realtime.numMaxPoints * chart.options.realtime.refreshRate,
             new Date().getTime() - server_time_diff,
             true
         );
-       
+
         chart_activeTimeouts[chart.options.chart.renderTo] = setTimeout(
-            chart.options.realtime.timeoutCallBack, 
+            chart.options.realtime.timeoutCallBack,
             chart.options.realtime.refreshRate
         );
     });
-    
+
     // Ajax refresh of variables (always the first element in each tab)
-    $('.buttonlinks a.tabRefresh').click(function() { 
+    $('.buttonlinks a.tabRefresh').click(function() {
         // ui-tabs-panel class is added by the jquery tabs feature
         var tab=$(this).parents('div.ui-tabs-panel');
         var that = this;
-        
+
         // Show ajax load icon
         $(this).find('img').show();
 
@@ -182,21 +182,21 @@ $(function() {
             $(that).find('img').hide();
             initTab(tab,data);
         });
-        
+
         tabStatus[tab.attr('id')]='data';
-        
+
         return false;
     });
-    
-    
+
+
     /** Realtime charting of variables **/
-    
+
     // Live traffic charting
     $('.buttonlinks a.livetrafficLink').click(function() {
         // ui-tabs-panel class is added by the jquery tabs feature
         var $tab=$(this).parents('div.ui-tabs-panel');
         var tabstat = tabStatus[$tab.attr('id')];
-        
+
         if(tabstat=='static' || tabstat=='liveconnections') {
             var settings = {
                 series: [
@@ -210,35 +210,35 @@ $(function() {
                                if(lastVal==null) return;
                                 chartObj.series[0].addPoint(
                                     { x: curVal.x, y: (curVal.y_sent - lastVal.y_sent) / 1024 },
-                                    false, 
+                                    false,
                                     numLoadedPoints >= chartObj.options.realtime.numMaxPoints
                                 );
                                 chartObj.series[1].addPoint(
                                     { x: curVal.x, y: (curVal.y_received - lastVal.y_received) / 1024 },
-                                    true, 
+                                    true,
                                     numLoadedPoints >= chartObj.options.realtime.numMaxPoints
-                                );                                            
+                                );
                             }
                          }
             }
-            
+
             setupLiveChart($tab,this,settings);
-            if(tabstat == 'liveconnections') 
+            if(tabstat == 'liveconnections')
                 $tab.find('.buttonlinks a.liveconnectionsLink').html(PMA_messages['strLiveConnChart']);
             tabStatus[$tab.attr('id')]='livetraffic';
         } else {
             $(this).html(PMA_messages['strLiveTrafficChart']);
             setupLiveChart($tab,this,null);
         }
-        
+
         return false;
     });
-    
+
     // Live connection/process charting
     $('.buttonlinks a.liveconnectionsLink').click(function() {
         var $tab=$(this).parents('div.ui-tabs-panel');
         var tabstat = tabStatus[$tab.attr('id')];
-        
+
         if(tabstat == 'static' || tabstat == 'livetraffic') {
             var settings = {
                 series: [
@@ -252,35 +252,35 @@ $(function() {
                                if(lastVal==null) return;
                                 chartObj.series[0].addPoint(
                                     { x: curVal.x, y: curVal.y_conn - lastVal.y_conn },
-                                    false, 
+                                    false,
                                     numLoadedPoints >= chartObj.options.realtime.numMaxPoints
                                 );
                                 chartObj.series[1].addPoint(
                                     { x: curVal.x, y: curVal.y_proc },
-                                    true, 
+                                    true,
                                     numLoadedPoints >= chartObj.options.realtime.numMaxPoints
-                                );                                            
+                                );
                             }
                          }
             };
-            
+
             setupLiveChart($tab,this,settings);
-            if(tabstat == 'livetraffic') 
+            if(tabstat == 'livetraffic')
                 $tab.find('.buttonlinks a.livetrafficLink').html(PMA_messages['strLiveTrafficChart']);
             tabStatus[$tab.attr('id')]='liveconnections';
         } else {
             $(this).html(PMA_messages['strLiveConnChart']);
             setupLiveChart($tab,this,null);
         }
-        
+
         return false;
     });
 
     // Live query statistics
     $('.buttonlinks a.livequeriesLink').click(function() {
         var $tab = $(this).parents('div.ui-tabs-panel');
-        var settings = null; 
-        
+        var settings = null;
+
         if(tabStatus[$tab.attr('id')] == 'static') {
             settings = {
                 series: [ { name: PMA_messages['strChartIssuedQueries'], data: [] } ],
@@ -292,7 +292,7 @@ $(function() {
                                 if(lastVal == null) return;
                                 chartObj.series[0].addPoint(
                                     { x: curVal.x,  y: curVal.y - lastVal.y, name: sortedQueriesPointInfo(curVal,lastVal) },
-                                    true, 
+                                    true,
                                     numLoadedPoints >= chartObj.options.realtime.numMaxPoints
                                 );
                             }
@@ -304,9 +304,9 @@ $(function() {
 
         setupLiveChart($tab,this,settings);
         tabStatus[$tab.attr('id')] = 'livequeries';
-        return false; 
+        return false;
     });
-    
+
     function setupLiveChart($tab,link,settings) {
         if(settings != null) {
             // Loading a chart with existing chart => remove old chart first
@@ -320,7 +320,7 @@ $(function() {
 
             if(! settings.chart) settings.chart = {};
             settings.chart.renderTo = $tab.attr('id') + "_chart_cnt";
-                        
+
             $tab.find('.tabInnerContent')
                 .hide()
                 .after('<div class="liveChart" id="' + $tab.attr('id') + '_chart_cnt"></div>');
@@ -346,29 +346,29 @@ $(function() {
         alertFilter = this.checked;
         filterVariables();
     });
-    
+
     $('#filterText').keyup(function(e) {
         word = $(this).val().replace('_',' ');
-        
+
         if(word.length == 0) textFilter = null;
         else textFilter = new RegExp("(^|_)" + word,'i');
-        
+
         text = word;
-        
+
         filterVariables();
     });
-    
+
     $('#filterCategory').change(function() {
         categoryFilter = $(this).val();
         filterVariables();
     });
-    
+
     /* Adjust DOM / Add handlers to the tabs */
     function initTab(tab,data) {
         switch(tab.attr('id')) {
             case 'statustabs_traffic':
                 if(data != null) tab.find('.tabInnerContent').html(data);
-                PMA_convertFootnotesToTooltips(); 
+                PMA_convertFootnotesToTooltips();
                 break;
             case 'statustabs_queries':
                 if(data != null) {
@@ -381,7 +381,7 @@ $(function() {
                 $.each(jQuery.parseJSON($('#serverstatusquerieschart span').html()),function(key,value) {
                     cdata.push([key,parseInt(value)]);
                 });
-                
+
                 queryPieChart = PMA_createChart({
                     chart: {
                         renderTo: 'serverstatusquerieschart'
@@ -406,15 +406,15 @@ $(function() {
                                }
                             }
                         }
-                    },        
+                    },
                     tooltip: {
-                        formatter: function() { 
-                            return '<b>' + this.point.name + '</b><br/>' + Highcharts.numberFormat(this.y, 2) + '<br/>(' + Highcharts.numberFormat(this.percentage, 2) + ' %)'; 
+                        formatter: function() {
+                            return '<b>' + this.point.name + '</b><br/>' + Highcharts.numberFormat(this.y, 2) + '<br/>(' + Highcharts.numberFormat(this.percentage, 2) + ' %)';
                         }
                     }
                 });
                 break;
-                
+
             case 'statustabs_allvars':
                 if(data != null) {
                     tab.find('.tabInnerContent').html(data);
@@ -422,10 +422,10 @@ $(function() {
                 }
                 break;
         }
-        
-        initTableSorter(tab.attr('id'));        
+
+        initTableSorter(tab.attr('id'));
     }
-    
+
     function initTableSorter(tabid) {
         switch(tabid) {
             case 'statustabs_queries':
@@ -437,12 +437,12 @@ $(function() {
                             2: { sorter: 'fancyNumber' }
                         }
                     });
-                    
+
                 $('#serverstatusqueriesdetails tr:first th')
                     .append('<img class="icon sortableIcon" src="themes/dot.gif" alt="">');
-                    
+
                 break;
-            
+
             case 'statustabs_allvars':
                 $('#serverstatusvariables').tablesorter({
                         sortList: [[0,0]],
@@ -451,21 +451,21 @@ $(function() {
                             1: { sorter: 'fancyNumber' }
                         }
                     });
-                    
+
                 $('#serverstatusvariables tr:first th')
                     .append('<img class="icon sortableIcon" src="themes/dot.gif" alt="">');
-                    
+
                 break;
         }
     }
-    
+
     /* Filters the status variables by name/category/alert in the variables tab */
     function filterVariables() {
         var useful_links = 0;
         var section = text;
-        
+
         if(categoryFilter.length > 0) section = categoryFilter;
-        
+
         if(section.length > 1) {
             $('#linkSuggestions span').each(function() {
                 if($(this).attr('class').indexOf('status_'+section) != -1) {
@@ -474,21 +474,21 @@ $(function() {
                 } else {
                     $(this).css('display','none');
                 }
-                
-                
+
+
             });
         }
-        
-        if(useful_links > 0) 
+
+        if(useful_links > 0)
             $('#linkSuggestions').css('display','');
         else $('#linkSuggestions').css('display','none');
-        
+
         odd_row=false;
         $('#serverstatusvariables th.name').each(function() {
             if((textFilter == null || textFilter.exec($(this).text()))
                 && (! alertFilter || $(this).next().find('span.attention').length>0)
                 && (categoryFilter.length == 0 || $(this).parent().hasClass('s_'+categoryFilter))) {
-                odd_row = ! odd_row;                    
+                odd_row = ! odd_row;
                 $(this).parent().css('display','');
                 if(odd_row) {
                     $(this).parent().addClass('odd');
@@ -502,7 +502,7 @@ $(function() {
             }
         });
     }
-    
+
     // Provides a nicely formatted and sorted tooltip of each datapoint of the query statistics
     function sortedQueriesPointInfo(queries, lastQueries){
         var max, maxIdx, num=0;
@@ -510,7 +510,7 @@ $(function() {
         var queryValues = new Array();
         var sumOther=0;
         var sumTotal=0;
-        
+
         // Separate keys and values, then  sort them
         $.each(queries.pointInfo, function(key,value) {
             if(value-lastQueries.pointInfo[key] > 0) {
@@ -521,7 +521,7 @@ $(function() {
         });
         var numQueries = queryKeys.length;
         var pointInfo = '<b>' + PMA_messages['strTotal'] + ': ' + sumTotal + '</b><br>';
-        
+
         while(queryKeys.length > 0) {
             max = 0;
             for(var i=0; i < queryKeys.length; i++) {
@@ -532,29 +532,29 @@ $(function() {
             }
             if(numQueries > 8 && num >= 6)
                 sumOther += queryValues[maxIdx];
-            else pointInfo += queryKeys[maxIdx].substr(4).replace('_',' ') + ': ' + queryValues[maxIdx] + '<br>'; 
-            
+            else pointInfo += queryKeys[maxIdx].substr(4).replace('_',' ') + ': ' + queryValues[maxIdx] + '<br>';
+
             queryKeys.splice(maxIdx,1);
             queryValues.splice(maxIdx,1);
             num++;
         }
-        
-        if(sumOther>0) 
+
+        if(sumOther>0)
             pointInfo += PMA_messages['strOther'] + ': ' + sumOther;
 
         return pointInfo;
     }
 
-    
-    
-    
+
+
+
     /**** Monitor charting implementation ****/
     /* Saves the previous ajax response for differential values */
     var oldChartData = null;
-    // Holds about to created chart 
+    // Holds about to created chart
     var newChart = null;
     var chartSpacing;
-    
+
     // Runtime parameter of the monitor
     var runtime = {
         // Holds all visible charts in the grid
@@ -562,7 +562,7 @@ $(function() {
         // Current max points per chart (needed for auto calculation)
         gridMaxPoints: 20,
         // displayed time frame
-        xmin: -1, 
+        xmin: -1,
         xmax: -1,
         // Stores the timeout handler so it can be cleared
         refreshTimeout: null,
@@ -574,22 +574,22 @@ $(function() {
         redrawCharts: false,
         // Object that contains a list of nodes that need to be retrieved from the server for chart updates
         dataList: []
-    }
-    
+    };
+
     var monitorSettings = null;
-    
+
     var defaultMonitorSettings = {
         columns: 4,
         chartSize: { width: 295, height: 250 },
         // Max points in each chart. Settings it to 'auto' sets gridMaxPoints to (chartwidth - 40) / 12
-        gridMaxPoints: 'auto', 
+        gridMaxPoints: 'auto',
         /* Refresh rate of all grid charts in ms */
         gridRefresh: 5000
-    }
-    
+    };
+
     // Allows drag and drop rearrange and print/edit icons on charts
     var editMode = false;
-    
+
     var presetCharts = {
         'cpu-WINNT': {
             title: PMA_messages['strSystemCPUUsage'],
@@ -598,24 +598,27 @@ $(function() {
         'memory-WINNT': {
             title: PMA_messages['strSystemMemory'],
             nodes: [
-                { dataType: 'memory', name: 'MemTotal', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, 
-                { dataType: 'memory', name: 'MemUsed', valueDivisor: 1024, unit: PMA_messages['strMiB']  }, 
+                { dataType: 'memory', name: 'MemTotal', valueDivisor: 1024, unit: PMA_messages['strMiB'] },
+                { dataType: 'memory', name: 'MemUsed', valueDivisor: 1024, unit: PMA_messages['strMiB']  },
             ]
         },
         'swap-WINNT': {
             title: PMA_messages['strSystemSwap'],
             nodes: [
-                { dataType: 'memory', name: 'SwapTotal', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, 
-                { dataType: 'memory', name: 'SwapUsed', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, 
+                { dataType: 'memory', name: 'SwapTotal', valueDivisor: 1024, unit: PMA_messages['strMiB'] },
+                { dataType: 'memory', name: 'SwapUsed', valueDivisor: 1024, unit: PMA_messages['strMiB'] },
             ]
         },
         'cpu-Linux': {
             title: PMA_messages['strSystemCPUUsage'],
             nodes: [
-                { dataType: 'cpu', 
-                  name: PMA_messages['strAverageLoad'], 
+                { dataType: 'cpu',
+                  name: PMA_messages['strAverageLoad'],
                   unit: '%',
                   transformFn: function(cur, prev) {
+                      console.log('cpu-linux chart, transformFn()');
+                      console.log(cur);
+                      console.log(prev);
                       if(prev == null) return undefined;
                       var diff_total = cur.busy + cur.idle - (prev.busy + prev.idle);
                       var diff_idle = cur.idle - prev.idle;
@@ -627,8 +630,8 @@ $(function() {
         'memory-Linux': {
             title: PMA_messages['strSystemMemory'],
             nodes: [
-                { dataType: 'memory', name: 'MemUsed', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, 
-                { dataType: 'memory', name: 'Cached',  valueDivisor: 1024, unit: PMA_messages['strMiB'] }, 
+                { dataType: 'memory', name: 'MemUsed', valueDivisor: 1024, unit: PMA_messages['strMiB'] },
+                { dataType: 'memory', name: 'Cached',  valueDivisor: 1024, unit: PMA_messages['strMiB'] },
                 { dataType: 'memory', name: 'Buffers', valueDivisor: 1024, unit: PMA_messages['strMiB'] },
                 { dataType: 'memory', name: 'MemFree', valueDivisor: 1024, unit: PMA_messages['strMiB'] },
             ],
@@ -647,9 +650,9 @@ $(function() {
         'swap-Linux': {
             title: PMA_messages['strSystemSwap'],
             nodes: [
-                { dataType: 'memory', name: 'SwapUsed',   valueDivisor: 1024, unit: PMA_messages['strMiB'] }, 
-                { dataType: 'memory', name: 'SwapCached', valueDivisor: 1024, unit: PMA_messages['strMiB'] }, 
-                { dataType: 'memory', name: 'SwapFree',   valueDivisor: 1024, unit: PMA_messages['strMiB'] }, 
+                { dataType: 'memory', name: 'SwapUsed',   valueDivisor: 1024, unit: PMA_messages['strMiB'] },
+                { dataType: 'memory', name: 'SwapCached', valueDivisor: 1024, unit: PMA_messages['strMiB'] },
+                { dataType: 'memory', name: 'SwapFree',   valueDivisor: 1024, unit: PMA_messages['strMiB'] },
             ],
             settings: {
                 chart: {
@@ -663,8 +666,8 @@ $(function() {
                 }
             }
         }
-    }
-    
+    };
+
     // Default setting
     defaultChartGrid = {
         'c0': {  title: PMA_messages['strQuestions'],
@@ -683,15 +686,15 @@ $(function() {
                  ]
          }
     };
-    
-    // Server is localhost => We can add cpu/memory/swap 
+
+    // Server is localhost => We can add cpu/memory/swap
     if(server_db_isLocal) {
         defaultChartGrid['c3'] = presetCharts['cpu-' + server_os];
         defaultChartGrid['c4'] = presetCharts['memory-' + server_os];
         defaultChartGrid['c5'] = presetCharts['swap-' + server_os];
     }
-    
-    var gridbuttons = { 
+
+    var gridbuttons = {
         cogButton: {
             //enabled: true,
             symbol: 'url(' + pmaThemeImage  + 's_cog.png)',
@@ -713,7 +716,7 @@ $(function() {
             }]
         }
     };
-    
+
     Highcharts.setOptions({
         lang: {
             settings:    PMA_messages['strSettings'],
@@ -721,20 +724,20 @@ $(function() {
             editChart:   PMA_messages['strEditChart']
         }
     });
-    
+
     $('a[href="#rearrangeCharts"], a[href="#endChartEditMode"]').click(function() {
         editMode = !editMode;
         if($(this).attr('href') == '#endChartEditMode') editMode = false;
-        
+
         // Icon graphics have zIndex 19,20 and 21. Let's just hope nothing else has the same zIndex
         $('table#chartGrid div svg').find('*[zIndex=20], *[zIndex=21], *[zIndex=19]').toggle(editMode)
-        
+
         $('a[href="#endChartEditMode"]').toggle(editMode);
-        
+
         if(editMode) {
             // Close the settings popup
             $('#statustabs_charting .popupContent').hide().removeClass('openedPopup');
-            
+
             $("#chartGrid").sortableTable({
                 ignoreRect: {
                     top: 8,
@@ -748,13 +751,13 @@ $(function() {
                     },
                     // Drop event. The drag child element is moved into the drop element
                     // and vice versa. So the parameters are switched.
-                    drop: function(drag, drop, pos) { 
+                    drop: function(drag, drop, pos) {
                         var dragKey, dropKey, dropRender;
                         var dragRender = $(drag).children().first().attr('id');
-                        
+
                         if($(drop).children().length > 0)
                             dropRender = $(drop).children().first().attr('id');
-                        
+
                         // Find the charts in the array
                         $.each(runtime.charts, function(key, value) {
                             if(value.chart.options.chart.renderTo == dragRender)
@@ -762,7 +765,7 @@ $(function() {
                             if(dropRender && value.chart.options.chart.renderTo == dropRender)
                                 dropKey = key;
                         });
-                        
+
                         // Case 1: drag and drop are charts -> Switch keys
                         if(dropKey) {
                             if(dragKey) {
@@ -777,14 +780,14 @@ $(function() {
                                 var values = [];
                                 var newChartList = {};
                                 var c = 0;
-                                    
+
                                 $.each(runtime.charts, function(key, value) {
                                     if(key != dropKey)
                                         keys.push(key);
                                 });
-                                
+
                                 keys.sort();
-                                
+
                                 // Rebuilds all ids, with the dragged chart correctly inserted
                                 for(var i=0; i<keys.length; i++) {
                                     if(keys[i] == insertBefore) {
@@ -793,37 +796,37 @@ $(function() {
                                     }
                                     newChartList['c' + (c++)] = runtime.charts[keys[i]];
                                 }
-                                
+
                                 // Not inserted => put at the end
                                 if(insertBefore != -1)
                                     newChartList['c' + (c++)] = runtime.charts[dropKey];
-                                
+
                                 runtime.charts = newChartList;
                             }
-                            
+
                             saveMonitor();
                         }
                     }
                 }
             });
-           
+
         } else {
             $("#chartGrid").sortableTable('destroy');
             saveMonitor(); // Save settings
         }
-        
+
         return false;
     });
-    
+
     // global settings
     $('div#statustabs_charting div.popupContent select[name="chartColumns"]').change(function() {
         monitorSettings.columns = parseInt(this.value);
-        
+
         var newSize = chartSize();
-        
+
         // Empty cells should keep their size so you can drop onto them
         $('table#chartGrid tr td').css('width',newSize.width + 'px');
-        
+
         /* Reorder all charts that it fills all column cells */
         var numColumns;
         var $tr = $('table#chartGrid tr:first');
@@ -838,7 +841,7 @@ $(function() {
                 }
                 numColumns++;
             });
-            
+
             // To little cells in one row => for each cell to little, move all cells backwards by 1
             if($tr.next().length > 0) {
                 var cnt = monitorSettings.columns - $tr.find('td').length;
@@ -850,57 +853,57 @@ $(function() {
                     });
                 }
             }
-            
+
             $tr = $tr.next();
             row++;
         }
-        
+
         /* Apply new chart size to all charts */
         $.each(runtime.charts, function(key, value) {
             value.chart.setSize(
                 newSize.width,
-                newSize.height, 
+                newSize.height,
                 false
             );
         });
-        
+
         if(monitorSettings.gridMaxPoints == 'auto')
             runtime.gridMaxPoints = Math.round((newSize.width - 40) / 12);
-        
+
         runtime.xmin = new Date().getTime() - server_time_diff - runtime.gridMaxPoints * monitorSettings.gridRefresh;
         runtime.xmax = new Date().getTime() - server_time_diff + monitorSettings.gridRefresh;
-        
+
         if(editMode)
             $("#chartGrid").sortableTable('refresh');
-        
+
         saveMonitor(); // Save settings
     });
-    
+
     $('div#statustabs_charting div.popupContent select[name="gridChartRefresh"]').change(function() {
         monitorSettings.gridRefresh = parseInt(this.value) * 1000;
         clearTimeout(runtime.refreshTimeout);
-        
+
         if(runtime.refreshRequest)
             runtime.refreshRequest.abort();
-        
+
         runtime.xmin = new Date().getTime() - server_time_diff - runtime.gridMaxPoints * monitorSettings.gridRefresh;
         runtime.xmax = new Date().getTime() - server_time_diff + monitorSettings.gridRefresh;
-        
+
         $.each(runtime.charts, function(key, value) {
             value.chart.xAxis[0].setExtremes(runtime.xmin, runtime.xmax, false);
         });
-        
+
         runtime.refreshTimeout = setTimeout(refreshChartGrid, monitorSettings.gridRefresh);
-        
+
         saveMonitor(); // Save settings
     });
-    
+
     $('a[href="#addNewChart"]').click(function() {
         var dlgButtons = { };
-        
+
         dlgButtons[PMA_messages['strAddChart']] = function() {
             var type = $('input[name="chartType"]:checked').val();
-            
+
             if(type == 'cpu' || type == 'memory' || type=='swap')
                 newChart = presetCharts[type + '-' + server_os];
             else {
@@ -909,36 +912,36 @@ $(function() {
                     return;
                 }
             }
-            
+
             newChart.title = $('input[name="chartTitle"]').attr('value');
             // Add a cloned object to the chart grid
             addChart($.extend(true, {}, newChart));
-            
+
             newChart = null;
-                
+
             saveMonitor(); // Save settings
 
             $(this).dialog("close");
         }
-        
+
         dlgButtons[PMA_messages['strClose']] = function() {
             newChart = null;
             $('span#clearSeriesLink').hide();
             $('#seriesPreview').html('');
             $(this).dialog("close");
         }
-        
+
         $('div#addChartDialog').dialog({
             width:'auto',
             height:'auto',
             buttons: dlgButtons
         });
-        
+
         $('div#addChartDialog #seriesPreview').html('<i>' + PMA_messages['strNone'] + '</i>');
-        
+
         return false;
     });
-    
+
     $('a[href="#pauseCharts"]').click(function() {
         runtime.redrawCharts = ! runtime.redrawCharts;
         if(! runtime.redrawCharts)
@@ -952,109 +955,109 @@ $(function() {
         }
         return false;
     });
-    
+
     $('a[href="#monitorInstructionsDialog"]').click(function() {
         var $dialog = $('div#monitorInstructionsDialog');
-        
+
         $dialog.dialog({
             width: 595,
             height: 'auto'
         }).find('img.ajaxIcon').show();
-        
+
         var loadLogVars = function(getvars) {
             vars = { ajax_request: true, logging_vars: true };
             if(getvars) $.extend(vars,getvars);
-            
+
             $.get('server_status.php?' + url_query, vars,
                 function(data) {
                     var logVars = $.parseJSON(data),
                         icon = 'ic_s_success', msg='', str='';
-                    
+
                     if(logVars['general_log'] == 'ON') {
-                        if(logVars['slow_query_log'] == 'ON') 
+                        if(logVars['slow_query_log'] == 'ON')
                             msg = PMA_messages['strBothLogOn'];
-                        else 
+                        else
                             msg = PMA_messages['strGenLogOn'];
                     }
-                    
+
                     if(msg.length == 0 && logVars['slow_query_log'] == 'ON') {
                         msg = PMA_messages['strSlowLogOn'];
                     }
-                    
+
                     if(msg.length == 0) {
                         icon = 'ic_s_error';
                         msg = PMA_messages['strBothLogOff'];
                     }
-                    
+
                     str = '<b>' + PMA_messages['strCurrentSettings'] + '</b><br><div class="smallIndent">';
                     str += '<img src="themes/dot.gif" class="icon ' + icon + '" alt=""/> ' + msg + '<br />';
-                    
+
                     if(logVars['log_output'] != 'TABLE')
                         str += '<img src="themes/dot.gif" class="icon ic_s_error" alt=""/> ' + PMA_messages['strLogOutNotTable'] + '<br />';
-                    else 
+                    else
                         str += '<img src="themes/dot.gif" class="icon ic_s_success" alt=""/> ' + PMA_messages['strLogOutIsTable'] + '<br />';
-                    
+
                     if(logVars['slow_query_log'] == 'ON') {
                         if(logVars['long_query_time'] > 2)
                             str += '<img src="themes/dot.gif" class="icon ic_s_attention" alt=""/> '
                                 + $.sprintf(PMA_messages['strSmallerLongQueryTimeAdvice'], logVars['long_query_time'])
                                 + '<br />';
-                        
+
                         if(logVars['long_query_time'] < 2)
                             str += '<img src="themes/dot.gif" class="icon ic_s_success" alt=""/> '
                                 + $.sprintf(PMA_messages['strLongQueryTimeSet'], logVars['long_query_time'])
                                 + '<br />';
                     }
-                    
+
                     str += '</div>';
-                    
+
                     if(is_superuser) {
                         str += '<p></p><b>Change settings</b>';
                         str += '<div class="smallIndent">';
                         str += PMA_messages['strSettingsAppliedGlobal'] + '<br/>';
-                        
+
                         var varValue = 'TABLE';
                         if(logVars['log_output'] == 'TABLE') varValue = 'FILE';
-                        
+
                         str += '- <a class="set" href="#log_output-' + varValue + '">'
                             + $.sprintf(PMA_messages['strSetLogOutput'], varValue)
                             + ' </a><br />';
-                        
+
                         if(logVars['general_log'] != 'ON')
-                            str += '- <a class="set" href="#general_log-ON">' 
-                                + $.sprintf(PMA_messages['strEnableVar'], 'general_log') 
+                            str += '- <a class="set" href="#general_log-ON">'
+                                + $.sprintf(PMA_messages['strEnableVar'], 'general_log')
                                 + ' </a><br />';
-                        else 
-                            str += '- <a class="set" href="#general_log-OFF">' 
-                                + $.sprintf(PMA_messages['strDisableVar'], 'general_log') 
+                        else
+                            str += '- <a class="set" href="#general_log-OFF">'
+                                + $.sprintf(PMA_messages['strDisableVar'], 'general_log')
                                 + ' </a><br />';
-                        
+
                         if(logVars['slow_query_log'] != 'ON')
-                            str += '- <a class="set" href="#slow_query_log-ON">' 
+                            str += '- <a class="set" href="#slow_query_log-ON">'
                                 +  $.sprintf(PMA_messages['strEnableVar'], 'slow_query_log')
                                 + ' </a><br />';
-                        else 
-                            str += '- <a class="set" href="#slow_query_log-OFF">' 
+                        else
+                            str += '- <a class="set" href="#slow_query_log-OFF">'
                                 +  $.sprintf(PMA_messages['strDisableVar'], 'slow_query_log')
                                 + ' </a><br />';
-                        
-                        
+
+
                         varValue = 5;
                         if(logVars['long_query_time'] > 2) varValue = 1;
-                        
-                        str += '- <a class="set" href="#long_query_time-' + varValue + '">' 
+
+                        str += '- <a class="set" href="#long_query_time-' + varValue + '">'
                             + $.sprintf(PMA_messages['setSetLongQueryTime'], varValue)
                             + ' </a><br />';
-                            
-                    } else 
+
+                    } else
                         str += PMA_messages['strNoSuperUser'] + '<br/>';
-                    
+
                     str += '</div>';
-                    
+
                     $dialog.find('div.monitorUse').toggle(
                         logVars['log_output'] == 'TABLE' && (logVars['slow_query_log'] == 'ON' || logVars['general_log'] == 'ON')
                     );
-                    
+
                     $dialog.find('div.ajaxContent').html(str);
                     $dialog.find('img.ajaxIcon').hide();
                     $dialog.find('a.set').click(function() {
@@ -1065,13 +1068,13 @@ $(function() {
                 }
             );
         }
-        
-        
+
+
         loadLogVars();
-        
+
         return false;
     });
-    
+
     $('input[name="chartType"]').change(function() {
         $('#chartVariableSettings').toggle(this.checked && this.value == 'variable');
         var title = $('input[name="chartTitle"]').attr('value');
@@ -1079,21 +1082,21 @@ $(function() {
             $('input[name="chartTitle"]').data('lastRadio',$(this).attr('id'));
             $('input[name="chartTitle"]').attr('value',$('label[for="'+$(this).attr('id')+'"]').text());
         }
-        
+
     });
-    
+
     $('input[name="useDivisor"]').change(function() {
         $('span.divisorInput').toggle(this.checked);
     });
     $('input[name="useUnit"]').change(function() {
         $('span.unitInput').toggle(this.checked);
     });
-    
+
     $('select[name="varChartList"]').change(function () {
         if(this.selectedIndex!=0)
             $('#variableInput').attr('value',this.value);
     });
-    
+
     $('a[href="#kibDivisor"]').click(function() {
         $('input[name="valueDivisor"]').attr('value',1024);
         $('input[name="valueUnit"]').attr('value',PMA_messages['strKiB']);
@@ -1101,7 +1104,7 @@ $(function() {
         $('input[name="useUnit"]').prop('checked',true);
         return false;
     });
-    
+
     $('a[href="#mibDivisor"]').click(function() {
         $('input[name="valueDivisor"]').attr('value',1024*1024);
         $('input[name="valueUnit"]').attr('value',PMA_messages['strMiB']);
@@ -1109,48 +1112,48 @@ $(function() {
         $('input[name="useUnit"]').prop('checked',true);
         return false;
     });
-    
+
     $('a[href="#submitClearSeries"]').click(function() {
         $('#seriesPreview').html('<i>' + PMA_messages['strNone'] + '</i>');
         newChart = null;
         $('span#clearSeriesLink').hide();
     });
-    
+
     $('a[href="#submitAddSeries"]').click(function() {
         if($('input#variableInput').attr('value').length == 0) return false;
-        
+
         if(newChart == null) {
             $('#seriesPreview').html('');
-        
+
             newChart = {
                 title: $('input[name="chartTitle"]').attr('value'),
                 nodes: []
             }
         }
-        
+
         var serie = {
             dataType:'statusvar',
             name: $('input#variableInput').attr('value'),
-            display: $('input[name="differentialValue"]').attr('checked') ? 'differential' : '',
+            display: $('input[name="differentialValue"]').attr('checked') ? 'differential' : ''
         };
-        
+
         if(serie.name == 'Processes') serie.dataType='proc';
-        
-        if($('input[name="useDivisor"]').attr('checked')) 
+
+        if($('input[name="useDivisor"]').attr('checked'))
             serie.valueDivisor = parseInt($('input[name="valueDivisor"]').attr('value'));
 
         if($('input[name="useUnit"]').attr('checked'))
             serie.unit = $('input[name="valueUnit"]').attr('value');
-        
-        
-        
+
+
+
         var str = serie.display == 'differential' ? ', ' + PMA_messages['strDifferential'] : '';
         str += serie.valueDivisor ? (', ' + $.sprintf(PMA_messages['strDividedBy'], serie.valueDivisor)) : '';
-        
+
         $('#seriesPreview').append('- ' + serie.name + str + '<br>');
-        
+
         newChart.nodes.push(serie);
-        
+
         $('input#variableInput').attr('value','');
         $('input[name="differentialValue"]').attr('checked',true);
         $('input[name="useDivisor"]').attr('checked',false);
@@ -1158,17 +1161,17 @@ $(function() {
         $('input[name="useDivisor"]').trigger('change');
         $('input[name="useUnit"]').trigger('change');
         $('select[name="varChartList"]').get(0).selectedIndex=0;
-        
+
         $('span#clearSeriesLink').show();
 
         return false;
     });
-    
+
     $("input#variableInput").autocomplete({
             source: variableNames
     });
-    
-    
+
+
     function initGrid() {
         var settings;
         var series;
@@ -1179,23 +1182,23 @@ $(function() {
                 runtime.charts = $.parseJSON(window.localStorage['monitorCharts']);
             if(window.localStorage['monitorSettings'])
                 monitorSettings = $.parseJSON(window.localStorage['monitorSettings']);
-            
+
             $('a[href="#clearMonitorConfig"]').toggle(runtime.charts != null);
         }
-        
+
         if(runtime.charts == null)
             runtime.charts = defaultChartGrid;
         if(monitorSettings == null)
             monitorSettings = defaultMonitorSettings;
-         
+
         $('select[name="gridChartRefresh"]').attr('value',monitorSettings.gridRefresh / 1000);
         $('select[name="chartColumns"]').attr('value',monitorSettings.columns);
-        
+
         if(monitorSettings.gridMaxPoints == 'auto')
             runtime.gridMaxPoints = Math.round((monitorSettings.chartSize.width - 40) / 12);
-        else 
+        else
             runtime.gridMaxPoints = monitorSettings.gridMaxPoints;
-        
+
         runtime.xmin = new Date().getTime() - server_time_diff - runtime.gridMaxPoints * monitorSettings.gridRefresh;
         runtime.xmax = new Date().getTime() - server_time_diff + monitorSettings.gridRefresh;
 
@@ -1206,7 +1209,7 @@ $(function() {
             height: $('table#chartGrid tr:nth-child(2) td:nth-child(2)').offset().top - $('table#chartGrid tr:nth-child(1) td:nth-child(1)').offset().top
         }
         $('table#chartGrid').html('');
-        
+
         /* Add all charts - in correct order */
         var keys = [];
         $.each(runtime.charts, function(key, value) {
@@ -1215,22 +1218,22 @@ $(function() {
         keys.sort();
         for(var i=0; i<keys.length; i++)
             addChart(runtime.charts[keys[i]],true);
-        
+
         /* Fill in missing cells */
         var numCharts = $('table#chartGrid .monitorChart').length;
         var numMissingCells = (monitorSettings.columns - numCharts % monitorSettings.columns) % monitorSettings.columns;
         for(var i=0; i < numMissingCells; i++) {
             $('table#chartGrid tr:last').append('<td></td>');
         }
-        
+
         // Empty cells should keep their size so you can drop onto them
         $('table#chartGrid tr td').css('width',chartSize().width + 'px');
 
-        
+
         buildRequiredDataList();
         refreshChartGrid();
     }
-    
+
     function chartSize() {
         var wdt = $('div#logTable').innerWidth() / monitorSettings.columns - (monitorSettings.columns - 1) * chartSpacing.width;
         return {
@@ -1238,12 +1241,12 @@ $(function() {
             height: 0.75 * wdt
         }
     }
-    
+
     function addChart(chartObj, initialize) {
         series = [];
         for(var j=0; j<chartObj.nodes.length; j++)
             series.push(chartObj.nodes[j]);
-        
+
         settings = {
             chart: {
                 renderTo: 'gridchart' + runtime.chartAI,
@@ -1254,64 +1257,58 @@ $(function() {
                 events: {
                     selection: function(event) {
                         if(editMode) return false;
-                        
-                        var extremesObject = event.xAxis[0], 
+
+                        var extremesObject = event.xAxis[0],
                             min = extremesObject.min,
                             max = extremesObject.max;
-                        
-                        $('#logAnalyseDialog').html(
-                            '<p>' + PMA_messages['strSelectedTimeRange']
-                            + '<input type="text" name="dateStart" class="datetimefield" value="' + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S',new Date(min)) + '" /> - ' 
-                            + '<input type="text" name="dateEnd" class="datetimefield" value="' + Highcharts.dateFormat('%Y-%m-%d %H:%M:%S',new Date(max)) + '" /></p>'
-                            + '<input type="checkbox" id="groupInserts" value="1" checked="checked" />'
-                            + '<label for="groupData">' + PMA_messages['strGroupInserts'] + '</label>'
-                            + PMA_messages['strLogAnalyseInfo']
-                        );
-                        
-                        PMA_addDatepicker($('#logAnalyseDialog').find('input[name="dateStart"],input[name="dateEnd"]'), { 
-                            showOn: 'focus',
-                            beforeShow: function() {
-                                // Fix wrong timepicker z-index, doesn't work without timeout
-                                setTimeout(function() {
-                                    $('#ui-timepicker-div').css('z-index',$('#ui-datepicker-div').css('z-index')) 
-                                },0);
-                            }
-                        });
-                        
+
+                        $('#logAnalyseDialog input[name="dateStart"]')
+                            .attr('value', Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', new Date(min)));
+                        $('#logAnalyseDialog input[name="dateEnd"]')
+                            .attr('value', Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', new Date(max)));
+
                         var dlgBtns = { };
-                        
+
                         dlgBtns[PMA_messages['strFromSlowLog']] = function() {
                             var dateStart = Date.parse($('#logAnalyseDialog input[name="dateStart"]').attr('value')) || min;
                             var dateEnd = Date.parse($('#logAnalyseDialog input[name="dateEnd"]').attr('value')) || max;
-                            
-                            loadLogStatistics(
-                                { src: 'slow', start: dateStart, end: dateEnd, groupInserts: $('input#groupInserts').attr('checked') } 
-                            );
-                                
+
+                            loadLogStatistics({
+                                src: 'slow',
+                                start: dateStart,
+                                end: dateEnd,
+                                removeVariables: $('input#removeVariables').prop('checked'),
+                                limitTypes: $('input#limitTypes').prop('checked')
+                            });
+
                             $('#logAnalyseDialog').find('dateStart,dateEnd').datepicker('destroy');
-                            
+
                             $(this).dialog("close");
                         }
-                        
+
                         dlgBtns[PMA_messages['strFromGeneralLog']] = function() {
                             var dateStart = Date.parse($('#logAnalyseDialog input[name="dateStart"]').attr('value')) || min;
                             var dateEnd = Date.parse($('#logAnalyseDialog input[name="dateEnd"]').attr('value')) || max;
-                            
-                            loadLogStatistics(
-                                { src: 'general', start: dateStart, end: dateEnd, groupInserts: $('input#groupInserts').attr('checked') }
-                            );
-                                
+
+                            loadLogStatistics({
+                                src: 'general',
+                                start: dateStart,
+                                end: dateEnd,
+                                removeVariables: $('input#removeVariables').prop('checked'),
+                                limitTypes: $('input#limitTypes').prop('checked')
+                            });
+
                             $('#logAnalyseDialog').find('dateStart,dateEnd').datepicker('destroy');
-                            
+
                             $(this).dialog("close");
                         }
-                        
+
                         $('#logAnalyseDialog').dialog({
                             width: 'auto',
                             height: 'auto',
                             buttons: dlgBtns
                         });
-                        
+
                         return false;
                     }
                 }
@@ -1329,12 +1326,12 @@ $(function() {
             tooltip: {
                 formatter: function() {
                         var s = '<b>'+Highcharts.dateFormat('%H:%M:%S', this.x)+'</b>';
-                    
+
                         $.each(this.points, function(i, point) {
                             s += '<br/><span style="color:'+point.series.color+'">'+ point.series.name +':</span> '+
                                 ((parseInt(point.y) == point.y) ? point.y : Highcharts.numberFormat(this.y, 2)) + ' ' + (point.series.options.unit || '');
                         });
-                        
+
                         return s;
                 },
                 shared: true
@@ -1344,66 +1341,66 @@ $(function() {
             },
             series: series,
             buttons: gridbuttons,
-            title: { text: chartObj.title },
+            title: { text: chartObj.title }
         };
-        
+
         if(chartObj.settings)
             $.extend(true,settings,chartObj.settings);
-                
+
         if($('#'+settings.chart.renderTo).length==0) {
             var numCharts = $('table#chartGrid .monitorChart').length;
-    
+
             if(numCharts == 0 || !( numCharts % monitorSettings.columns))
                 $('table#chartGrid').append('<tr></tr>');
-            
+
             $('table#chartGrid tr:last').append('<td><div class="ui-state-default monitorChart" id="'+settings.chart.renderTo+'"></div></td>');
         }
-        
+
         chartObj.chart = PMA_createChart(settings);
         chartObj.numPoints = 0;
-        
+
         if(initialize != true) {
             runtime.charts['c'+runtime.chartAI] = chartObj;
             buildRequiredDataList();
         }
-        
+
         // Edit,Print icon only in edit mode
         $('table#chartGrid div svg').find('*[zIndex=20], *[zIndex=21], *[zIndex=19]').toggle(editMode)
-        
+
         runtime.chartAI++;
     }
-    
+
     function removeChart(chartObj) {
         var htmlnode = chartObj.options.chart.renderTo;
         if(! htmlnode ) return;
-        
-        
+
+
         $.each(runtime.charts, function(key, value) {
             if(value.chart.options.chart.renderTo == htmlnode) {
                 delete runtime.charts[key];
                 return false;
             }
         });
-        
+
         buildRequiredDataList();
-        
-        // Using settimeout() because clicking the remove link fires an onclick event 
+
+        // Using settimeout() because clicking the remove link fires an onclick event
         // which throws an error when the chart is destroyed
         setTimeout(function() {
             chartObj.destroy();
             $('li#' + htmlnode).remove();
         },10);
-        
+
         saveMonitor(); // Save settings
     }
-    
+
     function refreshChartGrid() {
         /* Send to server */
         runtime.refreshRequest = $.post('server_status.php?'+url_query, { ajax_request: true, chart_data: 1, type: 'chartgrid', requiredData: $.toJSON(runtime.dataList) },function(data) {
             var chartData = $.parseJSON(data);
             var value, i=0;
             var diff;
-    
+
             /* Update values in each graph */
             $.each(runtime.charts, function(orderKey, elem) {
                 var key = elem.chartID;
@@ -1416,18 +1413,18 @@ $(function() {
                     if(i==0 && j==0) {
                         if(oldChartData==null) diff = chartData.x - runtime.xmax;
                         else diff = parseInt(chartData.x - oldChartData.x);
-                        
+
                         runtime.xmin+= diff;
                         runtime.xmax+= diff;
                     }
-                    
+
                     elem.chart.xAxis[0].setExtremes(runtime.xmin, runtime.xmax, false);
-                    
+
                     if(elem.nodes[j].display == 'differential') {
                         if(oldChartData == null || oldChartData[key] == null) continue;
                         value -= oldChartData[key][j].y;
                     }
-                    
+
                     if(elem.nodes[j].valueDivisor)
                         value = value / elem.nodes[j].valueDivisor;
 
@@ -1437,28 +1434,28 @@ $(function() {
                             (oldChartData == null) ? null : oldChartData[key][j]
                         );
                     }
-                    
+
                     if(value != undefined)
                         elem.chart.series[j].addPoint(
                             {  x: chartData.x, y: value },
-                            false, 
+                            false,
                             elem.numPoints >= runtime.gridMaxPoints
                         );
                 }
-                
+
                 i++;
-                
+
                 runtime.charts[orderKey].numPoints++;
                 if(runtime.redrawCharts)
                     elem.chart.redraw();
             });
-            
+
             oldChartData = chartData;
-            
+
             runtime.refreshTimeout = setTimeout(refreshChartGrid, monitorSettings.gridRefresh);
         });
     }
-    
+
     /* Build list of nodes that need to be retrieved */
     function buildRequiredDataList() {
         runtime.dataList = {};
@@ -1470,15 +1467,16 @@ $(function() {
             chartID++;
         });
     }
-    
+
     function loadLogStatistics(opts) {
         var tableStr = '';
         var logRequest = null;
-        var groupInsert = false;
-        
-        if(opts.groupInserts)
-            groupInserts = true;
-        
+
+        if(! opts.removeVariables)
+            opts.removeVariables = false;
+        if(! opts.limitTypes)
+            opts.limitTypes = false;
+
         $('#loadingLogsDialog').html(PMA_messages['strAnalysingLogs'] + ' <img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">');
 
         $('#loadingLogsDialog').dialog({
@@ -1486,195 +1484,409 @@ $(function() {
             height: 'auto',
             buttons: {
                 'Cancel request': function() {
-                    if(logRequest != null) 
+                    if(logRequest != null)
                         logRequest.abort();
-                    
-                    $(this).dialog("close"); 
+
+                    $(this).dialog("close");
                 }
             }
         });
-        
-        
-        var formatValue = function(name, value) {
-            switch(name) {
-                case 'user_host': 
-                    return value.replace(/(\[.*?\])+/g,'');
-            }
-            return value;
-        }
-        
-        logRequest = $.get('server_status.php?'+url_query, 
-            { ajax_request: true, log_data: 1, type: opts.src, time_start: Math.round(opts.start / 1000), time_end: Math.round(opts.end / 1000), groupInserts: groupInserts },
-            function(data) { 
-                var data = $.parseJSON(data);
-                var rows = data.rows;
-                var cols = new Array();
-                
-                if(rows.length != 0) {
-                    tableStr = '<table border="0" class="sortable">';
-                    
-                    for(var i=0; i < rows.length; i++) {
-                        if(i == 0) {
-                            tableStr += '<thead>';
-                            $.each(rows[0],function(key, value) {
-                                cols.push(key);
-                            });
-                            tableStr += '<tr><th class="nowrap">' + cols.join('</th><th class="nowrap">') + '</th></tr>';
-                            tableStr += '</thead><tbody>';
-                        }
-                        
-                        tableStr += '<tr>';
-                        for(var j=0; j < cols.length; j++)
-                            tableStr += '<td>' + formatValue(cols[j], rows[i][cols[j]]) + '</td>';
-                        tableStr += '</tr>';    
-                    }
 
-                    tableStr += '</tbody><tfoot>';
-                    tableStr += '<tr><th colspan="' + (cols.length - 1) + '">Sum of grouped rows: '+ data.numRows +'<span style="float:right">Total:</span></th><th align="right">' + data.sum.TOTAL + '</th></tr>';
-                    tableStr += '</tfoot></table>';
-            
-                    $('#logTable').html(tableStr);
-                    
-                    // Append a tooltip to the count column, if there exist one
-                    if($('#logTable th:last').html() == '#') {
-                        $('#logTable th:last').append(' <img class="qroupedQueryInfoIcon icon ic_b_docs" src="themes/dot.gif" alt="" />');
-                    
-                        var qtipContent = PMA_messages['strCountColumnExplanation'];
-                        if(groupInserts) qtipContent += '<p>' + PMA_messages['strMoreCountColumnExplanation'] + '</p>';
-                        
-                        $('img.qroupedQueryInfoIcon').qtip({
-                            content: qtipContent,
-                            position: {
-                                corner: {
-                                    target: 'bottomMiddle',
-                                    tooltip: 'topRight'
-                                }
-                                
-                            },
-                            hide: { delay: 1000 }
-                        })
-                    }
-                    
-                    
-                    
-                    $('div#logTable table').tablesorter({
-                        sortList: [[0,1]],
-                        widgets: ['zebra']
-                    });
-                    
-                    $('div#logTable table thead th')
-                        .append('<img class="icon sortableIcon" src="themes/dot.gif" alt="">');
 
-                    
+        logRequest = $.get('server_status.php?'+url_query,
+            {   ajax_request: true,
+                log_data: 1,
+                type: opts.src,
+                time_start: Math.round(opts.start / 1000),
+                time_end: Math.round(opts.end / 1000),
+                removeVariables: opts.removeVariables,
+                limitTypes: opts.limitTypes
+            },
+            function(data) {
+                var logData = $.parseJSON(data);
+
+                if(logData.rows.length != 0) {
+                    runtime.logDataCols = buildLogTable(logData);
+
+                    /* Show some stats in the dialog */
                     $('#loadingLogsDialog').html('<p>' + PMA_messages['strLogDataLoaded'] + '</p>');
-                    $.each(data.sum, function(key, value) {
+                    $.each(logData.sum, function(key, value) {
                         key = key.charAt(0).toUpperCase() + key.slice(1).toLowerCase();
                         if(key == 'Total') key = '<b>' + key + '</b>';
                         $('#loadingLogsDialog').append(key + ': ' + value + '<br/>');
                     });
-                    
-                    if(data.numRows > 12) {
+
+                    /* Add filter options if more than a bunch of rows there to filter */
+                    if(logData.numRows > 12) {
                         $('div#logTable').prepend(
                             '<fieldset id="logDataFilter">' +
-                            '    <legend>Filters</legend>' +
-                            '    <div class="formelement">' +
-                            '        <label for="filterQueryText">Filter queries by word/regexp:</label>' +
-                            '        <input name="filterQueryText" type="text" id="filterQueryText" style="vertical-align: baseline;" />' +
-                            ((data.numRows > 250) ? ' <button name="startFilterQueryText" id="startFilterQueryText">Filter</button>' : '') +                        
-                            '    </div>' +
+                            '	<legend>' + PMA_messages['strFilters'] + '</legend>' +
+                            '	<div class="formelement">' +
+                            '		<label for="filterQueryText">' + PMA_messages['strFilterByWordRegexp'] + '</label>' +
+                            '		<input name="filterQueryText" type="text" id="filterQueryText" style="vertical-align: baseline;" />' +
+                            '	</div>' +
+                            ((logData.numRows > 250) ? ' <div class="formelement"><button name="startFilterQueryText" id="startFilterQueryText">' + PMA_messages['strFilter'] + '</button></div>' : '') +
+                            '	<div class="formelement">' +
+                            '       <input type="checkbox" id="noWHEREData" name="noWHEREData" value="1" /> ' +
+                            '       <label for="noWHEREData"> ' + PMA_messages['strIgnoreWhereAndGroup'] + '</label>' +
+                            '   </div' +
                             '</fieldset>'
                         );
-                        
-                        if(data.numRows > 250) {
+
+                        $('div#logTable input#noWHEREData').change(function() {
+                            filterQueries(true);
+                        });
+
+                        //preg_replace('/\s+([^=]+)=(\d+|((\'|"|)(?U)(.+)(?<!\\\)\4(\s+|$)))/i',' $1={} ',$str);
+
+                        if(logData.numRows > 250) {
                             $('div#logTable button#startFilterQueryText').click(filterQueries);
                         } else {
                             $('div#logTable input#filterQueryText').keyup(filterQueries);
                         }
-                        
-                        function filterQueries() {
-                            var odd_row=false, cell, textFilter;
-                            var val = $('div#logTable input#filterQueryText').val();
-                            
-                            if(val.length == 0) textFilter = null;
-                            else textFilter = new RegExp(val, 'i');
-                            
-                            var rowSum = 0, totalSum = 0;
-                            
-                            $('div#logTable table tbody tr').each(function() {
-                                // We just assume the sql text is always in the second last column
-                                cell = $(this).children(':nth-child(' + (cols.length - 1) + ')');
-                                
-                                if(textFilter==null || textFilter.exec(cell.text())) {
-                                    // And that total count is right of the sql text
-                                    totalSum += parseInt(cell.next().text());
-                                    rowSum ++;
-                                    
-                                    odd_row = !odd_row;    
-                                    $(this).css('display','');
-                                    if(odd_row) {
-                                        $(this).addClass('odd');
-                                        $(this).removeClass('even');
-                                    } else {
-                                        $(this).addClass('even');
-                                        $(this).removeClass('odd');
-                                    }
-                                } else {
-                                    $(this).css('display','none');
-                                }
-                            });
-                            
-                            
-                            $('div#logTable table tfoot tr')
-                                .html('<th colspan="' + (cols.length - 1) + 
-                                    '">Sum of grouped rows: '+ rowSum +'<span style="float:right">Total:</span></th><th align="right">' + 
-                                     totalSum + '</th>');
-                        };
+
                     }
-                    
+
                     var dlgBtns = {};
-                    dlgBtns[PMA_messages['strJumpToTable']] = function() { 
-                        $(this).dialog("close"); 
+                    dlgBtns[PMA_messages['strJumpToTable']] = function() {
+                        $(this).dialog("close");
                         $(document).scrollTop($('div#logTable').offset().top);
                     }
-                    
+
                     $('#loadingLogsDialog').dialog( "option", "buttons", dlgBtns);
-                    
+
                 } else {
                     $('#loadingLogsDialog').html('<p>' + PMA_messages['strNoDataFound'] + '</p>');
-                    
+
                     var dlgBtns = {};
-                    dlgBtns[PMA_messages['strClose']] = function() { 
-                        $(this).dialog("close"); 
+                    dlgBtns[PMA_messages['strClose']] = function() {
+                        $(this).dialog("close");
                     }
-                    
+
                     $('#loadingLogsDialog').dialog( "option", "buttons", dlgBtns );
                 }
             }
         );
+
+        function filterQueries(varFilterChange) {
+            var odd_row=false, cell, textFilter;
+            var val = $('div#logTable input#filterQueryText').val();
+
+            if(val.length == 0) textFilter = null;
+            else textFilter = new RegExp(val, 'i');
+
+            var rowSum = 0, totalSum = 0;
+
+            var i=0, q;
+            var noVars = $('div#logTable input#noWHEREData').attr('checked');
+            var equalsFilter = /([^=]+)=(\d+|((\'|"|).*?[^\\])\4((\s+)|$))/gi;
+            var functionFilter = /([a-z0-9_]+)\(.+?\)/gi;
+            var filteredQueries = {};
+            var filteredQueriesLines = {};
+            var hide = false;
+            var queryColumnName = runtime.logDataCols[runtime.logDataCols.length - 2];
+            var sumColumnName = runtime.logDataCols[runtime.logDataCols.length - 1];
+
+            // We just assume the sql text is always in the second last column, and that the total count is right of it
+            $('div#logTable table tbody tr td:nth-child(' + (runtime.logDataCols.length - 1) + ')').each(function() {
+                if(varFilterChange && $(this).html().match(/^SELECT/i)) {
+                    if(noVars) {
+                        q = $(this).text().replace(equalsFilter, '$1=...$6').trim();
+                        q = q.replace(functionFilter, ' $1(...)');
+
+                        // Js does not specify a limit on property name length, so we can abuse it as index :-)
+                        if(filteredQueries[q]) {
+                            filteredQueries[q] += parseInt($(this).next().text());
+                            totalSum += parseInt($(this).next().text());
+                            hide = true;
+                        } else {
+                            filteredQueries[q] = parseInt($(this).next().text());;
+                            filteredQueriesLines[q] = i;
+                            $(this).text(q);
+                        }
+
+                    } else {
+                        $(this).text($(this).parent().data('query')[queryColumnName]);
+                        $(this).next().text($(this).parent().data('query')[sumColumnName]);
+                    }
+                }
+
+                if(! hide && (textFilter != null && ! textFilter.exec($(this).text()))) hide = true;
+
+                if(hide) {
+                    $(this).parent().css('display','none');
+                } else {
+                    totalSum += parseInt($(this).next().text());
+                    rowSum ++;
+
+                    odd_row = ! odd_row;
+                    $(this).parent().css('display','');
+                    if(odd_row) {
+                        $(this).parent().addClass('odd');
+                        $(this).parent().removeClass('even');
+                    } else {
+                        $(this).parent().addClass('even');
+                        $(this).parent().removeClass('odd');
+                    }
+                }
+
+                hide = false;
+                i++;
+            });
+
+            if(varFilterChange) {
+                if(noVars) {
+                    $.each(filteredQueriesLines, function(key,value) {
+                        if(filteredQueries[value] <= 1) return;
+
+                        var numCol = $('div#logTable table tbody tr:nth-child(' + (value+1) + ')')
+                                        .children(':nth-child(' + (runtime.logDataCols.length) + ')');
+
+                        numCol.text(filteredQueries[key]);
+                    });
+                }
+
+                $('div#logTable table').trigger("update");
+                setTimeout(function() {
+
+                    $('div#logTable table').trigger('sorton',[[[runtime.logDataCols.length - 1,1]]]);
+                }, 0);
+            }
+
+            $('div#logTable table tfoot tr')
+                .html('<th colspan="' + (runtime.logDataCols.length - 1) + '">' +
+                      PMA_messages['strSumRows'] + ' '+ rowSum +'<span style="float:right">' +
+                      PMA_messages['strTotal'] + '</span></th><th align="right">' + totalSum + '</th>');
+        }
+    }
+
+    /*loadLogStatistics({
+        src: 'general',
+        start:1311076210*1000,
+        end:1311162689*1000,
+        removeVariables: true,
+        limitTypes: true
+    });*/
+
+    function buildLogTable(data) {
+        var rows = data.rows;
+        var cols = new Array();
+        var $table = $('<table border="0" class="sortable"></table>');
+        var $tBody, $tRow, $tCell;
+
+        $('#logTable').html($table);
+
+        var formatValue = function(name, value) {
+            switch(name) {
+                case 'user_host':
+                    return value.replace(/(\[.*?\])+/g,'');
+            }
+            return value;
+        }
+
+        for(var i=0; i < rows.length; i++) {
+            if(i == 0) {
+                $.each(rows[0],function(key, value) {
+                    cols.push(key);
+                });
+                $table.append( '<thead>' +
+                               '<tr><th class="nowrap">' + cols.join('</th><th class="nowrap">') + '</th></tr>' +
+                               '</thead>');
+
+                $table.append($tBody = $('<tbody></tbody>'));
+            }
+
+            $tBody.append($tRow = $('<tr class="noclick"></tr>'));
+            var cl=''
+            for(var j=0; j < cols.length; j++) {
+                // Assuming the query column is the second last
+                if(j == cols.length - 2 && rows[i][cols[j]].match(/^SELECT/i)) {
+                    $tRow.append($tCell=$('<td class="analyzableQuery">' + formatValue(cols[j], rows[i][cols[j]]) + '</td>'));
+                    $tCell.click(queryAnalyzer);
+                } else
+                    $tRow.append('<td>' + formatValue(cols[j], rows[i][cols[j]]) + '</td>');
+
+
+                $tRow.data('query',rows[i]);
+            }
+        }
+
+        $table.append('<tfoot>' +
+                    '<tr><th colspan="' + (cols.length - 1) + '">' + PMA_messages['strSumRows'] +
+                    ' '+ data.numRows +'<span style="float:right">' + PMA_messages['strTotal'] +
+                    '</span></th><th align="right">' + data.sum.TOTAL + '</th></tr></tfoot>');
+
+
+        function queryAnalyzer() {
+            var query = $(this).parent().data('query')[cols[cols.length-2]];
+
+            /* A very basic SQL Formatter. Totally fails in the cases of
+               - Any string appearance containing a MySQL Keyword, surrounded by whitespaces
+               - Subqueries too probably
+            */
+            // .* selector doesn't includde whitespace, [^] doesn't work in IE8, thus we use [^\0] since the zero-byte char (hopefully) doesn't appear in table names ;)
+            var sLists = query.match(/SELECT\s+[^\0]+\s+FROM\s+/gi);
+            if(sLists) {
+                for(var i=0; i < sLists.length; i++) {
+                    query = query.replace(sLists[i],sLists[i].replace(/\s*((`|'|"|).*?\1,)\s*/gi,'$1\n\t'));
+                }
+                query = query
+                  .replace(/(\s+|^)(SELECT|FROM|WHERE|GROUP BY|HAVING|ORDER BY|LIMIT)(\s+|$)/gi,'\n$2\n\t')
+                  .replace(/\s+UNION\s+/gi,'\n\nUNION\n\n')
+                  .replace(/\s+(AND)\s+/gi,' $1\n\t')
+                  .trim();
+            }
+
+            codemirror_editor.setValue(query);
+
+            var profilingChart = null;
+
+            $('div#queryAnalyzerDialog').dialog({
+                width: 'auto',
+                height: 'auto',
+                resizable: false,
+                buttons: {
+                    'Analyse Query' : function() {
+                        $('div#queryAnalyzerDialog div.placeHolder').html('Analyzing... ' + '<img class="ajaxIcon" src="' + pmaThemeImage + 'ajax_clock_small.gif" alt="">');
+
+                        $.post('server_status.php?'+url_query, {
+                            ajax_request: true,
+                            query_analyzer: true,
+                            query: codemirror_editor.getValue()
+                        }, function(data) {
+                            data = $.parseJSON(data);
+                            var totalTime = 0;
+
+                            if(data.error) {
+                                $('div#queryAnalyzerDialog div.placeHolder').html('<div class="error">' + data.error + '</div>');
+                                return;
+                            }
+
+                            // Float sux, I'll use table :(
+                            $('div#queryAnalyzerDialog div.placeHolder')
+                                .html('<table width="100%" border="0"><tr><td class="explain"></td><td class="chart"></td></tr></table>');
+
+                            var explain = '<b>Explain output</b><p></p>';
+                            $.each(data.explain, function(key,value) {
+                                value = (value==null)?'null':value;
+
+                                explain += key+': ' + value + '<br />';
+                            });
+                            $('div#queryAnalyzerDialog div.placeHolder td.explain').append(explain);
+
+                            if(data.profiling) {
+                                var chartData = [];
+                                var numberTable = '<table class="queryNums"><thead><tr><th>Status</th><th>Time</th></tr></thead><tbody>';
+                                var duration;
+
+                                for(var i=0; i < data.profiling.length; i++) {
+                                    duration = parseFloat(data.profiling[i].duration);
+
+                                    chartData.push([data.profiling[i].state, duration]);
+                                    totalTime+=duration;
+
+                                    numberTable += '<tr><td>' + data.profiling[i].state + ' </td><td> ' + PMA_prettyProfilingNum(duration,2) + '</td></tr>';
+                                }
+                                numberTable += '<tr><td><b>Total time:</b></td><td>' + PMA_prettyProfilingNum(totalTime,2) + '</td></tr>';
+                                numberTable += '</tbody></table>';
+
+                                $('div#queryAnalyzerDialog div.placeHolder td.chart').append('<b>Profiling results</b> (<a href="#showNums">Table</a> | <a href="#showChart">Chart</a>)<br/>' + numberTable + ' <div id="queryProfiling"></div>');
+
+                                $('div#queryAnalyzerDialog div.placeHolder a[href="#showNums"]').click(function() {
+                                    $('div#queryAnalyzerDialog div#queryProfiling').hide();
+                                    $('div#queryAnalyzerDialog table.queryNums').show();
+                                    return false;
+                                });
+
+                                $('div#queryAnalyzerDialog div.placeHolder a[href="#showChart"]').click(function() {
+                                    $('div#queryAnalyzerDialog div#queryProfiling').show();
+                                    $('div#queryAnalyzerDialog table.queryNums').hide();
+                                    return false;
+                                });
+
+                                profilingChart = PMA_createProfilingChart(chartData, {
+                                    chart: {
+                                        renderTo: 'queryProfiling'
+                                    },
+                                    plotOptions: {
+                                        pie: {
+                                            size: '50%'
+                                        }
+                                    }
+                                });
+
+
+                                $('div#queryProfiling').resizable();
+                            }
+
+                        });
+                    },
+                    'Close' : function() {
+                        if(profilingChart != null) {
+                            profilingChart.destroy();
+                        }
+                        $('div#queryAnalyzerDialog div.placeHolder').html('');
+                        codemirror_editor.setValue('');
+
+                        $(this).dialog("close");
+                    }
+                }
+            });
+        }
+
+        // Append a tooltip to the count column, if there exist one
+        if($('#logTable th:last').html() == '#') {
+            $('#logTable th:last').append(' <img class="qroupedQueryInfoIcon icon ic_b_docs" src="themes/dot.gif" alt="" />');
+
+            var qtipContent = PMA_messages['strCountColumnExplanation'];
+            if(groupInserts) qtipContent += '<p>' + PMA_messages['strMoreCountColumnExplanation'] + '</p>';
+
+            $('img.qroupedQueryInfoIcon').qtip({
+                content: qtipContent,
+                position: {
+                    corner: {
+                        target: 'bottomMiddle',
+                        tooltip: 'topRight'
+                    }
+
+                },
+                hide: { delay: 1000 }
+            })
+        }
+
+        $('div#logTable table').tablesorter({
+            sortList: [[cols.length - 1,1]],
+            widgets: ['zebra']
+        });
+
+        $('div#logTable table thead th')
+            .append('<img class="icon sortableIcon" src="themes/dot.gif" alt="">');
+
+        return cols;
     }
-    
+
     function saveMonitor() {
         var gridCopy = {};
-            
+
         $.each(runtime.charts, function(key, elem) {
             gridCopy[key] = {};
             gridCopy[key].nodes = elem.nodes;
             gridCopy[key].settings = elem.settings;
             gridCopy[key].title = elem.title;
         });
-        
+
         if(window.localStorage) {
             window.localStorage['monitorCharts'] = $.toJSON(gridCopy);
             window.localStorage['monitorSettings'] = $.toJSON(monitorSettings);
         }
-        
+
         $('a[href="#clearMonitorConfig"]').show();
     }
-    
+
     $('a[href="#clearMonitorConfig"]').click(function() {
         window.localStorage.removeItem('monitorCharts');
         window.localStorage.removeItem('monitorSettings');
         $(this).hide();
     });
-    
+
 });
diff --git a/js/sql.js b/js/sql.js
index fb24f5d..e762bb5 100644
--- a/js/sql.js
+++ b/js/sql.js
@@ -55,6 +55,7 @@ function getFieldName($this_field) {
 function appendInlineAnchor() {
     // TODO: remove two lines below if vertical display mode has been completely removed
     var disp_mode = $("#top_direction_dropdown").val();
+
     if (disp_mode != 'vertical') {
         $('.edit_row_anchor').each(function() {
 
@@ -65,8 +66,9 @@ function appendInlineAnchor() {
 
             var $img_object = $cloned_anchor.find('img').attr('title', PMA_messages['strInlineEdit']);
             if ($img_object.length != 0) {
-                var img_class = $img_object.attr('class').replace(/b_edit/,'b_inline_edit');
-                $img_object.attr('class', img_class);
+                $img_object.removeClass('ic_b_edit');
+                $img_object.addClass('ic_b_inline_edit');
+
                 $cloned_anchor.find('a').attr('href', '#');
                 var $edit_span = $cloned_anchor.find('span:contains("' + PMA_messages['strEdit'] + '")');
                 var $span = $cloned_anchor.find('a').find('span');
@@ -85,8 +87,8 @@ function appendInlineAnchor() {
                 // the link was too big so <input type="image"> is there
                 $img_object = $cloned_anchor.find('input:image').attr('title', PMA_messages['strInlineEdit']);
                 if ($img_object.length > 0) {
-                    var img_class = $img_object.attr('class').replace(/b_edit/,'b_inline_edit');
-                    $img_object.attr('class', img_class);
+                    $img_object.removeClass('ic_b_edit');
+                    $img_object.addClass('ic_b_inline_edit');
                 }
                 $cloned_anchor
                  .find('.clickprevimage')
@@ -445,8 +447,8 @@ $(document).ready(function() {
         // If icons are displayed. See $cfg['PropertiesIconic']
         if ($img_object.length > 0) {
             $img_object.attr('title', PMA_messages['strSave']);
-            var img_class = $img_object.attr('class').replace(/b_inline_edit/,'b_save');
-            $img_object.attr('class', img_class);
+            $img_object.removeClass('ic_b_inline_edit');
+            $img_object.addClass('ic_b_save');
             $this_children.prepend($img_object);
         }
 
@@ -465,8 +467,8 @@ $(document).ready(function() {
         // If icons are displayed. See $cfg['PropertiesIconic']
         if ($img_object.length > 0) {
             $img_object.attr('title', PMA_messages['strHide']);
-            var img_class = $img_object.attr('class').replace(/b_save/,'b_close');
-            $img_object.attr('class', img_class);
+            $img_object.removeClass('ic_b_save');
+            $img_object.addClass('ic_b_close');
             $hide_span.prepend($img_object);
         }
 
@@ -1230,47 +1232,20 @@ $(document).ready(function() {
 /*
  * Profiling Chart
  */
-function createProfilingChart() {
+function makeProfilingChart() {
     if ($('#profilingchart').length == 0) {
         return;
     }
 
-    var cdata = new Array();
+    var data = new Array();
     $.each(jQuery.parseJSON($('#profilingchart').html()),function(key,value) {
-        cdata.push([key,parseFloat(value)]);
+        data.push([key,parseFloat(value)]);
     });
 
     // Prevent the user from seeing the JSON code
     $('div#profilingchart').html('').show();
 
-    PMA_createChart({
-        chart: {
-            renderTo: 'profilingchart',
-            backgroundColor: $('#sqlqueryresults fieldset').css('background-color')
-        },
-        title: { text:'', margin:0 },
-        series: [{
-            type:'pie',
-            name: 'Query execution time',
-            data: cdata
-        }],
-        plotOptions: {
-            pie: {
-                allowPointSelect: true,
-                cursor: 'pointer',
-                dataLabels: {
-                    enabled: true,
-                    distance: 35,
-                    formatter: function() {
-                        return '<b>'+ this.point.name +'</b><br/>'+ Highcharts.numberFormat(this.percentage, 2) +' %';
-                   }
-                }
-            }
-        },
-        tooltip: {
-            formatter: function() { return '<b>'+ this.point.name +'</b><br/>'+this.y+'s<br/>('+Highcharts.numberFormat(this.percentage, 2) +' %)'; }
-        }
-    });
+    PMA_createProfilingChart(data);
 }
 
 
diff --git a/libraries/common.lib.php b/libraries/common.lib.php
index 27d99bc..61f5aa6 100644
--- a/libraries/common.lib.php
+++ b/libraries/common.lib.php
@@ -66,9 +66,10 @@ function PMA_pow($base, $exp, $use_function = false)
  * @param string  $alternate  alternate text
  * @param boolean $container  include in container
  * @param boolean $force_text whether to force alternate text to be displayed
+ * @param boolean $noSprite   If true, the image source will be not replaced with a CSS Sprite
  * @return html img tag
  */
-function PMA_getIcon($icon, $alternate = '', $container = false, $force_text = false)
+function PMA_getIcon($icon, $alternate = '', $container = false, $force_text = false, $noSprite = false)
 {
     $include_icon = false;
     $include_text = false;
@@ -80,9 +81,7 @@ function PMA_getIcon($icon, $alternate = '', $container = false, $force_text = f
          $include_icon = true;
     }
 
-    if ($force_text
-     || ! (true === $GLOBALS['cfg']['PropertiesIconic'])
-     || ! $include_icon) {
+    if ($force_text || true !== $GLOBALS['cfg']['PropertiesIconic']) {
         // $cfg['PropertiesIconic'] is false or both
         // OR we have no $include_icon
         $include_text = true;
@@ -97,9 +96,14 @@ function PMA_getIcon($icon, $alternate = '', $container = false, $force_text = f
     $button .= '<span class="nowrap">';
 
     if ($include_icon) {
-        $button .= '<img src="themes/dot.gif"'
-            . ' title="' . $alternate . '" alt="' . $alternate . '"'
-            . ' class="icon ic_' . str_replace('.png','',$icon) . '" />';
+        if($noSprite) {
+            $button .= '<img src="' . $GLOBALS['pmaThemeImage'] . $icon . '"'
+                    . ' class="icon" width="16" height="16" />';
+        } else {
+            $button .= '<img src="themes/dot.gif"'
+                . ' title="' . $alternate . '" alt="' . $alternate . '"'
+                . ' class="icon ic_' . str_replace(array('.gif','.png'),array('',''),$icon) . '" />';
+        }
     }
 
     if ($include_icon && $include_text) {
@@ -474,7 +478,7 @@ function PMA_showHint($message, $bbcode = false, $type = 'notice')
 
     // footnotemarker used in js/tooltip.js
     return '<sup class="footnotemarker">' . $nr . '</sup>' .
-    '<img class="footnotemarker ic_b_help footnote_' . $nr . '" src="themes/dot.gif" alt="" />';
+    '<img class="footnotemarker footnote_' . $nr . ' ic_b_help" src="themes/dot.gif" alt="" />';
 }
 
 /**
@@ -1648,6 +1652,7 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
         return '';
     }
 
+
     if (! is_array($tag_params)) {
         $tmp = $tag_params;
         $tag_params = array();
@@ -1669,11 +1674,17 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
         $tag_params_strings[] = $par_name . '="' . $par_value . '"';
     }
 
+    $displayed_message = '';
+    // Add text if not already added
+    if (stristr($message, '<img') && (!$strip_img || $GLOBALS['cfg']['PropertiesIconic'] === true) && strip_tags($message)==$message) {
+        $displayed_message = '<span>' . htmlspecialchars(preg_replace('/^.*\salt="([^"]*)".*$/si', '\1', $message)) . '</span>';
+    }
+
     if ($url_length <= $GLOBALS['cfg']['LinkLengthLimit']) {
         // no whitespace within an <a> else Safari will make it part of the link
         $ret = "\n" . '<a href="' . $url . '" '
             . implode(' ', $tag_params_strings) . '>'
-            . $message . '</a>' . "\n";
+            . $message . $displayed_message . '</a>' . "\n";
     } else {
         // no spaces (linebreaks) at all
         // or after the hidden fields
@@ -1702,7 +1713,7 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
                  . ' method="post"' . $target . ' style="display: inline;">';
             $subname_open   = '';
             $subname_close  = '';
-            $submit_name    = '';
+            $submit_link    = '#';
         } else {
             $query_parts[] = 'redirect=' . $url_parts['path'];
             if (empty($GLOBALS['subform_counter'])) {
@@ -1712,7 +1723,7 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
             $ret            = '';
             $subname_open   = 'subform[' . $GLOBALS['subform_counter'] . '][';
             $subname_close  = ']';
-            $submit_name    = ' name="usesubform[' . $GLOBALS['subform_counter'] . ']"';
+            $submit_link    = '#usesubform[' . $GLOBALS['subform_counter'] . ']=1';
         }
         foreach ($query_parts as $query_pair) {
             list($eachvar, $eachval) = explode('=', $query_pair);
@@ -1721,35 +1732,10 @@ function PMA_linkOrButton($url, $message, $tag_params = array(),
                 . htmlspecialchars(urldecode($eachval)) . '" />';
         } // end while
 
-        if (stristr($message, '<img')) {
-            if ($strip_img) {
-                $message = trim(strip_tags($message));
-                $ret .= '<input type="submit"' . $submit_name . ' '
-                    . implode(' ', $tag_params_strings)
-                    . ' value="' . htmlspecialchars($message) . '" />';
-            } else {
-                $displayed_message = htmlspecialchars(
-                        preg_replace('/^.*\salt="([^"]*)".*$/si', '\1',
-                            $message));
-                $ret .= '<input type="image"' . $submit_name . ' '
-                    . implode(' ', $tag_params_strings)
-                    . ' src="' . preg_replace(
-                        '/^.*\ssrc="([^"]*)".*$/si', '\1', $message) . '"'
-                        . ' value="' . $displayed_message . '" title="' . $displayed_message . '" />';
-                // Here we cannot obey PropertiesIconic completely as a
-                // generated link would have a length over LinkLengthLimit
-                // but we can at least show the message.
-                // If PropertiesIconic is false or 'both'
-                if ($GLOBALS['cfg']['PropertiesIconic'] !== true) {
-                    $ret .= ' <span class="clickprevimage">' . $displayed_message . '</span>';
-                }
-            }
-        } else {
-            $message = trim(strip_tags($message));
-            $ret .= '<input type="submit"' . $submit_name . ' '
-                . implode(' ', $tag_params_strings)
-                . ' value="' . htmlspecialchars($message) . '" />';
-        }
+        $ret .= "\n" . '<a href="' . $submit_link . '" class="formLinkSubmit" '
+        . implode(' ', $tag_params_strings) . '>'
+        . $message . ' ' . $displayed_message . '</a>' . "\n";
+
         if ($new_form) {
             $ret .= '</form>';
         }
diff --git a/libraries/header_scripts.inc.php b/libraries/header_scripts.inc.php
index c25aa99..05d1ee3 100644
--- a/libraries/header_scripts.inc.php
+++ b/libraries/header_scripts.inc.php
@@ -33,7 +33,7 @@ if (! isset($page_title)) {
 $is_superuser    = function_exists('PMA_isSuperuser') && PMA_isSuperuser();
 
 $GLOBALS['js_include'][] = 'functions.js';
-$GLOBALS['js_include'][] = 'jquery/jquery.qtip-1.0.0.min.js';
+$GLOBALS['js_include'][] = 'jquery/jquery.qtip-1.0.0-rc3.js';
 $params = array('lang' => $GLOBALS['lang']);
 if (isset($GLOBALS['db'])) {
     $params['db'] = $GLOBALS['db'];
diff --git a/server_status.php b/server_status.php
index 9065fce..3ff8f09 100644
--- a/server_status.php
+++ b/server_status.php
@@ -21,21 +21,6 @@ if (isset($_REQUEST['ajax_request']) && $_REQUEST['ajax_request'] == true)
 require_once './libraries/common.inc.php';
 
 /**
- * Function to output refresh rate selection.
- */
-function PMA_choose_refresh_rate() {
-    echo '<option value="5">' . __('Refresh rate') . '</option>';
-    foreach (array(1, 2, 5, 20, 40, 60, 120, 300, 600) as $rate) {
-        if ($rate % 60 == 0) {
-            $minrate = $rate / 60;
-            echo '<option value="' . $rate . '">' . sprintf(_ngettext('%d minute', '%d minutes', $minrate), $minrate) . '</option>';
-        } else {
-            echo '<option value="' . $rate . '">' . sprintf(_ngettext('%d second', '%d seconds', $rate), $rate) . '</option>';
-        }
-    }
-}
-
-/**
  * Ajax request
  */
 
@@ -43,22 +28,6 @@ if (isset($_REQUEST['ajax_request']) && $_REQUEST['ajax_request'] == true) {
     // Send with correct charset
     header('Content-Type: text/html; charset=UTF-8');
 
-    if (isset($_REQUEST['logging_vars'])) {
-        if (isset($_REQUEST['varName']) && isset($_REQUEST['varValue'])) {
-            $value = PMA_sqlAddslashes($_REQUEST['varValue']);
-            if (!is_numeric($value)) $value="'".$value."'";
-
-            if (!preg_match("/[^a-zA-Z0-9_]+/",$_REQUEST['varName']))
-                PMA_DBI_query('SET GLOBAL ' . $_REQUEST['varName'] . ' = '.$value);
-
-        }
-
-        $loggingVars = PMA_DBI_fetch_result(
-            "SHOW GLOBAL VARIABLES WHERE Variable_name IN (
-                'general_log', 'slow_query_log', 'long_query_time', 'log_output')", 0, 1);
-        exit(json_encode($loggingVars));
-    }
-
     // real-time charting data
     if (isset($_REQUEST['chart_data'])) {
         switch($_REQUEST['type']) {
@@ -203,10 +172,14 @@ if (isset($_REQUEST['ajax_request']) && $_REQUEST['ajax_request'] == true) {
             exit(json_encode($return));
         }
 
-        if ($_REQUEST['type'] == 'general') {
-            $q = 'SELECT TIME(event_time) as event_time, user_host, thread_id, server_id, argument, count(argument) as \'#\' FROM `mysql`.`general_log` WHERE command_type=\'Query\' '.
+        if($_REQUEST['type'] == 'general') {
+            $limitTypes = (isset($_REQUEST['limitTypes']) && $_REQUEST['limitTypes'])
+                            ? 'AND argument REGEXP \'^(INSERT|SELECT|UPDATE|DELETE)\' ' : '';
+
+            $q = 'SELECT TIME(event_time) as event_time, user_host, thread_id, server_id, argument, count(argument) as \'#\' '.
+                 'FROM `mysql`.`general_log` WHERE command_type=\'Query\' '.
                  'AND event_time > FROM_UNIXTIME('.$start.') AND event_time < FROM_UNIXTIME('.$end.') '.
-                 'AND argument REGEXP \'^(INSERT|SELECT|UPDATE|DELETE)\' GROUP by argument'; // HAVING count > 1';
+                 $limitTypes . 'GROUP by argument'; // HAVING count > 1';
 
             $result = PMA_DBI_try_query($q);
 
@@ -215,38 +188,47 @@ if (isset($_REQUEST['ajax_request']) && $_REQUEST['ajax_request'] == true) {
             $insertTables = array();
             $insertTablesFirst = -1;
             $i = 0;
+            $removeVars = isset($_REQUEST['removeVariables']) && $_REQUEST['removeVariables'];
 
             while ($row = PMA_DBI_fetch_assoc($result)) {
                 preg_match('/^(\w+)\s/',$row['argument'],$match);
                 $type = strtolower($match[1]);
-                // Ignore undefined index warning, just increase counter by one
-                @$return['sum'][$type] += $row['#'];
-
-                if ($type=='insert' || $type=='update') {
-                    // Group inserts if selected
-                    if ($type=='insert' && isset($_REQUEST['groupInserts']) && $_REQUEST['groupInserts'] && preg_match('/^INSERT INTO (`|\'|"|)([^\s\\1]+)\\1/i',$row['argument'],$matches)) {
-                        $insertTables[$matches[2]]++;
-                        if ($insertTables[$matches[2]] > 1) {
-                            $return['rows'][$insertTablesFirst]['#'] = $insertTables[$matches[2]];
-
-                            // Add a ... to the end of this query to indicate that there's been other queries
-                            if ($return['rows'][$insertTablesFirst]['argument'][strlen($return['rows'][$insertTablesFirst]['argument'])-1] != '.')
-                                $return['rows'][$insertTablesFirst]['argument'] .= '<br/>...';
-
-                            // Group this value, thus do not add to the result list
-                            continue;
-                        } else {
-                            $insertTablesFirst = $i;
-                            $insertTables[$matches[2]] += $row['#'] - 1;
+
+                if(!isset($return['sum'][$type])) $return['sum'][$type] = 0;
+                $return['sum'][$type] += $row['#'];
+
+                switch($type) {
+                    case 'insert':
+                        // Group inserts if selected
+                        if($removeVars && preg_match('/^INSERT INTO (`|\'|"|)([^\s\\1]+)\\1/i',$row['argument'],$matches)) {
+                            $insertTables[$matches[2]]++;
+                            if ($insertTables[$matches[2]] > 1) {
+                                $return['rows'][$insertTablesFirst]['#'] = $insertTables[$matches[2]];
+
+                                // Add a ... to the end of this query to indicate that there's been other queries
+                                if($return['rows'][$insertTablesFirst]['argument'][strlen($return['rows'][$insertTablesFirst]['argument'])-1] != '.')
+                                    $return['rows'][$insertTablesFirst]['argument'] .= '<br/>...';
+
+                                // Group this value, thus do not add to the result list
+                                continue 2;
+                            } else {
+                                $insertTablesFirst = $i;
+                                $insertTables[$matches[2]] += $row['#'] - 1;
+                            }
                         }
-                    }
+                        // No break here
 
-                    // Cut off big selects, but append byte count therefor
-                    if (strlen($row['argument']) > 180) {
-                        $row['argument'] = substr($row['argument'],0,160) . '... [' .
-                                            PMA_formatByteDown(strlen($row['argument']), 2).']';
-                    }
+                    case 'update':
+                        // Cut off big inserts and updates, but append byte count therefor
+                        if(strlen($row['argument']) > 180)
+                            $row['argument'] = substr($row['argument'],0,160) . '... [' .
+                                                PMA_formatByteDown(strlen($row['argument']), 2).']';
+
+                        break;
+
+                    default: break;
                 }
+
                 $return['rows'][] = $row;
                 $i++;
             }
@@ -259,6 +241,49 @@ if (isset($_REQUEST['ajax_request']) && $_REQUEST['ajax_request'] == true) {
             exit(json_encode($return));
         }
     }
+
+    if (isset($_REQUEST['logging_vars'])) {
+        if(isset($_REQUEST['varName']) && isset($_REQUEST['varValue'])) {
+            $value = PMA_sqlAddslashes($_REQUEST['varValue']);
+            if(!is_numeric($value)) $value="'".$value."'";
+
+            if(! preg_match("/[^a-zA-Z0-9_]+/",$_REQUEST['varName']))
+                PMA_DBI_query('SET GLOBAL '.$_REQUEST['varName'].' = '.$value);
+
+        }
+
+        $loggingVars = PMA_DBI_fetch_result('SHOW GLOBAL VARIABLES WHERE Variable_name IN ("general_log","slow_query_log","long_query_time","log_output")', 0, 1);
+        exit(json_encode($loggingVars));
+    }
+
+    if(isset($_REQUEST['query_analyzer'])) {
+        $return = array();
+
+        if ($profiling = PMA_profilingSupported())
+            PMA_DBI_query('SET PROFILING=1;');
+
+        // Do not cache query
+        $query = preg_replace('/^(\s*SELECT)/i','\\1 SQL_NO_CACHE',$_REQUEST['query']);
+
+        $result = PMA_DBI_try_query('EXPLAIN ' . $query);
+        $return['explain'] = PMA_DBI_fetch_assoc($result);
+
+        // In case an error happened
+        $return['error'] = PMA_DBI_getError();
+
+        PMA_DBI_free_result($result);
+
+        if($profiling) {
+            $return['profiling'] = array();
+            $result = PMA_DBI_try_query('SELECT seq,state,duration FROM INFORMATION_SCHEMA.PROFILING WHERE QUERY_ID=1 ORDER BY seq');
+            while ($row = PMA_DBI_fetch_assoc($result)) {
+                $return['profiling'][]= $row;
+            }
+            PMA_DBI_free_result($result);
+        }
+
+        exit(json_encode($return));
+    }
 }
 
 
@@ -287,6 +312,8 @@ $GLOBALS['js_include'][] = 'highcharts/exporting.js';
 $GLOBALS['js_include'][] = 'canvg/flashcanvas.js';
 $GLOBALS['js_include'][] = 'canvg/canvg.js';
 $GLOBALS['js_include'][] = 'canvg/rgbcolor.js';
+$GLOBALS['js_include'][] = 'codemirror/lib/codemirror.js';
+$GLOBALS['js_include'][] = 'codemirror/mode/mysql/mysql.js';
 
 /**
  * flush status variables if requested
@@ -1429,8 +1456,27 @@ function printMonitor() {
     <div id="loadingLogsDialog" title="<?php echo __('Loading logs'); ?>" style="display:none;">
     </div>
 
-    <div id="logAnalyseDialog" title="<?php echo __('Log statistics'); ?>">
+    <div id="logAnalyseDialog" title="<?php echo __('Log statistics'); ?>" style="display:none;">
+        <p> <?php echo __('Selected time range:'); ?>
+        <input type="text" name="dateStart" class="datetimefield" value="" /> -
+        <input type="text" name="dateEnd" class="datetimefield" value="" /></p>
+        <input type="checkbox" id="limitTypes" value="1" checked="checked" />
+        <label for="limitTypes">
+            <?php echo __('Only retrieve SELECT,INSERT,UPDATE and DELETE Statements'); ?>
+        </label>
+        <br/>
+        <input type="checkbox" id="removeVariables" value="1" checked="checked" />
+        <label for="removeVariables">
+            <?php echo __('Remove variable data in INSERT statements for better grouping'); ?>
+        </label>
+
+        <?php echo __('<p>Choose from which log you want the statistics to be generated from.</p> Results are grouped by query text.'); ?>
+    </div>
 
+    <div id="queryAnalyzerDialog" title="<?php echo __('Query analyzer'); ?>" style="display:none;">
+        <textarea id="sqlquery"> </textarea>
+        <p></p>
+        <div class="placeHolder"></div>
     </div>
 
     <table border="0" class="clearfloat" id="chartGrid">
diff --git a/sql.php b/sql.php
index 4d22876..94a0b0d 100644
--- a/sql.php
+++ b/sql.php
@@ -932,7 +932,7 @@ else {
 <script type="text/javascript">
 pma_token = '<?php echo $_SESSION[' PMA_token ']; ?>';
 url_query = '<?php echo isset($url_query)?$url_query:PMA_generate_common_url($db);?>';
-$(document).ready(createProfilingChart);
+$(document).ready(makeProfilingChart);
 </script>
 <?php
         echo '<fieldset><legend>' . __('Profiling') . '</legend>' . "\n";
diff --git a/themes/original/css/theme_left.css.php b/themes/original/css/theme_left.css.php
index 7ffbb69..f1b6ef8 100644
--- a/themes/original/css/theme_left.css.php
+++ b/themes/original/css/theme_left.css.php
@@ -87,6 +87,8 @@ button {
 .ic_b_browse { background-position: 0 -18px; } 
 .ic_b_sbrowse { background-position: 0 -660px; width: 10px; height: 10px; } 
 .ic_b_view { background-position: 0 -1044px; } 
+.ic_b_minus { background-position: 0 -440px; width: 9px; height: 9px; } 
+.ic_b_plus { background-position: 0 -523px; width: 9px; height: 9px; } 
 
 /******************************************************************************/
 /* classes */
diff --git a/themes/original/img/s_sortable.png b/themes/original/img/s_sortable.png
new file mode 100644
index 0000000..f403240
Binary files /dev/null and b/themes/original/img/s_sortable.png differ
diff --git a/themes/pmahomme/css/theme_left.css.php b/themes/pmahomme/css/theme_left.css.php
index ae504ea..247df08 100644
--- a/themes/pmahomme/css/theme_left.css.php
+++ b/themes/pmahomme/css/theme_left.css.php
@@ -92,6 +92,10 @@ button {
 .ic_s_loggoff { background-position: -1698px 0; }
 .ic_b_browse, .ic_b_sbrowse { background-position: -34px 0; }
 .ic_b_view { background-position: -1077px 0; }
+.ic_b_plus { background-position: -573px 0; }
+.ic_b_minus { background-position: -471px 0; }
+
+.ic_b_views, .ic_s_views { background-position: -1094px 0; }
 
 /******************************************************************************/
 /* classes */
diff --git a/themes/pmahomme/css/theme_right.css.php b/themes/pmahomme/css/theme_right.css.php
index a151563..d2d78e8 100644
--- a/themes/pmahomme/css/theme_right.css.php
+++ b/themes/pmahomme/css/theme_right.css.php
@@ -1308,6 +1308,12 @@ div#tablestatistics table {
 
 /* serverstatus */
 
+div#logTable table td.analyzableQuery:hover {
+    text-decoration:    underline;
+    color:              #235a81;
+    cursor: pointer;
+}
+
 h3#serverstatusqueries span {
     font-size:60%;
     display:inline;
@@ -1425,10 +1431,33 @@ div#logTable table {
     width:100%;
 }
 
+div#queryAnalyzerDialog {
+    min-width: 700px;
+}
+
+div#queryAnalyzerDialog div.CodeMirror-scroll {
+    height:auto;
+}
+
+div#queryAnalyzerDialog div#queryProfiling {
+	height: 250px;
+}
+
+div#queryAnalyzerDialog td.explain {
+    width: 250px;
+}
+
+div#queryAnalyzerDialog table.queryNums {
+	display: none;
+	border:0;
+	text-align:left;
+}
+
 .smallIndent {
     padding-left: 7px;
 }
 
+
 /* end serverstatus */
 
 /* server variables */
diff --git a/themes/pmahomme/img/pause.png b/themes/pmahomme/img/pause.png
new file mode 100644
index 0000000..a131617
Binary files /dev/null and b/themes/pmahomme/img/pause.png differ


hooks/post-receive
-- 
phpMyAdmin




More information about the Git mailing list