diff --git a/airtime_mvc/application/models/Block.php b/airtime_mvc/application/models/Block.php
index 93ada2b34..0c349d9f4 100644
--- a/airtime_mvc/application/models/Block.php
+++ b/airtime_mvc/application/models/Block.php
@@ -1297,6 +1297,9 @@ SQL;
                     $i++;
                 }
             }
+            
+            // check if file exists
+            $qry->add("file_exists", "true", Criteria::EQUAL);
             $qry->addAscendingOrderByColumn('random()');
         }
         // construct limit restriction
diff --git a/airtime_mvc/application/views/scripts/form/showbuilder.phtml b/airtime_mvc/application/views/scripts/form/showbuilder.phtml
index ddca06770..877f28849 100644
--- a/airtime_mvc/application/views/scripts/form/showbuilder.phtml
+++ b/airtime_mvc/application/views/scripts/form/showbuilder.phtml
@@ -2,9 +2,9 @@
 <?php echo $this->element->getElement('sb_time_start'); ?>
 <?php echo $this->element->getElement('sb_date_end'); ?>
 <?php echo $this->element->getElement('sb_time_end'); ?>
-<div id="sb_submit" class="ui-button ui-state-default" title="Find Shows">
-    <span class="ui-icon ui-icon-search"></span>
-</div>
+
+<a id="sb_submit" class="btn btn-small" href="#" title="Find Shows">
+    <i class="icon-white icon-search"></i> Find Shows</a>
 <div class="sb-advanced-options">
     <fieldset class="padded display_field push-down-8 closed">
         <legend style="cursor: pointer;">
diff --git a/airtime_mvc/application/views/scripts/showbuilder/index.phtml b/airtime_mvc/application/views/scripts/showbuilder/index.phtml
index 6e708004c..f159ba99b 100644
--- a/airtime_mvc/application/views/scripts/showbuilder/index.phtml
+++ b/airtime_mvc/application/views/scripts/showbuilder/index.phtml
@@ -11,9 +11,9 @@
 <div id="show_builder" class="sb-content ui-widget ui-widget-content block-shadow omega-block padded">
     <div class="sb-timerange">
         <?php if(!$this->disableLib && !$this->showLib):?>
-        <div id="sb_edit" class="ui-button ui-state-default" title="open the library to schedule files.">
-            <span class="ui-icon ui-icon-arrowthick-1-nw"></span>
-        </div> 
+        <a id="sb_edit" class="btn btn-small" href="#" title="open the library to schedule files.">
+            Schedule files
+        </a> 
         <?php endif; ?>
     <?php echo $this->sb_form; ?>
     </div>
diff --git a/airtime_mvc/public/css/media_library.css b/airtime_mvc/public/css/media_library.css
index 3b0db5046..06120698d 100644
--- a/airtime_mvc/public/css/media_library.css
+++ b/airtime_mvc/public/css/media_library.css
@@ -146,7 +146,7 @@ td.library_bitrate {
 			}
 
 
-.fg-toolbar .btn-toolbar {margin: 6px 5px 6px 2px;}
+.fg-toolbar .btn-toolbar {margin: 6px 5px -6px 5px;}
 
 
 /* ///////////////////// ADVANCED SEARCH ///////////////////// */
