template/html/jquery-tablesorter.js
function( table, c ) {
         // if no thead or tbody, or tablesorter is already present, quit
         if ( !table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true ) {
            if ( c.debug ) {
               if ( table.hasInitialized ) {
                  console.warn( 'Stopping initialization. Tablesorter has already been initialized' );
               } else {
                  console.error( 'Stopping initialization! No table, thead or tbody', table );
               }
            }
            return;
         }

         var tmp = '',
          $table = $( table ),
          meta = $.metadata;
         // initialization flag
         table.hasInitialized = false;
         // table is being processed flag
         table.isProcessing = true;
         // make sure to store the config object
         table.config = c;
         // save the settings where they read
         $.data( table, 'tablesorter', c );
         if ( c.debug ) {
            console[ console.group ? 'group' : 'log' ]( 'Initializing tablesorter' );
            $.data( table, 'startoveralltimer', new Date() );
         }

         // removing this in version 3 (only supports jQuery 1.7+)
         c.supportsDataObject = ( function( version ) {
            version[ 0 ] = parseInt( version[ 0 ], 10 );
            return ( version[ 0 ] > 1 ) || ( version[ 0 ] === 1 && parseInt( version[ 1 ], 10 ) >= 4 );
         })( $.fn.jquery.split( '.' ) );
         // ensure case insensitivity
         c.emptyTo = c.emptyTo.toLowerCase();
         c.stringTo = c.stringTo.toLowerCase();
         c.last = { sortList : [], clickedIndex : -1 };
         // add table theme class only if there isn't already one there
         if ( !/tablesorter\-/.test( $table.attr( 'class' ) ) ) {
            tmp = ( c.theme !== '' ? ' tablesorter-' + c.theme : '' );
         }
         c.table = table;
         c.$table = $table
          .addClass( ts.css.table + ' ' + c.tableClass + tmp )
          .attr( 'role', 'grid' );
         c.$headers = $table.find( c.selectorHeaders );

         // give the table a unique id, which will be used in namespace binding
         if ( !c.namespace ) {
            c.namespace = '.tablesorter' + Math.random().toString( 16 ).slice( 2 );
         } else {
            // make sure namespace starts with a period & doesn't have weird characters
            c.namespace = '.' + c.namespace.replace( ts.regex.nonWord, '' );
         }

         c.$table.children().children( 'tr' ).attr( 'role', 'row' );
         c.$tbodies = $table.children( 'tbody:not(.' + c.cssInfoBlock + ')' ).attr({
            'aria-live' : 'polite',
            'aria-relevant' : 'all'
         });
         if ( c.$table.children( 'caption' ).length ) {
            tmp = c.$table.children( 'caption' )[ 0 ];
            if ( !tmp.id ) { tmp.id = c.namespace.slice( 1 ) + 'caption'; }
            c.$table.attr( 'aria-labelledby', tmp.id );
         }
         c.widgetInit = {}; // keep a list of initialized widgets
         // change textExtraction via data-attribute
         c.textExtraction = c.$table.attr( 'data-text-extraction' ) || c.textExtraction || 'basic';
         // build headers
         ts.buildHeaders( c );
         // fixate columns if the users supplies the fixedWidth option
         // do this after theme has been applied
         ts.fixColumnWidth( table );
         // add widgets from class name
         ts.addWidgetFromClass( table );
         // add widget options before parsing (e.g. grouping widget has parser settings)
         ts.applyWidgetOptions( table );
         // try to auto detect column type, and store in tables config
         ts.setupParsers( c );
         // start total row count at zero
         c.totalRows = 0;
         // build the cache for the tbody cells
         // delayInit will delay building the cache until the user starts a sort
         if ( !c.delayInit ) { ts.buildCache( c ); }
         // bind all header events and methods
         ts.bindEvents( table, c.$headers, true );
         ts.bindMethods( c );
         // get sort list from jQuery data or metadata
         // in jQuery < 1.4, an error occurs when calling $table.data()
         if ( c.supportsDataObject && typeof $table.data().sortlist !== 'undefined' ) {
            c.sortList = $table.data().sortlist;
         } else if ( meta && ( $table.metadata() && $table.metadata().sortlist ) ) {
            c.sortList = $table.metadata().sortlist;
         }
         // apply widget init code
         ts.applyWidget( table, true );
         // if user has supplied a sort list to constructor
         if ( c.sortList.length > 0 ) {
            ts.sortOn( c, c.sortList, {}, !c.initWidgets );
         } else {
            ts.setHeadersCss( c );
            if ( c.initWidgets ) {
               // apply widget format
               ts.applyWidget( table, false );
            }
         }

         // show processesing icon
         if ( c.showProcessing ) {
            $table
             .unbind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace )
             .bind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace, function( e ) {
                clearTimeout( c.timerProcessing );
                ts.isProcessing( table );
                if ( e.type === 'sortBegin' ) {
                   c.timerProcessing = setTimeout( function() {
                      ts.isProcessing( table, true );
                   }, 500 );
                }
             });
         }

         // initialized
         table.hasInitialized = true;
         table.isProcessing = false;
         if ( c.debug ) {
            console.log( 'Overall initialization time: ' + ts.benchmark( $.data( table, 'startoveralltimer' ) ) );
            if ( c.debug && console.groupEnd ) { console.groupEnd(); }
         }
         $table.triggerHandler( 'tablesorter-initialized', table );
         if ( typeof c.initialized === 'function' ) {
            c.initialized( table );
         }
      }
function( table, c ) {
         // if no thead or tbody, or tablesorter is already present, quit
         if ( !table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true ) {
            if ( c.debug ) {
               if ( table.hasInitialized ) {
                  console.warn( 'Stopping initialization. Tablesorter has already been initialized' );
               } else {
                  console.error( 'Stopping initialization! No table, thead or tbody', table );
               }
            }
            return;
         }

         var tmp = '',
          $table = $( table ),
          meta = $.metadata;
         // initialization flag
         table.hasInitialized = false;
         // table is being processed flag
         table.isProcessing = true;
         // make sure to store the config object
         table.config = c;
         // save the settings where they read
         $.data( table, 'tablesorter', c );
         if ( c.debug ) {
            console[ console.group ? 'group' : 'log' ]( 'Initializing tablesorter' );
            $.data( table, 'startoveralltimer', new Date() );
         }

         // removing this in version 3 (only supports jQuery 1.7+)
         c.supportsDataObject = ( function( version ) {
            version[ 0 ] = parseInt( version[ 0 ], 10 );
            return ( version[ 0 ] > 1 ) || ( version[ 0 ] === 1 && parseInt( version[ 1 ], 10 ) >= 4 );
         })( $.fn.jquery.split( '.' ) );
         // ensure case insensitivity
         c.emptyTo = c.emptyTo.toLowerCase();
         c.stringTo = c.stringTo.toLowerCase();
         c.last = { sortList : [], clickedIndex : -1 };
         // add table theme class only if there isn't already one there
         if ( !/tablesorter\-/.test( $table.attr( 'class' ) ) ) {
            tmp = ( c.theme !== '' ? ' tablesorter-' + c.theme : '' );
         }
         c.table = table;
         c.$table = $table
          .addClass( ts.css.table + ' ' + c.tableClass + tmp )
          .attr( 'role', 'grid' );
         c.$headers = $table.find( c.selectorHeaders );

         // give the table a unique id, which will be used in namespace binding
         if ( !c.namespace ) {
            c.namespace = '.tablesorter' + Math.random().toString( 16 ).slice( 2 );
         } else {
            // make sure namespace starts with a period & doesn't have weird characters
            c.namespace = '.' + c.namespace.replace( ts.regex.nonWord, '' );
         }

         c.$table.children().children( 'tr' ).attr( 'role', 'row' );
         c.$tbodies = $table.children( 'tbody:not(.' + c.cssInfoBlock + ')' ).attr({
            'aria-live' : 'polite',
            'aria-relevant' : 'all'
         });
         if ( c.$table.children( 'caption' ).length ) {
            tmp = c.$table.children( 'caption' )[ 0 ];
            if ( !tmp.id ) { tmp.id = c.namespace.slice( 1 ) + 'caption'; }
            c.$table.attr( 'aria-labelledby', tmp.id );
         }
         c.widgetInit = {}; // keep a list of initialized widgets
         // change textExtraction via data-attribute
         c.textExtraction = c.$table.attr( 'data-text-extraction' ) || c.textExtraction || 'basic';
         // build headers
         ts.buildHeaders( c );
         // fixate columns if the users supplies the fixedWidth option
         // do this after theme has been applied
         ts.fixColumnWidth( table );
         // add widgets from class name
         ts.addWidgetFromClass( table );
         // add widget options before parsing (e.g. grouping widget has parser settings)
         ts.applyWidgetOptions( table );
         // try to auto detect column type, and store in tables config
         ts.setupParsers( c );
         // start total row count at zero
         c.totalRows = 0;
         // build the cache for the tbody cells
         // delayInit will delay building the cache until the user starts a sort
         if ( !c.delayInit ) { ts.buildCache( c ); }
         // bind all header events and methods
         ts.bindEvents( table, c.$headers, true );
         ts.bindMethods( c );
         // get sort list from jQuery data or metadata
         // in jQuery < 1.4, an error occurs when calling $table.data()
         if ( c.supportsDataObject && typeof $table.data().sortlist !== 'undefined' ) {
            c.sortList = $table.data().sortlist;
         } else if ( meta && ( $table.metadata() && $table.metadata().sortlist ) ) {
            c.sortList = $table.metadata().sortlist;
         }
         // apply widget init code
         ts.applyWidget( table, true );
         // if user has supplied a sort list to constructor
         if ( c.sortList.length > 0 ) {
            ts.sortOn( c, c.sortList, {}, !c.initWidgets );
         } else {
            ts.setHeadersCss( c );
            if ( c.initWidgets ) {
               // apply widget format
               ts.applyWidget( table, false );
            }
         }

         // show processesing icon
         if ( c.showProcessing ) {
            $table
             .unbind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace )
             .bind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace, function( e ) {
                clearTimeout( c.timerProcessing );
                ts.isProcessing( table );
                if ( e.type === 'sortBegin' ) {
                   c.timerProcessing = setTimeout( function() {
                      ts.isProcessing( table, true );
                   }, 500 );
                }
             });
         }

         // initialized
         table.hasInitialized = true;
         table.isProcessing = false;
         if ( c.debug ) {
            console.log( 'Overall initialization time: ' + ts.benchmark( $.data( table, 'startoveralltimer' ) ) );
            if ( c.debug && console.groupEnd ) { console.groupEnd(); }
         }
         $table.triggerHandler( 'tablesorter-initialized', table );
         if ( typeof c.initialized === 'function' ) {
            c.initialized( table );
         }
      }
/*
▄█████ ██████ ██████ ██  ██ █████▄
▀█▄    ██▄▄     ██   ██  ██ ██▄▄██
▀█▄ ██▀▀     ██   ██  ██ ██▀▀▀
█████▀ ██████   ██   ▀████▀ ██