diff --git a/airtime_mvc/public/js/airtime/buttons/buttons.js b/airtime_mvc/public/js/airtime/buttons/buttons.js
index 7af88e352..23a904001 100644
--- a/airtime_mvc/public/js/airtime/buttons/buttons.js
+++ b/airtime_mvc/public/js/airtime/buttons/buttons.js
@@ -1,39 +1,45 @@
-var AIRTIME = (function(AIRTIME){
-	var mod,
-		DEFAULT_CLASS = 'ui-button ui-state-default',
-		DISABLED_CLASS = 'ui-state-disabled';
-	
-	if (AIRTIME.button === undefined) {
-		AIRTIME.button = {};
-	}
-	mod = AIRTIME.button;
-	
-	mod.isDisabled = function(c) {
-		var button = $("."+c);
-		
-	    if (button.hasClass(DISABLED_CLASS)) {
-	        return true;
-	    }
-	    
-	    return false;
-	};
-	
-	mod.enableButton = function(c) {
-		var button = $("."+c);
-		
-	    if (button.hasClass(DISABLED_CLASS)) {
-	        button.removeClass(DISABLED_CLASS);
-	    }
-	};
+var AIRTIME = (function(AIRTIME) {
+    var mod, DEFAULT_CLASS = 'ui-button ui-state-default', DISABLED_CLASS = 'ui-state-disabled';
+
+    if (AIRTIME.button === undefined) {
+        AIRTIME.button = {};
+    }
+    mod = AIRTIME.button;
+
+    mod.isDisabled = function(c) {
+        var button = $("." + c);
+
+        if (button.hasClass(DISABLED_CLASS)) {
+            return true;
+        }
+
+        return false;
+    };
+
+    mod.enableButton = function(c, useParent) {
+        if (useParent) {
+            var button = $("." + c).parent();
+        } else {
+            var button = $("." + c);
+        }
+
+        if (button.hasClass(DISABLED_CLASS)) {
+            button.removeClass(DISABLED_CLASS);
+        }
+    };
+
+    mod.disableButton = function(c, useParent) {
+        if (useParent) {
+            var button = $("." + c).parent();
+        } else {
+            var button = $("." + c);
+        }
+
+        if (!button.hasClass(DISABLED_CLASS)) {
+            button.addClass(DISABLED_CLASS);
+        }
+    };
+
+    return AIRTIME;
 
-	mod.disableButton = function(c) {
-		var button = $("."+c);
-		
-	    if (!button.hasClass(DISABLED_CLASS)) {
-	        button.addClass(DISABLED_CLASS);
-	    }
-	};
-	
-	return AIRTIME;
-	
 }(AIRTIME || {}));
\ No newline at end of file
diff --git a/airtime_mvc/public/js/airtime/library/spl.js b/airtime_mvc/public/js/airtime/library/spl.js
index 4cc478f6a..11d5221c6 100644
--- a/airtime_mvc/public/js/airtime/library/spl.js
+++ b/airtime_mvc/public/js/airtime/library/spl.js
@@ -307,6 +307,7 @@ var AIRTIME = (function(AIRTIME){
 	    setCueEvents();
 	    setFadeEvents();
 		setModified(json.modified);
+		AIRTIME.playlist.validatePlaylistElements();
 		redrawLib();
 	}
 	
@@ -409,8 +410,6 @@ var AIRTIME = (function(AIRTIME){
 		
 		$pl.delegate(".spl_cue", 
 				{"click": openCueEditor});
-
-        mod.validatePlaylistElements();
     		
 		$pl.delegate(".spl_block_expand",
 		        {"click": function(ev){
@@ -773,6 +772,7 @@ var AIRTIME = (function(AIRTIME){
 		}());
 
 		$pl.find("#spl_sortable").sortable(sortableConf);
+		AIRTIME.playlist.validatePlaylistElements();
 	}
 	
 	mod.fnNew = function() {
diff --git a/airtime_mvc/public/js/airtime/showbuilder/builder.js b/airtime_mvc/public/js/airtime/showbuilder/builder.js
index 8af595775..942bfbf0d 100644
--- a/airtime_mvc/public/js/airtime/showbuilder/builder.js
+++ b/airtime_mvc/public/js/airtime/showbuilder/builder.js
@@ -66,10 +66,10 @@ var AIRTIME = (function(AIRTIME){
         var $selectable = $sbTable.find("tbody").find("input:checkbox");
         
         if ($selectable.length !== 0) {
-            AIRTIME.button.enableButton("sb-button-select");
+            AIRTIME.button.enableButton("btn-group #timeline-select", true);
         }
         else {
-            AIRTIME.button.disableButton("sb-button-select");
+            AIRTIME.button.disableButton("btn-group #timeline-select", true);
         }
     };
     
@@ -77,10 +77,10 @@ var AIRTIME = (function(AIRTIME){
         var $over = $sbTable.find(".sb-over.sb-allowed");
         
         if ($over.length !== 0) {
-            AIRTIME.button.enableButton("sb-button-trim");
+            AIRTIME.button.enableButton("icon-cut", true);
         }
         else {
-            AIRTIME.button.disableButton("sb-button-trim");
+            AIRTIME.button.disableButton("icon-cut", true);
         }
     };
     
@@ -88,10 +88,10 @@ var AIRTIME = (function(AIRTIME){
         var $selected = $sbTable.find("tbody").find("input:checkbox").filter(":checked");
         
         if ($selected.length !== 0) {
-            AIRTIME.button.enableButton("sb-button-delete");
+            AIRTIME.button.enableButton("icon-trash", true);
         }
         else {
-            AIRTIME.button.disableButton("sb-button-delete");
+            AIRTIME.button.disableButton("icon-trash", true);
         }
     };
     
@@ -99,10 +99,10 @@ var AIRTIME = (function(AIRTIME){
         var $current = $sbTable.find("."+NOW_PLAYING_CLASS);
         
         if ($current.length !== 0) {
-            AIRTIME.button.enableButton("sb-button-current");
+            AIRTIME.button.enableButton("icon-step-forward", true);
         }
         else {
-            AIRTIME.button.disableButton("sb-button-current");
+            AIRTIME.button.disableButton("icon-step-forward", true);
         }
     };
     
@@ -113,10 +113,10 @@ var AIRTIME = (function(AIRTIME){
             userType = localStorage.getItem('user-type');
         
         if ($current.length !== 0 && (userType === 'A' || userType === 'P')) {
-            AIRTIME.button.enableButton("sb-button-cancel");
+            AIRTIME.button.enableButton("icon-ban-circle", true);
         }
         else {
-            AIRTIME.button.disableButton("sb-button-cancel");
+            AIRTIME.button.disableButton("icon-ban-circle", true);
         }
     };
     
@@ -333,15 +333,15 @@ var AIRTIME = (function(AIRTIME){
         /*
          * Icon hover states in the toolbar.
          */
-        $sbContent.on("mouseenter", ".fg-toolbar ul li", function(ev) {
+        $sbContent.on("mouseenter", "#timeline-select .dropdown-toggle", function(ev) {
             $el = $(this);
             
             if (!$el.hasClass("ui-state-disabled")) {
                 $el.addClass("ui-state-hover");
-                $("#show_builder .ui-icon-document-b").contextMenu(true);
+                $("#timeline-select .caret").contextMenu(true);
             }
             else {
-                $("#show_builder .ui-icon-document-b").contextMenu(false);
+                $("#timeline-select .caret").contextMenu(false);
             }       
         });
         $sbContent.on("mouseleave", ".fg-toolbar ul li", function(ev) {
@@ -958,37 +958,44 @@ var AIRTIME = (function(AIRTIME){
         
         //start setup of the builder toolbar.
         $toolbar = $(".sb-content .fg-toolbar");
+
+        $menu = $("<div class='btn-toolbar'/>");
+        $menu.append("<div class='btn-group'>" +
+                     "<button class='btn btn-small dropdown-toggle'  id='timeline-select' data-toggle='dropdown'>" +
+                         "Select <span class='caret'></span>" +
+                     "</button>" +
+                     "<ul class='dropdown-menu'>" +
+                         "<li id='timeline-sa'><a href='#'>Select all</a></li>" +
+                         "<li id='timeline-sn'><a href='#'>Select none</a></li>" +
+                     "</ul>" +
+                     "</div>")
+            .append("<div class='btn-group'>" +
+                    "<button title='Remove overbooked tracks' class='ui-state-disabled btn btn-small'>" +
+                    "<i class='icon-white icon-cut'></i></button></div>")
+            .append("<div class='btn-group'>" +
+                    "<button title='Remove selected scheduled items' class='ui-state-disabled btn btn-small'>" +
+                    "<i class='icon-white icon-trash'></i></button></div>")
+            .append("<div class='btn-group'>" +
+                    "<button  title='Jump to the current playing track' class='ui-state-disabled btn btn-small'>" +
+                    "<i class='icon-white icon-step-forward'></i></button></div>")
+            .append("<div class='btn-group'>" +
+                    "<button title='Cancel current show' class='ui-state-disabled btn btn-small btn-danger'>" +
+                    "<i class='icon-white icon-ban-circle'></i></button></div>");
+
+        $toolbar.append($menu);
+        $menu = undefined;
         
-        $ul = $("<ul/>");
-        $ul.append('<li class="ui-state-default sb-button-select" title="Select"><span class="ui-icon ui-icon-document-b"></span></li>')
-            .append('<li class="ui-state-default ui-state-disabled sb-button-trim" title="Remove all overbooked tracks"><span class="ui-icon ui-icon-scissors"></span></li>')
-            .append('<li class="ui-state-default ui-state-disabled sb-button-delete" title="Remove selected scheduled items"><span class="ui-icon ui-icon-trash"></span></li>');    
-        $toolbar.append($ul);
+        $('#timeline-sa').click(function(){mod.selectAll();});
+        $('#timeline-sn').click(function(){mod.selectNone();});
         
-        $ul = $("<ul/>");
-        $ul.append('<li class="ui-state-default ui-state-disabled sb-button-current" title="Jump to the currently playing track"><span class="ui-icon ui-icon-arrowstop-1-s"></span></li>')
-            .append('<li class="ui-state-default ui-state-disabled sb-button-cancel" title="Cancel current show"><span class="ui-icon ui-icon-eject"></span></li>');
-        $toolbar.append($ul);
-        $ul = undefined;
-        
-        $.contextMenu({
-            selector: '#show_builder .ui-icon-document-b',
-            trigger: "left",
-            ignoreRightClick: true,
-            items: {
-                "sa": {name: "Select All", callback: mod.selectAll},
-                "sn": {name: "Select None", callback: mod.selectNone}
-            }
-        });
-        
-        //jump to current
-        $toolbar.find('.sb-button-cancel')
+        //cancel current show
+        $toolbar.find('.icon-ban-circle')
             .click(function() {
                 var $tr,
                     data,
                     msg = 'Cancel Current Show?';
                 
-                if (AIRTIME.button.isDisabled('sb-button-cancel') === true) {
+                if (AIRTIME.button.isDisabled('icon-ban-circle') === true) {
                     return;
                 }
                 
@@ -1016,10 +1023,10 @@ var AIRTIME = (function(AIRTIME){
             });
         
         //jump to current
-        $toolbar.find('.sb-button-current')
+        $toolbar.find('.icon-step-forward')
             .click(function() {
                 
-                if (AIRTIME.button.isDisabled('sb-button-current') === true) {
+                if (AIRTIME.button.isDisabled('icon-step-forward') === true) {
                     return;
                 }
                 
@@ -1033,10 +1040,10 @@ var AIRTIME = (function(AIRTIME){
             });
         
         //delete overbooked tracks.
-        $toolbar.find('.sb-button-trim')
+        $toolbar.find('.icon-cut')
             .click(function() {
                 
-                if (AIRTIME.button.isDisabled('sb-button-trim') === true) {
+                if (AIRTIME.button.isDisabled('icon-cut') === true) {
                     return;
                 }
                 
@@ -1053,10 +1060,10 @@ var AIRTIME = (function(AIRTIME){
             });
         
         //delete selected tracks
-        $toolbar.find('.sb-button-delete')
+        $toolbar.find('.icon-trash')
             .click(function() {
                 
-                if (AIRTIME.button.isDisabled('sb-button-delete') === true) {
+                if (AIRTIME.button.isDisabled('icon-trash') === true) {
                     return;
                 }
                 
diff --git a/airtime_mvc/public/js/airtime/showbuilder/main_builder.js b/airtime_mvc/public/js/airtime/showbuilder/main_builder.js
index 7f02199c8..dc286f5da 100644
--- a/airtime_mvc/public/js/airtime/showbuilder/main_builder.js
+++ b/airtime_mvc/public/js/airtime/showbuilder/main_builder.js
@@ -15,7 +15,7 @@ AIRTIME = (function(AIRTIME) {
 		timeStartId = "#sb_time_start",
 		dateEndId = "#sb_date_end",
 		timeEndId = "#sb_time_end",
-		$toggleLib = $('<div id="sb_edit" class="ui-button ui-state-default" title="open the library to schedule files."><span class="ui-icon ui-icon-arrowthick-1-nw"></span></div>'),
+		$toggleLib = $("<a id='sb_edit' class='btn btn-small' href='#' title='Open library to schedule files'>Schedule files</a>"),
 		$libClose = $('<a />', {
 			"class": "close-round",
 			"href": "#",
diff --git a/airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README b/airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README_COLUMN_FILTER
similarity index 100%
rename from airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README
rename to airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README_COLUMN_FILTER
diff --git a/airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README_COL_VIS b/airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README_COL_VIS
new file mode 100644
index 000000000..c332d036e
--- /dev/null
+++ b/airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README_COL_VIS
@@ -0,0 +1,33 @@
+Before you overwrite dataTables.ColVis.js, note that we have changed a few lines
+in this file.
+
+The following function has been modified:
+
+_fnDomBaseButton
+
+The new _fnDomBaseButton looks like this:
+
+    "_fnDomBaseButton": function ( text )
+    {
+        var
+            that = this,
+            nButton = document.createElement('button'),
+            nSpan = document.createElement('span'),
+            sEvent = this.s.activate=="mouseover" ? "mouseover" : "click";
+        
+        //nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
+            //"ColVis_Button TableTools_Button ui-button ui-state-default";
+        nButton.className = "btn-toolbar btn btn-small dropdown-toggle ColVis_MasterButton";
+        
+        nButton.appendChild( nSpan );
+        $(nButton).append("<span class='caret'></span>");
+        nSpan.innerHTML = text;
+        
+        $(nButton).bind( 'click', function (e) {
+            that._fnCollectionShow();
+            e.preventDefault();
+        } );
+        
+        return nButton;
+    },
+    
\ No newline at end of file
diff --git a/airtime_mvc/public/js/datatables/plugin/dataTables.ColVis.js b/airtime_mvc/public/js/datatables/plugin/dataTables.ColVis.js
index 19d91d39b..2f1c8ed02 100644
--- a/airtime_mvc/public/js/datatables/plugin/dataTables.ColVis.js
+++ b/airtime_mvc/public/js/datatables/plugin/dataTables.ColVis.js
@@ -29,861 +29,864 @@
  */
 ColVis = function( oDTSettings, oInit )
 {
-	/* Santiy check that we are a new instance */
-	if ( !this.CLASS || this.CLASS != "ColVis" )
-	{
-		alert( "Warning: ColVis must be initialised with the keyword 'new'" );
-	}
-	
-	if ( typeof oInit == 'undefined' )
-	{
-		oInit = {};
-	}
-	
-	
-	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-	 * Public class variables
-	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-	
-	/**
-	 * @namespace Settings object which contains customisable information for ColVis instance
-	 */
-	this.s = {
-		/**
-		 * DataTables settings object
-		 *  @property dt
-		 *  @type     Object
-		 *  @default  null
-		 */
-		"dt": null,
-		
-		/**
-		 * Customisation object
-		 *  @property oInit
-		 *  @type     Object
-		 *  @default  passed in
-		 */
-		"oInit": oInit,
-		
-		/**
-		 * Callback function to tell the user when the state has changed
-		 *  @property fnStateChange
-		 *  @type     function
-		 *  @default  null
-		 */
-		"fnStateChange": null,
-		
-		/**
-		 * Mode of activation. Can be 'click' or 'mouseover'
-		 *  @property activate
-		 *  @type     String
-		 *  @default  click
-		 */
-		"activate": "click",
-		
-		/**
-		 * Position of the collection menu when shown - align "left" or "right"
-		 *  @property sAlign
-		 *  @type     String
-		 *  @default  right
-		 */
-		"sAlign": "left",
-		
-		/**
-		 * Text used for the button
-		 *  @property buttonText
-		 *  @type     String
-		 *  @default  Show / hide columns
-		 */
-		"buttonText": "Show / hide columns",
-		
-		/**
-		 * Flag to say if the collection is hidden
-		 *  @property hidden
-		 *  @type     boolean
-		 *  @default  true
-		 */
-		"hidden": true,
-		
-		/**
-		 * List of columns (integers) which should be excluded from the list
-		 *  @property aiExclude
-		 *  @type     Array
-		 *  @default  []
-		 */
-		"aiExclude": [],
-		
-		/**
-		 * Store the original viisbility settings so they could be restored
-		 *  @property abOriginal
-		 *  @type     Array
-		 *  @default  []
-		 */
-		"abOriginal": [],
-		
-		/**
-		 * Show Show-All button
-		 *  @property bShowAll
-		 *  @type     Array
-		 *  @default  []
-		 */
-		"bShowAll": false,
-		
-		/**
-		 * Show All button text
-		 *  @property sShowAll
-		 *  @type     String
-		 *  @default  Restore original
-		 */
-		"sShowAll": "Show All",
-		
-		/**
-		 * Show restore button
-		 *  @property bRestore
-		 *  @type     Array
-		 *  @default  []
-		 */
-		"bRestore": false,
-		
-		/**
-		 * Restore button text
-		 *  @property sRestore
-		 *  @type     String
-		 *  @default  Restore original
-		 */
-		"sRestore": "Restore original",
-		
-		/**
-		 * Overlay animation duration in mS
-		 *  @property iOverlayFade
-		 *  @type     Integer
-		 *  @default  500
-		 */
-		"iOverlayFade": 500,
-		
-		/**
-		 * Label callback for column names. Takes three parameters: 1. the column index, 2. the column
-		 * title detected by DataTables and 3. the TH node for the column
-		 *  @property fnLabel
-		 *  @type     Function
-		 *  @default  null
-		 */
-		"fnLabel": null,
-		
-		/**
-		 * Indicate if ColVis should automatically calculate the size of buttons or not. The default
-		 * is for it to do so. Set to "css" to disable the automatic sizing
-		 *  @property sSize
-		 *  @type     String
-		 *  @default  auto
-		 */
-		"sSize": "auto",
-		
-		/**
-		 * Indicate if the column list should be positioned by Javascript, visually below the button
-		 * or allow CSS to do the positioning
-		 *  @property bCssPosition
-		 *  @type     boolean
-		 *  @default  false
-		 */
-		"bCssPosition": false
-	};
-	
-	
-	/**
-	 * @namespace Common and useful DOM elements for the class instance
-	 */
-	this.dom = {
-		/**
-		 * Wrapper for the button - given back to DataTables as the node to insert
-		 *  @property wrapper
-		 *  @type     Node
-		 *  @default  null
-		 */
-		"wrapper": null,
-		
-		/**
-		 * Activation button
-		 *  @property button
-		 *  @type     Node
-		 *  @default  null
-		 */
-		"button": null,
-		
-		/**
-		 * Collection list node
-		 *  @property collection
-		 *  @type     Node
-		 *  @default  null
-		 */
-		"collection": null,
-		
-		/**
-		 * Background node used for shading the display and event capturing
-		 *  @property background
-		 *  @type     Node
-		 *  @default  null
-		 */
-		"background": null,
-		
-		/**
-		 * Element to position over the activation button to catch mouse events when using mouseover
-		 *  @property catcher
-		 *  @type     Node
-		 *  @default  null
-		 */
-		"catcher": null,
-		
-		/**
-		 * List of button elements
-		 *  @property buttons
-		 *  @type     Array
-		 *  @default  []
-		 */
-		"buttons": [],
-		
-		/**
-		 * Restore button
-		 *  @property restore
-		 *  @type     Node
-		 *  @default  null
-		 */
-		"restore": null
-	};
-	
-	/* Store global reference */
-	ColVis.aInstances.push( this );
-	
-	/* Constructor logic */
-	this.s.dt = oDTSettings;
-	this._fnConstruct();
-	return this;
+    /* Santiy check that we are a new instance */
+    if ( !this.CLASS || this.CLASS != "ColVis" )
+    {
+        alert( "Warning: ColVis must be initialised with the keyword 'new'" );
+    }
+    
+    if ( typeof oInit == 'undefined' )
+    {
+        oInit = {};
+    }
+    
+    
+    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+     * Public class variables
+     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+    
+    /**
+     * @namespace Settings object which contains customisable information for ColVis instance
+     */
+    this.s = {
+        /**
+         * DataTables settings object
+         *  @property dt
+         *  @type     Object
+         *  @default  null
+         */
+        "dt": null,
+        
+        /**
+         * Customisation object
+         *  @property oInit
+         *  @type     Object
+         *  @default  passed in
+         */
+        "oInit": oInit,
+        
+        /**
+         * Callback function to tell the user when the state has changed
+         *  @property fnStateChange
+         *  @type     function
+         *  @default  null
+         */
+        "fnStateChange": null,
+        
+        /**
+         * Mode of activation. Can be 'click' or 'mouseover'
+         *  @property activate
+         *  @type     String
+         *  @default  click
+         */
+        "activate": "click",
+        
+        /**
+         * Position of the collection menu when shown - align "left" or "right"
+         *  @property sAlign
+         *  @type     String
+         *  @default  right
+         */
+        "sAlign": "left",
+        
+        /**
+         * Text used for the button
+         *  @property buttonText
+         *  @type     String
+         *  @default  Show / hide columns
+         */
+        "buttonText": "Show / hide columns",
+        
+        /**
+         * Flag to say if the collection is hidden
+         *  @property hidden
+         *  @type     boolean
+         *  @default  true
+         */
+        "hidden": true,
+        
+        /**
+         * List of columns (integers) which should be excluded from the list
+         *  @property aiExclude
+         *  @type     Array
+         *  @default  []
+         */
+        "aiExclude": [],
+        
+        /**
+         * Store the original viisbility settings so they could be restored
+         *  @property abOriginal
+         *  @type     Array
+         *  @default  []
+         */
+        "abOriginal": [],
+        
+        /**
+         * Show Show-All button
+         *  @property bShowAll
+         *  @type     Array
+         *  @default  []
+         */
+        "bShowAll": false,
+        
+        /**
+         * Show All button text
+         *  @property sShowAll
+         *  @type     String
+         *  @default  Restore original
+         */
+        "sShowAll": "Show All",
+        
+        /**
+         * Show restore button
+         *  @property bRestore
+         *  @type     Array
+         *  @default  []
+         */
+        "bRestore": false,
+        
+        /**
+         * Restore button text
+         *  @property sRestore
+         *  @type     String
+         *  @default  Restore original
+         */
+        "sRestore": "Restore original",
+        
+        /**
+         * Overlay animation duration in mS
+         *  @property iOverlayFade
+         *  @type     Integer
+         *  @default  500
+         */
+        "iOverlayFade": 500,
+        
+        /**
+         * Label callback for column names. Takes three parameters: 1. the column index, 2. the column
+         * title detected by DataTables and 3. the TH node for the column
+         *  @property fnLabel
+         *  @type     Function
+         *  @default  null
+         */
+        "fnLabel": null,
+        
+        /**
+         * Indicate if ColVis should automatically calculate the size of buttons or not. The default
+         * is for it to do so. Set to "css" to disable the automatic sizing
+         *  @property sSize
+         *  @type     String
+         *  @default  auto
+         */
+        "sSize": "auto",
+        
+        /**
+         * Indicate if the column list should be positioned by Javascript, visually below the button
+         * or allow CSS to do the positioning
+         *  @property bCssPosition
+         *  @type     boolean
+         *  @default  false
+         */
+        "bCssPosition": false
+    };
+    
+    
+    /**
+     * @namespace Common and useful DOM elements for the class instance
+     */
+    this.dom = {
+        /**
+         * Wrapper for the button - given back to DataTables as the node to insert
+         *  @property wrapper
+         *  @type     Node
+         *  @default  null
+         */
+        "wrapper": null,
+        
+        /**
+         * Activation button
+         *  @property button
+         *  @type     Node
+         *  @default  null
+         */
+        "button": null,
+        
+        /**
+         * Collection list node
+         *  @property collection
+         *  @type     Node
+         *  @default  null
+         */
+        "collection": null,
+        
+        /**
+         * Background node used for shading the display and event capturing
+         *  @property background
+         *  @type     Node
+         *  @default  null
+         */
+        "background": null,
+        
+        /**
+         * Element to position over the activation button to catch mouse events when using mouseover
+         *  @property catcher
+         *  @type     Node
+         *  @default  null
+         */
+        "catcher": null,
+        
+        /**
+         * List of button elements
+         *  @property buttons
+         *  @type     Array
+         *  @default  []
+         */
+        "buttons": [],
+        
+        /**
+         * Restore button
+         *  @property restore
+         *  @type     Node
+         *  @default  null
+         */
+        "restore": null
+    };
+    
+    /* Store global reference */
+    ColVis.aInstances.push( this );
+    
+    /* Constructor logic */
+    this.s.dt = oDTSettings;
+    this._fnConstruct();
+    return this;
 };
 
 
 
 ColVis.prototype = {
-	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-	 * Public methods
-	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-	
-	/**
-	 * Rebuild the list of buttons for this instance (i.e. if there is a column header update)
-	 *  @method  fnRebuild
-	 *  @returns void
-	 */
-	"fnRebuild": function ()
-	{
-		/* Remove the old buttons */
-		for ( var i=this.dom.buttons.length-1 ; i>=0 ; i-- )
-		{
-			if ( this.dom.buttons[i] !== null )
-			{
-				this.dom.collection.removeChild( this.dom.buttons[i] );
-			}
-		}
-		this.dom.buttons.splice( 0, this.dom.buttons.length );
-		
-		if ( this.dom.restore )
-		{
-			this.dom.restore.parentNode( this.dom.restore );
-		}
-		
-		/* Re-add them (this is not the optimal way of doing this, it is fast and effective) */
-		this._fnAddButtons();
-		
-		/* Update the checkboxes */
-		this._fnDrawCallback();
-	},
-	
-	
-	
-	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-	 * Private methods (they are of course public in JS, but recommended as private)
-	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-	
-	/**
-	 * Constructor logic
-	 *  @method  _fnConstruct
-	 *  @returns void
-	 *  @private 
-	 */
-	"_fnConstruct": function ()
-	{
-		this._fnApplyCustomisation();
-		
-		var that = this;
-		this.dom.wrapper = document.createElement('div');
-		this.dom.wrapper.className = "ColVis TableTools";
-		
-		this.dom.button = this._fnDomBaseButton( this.s.buttonText );
-		this.dom.button.className += " ColVis_MasterButton";
-		this.dom.wrapper.appendChild( this.dom.button );
-		
-		this.dom.catcher = this._fnDomCatcher();
-		this.dom.collection = this._fnDomCollection();
-		this.dom.background = this._fnDomBackground();
-		
-		this._fnAddButtons();
-		
-		/* Store the original visbility information */
-		for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
-		{
-			this.s.abOriginal.push( this.s.dt.aoColumns[i].bVisible );
-		}
-		
-		/* Update on each draw */
-		this.s.dt.aoDrawCallback.push( {
-			"fn": function () {
-				that._fnDrawCallback.call( that );
-			},
-			"sName": "ColVis"
-		} );
-	},
-	
-	
-	/**
-	 * Apply any customisation to the settings from the DataTables initialisation
-	 *  @method  _fnApplyCustomisation
-	 *  @returns void
-	 *  @private 
-	 */
-	"_fnApplyCustomisation": function ()
-	{
-		var oConfig = this.s.oInit;
-		
-		if ( typeof oConfig.activate != 'undefined' )
-		{
-			this.s.activate = oConfig.activate;
-		}
-		
-		if ( typeof oConfig.buttonText != 'undefined' )
-		{
-			this.s.buttonText = oConfig.buttonText;
-		}
-		
-		if ( typeof oConfig.aiExclude != 'undefined' )
-		{
-			this.s.aiExclude = oConfig.aiExclude;
-		}
-		
-		if ( typeof oConfig.bRestore != 'undefined' )
-		{
-			this.s.bRestore = oConfig.bRestore;
-		}
-		
-		if ( typeof oConfig.sRestore != 'undefined' )
-		{
-			this.s.sRestore = oConfig.sRestore;
-		}
-		
-		if ( typeof oConfig.bShowAll != 'undefined' )
-		{
-			this.s.bShowAll = oConfig.bShowAll;
-		}
-		
-		if ( typeof oConfig.sShowAll != 'undefined' )
-		{
-			this.s.sShowAll = oConfig.sShowAll;
-		}
-		
-		if ( typeof oConfig.sAlign != 'undefined' )
-		{
-			this.s.sAlign = oConfig.sAlign;
-		}
-		
-		if ( typeof oConfig.fnStateChange != 'undefined' )
-		{
-			this.s.fnStateChange = oConfig.fnStateChange;
-		}
-		
-		if ( typeof oConfig.iOverlayFade != 'undefined' )
-		{
-			this.s.iOverlayFade = oConfig.iOverlayFade;
-		}
-		
-		if ( typeof oConfig.fnLabel != 'undefined' )
-		{
-			this.s.fnLabel = oConfig.fnLabel;
-		}
-		
-		if ( typeof oConfig.sSize != 'undefined' )
-		{
-			this.s.sSize = oConfig.sSize;
-		}
+    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+     * Public methods
+     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+    
+    /**
+     * Rebuild the list of buttons for this instance (i.e. if there is a column header update)
+     *  @method  fnRebuild
+     *  @returns void
+     */
+    "fnRebuild": function ()
+    {
+        /* Remove the old buttons */
+        for ( var i=this.dom.buttons.length-1 ; i>=0 ; i-- )
+        {
+            if ( this.dom.buttons[i] !== null )
+            {
+                this.dom.collection.removeChild( this.dom.buttons[i] );
+            }
+        }
+        this.dom.buttons.splice( 0, this.dom.buttons.length );
+        
+        if ( this.dom.restore )
+        {
+            this.dom.restore.parentNode( this.dom.restore );
+        }
+        
+        /* Re-add them (this is not the optimal way of doing this, it is fast and effective) */
+        this._fnAddButtons();
+        
+        /* Update the checkboxes */
+        this._fnDrawCallback();
+    },
+    
+    
+    
+    /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+     * Private methods (they are of course public in JS, but recommended as private)
+     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+    
+    /**
+     * Constructor logic
+     *  @method  _fnConstruct
+     *  @returns void
+     *  @private 
+     */
+    "_fnConstruct": function ()
+    {
+        this._fnApplyCustomisation();
+        
+        var that = this;
+        this.dom.wrapper = document.createElement('div');
+        this.dom.wrapper.className = "ColVis TableTools";
+        
+        this.dom.button = this._fnDomBaseButton( this.s.buttonText );
+        this.dom.button.className += " ColVis_MasterButton";
+        this.dom.wrapper.appendChild( this.dom.button );
+        
+        this.dom.catcher = this._fnDomCatcher();
+        this.dom.collection = this._fnDomCollection();
+        this.dom.background = this._fnDomBackground();
+        
+        this._fnAddButtons();
+        
+        /* Store the original visbility information */
+        for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
+        {
+            this.s.abOriginal.push( this.s.dt.aoColumns[i].bVisible );
+        }
+        
+        /* Update on each draw */
+        this.s.dt.aoDrawCallback.push( {
+            "fn": function () {
+                that._fnDrawCallback.call( that );
+            },
+            "sName": "ColVis"
+        } );
+    },
+    
+    
+    /**
+     * Apply any customisation to the settings from the DataTables initialisation
+     *  @method  _fnApplyCustomisation
+     *  @returns void
+     *  @private 
+     */
+    "_fnApplyCustomisation": function ()
+    {
+        var oConfig = this.s.oInit;
+        
+        if ( typeof oConfig.activate != 'undefined' )
+        {
+            this.s.activate = oConfig.activate;
+        }
+        
+        if ( typeof oConfig.buttonText != 'undefined' )
+        {
+            this.s.buttonText = oConfig.buttonText;
+        }
+        
+        if ( typeof oConfig.aiExclude != 'undefined' )
+        {
+            this.s.aiExclude = oConfig.aiExclude;
+        }
+        
+        if ( typeof oConfig.bRestore != 'undefined' )
+        {
+            this.s.bRestore = oConfig.bRestore;
+        }
+        
+        if ( typeof oConfig.sRestore != 'undefined' )
+        {
+            this.s.sRestore = oConfig.sRestore;
+        }
+        
+        if ( typeof oConfig.bShowAll != 'undefined' )
+        {
+            this.s.bShowAll = oConfig.bShowAll;
+        }
+        
+        if ( typeof oConfig.sShowAll != 'undefined' )
+        {
+            this.s.sShowAll = oConfig.sShowAll;
+        }
+        
+        if ( typeof oConfig.sAlign != 'undefined' )
+        {
+            this.s.sAlign = oConfig.sAlign;
+        }
+        
+        if ( typeof oConfig.fnStateChange != 'undefined' )
+        {
+            this.s.fnStateChange = oConfig.fnStateChange;
+        }
+        
+        if ( typeof oConfig.iOverlayFade != 'undefined' )
+        {
+            this.s.iOverlayFade = oConfig.iOverlayFade;
+        }
+        
+        if ( typeof oConfig.fnLabel != 'undefined' )
+        {
+            this.s.fnLabel = oConfig.fnLabel;
+        }
+        
+        if ( typeof oConfig.sSize != 'undefined' )
+        {
+            this.s.sSize = oConfig.sSize;
+        }
 
-		if ( typeof oConfig.bCssPosition != 'undefined' )
-		{
-			this.s.bCssPosition = oConfig.bCssPosition;
-		}
-	},
-	
-	
-	/**
-	 * On each table draw, check the visiblity checkboxes as needed. This allows any process to
-	 * update the table's column visiblity and ColVis will still be accurate.
-	 *  @method  _fnDrawCallback
-	 *  @returns void
-	 *  @private 
-	 */
-	"_fnDrawCallback": function ()
-	{
-		var aoColumns = this.s.dt.aoColumns;
-		
-		for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
-		{
-			if ( this.dom.buttons[i] !== null )
-			{
-				if ( aoColumns[i].bVisible )
-				{
-					$('input', this.dom.buttons[i]).attr('checked','checked');
-				}
-				else
-				{
-					$('input', this.dom.buttons[i]).removeAttr('checked');
-				}
-			}
-		}
-	},
-	
-	
-	/**
-	 * Loop through the columns in the table and as a new button for each one.
-	 *  @method  _fnAddButtons
-	 *  @returns void
-	 *  @private 
-	 */
-	"_fnAddButtons": function ()
-	{
-		var
-			nButton,
-			sExclude = ","+this.s.aiExclude.join(',')+",";
-		
-		for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
-		{
-			if ( sExclude.indexOf( ","+i+"," ) == -1 )
-			{
-				nButton = this._fnDomColumnButton( i );
-				this.dom.buttons.push( nButton );
-				this.dom.collection.appendChild( nButton );
-			}
-			else
-			{
-				this.dom.buttons.push( null );
-			}
-		}
-		
-		if ( this.s.bRestore )
-		{
-			nButton = this._fnDomRestoreButton();
-			nButton.className += " ColVis_Restore";
-			this.dom.buttons.push( nButton );
-			this.dom.collection.appendChild( nButton );
-		}
-		
-		if ( this.s.bShowAll )
-		{
-			nButton = this._fnDomShowAllButton();
-			nButton.className += " ColVis_ShowAll";
-			this.dom.buttons.push( nButton );
-			this.dom.collection.appendChild( nButton );
-		}
-	},
-	
-	
-	/**
-	 * Create a button which allows a "restore" action
-	 *  @method  _fnDomRestoreButton
-	 *  @returns {Node} Created button
-	 *  @private 
-	 */
-	"_fnDomRestoreButton": function ()
-	{
-		var
-			that = this,
-			nButton = document.createElement('button'),
-			nSpan = document.createElement('span');
-		
-		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
-			"ColVis_Button TableTools_Button ui-button ui-state-default";
-		nButton.appendChild( nSpan );
-		$(nSpan).html( '<span class="ColVis_title">'+this.s.sRestore+'</span>' );
-		
-		$(nButton).click( function (e) {
-			for ( var i=0, iLen=that.s.abOriginal.length ; i<iLen ; i++ )
-			{
-				that.s.dt.oInstance.fnSetColumnVis( i, that.s.abOriginal[i], false );
-			}
-			that._fnAdjustOpenRows();
-			that.s.dt.oInstance.fnDraw( false );
-		} );
-		
-		return nButton;
-	},
-	
-	
-	/**
-	 * Create a button which allows a "show all" action
-	 *  @method  _fnDomShowAllButton
-	 *  @returns {Node} Created button
-	 *  @private 
-	 */
-	"_fnDomShowAllButton": function ()
-	{
-		var
-			that = this,
-			nButton = document.createElement('button'),
-			nSpan = document.createElement('span');
-		
-		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
-			"ColVis_Button TableTools_Button ui-button ui-state-default";
-		nButton.appendChild( nSpan );
-		$(nSpan).html( '<span class="ColVis_title">'+this.s.sShowAll+'</span>' );
-		
-		$(nButton).click( function (e) {
-			for ( var i=0, iLen=that.s.abOriginal.length ; i<iLen ; i++ )
-			{
-				if (that.s.aiExclude.indexOf(i) === -1)
-				{
-					that.s.dt.oInstance.fnSetColumnVis( i, true, false );
-				}
-			}
-			that._fnAdjustOpenRows();
-			that.s.dt.oInstance.fnDraw( false );
-		} );
-		
-		return nButton;
-	},
-	
-	
-	/**
-	 * Create the DOM for a show / hide button
-	 *  @method  _fnDomColumnButton
-	 *  @param {int} i Column in question
-	 *  @returns {Node} Created button
-	 *  @private 
-	 */
-	"_fnDomColumnButton": function ( i )
-	{
-		var
-			that = this,
-			oColumn = this.s.dt.aoColumns[i],
-			nButton = document.createElement('button'),
-			nSpan = document.createElement('span'),
-			dt = this.s.dt;
-		
-		nButton.className = !dt.bJUI ? "ColVis_Button TableTools_Button" :
-			"ColVis_Button TableTools_Button ui-button ui-state-default";
-		nButton.appendChild( nSpan );
-		var sTitle = this.s.fnLabel===null ? oColumn.sTitle : this.s.fnLabel( i, oColumn.sTitle, oColumn.nTh );
-		$(nSpan).html(
-			'<span class="ColVis_radio"><input type="checkbox"/></span>'+
-			'<span class="ColVis_title">'+sTitle+'</span>' );
-		
-		$(nButton).click( function (e) {
-			var showHide = !$('input', this).is(":checked");
-			if ( e.target.nodeName.toLowerCase() == "input" )
-			{
-				showHide = $('input', this).is(":checked");
-			}
-			
-			/* Need to consider the case where the initialiser created more than one table - change the
-			 * API index that DataTables is using
-			 */
-			var oldIndex = $.fn.dataTableExt.iApiIndex;
-			$.fn.dataTableExt.iApiIndex = that._fnDataTablesApiIndex.call(that);
+        if ( typeof oConfig.bCssPosition != 'undefined' )
+        {
+            this.s.bCssPosition = oConfig.bCssPosition;
+        }
+    },
+    
+    
+    /**
+     * On each table draw, check the visiblity checkboxes as needed. This allows any process to
+     * update the table's column visiblity and ColVis will still be accurate.
+     *  @method  _fnDrawCallback
+     *  @returns void
+     *  @private 
+     */
+    "_fnDrawCallback": function ()
+    {
+        var aoColumns = this.s.dt.aoColumns;
+        
+        for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
+        {
+            if ( this.dom.buttons[i] !== null )
+            {
+                if ( aoColumns[i].bVisible )
+                {
+                    $('input', this.dom.buttons[i]).attr('checked','checked');
+                }
+                else
+                {
+                    $('input', this.dom.buttons[i]).removeAttr('checked');
+                }
+            }
+        }
+    },
+    
+    
+    /**
+     * Loop through the columns in the table and as a new button for each one.
+     *  @method  _fnAddButtons
+     *  @returns void
+     *  @private 
+     */
+    "_fnAddButtons": function ()
+    {
+        var
+            nButton,
+            sExclude = ","+this.s.aiExclude.join(',')+",";
+        
+        for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
+        {
+            if ( sExclude.indexOf( ","+i+"," ) == -1 )
+            {
+                nButton = this._fnDomColumnButton( i );
+                this.dom.buttons.push( nButton );
+                this.dom.collection.appendChild( nButton );
+            }
+            else
+            {
+                this.dom.buttons.push( null );
+            }
+        }
+        
+        if ( this.s.bRestore )
+        {
+            nButton = this._fnDomRestoreButton();
+            nButton.className += " ColVis_Restore";
+            this.dom.buttons.push( nButton );
+            this.dom.collection.appendChild( nButton );
+        }
+        
+        if ( this.s.bShowAll )
+        {
+            nButton = this._fnDomShowAllButton();
+            nButton.className += " ColVis_ShowAll";
+            this.dom.buttons.push( nButton );
+            this.dom.collection.appendChild( nButton );
+        }
+    },
+    
+    
+    /**
+     * Create a button which allows a "restore" action
+     *  @method  _fnDomRestoreButton
+     *  @returns {Node} Created button
+     *  @private 
+     */
+    "_fnDomRestoreButton": function ()
+    {
+        var
+            that = this,
+            nButton = document.createElement('button'),
+            nSpan = document.createElement('span');
+        
+        nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
+            "ColVis_Button TableTools_Button ui-button ui-state-default";
+        nButton.appendChild( nSpan );
+        $(nSpan).html( '<span class="ColVis_title">'+this.s.sRestore+'</span>' );
+        
+        $(nButton).click( function (e) {
+            for ( var i=0, iLen=that.s.abOriginal.length ; i<iLen ; i++ )
+            {
+                that.s.dt.oInstance.fnSetColumnVis( i, that.s.abOriginal[i], false );
+            }
+            that._fnAdjustOpenRows();
+            that.s.dt.oInstance.fnDraw( false );
+        } );
+        
+        return nButton;
+    },
+    
+    
+    /**
+     * Create a button which allows a "show all" action
+     *  @method  _fnDomShowAllButton
+     *  @returns {Node} Created button
+     *  @private 
+     */
+    "_fnDomShowAllButton": function ()
+    {
+        var
+            that = this,
+            nButton = document.createElement('button'),
+            nSpan = document.createElement('span');
+        
+        nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
+            "ColVis_Button TableTools_Button ui-button ui-state-default";
+        nButton.appendChild( nSpan );
+        $(nSpan).html( '<span class="ColVis_title">'+this.s.sShowAll+'</span>' );
+        
+        $(nButton).click( function (e) {
+            for ( var i=0, iLen=that.s.abOriginal.length ; i<iLen ; i++ )
+            {
+                if (that.s.aiExclude.indexOf(i) === -1)
+                {
+                    that.s.dt.oInstance.fnSetColumnVis( i, true, false );
+                }
+            }
+            that._fnAdjustOpenRows();
+            that.s.dt.oInstance.fnDraw( false );
+        } );
+        
+        return nButton;
+    },
+    
+    
+    /**
+     * Create the DOM for a show / hide button
+     *  @method  _fnDomColumnButton
+     *  @param {int} i Column in question
+     *  @returns {Node} Created button
+     *  @private 
+     */
+    "_fnDomColumnButton": function ( i )
+    {
+        var
+            that = this,
+            oColumn = this.s.dt.aoColumns[i],
+            nButton = document.createElement('button'),
+            nSpan = document.createElement('span'),
+            dt = this.s.dt;
+        
+        nButton.className = !dt.bJUI ? "ColVis_Button TableTools_Button" :
+            "ColVis_Button TableTools_Button ui-button ui-state-default";
+        nButton.appendChild( nSpan );
+        var sTitle = this.s.fnLabel===null ? oColumn.sTitle : this.s.fnLabel( i, oColumn.sTitle, oColumn.nTh );
+        $(nSpan).html(
+            '<span class="ColVis_radio"><input type="checkbox"/></span>'+
+            '<span class="ColVis_title">'+sTitle+'</span>' );
+        
+        $(nButton).click( function (e) {
+            var showHide = !$('input', this).is(":checked");
+            if ( e.target.nodeName.toLowerCase() == "input" )
+            {
+                showHide = $('input', this).is(":checked");
+            }
+            
+            /* Need to consider the case where the initialiser created more than one table - change the
+             * API index that DataTables is using
+             */
+            var oldIndex = $.fn.dataTableExt.iApiIndex;
+            $.fn.dataTableExt.iApiIndex = that._fnDataTablesApiIndex.call(that);
 
-			// Optimisation for server-side processing when scrolling - don't do a full redraw
-			if ( dt.oFeatures.bServerSide && (dt.oScroll.sX !== "" || dt.oScroll.sY !== "" ) )
-			{
-				that.s.dt.oInstance.fnSetColumnVis( i, showHide, false );
-				that.s.dt.oInstance.oApi._fnScrollDraw( that.s.dt );
-				that._fnDrawCallback();
-			}
-			else
-			{
-				that.s.dt.oInstance.fnSetColumnVis( i, showHide );
-			}
+            // Optimisation for server-side processing when scrolling - don't do a full redraw
+            if ( dt.oFeatures.bServerSide && (dt.oScroll.sX !== "" || dt.oScroll.sY !== "" ) )
+            {
+                that.s.dt.oInstance.fnSetColumnVis( i, showHide, false );
+                that.s.dt.oInstance.oApi._fnScrollDraw( that.s.dt );
+                that._fnDrawCallback();
+            }
+            else
+            {
+                that.s.dt.oInstance.fnSetColumnVis( i, showHide );
+            }
 
-			$.fn.dataTableExt.iApiIndex = oldIndex; /* Restore */
-			
-			if ( that.s.fnStateChange !== null )
-			{
-				that.s.fnStateChange.call( that, i, showHide );
-			}
-		} );
-		
-		return nButton;
-	},
-	
-	
-	/**
-	 * Get the position in the DataTables instance array of the table for this instance of ColVis
-	 *  @method  _fnDataTablesApiIndex
-	 *  @returns {int} Index
-	 *  @private 
-	 */
-	"_fnDataTablesApiIndex": function ()
-	{
-		for ( var i=0, iLen=this.s.dt.oInstance.length ; i<iLen ; i++ )
-		{
-			if ( this.s.dt.oInstance[i] == this.s.dt.nTable )
-			{
-				return i;
-			}
-		}
-		return 0;
-	},
-	
-	
-	/**
-	 * Create the DOM needed for the button and apply some base properties. All buttons start here
-	 *  @method  _fnDomBaseButton
-	 *  @param   {String} text Button text
-	 *  @returns {Node} DIV element for the button
-	 *  @private 
-	 */
-	"_fnDomBaseButton": function ( text )
-	{
-		var
-			that = this,
-			nButton = document.createElement('button'),
-			nSpan = document.createElement('span'),
-			sEvent = this.s.activate=="mouseover" ? "mouseover" : "click";
-		
-		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
-			"ColVis_Button TableTools_Button ui-button ui-state-default";
-		nButton.appendChild( nSpan );
-		nSpan.innerHTML = text;
-		
-		$(nButton).bind( sEvent, function (e) {
-			that._fnCollectionShow();
-			e.preventDefault();
-		} );
-		
-		return nButton;
-	},
-	
-	
-	/**
-	 * Create the element used to contain list the columns (it is shown and hidden as needed)
-	 *  @method  _fnDomCollection
-	 *  @returns {Node} div container for the collection
-	 *  @private 
-	 */
-	"_fnDomCollection": function ()
-	{
-		var that = this;
-		var nHidden = document.createElement('div');
-		nHidden.style.display = "none";
-		nHidden.className = !this.s.dt.bJUI ? "ColVis_collection TableTools_collection" :
-			"ColVis_collection TableTools_collection ui-buttonset ui-buttonset-multi";
-		
-		if ( !this.s.bCssPosition )
-		{
-			nHidden.style.position = "absolute";
-		}
-		$(nHidden).css('opacity', 0);
-		
-		return nHidden;
-	},
-	
-	
-	/**
-	 * An element to be placed on top of the activate button to catch events
-	 *  @method  _fnDomCatcher
-	 *  @returns {Node} div container for the collection
-	 *  @private 
-	 */
-	"_fnDomCatcher": function ()
-	{
-		var 
-			that = this,
-			nCatcher = document.createElement('div');
-		nCatcher.className = "ColVis_catcher TableTools_catcher";
-		
-		$(nCatcher).click( function () {
-			that._fnCollectionHide.call( that, null, null );
-		} );
-		
-		return nCatcher;
-	},
-	
-	
-	/**
-	 * Create the element used to shade the background, and capture hide events (it is shown and 
-	 * hidden as needed)
-	 *  @method  _fnDomBackground
-	 *  @returns {Node} div container for the background
-	 *  @private 
-	 */
-	"_fnDomBackground": function ()
-	{
-		var that = this;
-		
-		var nBackground = document.createElement('div');
-		nBackground.style.position = "absolute";
-		nBackground.style.left = "0px";
-		nBackground.style.top = "0px";
-		nBackground.className = "ColVis_collectionBackground TableTools_collectionBackground";
-		$(nBackground).css('opacity', 0);
-		
-		$(nBackground).click( function () {
-			that._fnCollectionHide.call( that, null, null );
-		} );
-		
-		/* When considering a mouse over action for the activation, we also consider a mouse out
-		 * which is the same as a mouse over the background - without all the messing around of
-		 * bubbling events. Use the catcher element to avoid messing around with bubbling
-		 */
-		if ( this.s.activate == "mouseover" )
-		{
-			$(nBackground).mouseover( function () {
-				that.s.overcollection = false;
-				that._fnCollectionHide.call( that, null, null );
-			} );
-		}
-		
-		return nBackground;
-	},
-	
-	
-	/**
-	 * Show the show / hide list and the background
-	 *  @method  _fnCollectionShow
-	 *  @returns void
-	 *  @private 
-	 */
-	"_fnCollectionShow": function ()
-	{
-		var that = this, i, iLen;
-		var oPos = $(this.dom.button).offset();
-		var nHidden = this.dom.collection;
-		var nBackground = this.dom.background;
-		var iDivX = parseInt(oPos.left, 10);
-		var iDivY = parseInt(oPos.top + $(this.dom.button).outerHeight(), 10);
-		
-		if ( !this.s.bCssPosition )
-		{
-			nHidden.style.top = iDivY+"px";
-			nHidden.style.left = iDivX+"px";
-		}
-		nHidden.style.display = "block";
-		$(nHidden).css('opacity',0);
-		
-		var iWinHeight = $(window).height(), iDocHeight = $(document).height(),
-		 	iWinWidth = $(window).width(), iDocWidth = $(document).width();
-		
-		nBackground.style.height = ((iWinHeight>iDocHeight)? iWinHeight : iDocHeight) +"px";
-		nBackground.style.width = ((iWinWidth<iDocWidth)? iWinWidth : iDocWidth) +"px";
-		
-		var oStyle = this.dom.catcher.style;
-		oStyle.height = $(this.dom.button).outerHeight()+"px";
-		oStyle.width = $(this.dom.button).outerWidth()+"px";
-		oStyle.top = oPos.top+"px";
-		oStyle.left = iDivX+"px";
-		
-		document.body.appendChild( nBackground );
-		document.body.appendChild( nHidden );
-		document.body.appendChild( this.dom.catcher );
-		
-		/* Resize the buttons */
-		if ( this.s.sSize == "auto" )
-		{
-			var aiSizes = [];
-			this.dom.collection.style.width = "auto";
-			for ( i=0, iLen=this.dom.buttons.length ; i<iLen ; i++ )
-			{
-				if ( this.dom.buttons[i] !== null )
-				{
-					this.dom.buttons[i].style.width = "auto";
-					aiSizes.push( $(this.dom.buttons[i]).outerWidth() );
-				}
-			}
-			iMax = Math.max.apply(window, aiSizes);
-			for ( i=0, iLen=this.dom.buttons.length ; i<iLen ; i++ )
-			{
-				if ( this.dom.buttons[i] !== null )
-				{
-					this.dom.buttons[i].style.width = iMax+"px";
-				}
-			}
-			this.dom.collection.style.width = iMax+"px";
-		}
-		
-		/* Visual corrections to try and keep the collection visible */
-		if ( !this.s.bCssPosition )
-		{
-			nHidden.style.left = this.s.sAlign=="left" ?
-				iDivX+"px" : (iDivX-$(nHidden).outerWidth()+$(this.dom.button).outerWidth())+"px";
+            $.fn.dataTableExt.iApiIndex = oldIndex; /* Restore */
+            
+            if ( that.s.fnStateChange !== null )
+            {
+                that.s.fnStateChange.call( that, i, showHide );
+            }
+        } );
+        
+        return nButton;
+    },
+    
+    
+    /**
+     * Get the position in the DataTables instance array of the table for this instance of ColVis
+     *  @method  _fnDataTablesApiIndex
+     *  @returns {int} Index
+     *  @private 
+     */
+    "_fnDataTablesApiIndex": function ()
+    {
+        for ( var i=0, iLen=this.s.dt.oInstance.length ; i<iLen ; i++ )
+        {
+            if ( this.s.dt.oInstance[i] == this.s.dt.nTable )
+            {
+                return i;
+            }
+        }
+        return 0;
+    },
+    
+    
+    /**
+     * Create the DOM needed for the button and apply some base properties. All buttons start here
+     *  @method  _fnDomBaseButton
+     *  @param   {String} text Button text
+     *  @returns {Node} DIV element for the button
+     *  @private 
+     */
+    "_fnDomBaseButton": function ( text )
+    {
+        var
+            that = this,
+            nButton = document.createElement('button'),
+            nSpan = document.createElement('span'),
+            sEvent = this.s.activate=="mouseover" ? "mouseover" : "click";
+        
+        //nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
+            //"ColVis_Button TableTools_Button ui-button ui-state-default";
+        nButton.className = "btn-toolbar btn btn-small dropdown-toggle ColVis_MasterButton";
+        
+        nButton.appendChild( nSpan );
+        $(nButton).append("<span class='caret'></span>");
+        nSpan.innerHTML = text;
+        
+        $(nButton).bind( 'click', function (e) {
+            that._fnCollectionShow();
+            e.preventDefault();
+        } );
+        
+        return nButton;
+    },
+    
+    
+    /**
+     * Create the element used to contain list the columns (it is shown and hidden as needed)
+     *  @method  _fnDomCollection
+     *  @returns {Node} div container for the collection
+     *  @private 
+     */
+    "_fnDomCollection": function ()
+    {
+        var that = this;
+        var nHidden = document.createElement('div');
+        nHidden.style.display = "none";
+        nHidden.className = !this.s.dt.bJUI ? "ColVis_collection TableTools_collection" :
+            "ColVis_collection TableTools_collection ui-buttonset ui-buttonset-multi";
+        
+        if ( !this.s.bCssPosition )
+        {
+            nHidden.style.position = "absolute";
+        }
+        $(nHidden).css('opacity', 0);
+        
+        return nHidden;
+    },
+    
+    
+    /**
+     * An element to be placed on top of the activate button to catch events
+     *  @method  _fnDomCatcher
+     *  @returns {Node} div container for the collection
+     *  @private 
+     */
+    "_fnDomCatcher": function ()
+    {
+        var 
+            that = this,
+            nCatcher = document.createElement('div');
+        nCatcher.className = "ColVis_catcher TableTools_catcher";
+        
+        $(nCatcher).click( function () {
+            that._fnCollectionHide.call( that, null, null );
+        } );
+        
+        return nCatcher;
+    },
+    
+    
+    /**
+     * Create the element used to shade the background, and capture hide events (it is shown and 
+     * hidden as needed)
+     *  @method  _fnDomBackground
+     *  @returns {Node} div container for the background
+     *  @private 
+     */
+    "_fnDomBackground": function ()
+    {
+        var that = this;
+        
+        var nBackground = document.createElement('div');
+        nBackground.style.position = "absolute";
+        nBackground.style.left = "0px";
+        nBackground.style.top = "0px";
+        nBackground.className = "ColVis_collectionBackground TableTools_collectionBackground";
+        $(nBackground).css('opacity', 0);
+        
+        $(nBackground).click( function () {
+            that._fnCollectionHide.call( that, null, null );
+        } );
+        
+        /* When considering a mouse over action for the activation, we also consider a mouse out
+         * which is the same as a mouse over the background - without all the messing around of
+         * bubbling events. Use the catcher element to avoid messing around with bubbling
+         */
+        if ( this.s.activate == "mouseover" )
+        {
+            $(nBackground).mouseover( function () {
+                that.s.overcollection = false;
+                that._fnCollectionHide.call( that, null, null );
+            } );
+        }
+        
+        return nBackground;
+    },
+    
+    
+    /**
+     * Show the show / hide list and the background
+     *  @method  _fnCollectionShow
+     *  @returns void
+     *  @private 
+     */
+    "_fnCollectionShow": function ()
+    {
+        var that = this, i, iLen;
+        var oPos = $(this.dom.button).offset();
+        var nHidden = this.dom.collection;
+        var nBackground = this.dom.background;
+        var iDivX = parseInt(oPos.left, 10);
+        var iDivY = parseInt(oPos.top + $(this.dom.button).outerHeight(), 10);
+        
+        if ( !this.s.bCssPosition )
+        {
+            nHidden.style.top = iDivY+"px";
+            nHidden.style.left = iDivX+"px";
+        }
+        nHidden.style.display = "block";
+        $(nHidden).css('opacity',0);
+        
+        var iWinHeight = $(window).height(), iDocHeight = $(document).height(),
+            iWinWidth = $(window).width(), iDocWidth = $(document).width();
+        
+        nBackground.style.height = ((iWinHeight>iDocHeight)? iWinHeight : iDocHeight) +"px";
+        nBackground.style.width = ((iWinWidth<iDocWidth)? iWinWidth : iDocWidth) +"px";
+        
+        var oStyle = this.dom.catcher.style;
+        oStyle.height = $(this.dom.button).outerHeight()+"px";
+        oStyle.width = $(this.dom.button).outerWidth()+"px";
+        oStyle.top = oPos.top+"px";
+        oStyle.left = iDivX+"px";
+        
+        document.body.appendChild( nBackground );
+        document.body.appendChild( nHidden );
+        document.body.appendChild( this.dom.catcher );
+        
+        /* Resize the buttons */
+        if ( this.s.sSize == "auto" )
+        {
+            var aiSizes = [];
+            this.dom.collection.style.width = "auto";
+            for ( i=0, iLen=this.dom.buttons.length ; i<iLen ; i++ )
+            {
+                if ( this.dom.buttons[i] !== null )
+                {
+                    this.dom.buttons[i].style.width = "auto";
+                    aiSizes.push( $(this.dom.buttons[i]).outerWidth() );
+                }
+            }
+            iMax = Math.max.apply(window, aiSizes);
+            for ( i=0, iLen=this.dom.buttons.length ; i<iLen ; i++ )
+            {
+                if ( this.dom.buttons[i] !== null )
+                {
+                    this.dom.buttons[i].style.width = iMax+"px";
+                }
+            }
+            this.dom.collection.style.width = iMax+"px";
+        }
+        
+        /* Visual corrections to try and keep the collection visible */
+        if ( !this.s.bCssPosition )
+        {
+            nHidden.style.left = this.s.sAlign=="left" ?
+                iDivX+"px" : (iDivX-$(nHidden).outerWidth()+$(this.dom.button).outerWidth())+"px";
 
-			var iDivWidth = $(nHidden).outerWidth();
-			var iDivHeight = $(nHidden).outerHeight();
-			
-			if ( iDivX + iDivWidth > iDocWidth )
-			{
-				nHidden.style.left = (iDocWidth-iDivWidth)+"px";
-			}
-		}
-		
-		/* This results in a very small delay for the end user but it allows the animation to be
-		 * much smoother. If you don't want the animation, then the setTimeout can be removed
-		 */
-		setTimeout( function () {
-			$(nHidden).animate({"opacity": 1}, that.s.iOverlayFade);
-			$(nBackground).animate({"opacity": 0.1}, that.s.iOverlayFade, 'linear', function () {
-				/* In IE6 if you set the checked attribute of a hidden checkbox, then this is not visually
-				 * reflected. As such, we need to do it here, once it is visible. Unbelievable.
-				 */
-				if ( jQuery.browser.msie && jQuery.browser.version == "6.0" )
-				{
-					that._fnDrawCallback();
-				}
-			});
-		}, 10 );
-		
-		this.s.hidden = false;
-	},
-	
-	
-	/**
-	 * Hide the show / hide list and the background
-	 *  @method  _fnCollectionHide
-	 *  @returns void
-	 *  @private 
-	 */
-	"_fnCollectionHide": function (  )
-	{
-		var that = this;
-		
-		if ( !this.s.hidden && this.dom.collection !== null )
-		{
-			this.s.hidden = true;
-			
-			$(this.dom.collection).animate({"opacity": 0}, that.s.iOverlayFade, function (e) {
-				this.style.display = "none";
-			} );
-			
-			$(this.dom.background).animate({"opacity": 0}, that.s.iOverlayFade, function (e) {
-				document.body.removeChild( that.dom.background );
-				document.body.removeChild( that.dom.catcher );
-			} );
-		}
-	},
-	
-	
-	/**
-	 * Alter the colspan on any fnOpen rows
-	 */
-	"_fnAdjustOpenRows": function ()
-	{
-		var aoOpen = this.s.dt.aoOpenRows;
-		var iVisible = this.s.dt.oApi._fnVisbleColumns( this.s.dt );
-		
-		for ( var i=0, iLen=aoOpen.length ; i<iLen ; i++ ) {
-			aoOpen[i].nTr.getElementsByTagName('td')[0].colSpan = iVisible;
-		}
-	}
+            var iDivWidth = $(nHidden).outerWidth();
+            var iDivHeight = $(nHidden).outerHeight();
+            
+            if ( iDivX + iDivWidth > iDocWidth )
+            {
+                nHidden.style.left = (iDocWidth-iDivWidth)+"px";
+            }
+        }
+        
+        /* This results in a very small delay for the end user but it allows the animation to be
+         * much smoother. If you don't want the animation, then the setTimeout can be removed
+         */
+        setTimeout( function () {
+            $(nHidden).animate({"opacity": 1}, that.s.iOverlayFade);
+            $(nBackground).animate({"opacity": 0.1}, that.s.iOverlayFade, 'linear', function () {
+                /* In IE6 if you set the checked attribute of a hidden checkbox, then this is not visually
+                 * reflected. As such, we need to do it here, once it is visible. Unbelievable.
+                 */
+                if ( jQuery.browser.msie && jQuery.browser.version == "6.0" )
+                {
+                    that._fnDrawCallback();
+                }
+            });
+        }, 10 );
+        
+        this.s.hidden = false;
+    },
+    
+    
+    /**
+     * Hide the show / hide list and the background
+     *  @method  _fnCollectionHide
+     *  @returns void
+     *  @private 
+     */
+    "_fnCollectionHide": function (  )
+    {
+        var that = this;
+        
+        if ( !this.s.hidden && this.dom.collection !== null )
+        {
+            this.s.hidden = true;
+            
+            $(this.dom.collection).animate({"opacity": 0}, that.s.iOverlayFade, function (e) {
+                this.style.display = "none";
+            } );
+            
+            $(this.dom.background).animate({"opacity": 0}, that.s.iOverlayFade, function (e) {
+                document.body.removeChild( that.dom.background );
+                document.body.removeChild( that.dom.catcher );
+            } );
+        }
+    },
+    
+    
+    /**
+     * Alter the colspan on any fnOpen rows
+     */
+    "_fnAdjustOpenRows": function ()
+    {
+        var aoOpen = this.s.dt.aoOpenRows;
+        var iVisible = this.s.dt.oApi._fnVisbleColumns( this.s.dt );
+        
+        for ( var i=0, iLen=aoOpen.length ; i<iLen ; i++ ) {
+            aoOpen[i].nTr.getElementsByTagName('td')[0].colSpan = iVisible;
+        }
+    }
 };
 
 
@@ -903,19 +906,19 @@ ColVis.prototype = {
  */
 ColVis.fnRebuild = function ( oTable )
 {
-	var nTable = null;
-	if ( typeof oTable != 'undefined' )
-	{
-		nTable = oTable.fnSettings().nTable;
-	}
-	
-	for ( var i=0, iLen=ColVis.aInstances.length ; i<iLen ; i++ )
-	{
-		if ( typeof oTable == 'undefined' || nTable == ColVis.aInstances[i].s.dt.nTable )
-		{
-			ColVis.aInstances[i].fnRebuild();
-		}
-	}
+    var nTable = null;
+    if ( typeof oTable != 'undefined' )
+    {
+        nTable = oTable.fnSettings().nTable;
+    }
+    
+    for ( var i=0, iLen=ColVis.aInstances.length ; i<iLen ; i++ )
+    {
+        if ( typeof oTable == 'undefined' || nTable == ColVis.aInstances[i].s.dt.nTable )
+        {
+            ColVis.aInstances[i].fnRebuild();
+        }
+    }
 };
 
 
@@ -976,20 +979,20 @@ if ( typeof $.fn.dataTable == "function" &&
      typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
      $.fn.dataTableExt.fnVersionCheck('1.7.0') )
 {
-	$.fn.dataTableExt.aoFeatures.push( {
-		"fnInit": function( oDTSettings ) {
-			var init = (typeof oDTSettings.oInit.oColVis == 'undefined') ?
-				{} : oDTSettings.oInit.oColVis;
-			var oColvis = new ColVis( oDTSettings, init );
-			return oColvis.dom.wrapper;
-		},
-		"cFeature": "C",
-		"sFeature": "ColVis"
-	} );
+    $.fn.dataTableExt.aoFeatures.push( {
+        "fnInit": function( oDTSettings ) {
+            var init = (typeof oDTSettings.oInit.oColVis == 'undefined') ?
+                {} : oDTSettings.oInit.oColVis;
+            var oColvis = new ColVis( oDTSettings, init );
+            return oColvis.dom.wrapper;
+        },
+        "cFeature": "C",
+        "sFeature": "ColVis"
+    } );
 }
 else
 {
-	alert( "Warning: ColVis requires DataTables 1.7 or greater - www.datatables.net/download");
+    alert( "Warning: ColVis requires DataTables 1.7 or greater - www.datatables.net/download");
 }
 
 })(jQuery);
diff --git a/airtime_mvc/public/js/datatables/plugin/dataTables.ColVis_orig.js b/airtime_mvc/public/js/datatables/plugin/dataTables.ColVis_orig.js
new file mode 100644
index 000000000..19d91d39b
--- /dev/null
+++ b/airtime_mvc/public/js/datatables/plugin/dataTables.ColVis_orig.js
@@ -0,0 +1,995 @@
+/*
+ * File:        ColVis.js
+ * Version:     1.0.7
+ * CVS:         $Id$
+ * Description: Controls for column visiblity in DataTables
+ * Author:      Allan Jardine (www.sprymedia.co.uk)
+ * Created:     Wed Sep 15 18:23:29 BST 2010
+ * Modified:    $Date$ by $Author$
+ * Language:    Javascript
+ * License:     GPL v2 or BSD 3 point style
+ * Project:     Just a little bit of fun :-)
+ * Contact:     www.sprymedia.co.uk/contact
+ * 
+ * Copyright 2010-2011 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD style license, available at:
+ *   http://datatables.net/license_gpl2
+ *   http://datatables.net/license_bsd
+ */
+
+(function($) {
+
+/** 
+ * ColVis provides column visiblity control for DataTables
+ * @class ColVis
+ * @constructor
+ * @param {object} DataTables settings object
+ */
+ColVis = function( oDTSettings, oInit )
+{
+	/* Santiy check that we are a new instance */
+	if ( !this.CLASS || this.CLASS != "ColVis" )
+	{
+		alert( "Warning: ColVis must be initialised with the keyword 'new'" );
+	}
+	
+	if ( typeof oInit == 'undefined' )
+	{
+		oInit = {};
+	}
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Public class variables
+	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+	
+	/**
+	 * @namespace Settings object which contains customisable information for ColVis instance
+	 */
+	this.s = {
+		/**
+		 * DataTables settings object
+		 *  @property dt
+		 *  @type     Object
+		 *  @default  null
+		 */
+		"dt": null,
+		
+		/**
+		 * Customisation object
+		 *  @property oInit
+		 *  @type     Object
+		 *  @default  passed in
+		 */
+		"oInit": oInit,
+		
+		/**
+		 * Callback function to tell the user when the state has changed
+		 *  @property fnStateChange
+		 *  @type     function
+		 *  @default  null
+		 */
+		"fnStateChange": null,
+		
+		/**
+		 * Mode of activation. Can be 'click' or 'mouseover'
+		 *  @property activate
+		 *  @type     String
+		 *  @default  click
+		 */
+		"activate": "click",
+		
+		/**
+		 * Position of the collection menu when shown - align "left" or "right"
+		 *  @property sAlign
+		 *  @type     String
+		 *  @default  right
+		 */
+		"sAlign": "left",
+		
+		/**
+		 * Text used for the button
+		 *  @property buttonText
+		 *  @type     String
+		 *  @default  Show / hide columns
+		 */
+		"buttonText": "Show / hide columns",
+		
+		/**
+		 * Flag to say if the collection is hidden
+		 *  @property hidden
+		 *  @type     boolean
+		 *  @default  true
+		 */
+		"hidden": true,
+		
+		/**
+		 * List of columns (integers) which should be excluded from the list
+		 *  @property aiExclude
+		 *  @type     Array
+		 *  @default  []
+		 */
+		"aiExclude": [],
+		
+		/**
+		 * Store the original viisbility settings so they could be restored
+		 *  @property abOriginal
+		 *  @type     Array
+		 *  @default  []
+		 */
+		"abOriginal": [],
+		
+		/**
+		 * Show Show-All button
+		 *  @property bShowAll
+		 *  @type     Array
+		 *  @default  []
+		 */
+		"bShowAll": false,
+		
+		/**
+		 * Show All button text
+		 *  @property sShowAll
+		 *  @type     String
+		 *  @default  Restore original
+		 */
+		"sShowAll": "Show All",
+		
+		/**
+		 * Show restore button
+		 *  @property bRestore
+		 *  @type     Array
+		 *  @default  []
+		 */
+		"bRestore": false,
+		
+		/**
+		 * Restore button text
+		 *  @property sRestore
+		 *  @type     String
+		 *  @default  Restore original
+		 */
+		"sRestore": "Restore original",
+		
+		/**
+		 * Overlay animation duration in mS
+		 *  @property iOverlayFade
+		 *  @type     Integer
+		 *  @default  500
+		 */
+		"iOverlayFade": 500,
+		
+		/**
+		 * Label callback for column names. Takes three parameters: 1. the column index, 2. the column
+		 * title detected by DataTables and 3. the TH node for the column
+		 *  @property fnLabel
+		 *  @type     Function
+		 *  @default  null
+		 */
+		"fnLabel": null,
+		
+		/**
+		 * Indicate if ColVis should automatically calculate the size of buttons or not. The default
+		 * is for it to do so. Set to "css" to disable the automatic sizing
+		 *  @property sSize
+		 *  @type     String
+		 *  @default  auto
+		 */
+		"sSize": "auto",
+		
+		/**
+		 * Indicate if the column list should be positioned by Javascript, visually below the button
+		 * or allow CSS to do the positioning
+		 *  @property bCssPosition
+		 *  @type     boolean
+		 *  @default  false
+		 */
+		"bCssPosition": false
+	};
+	
+	
+	/**
+	 * @namespace Common and useful DOM elements for the class instance
+	 */
+	this.dom = {
+		/**
+		 * Wrapper for the button - given back to DataTables as the node to insert
+		 *  @property wrapper
+		 *  @type     Node
+		 *  @default  null
+		 */
+		"wrapper": null,
+		
+		/**
+		 * Activation button
+		 *  @property button
+		 *  @type     Node
+		 *  @default  null
+		 */
+		"button": null,
+		
+		/**
+		 * Collection list node
+		 *  @property collection
+		 *  @type     Node
+		 *  @default  null
+		 */
+		"collection": null,
+		
+		/**
+		 * Background node used for shading the display and event capturing
+		 *  @property background
+		 *  @type     Node
+		 *  @default  null
+		 */
+		"background": null,
+		
+		/**
+		 * Element to position over the activation button to catch mouse events when using mouseover
+		 *  @property catcher
+		 *  @type     Node
+		 *  @default  null
+		 */
+		"catcher": null,
+		
+		/**
+		 * List of button elements
+		 *  @property buttons
+		 *  @type     Array
+		 *  @default  []
+		 */
+		"buttons": [],
+		
+		/**
+		 * Restore button
+		 *  @property restore
+		 *  @type     Node
+		 *  @default  null
+		 */
+		"restore": null
+	};
+	
+	/* Store global reference */
+	ColVis.aInstances.push( this );
+	
+	/* Constructor logic */
+	this.s.dt = oDTSettings;
+	this._fnConstruct();
+	return this;
+};
+
+
+
+ColVis.prototype = {
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Public methods
+	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+	
+	/**
+	 * Rebuild the list of buttons for this instance (i.e. if there is a column header update)
+	 *  @method  fnRebuild
+	 *  @returns void
+	 */
+	"fnRebuild": function ()
+	{
+		/* Remove the old buttons */
+		for ( var i=this.dom.buttons.length-1 ; i>=0 ; i-- )
+		{
+			if ( this.dom.buttons[i] !== null )
+			{
+				this.dom.collection.removeChild( this.dom.buttons[i] );
+			}
+		}
+		this.dom.buttons.splice( 0, this.dom.buttons.length );
+		
+		if ( this.dom.restore )
+		{
+			this.dom.restore.parentNode( this.dom.restore );
+		}
+		
+		/* Re-add them (this is not the optimal way of doing this, it is fast and effective) */
+		this._fnAddButtons();
+		
+		/* Update the checkboxes */
+		this._fnDrawCallback();
+	},
+	
+	
+	
+	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+	 * Private methods (they are of course public in JS, but recommended as private)
+	 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+	
+	/**
+	 * Constructor logic
+	 *  @method  _fnConstruct
+	 *  @returns void
+	 *  @private 
+	 */
+	"_fnConstruct": function ()
+	{
+		this._fnApplyCustomisation();
+		
+		var that = this;
+		this.dom.wrapper = document.createElement('div');
+		this.dom.wrapper.className = "ColVis TableTools";
+		
+		this.dom.button = this._fnDomBaseButton( this.s.buttonText );
+		this.dom.button.className += " ColVis_MasterButton";
+		this.dom.wrapper.appendChild( this.dom.button );
+		
+		this.dom.catcher = this._fnDomCatcher();
+		this.dom.collection = this._fnDomCollection();
+		this.dom.background = this._fnDomBackground();
+		
+		this._fnAddButtons();
+		
+		/* Store the original visbility information */
+		for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
+		{
+			this.s.abOriginal.push( this.s.dt.aoColumns[i].bVisible );
+		}
+		
+		/* Update on each draw */
+		this.s.dt.aoDrawCallback.push( {
+			"fn": function () {
+				that._fnDrawCallback.call( that );
+			},
+			"sName": "ColVis"
+		} );
+	},
+	
+	
+	/**
+	 * Apply any customisation to the settings from the DataTables initialisation
+	 *  @method  _fnApplyCustomisation
+	 *  @returns void
+	 *  @private 
+	 */
+	"_fnApplyCustomisation": function ()
+	{
+		var oConfig = this.s.oInit;
+		
+		if ( typeof oConfig.activate != 'undefined' )
+		{
+			this.s.activate = oConfig.activate;
+		}
+		
+		if ( typeof oConfig.buttonText != 'undefined' )
+		{
+			this.s.buttonText = oConfig.buttonText;
+		}
+		
+		if ( typeof oConfig.aiExclude != 'undefined' )
+		{
+			this.s.aiExclude = oConfig.aiExclude;
+		}
+		
+		if ( typeof oConfig.bRestore != 'undefined' )
+		{
+			this.s.bRestore = oConfig.bRestore;
+		}
+		
+		if ( typeof oConfig.sRestore != 'undefined' )
+		{
+			this.s.sRestore = oConfig.sRestore;
+		}
+		
+		if ( typeof oConfig.bShowAll != 'undefined' )
+		{
+			this.s.bShowAll = oConfig.bShowAll;
+		}
+		
+		if ( typeof oConfig.sShowAll != 'undefined' )
+		{
+			this.s.sShowAll = oConfig.sShowAll;
+		}
+		
+		if ( typeof oConfig.sAlign != 'undefined' )
+		{
+			this.s.sAlign = oConfig.sAlign;
+		}
+		
+		if ( typeof oConfig.fnStateChange != 'undefined' )
+		{
+			this.s.fnStateChange = oConfig.fnStateChange;
+		}
+		
+		if ( typeof oConfig.iOverlayFade != 'undefined' )
+		{
+			this.s.iOverlayFade = oConfig.iOverlayFade;
+		}
+		
+		if ( typeof oConfig.fnLabel != 'undefined' )
+		{
+			this.s.fnLabel = oConfig.fnLabel;
+		}
+		
+		if ( typeof oConfig.sSize != 'undefined' )
+		{
+			this.s.sSize = oConfig.sSize;
+		}
+
+		if ( typeof oConfig.bCssPosition != 'undefined' )
+		{
+			this.s.bCssPosition = oConfig.bCssPosition;
+		}
+	},
+	
+	
+	/**
+	 * On each table draw, check the visiblity checkboxes as needed. This allows any process to
+	 * update the table's column visiblity and ColVis will still be accurate.
+	 *  @method  _fnDrawCallback
+	 *  @returns void
+	 *  @private 
+	 */
+	"_fnDrawCallback": function ()
+	{
+		var aoColumns = this.s.dt.aoColumns;
+		
+		for ( var i=0, iLen=aoColumns.length ; i<iLen ; i++ )
+		{
+			if ( this.dom.buttons[i] !== null )
+			{
+				if ( aoColumns[i].bVisible )
+				{
+					$('input', this.dom.buttons[i]).attr('checked','checked');
+				}
+				else
+				{
+					$('input', this.dom.buttons[i]).removeAttr('checked');
+				}
+			}
+		}
+	},
+	
+	
+	/**
+	 * Loop through the columns in the table and as a new button for each one.
+	 *  @method  _fnAddButtons
+	 *  @returns void
+	 *  @private 
+	 */
+	"_fnAddButtons": function ()
+	{
+		var
+			nButton,
+			sExclude = ","+this.s.aiExclude.join(',')+",";
+		
+		for ( var i=0, iLen=this.s.dt.aoColumns.length ; i<iLen ; i++ )
+		{
+			if ( sExclude.indexOf( ","+i+"," ) == -1 )
+			{
+				nButton = this._fnDomColumnButton( i );
+				this.dom.buttons.push( nButton );
+				this.dom.collection.appendChild( nButton );
+			}
+			else
+			{
+				this.dom.buttons.push( null );
+			}
+		}
+		
+		if ( this.s.bRestore )
+		{
+			nButton = this._fnDomRestoreButton();
+			nButton.className += " ColVis_Restore";
+			this.dom.buttons.push( nButton );
+			this.dom.collection.appendChild( nButton );
+		}
+		
+		if ( this.s.bShowAll )
+		{
+			nButton = this._fnDomShowAllButton();
+			nButton.className += " ColVis_ShowAll";
+			this.dom.buttons.push( nButton );
+			this.dom.collection.appendChild( nButton );
+		}
+	},
+	
+	
+	/**
+	 * Create a button which allows a "restore" action
+	 *  @method  _fnDomRestoreButton
+	 *  @returns {Node} Created button
+	 *  @private 
+	 */
+	"_fnDomRestoreButton": function ()
+	{
+		var
+			that = this,
+			nButton = document.createElement('button'),
+			nSpan = document.createElement('span');
+		
+		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
+			"ColVis_Button TableTools_Button ui-button ui-state-default";
+		nButton.appendChild( nSpan );
+		$(nSpan).html( '<span class="ColVis_title">'+this.s.sRestore+'</span>' );
+		
+		$(nButton).click( function (e) {
+			for ( var i=0, iLen=that.s.abOriginal.length ; i<iLen ; i++ )
+			{
+				that.s.dt.oInstance.fnSetColumnVis( i, that.s.abOriginal[i], false );
+			}
+			that._fnAdjustOpenRows();
+			that.s.dt.oInstance.fnDraw( false );
+		} );
+		
+		return nButton;
+	},
+	
+	
+	/**
+	 * Create a button which allows a "show all" action
+	 *  @method  _fnDomShowAllButton
+	 *  @returns {Node} Created button
+	 *  @private 
+	 */
+	"_fnDomShowAllButton": function ()
+	{
+		var
+			that = this,
+			nButton = document.createElement('button'),
+			nSpan = document.createElement('span');
+		
+		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
+			"ColVis_Button TableTools_Button ui-button ui-state-default";
+		nButton.appendChild( nSpan );
+		$(nSpan).html( '<span class="ColVis_title">'+this.s.sShowAll+'</span>' );
+		
+		$(nButton).click( function (e) {
+			for ( var i=0, iLen=that.s.abOriginal.length ; i<iLen ; i++ )
+			{
+				if (that.s.aiExclude.indexOf(i) === -1)
+				{
+					that.s.dt.oInstance.fnSetColumnVis( i, true, false );
+				}
+			}
+			that._fnAdjustOpenRows();
+			that.s.dt.oInstance.fnDraw( false );
+		} );
+		
+		return nButton;
+	},
+	
+	
+	/**
+	 * Create the DOM for a show / hide button
+	 *  @method  _fnDomColumnButton
+	 *  @param {int} i Column in question
+	 *  @returns {Node} Created button
+	 *  @private 
+	 */
+	"_fnDomColumnButton": function ( i )
+	{
+		var
+			that = this,
+			oColumn = this.s.dt.aoColumns[i],
+			nButton = document.createElement('button'),
+			nSpan = document.createElement('span'),
+			dt = this.s.dt;
+		
+		nButton.className = !dt.bJUI ? "ColVis_Button TableTools_Button" :
+			"ColVis_Button TableTools_Button ui-button ui-state-default";
+		nButton.appendChild( nSpan );
+		var sTitle = this.s.fnLabel===null ? oColumn.sTitle : this.s.fnLabel( i, oColumn.sTitle, oColumn.nTh );
+		$(nSpan).html(
+			'<span class="ColVis_radio"><input type="checkbox"/></span>'+
+			'<span class="ColVis_title">'+sTitle+'</span>' );
+		
+		$(nButton).click( function (e) {
+			var showHide = !$('input', this).is(":checked");
+			if ( e.target.nodeName.toLowerCase() == "input" )
+			{
+				showHide = $('input', this).is(":checked");
+			}
+			
+			/* Need to consider the case where the initialiser created more than one table - change the
+			 * API index that DataTables is using
+			 */
+			var oldIndex = $.fn.dataTableExt.iApiIndex;
+			$.fn.dataTableExt.iApiIndex = that._fnDataTablesApiIndex.call(that);
+
+			// Optimisation for server-side processing when scrolling - don't do a full redraw
+			if ( dt.oFeatures.bServerSide && (dt.oScroll.sX !== "" || dt.oScroll.sY !== "" ) )
+			{
+				that.s.dt.oInstance.fnSetColumnVis( i, showHide, false );
+				that.s.dt.oInstance.oApi._fnScrollDraw( that.s.dt );
+				that._fnDrawCallback();
+			}
+			else
+			{
+				that.s.dt.oInstance.fnSetColumnVis( i, showHide );
+			}
+
+			$.fn.dataTableExt.iApiIndex = oldIndex; /* Restore */
+			
+			if ( that.s.fnStateChange !== null )
+			{
+				that.s.fnStateChange.call( that, i, showHide );
+			}
+		} );
+		
+		return nButton;
+	},
+	
+	
+	/**
+	 * Get the position in the DataTables instance array of the table for this instance of ColVis
+	 *  @method  _fnDataTablesApiIndex
+	 *  @returns {int} Index
+	 *  @private 
+	 */
+	"_fnDataTablesApiIndex": function ()
+	{
+		for ( var i=0, iLen=this.s.dt.oInstance.length ; i<iLen ; i++ )
+		{
+			if ( this.s.dt.oInstance[i] == this.s.dt.nTable )
+			{
+				return i;
+			}
+		}
+		return 0;
+	},
+	
+	
+	/**
+	 * Create the DOM needed for the button and apply some base properties. All buttons start here
+	 *  @method  _fnDomBaseButton
+	 *  @param   {String} text Button text
+	 *  @returns {Node} DIV element for the button
+	 *  @private 
+	 */
+	"_fnDomBaseButton": function ( text )
+	{
+		var
+			that = this,
+			nButton = document.createElement('button'),
+			nSpan = document.createElement('span'),
+			sEvent = this.s.activate=="mouseover" ? "mouseover" : "click";
+		
+		nButton.className = !this.s.dt.bJUI ? "ColVis_Button TableTools_Button" :
+			"ColVis_Button TableTools_Button ui-button ui-state-default";
+		nButton.appendChild( nSpan );
+		nSpan.innerHTML = text;
+		
+		$(nButton).bind( sEvent, function (e) {
+			that._fnCollectionShow();
+			e.preventDefault();
+		} );
+		
+		return nButton;
+	},
+	
+	
+	/**
+	 * Create the element used to contain list the columns (it is shown and hidden as needed)
+	 *  @method  _fnDomCollection
+	 *  @returns {Node} div container for the collection
+	 *  @private 
+	 */
+	"_fnDomCollection": function ()
+	{
+		var that = this;
+		var nHidden = document.createElement('div');
+		nHidden.style.display = "none";
+		nHidden.className = !this.s.dt.bJUI ? "ColVis_collection TableTools_collection" :
+			"ColVis_collection TableTools_collection ui-buttonset ui-buttonset-multi";
+		
+		if ( !this.s.bCssPosition )
+		{
+			nHidden.style.position = "absolute";
+		}
+		$(nHidden).css('opacity', 0);
+		
+		return nHidden;
+	},
+	
+	
+	/**
+	 * An element to be placed on top of the activate button to catch events
+	 *  @method  _fnDomCatcher
+	 *  @returns {Node} div container for the collection
+	 *  @private 
+	 */
+	"_fnDomCatcher": function ()
+	{
+		var 
+			that = this,
+			nCatcher = document.createElement('div');
+		nCatcher.className = "ColVis_catcher TableTools_catcher";
+		
+		$(nCatcher).click( function () {
+			that._fnCollectionHide.call( that, null, null );
+		} );
+		
+		return nCatcher;
+	},
+	
+	
+	/**
+	 * Create the element used to shade the background, and capture hide events (it is shown and 
+	 * hidden as needed)
+	 *  @method  _fnDomBackground
+	 *  @returns {Node} div container for the background
+	 *  @private 
+	 */
+	"_fnDomBackground": function ()
+	{
+		var that = this;
+		
+		var nBackground = document.createElement('div');
+		nBackground.style.position = "absolute";
+		nBackground.style.left = "0px";
+		nBackground.style.top = "0px";
+		nBackground.className = "ColVis_collectionBackground TableTools_collectionBackground";
+		$(nBackground).css('opacity', 0);
+		
+		$(nBackground).click( function () {
+			that._fnCollectionHide.call( that, null, null );
+		} );
+		
+		/* When considering a mouse over action for the activation, we also consider a mouse out
+		 * which is the same as a mouse over the background - without all the messing around of
+		 * bubbling events. Use the catcher element to avoid messing around with bubbling
+		 */
+		if ( this.s.activate == "mouseover" )
+		{
+			$(nBackground).mouseover( function () {
+				that.s.overcollection = false;
+				that._fnCollectionHide.call( that, null, null );
+			} );
+		}
+		
+		return nBackground;
+	},
+	
+	
+	/**
+	 * Show the show / hide list and the background
+	 *  @method  _fnCollectionShow
+	 *  @returns void
+	 *  @private 
+	 */
+	"_fnCollectionShow": function ()
+	{
+		var that = this, i, iLen;
+		var oPos = $(this.dom.button).offset();
+		var nHidden = this.dom.collection;
+		var nBackground = this.dom.background;
+		var iDivX = parseInt(oPos.left, 10);
+		var iDivY = parseInt(oPos.top + $(this.dom.button).outerHeight(), 10);
+		
+		if ( !this.s.bCssPosition )
+		{
+			nHidden.style.top = iDivY+"px";
+			nHidden.style.left = iDivX+"px";
+		}
+		nHidden.style.display = "block";
+		$(nHidden).css('opacity',0);
+		
+		var iWinHeight = $(window).height(), iDocHeight = $(document).height(),
+		 	iWinWidth = $(window).width(), iDocWidth = $(document).width();
+		
+		nBackground.style.height = ((iWinHeight>iDocHeight)? iWinHeight : iDocHeight) +"px";
+		nBackground.style.width = ((iWinWidth<iDocWidth)? iWinWidth : iDocWidth) +"px";
+		
+		var oStyle = this.dom.catcher.style;
+		oStyle.height = $(this.dom.button).outerHeight()+"px";
+		oStyle.width = $(this.dom.button).outerWidth()+"px";
+		oStyle.top = oPos.top+"px";
+		oStyle.left = iDivX+"px";
+		
+		document.body.appendChild( nBackground );
+		document.body.appendChild( nHidden );
+		document.body.appendChild( this.dom.catcher );
+		
+		/* Resize the buttons */
+		if ( this.s.sSize == "auto" )
+		{
+			var aiSizes = [];
+			this.dom.collection.style.width = "auto";
+			for ( i=0, iLen=this.dom.buttons.length ; i<iLen ; i++ )
+			{
+				if ( this.dom.buttons[i] !== null )
+				{
+					this.dom.buttons[i].style.width = "auto";
+					aiSizes.push( $(this.dom.buttons[i]).outerWidth() );
+				}
+			}
+			iMax = Math.max.apply(window, aiSizes);
+			for ( i=0, iLen=this.dom.buttons.length ; i<iLen ; i++ )
+			{
+				if ( this.dom.buttons[i] !== null )
+				{
+					this.dom.buttons[i].style.width = iMax+"px";
+				}
+			}
+			this.dom.collection.style.width = iMax+"px";
+		}
+		
+		/* Visual corrections to try and keep the collection visible */
+		if ( !this.s.bCssPosition )
+		{
+			nHidden.style.left = this.s.sAlign=="left" ?
+				iDivX+"px" : (iDivX-$(nHidden).outerWidth()+$(this.dom.button).outerWidth())+"px";
+
+			var iDivWidth = $(nHidden).outerWidth();
+			var iDivHeight = $(nHidden).outerHeight();
+			
+			if ( iDivX + iDivWidth > iDocWidth )
+			{
+				nHidden.style.left = (iDocWidth-iDivWidth)+"px";
+			}
+		}
+		
+		/* This results in a very small delay for the end user but it allows the animation to be
+		 * much smoother. If you don't want the animation, then the setTimeout can be removed
+		 */
+		setTimeout( function () {
+			$(nHidden).animate({"opacity": 1}, that.s.iOverlayFade);
+			$(nBackground).animate({"opacity": 0.1}, that.s.iOverlayFade, 'linear', function () {
+				/* In IE6 if you set the checked attribute of a hidden checkbox, then this is not visually
+				 * reflected. As such, we need to do it here, once it is visible. Unbelievable.
+				 */
+				if ( jQuery.browser.msie && jQuery.browser.version == "6.0" )
+				{
+					that._fnDrawCallback();
+				}
+			});
+		}, 10 );
+		
+		this.s.hidden = false;
+	},
+	
+	
+	/**
+	 * Hide the show / hide list and the background
+	 *  @method  _fnCollectionHide
+	 *  @returns void
+	 *  @private 
+	 */
+	"_fnCollectionHide": function (  )
+	{
+		var that = this;
+		
+		if ( !this.s.hidden && this.dom.collection !== null )
+		{
+			this.s.hidden = true;
+			
+			$(this.dom.collection).animate({"opacity": 0}, that.s.iOverlayFade, function (e) {
+				this.style.display = "none";
+			} );
+			
+			$(this.dom.background).animate({"opacity": 0}, that.s.iOverlayFade, function (e) {
+				document.body.removeChild( that.dom.background );
+				document.body.removeChild( that.dom.catcher );
+			} );
+		}
+	},
+	
+	
+	/**
+	 * Alter the colspan on any fnOpen rows
+	 */
+	"_fnAdjustOpenRows": function ()
+	{
+		var aoOpen = this.s.dt.aoOpenRows;
+		var iVisible = this.s.dt.oApi._fnVisbleColumns( this.s.dt );
+		
+		for ( var i=0, iLen=aoOpen.length ; i<iLen ; i++ ) {
+			aoOpen[i].nTr.getElementsByTagName('td')[0].colSpan = iVisible;
+		}
+	}
+};
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Static object methods
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/**
+ * Rebuild the collection for a given table, or all tables if no parameter given
+ *  @method  ColVis.fnRebuild
+ *  @static
+ *  @param   object oTable DataTable instance to consider - optional
+ *  @returns void
+ */
+ColVis.fnRebuild = function ( oTable )
+{
+	var nTable = null;
+	if ( typeof oTable != 'undefined' )
+	{
+		nTable = oTable.fnSettings().nTable;
+	}
+	
+	for ( var i=0, iLen=ColVis.aInstances.length ; i<iLen ; i++ )
+	{
+		if ( typeof oTable == 'undefined' || nTable == ColVis.aInstances[i].s.dt.nTable )
+		{
+			ColVis.aInstances[i].fnRebuild();
+		}
+	}
+};
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Static object propterties
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/**
+ * Collection of all ColVis instances
+ *  @property ColVis.aInstances
+ *  @static
+ *  @type     Array
+ *  @default  []
+ */
+ColVis.aInstances = [];
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Constants
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/**
+ * Name of this class
+ *  @constant CLASS
+ *  @type     String
+ *  @default  ColVis
+ */
+ColVis.prototype.CLASS = "ColVis";
+
+
+/**
+ * ColVis version
+ *  @constant  VERSION
+ *  @type      String
+ *  @default   See code
+ */
+ColVis.VERSION = "1.0.7";
+ColVis.prototype.VERSION = ColVis.VERSION;
+
+
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Initialisation
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * Register a new feature with DataTables
+ */
+if ( typeof $.fn.dataTable == "function" &&
+     typeof $.fn.dataTableExt.fnVersionCheck == "function" &&
+     $.fn.dataTableExt.fnVersionCheck('1.7.0') )
+{
+	$.fn.dataTableExt.aoFeatures.push( {
+		"fnInit": function( oDTSettings ) {
+			var init = (typeof oDTSettings.oInit.oColVis == 'undefined') ?
+				{} : oDTSettings.oInit.oColVis;
+			var oColvis = new ColVis( oDTSettings, init );
+			return oColvis.dom.wrapper;
+		},
+		"cFeature": "C",
+		"sFeature": "ColVis"
+	} );
+}
+else
+{
+	alert( "Warning: ColVis requires DataTables 1.7 or greater - www.datatables.net/download");
+}
+
+})(jQuery);
diff --git a/install_minimal/upgrades/airtime-2.2.0/data/upgrade.sql b/install_minimal/upgrades/airtime-2.2.0/data/upgrade.sql
index ab129de75..71f59a40d 100644
--- a/install_minimal/upgrades/airtime-2.2.0/data/upgrade.sql
+++ b/install_minimal/upgrades/airtime-2.2.0/data/upgrade.sql
@@ -1,6 +1,9 @@
 DELETE FROM cc_pref WHERE keystr = 'system_version';
 INSERT INTO cc_pref (keystr, valstr) VALUES ('system_version', '2.2.0');
 
+--DELETE user column order prefs, since the number of columns has increased in 2.2
+DELETE FROM cc_pref where keystr = 'library_datatable';
+DELETE FROM cc_pref where keystr = 'timeline_datatable';
 
 INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s1_name', 'Airtime!', 'string');
 INSERT INTO cc_stream_setting (keyname, value, type) VALUES ('s2_name', '', 'string');