tablesorter/dist/js/jquery.tablesorter.combined.min.js

1044 lines
120 KiB
JavaScript
Raw Normal View History

2015-10-31 15:08:21 +00:00
/*** This file is dynamically generated ***
*/
2015-10-31 16:06:09 +00:00
/*! tablesorter (FORK) - updated 10-31-2015 (v2.24.0)*/
2015-10-31 15:08:21 +00:00
/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
2015-10-31 16:06:09 +00:00
!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&"object"==typeof module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){return function(a){"use strict";var b=a.tablesorter={version:"2.24.0",parsers:[],widgets:[],defaults:{
2015-10-31 15:08:21 +00:00
// *** appearance
theme:"default",// adds tablesorter-{theme} to the table for styling
widthFixed:!1,// adds colgroup to fix widths of columns
showProcessing:!1,// show an indeterminate timer icon in the header when the table is sorted or filtered.
headerTemplate:"{content}",// header layout template (HTML ok); {content} = innerHTML, {icon} = <i/> // class from cssIcon
onRenderTemplate:null,// function( index, template ){ return template; }, // template is a string
onRenderHeader:null,// function( index ){}, // nothing to return
// *** functionality
cancelSelection:!0,// prevent text selection in the header
tabIndex:!0,// add tabindex to header for keyboard accessibility
dateFormat:"mmddyyyy",// other options: 'ddmmyyy' or 'yyyymmdd'
sortMultiSortKey:"shiftKey",// key used to select additional columns
sortResetKey:"ctrlKey",// key used to remove sorting on a column
usNumberFormat:!0,// false for German '1.234.567,89' or French '1 234 567,89'
delayInit:!1,// if false, the parsed table contents will not update until the first sort
serverSideSorting:!1,// if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.
resort:!0,// default setting to trigger a resort after an 'update', 'addRows', 'updateCell', etc has completed
// *** sort options
headers:{},// set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
ignoreCase:!0,// ignore case while sorting
sortForce:null,// column(s) first sorted; always applied
sortList:[],// Initial sort order; applied initially; updated when manually sorted
sortAppend:null,// column(s) sorted last; always applied
sortStable:!1,// when sorting two rows with exactly the same content, the original sort order is maintained
sortInitialOrder:"asc",// sort direction on first click
sortLocaleCompare:!1,// replace equivalent character (accented characters)
sortReset:!1,// third click on the header will reset column to default - unsorted
sortRestart:!1,// restart sort to 'sortInitialOrder' when clicking on previously unsorted columns
emptyTo:"bottom",// sort empty cell to bottom, top, none, zero, emptyMax, emptyMin
stringTo:"max",// sort strings in numerical column as max, min, top, bottom, zero
textExtraction:"basic",// text extraction method/function - function( node, table, cellIndex ){}
textAttribute:"data-text",// data-attribute that contains alternate cell text (used in default textExtraction function)
textSorter:null,// choose overall or specific column sorter function( a, b, direction, table, columnIndex ) [alt: ts.sortText]
numberSorter:null,// choose overall numeric sorter function( a, b, direction, maxColumnValue )
// *** widget options
widgets:[],// method to add widgets, e.g. widgets: ['zebra']
widgetOptions:{zebra:["even","odd"]},initWidgets:!0,// apply widgets on tablesorter initialization
widgetClass:"widget-{name}",// table class name template to match to include a widget
// *** callbacks
initialized:null,// function( table ){},
// *** extra css class names
tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",// processing icon applied to header during sort/filter
cssChildRow:"tablesorter-childRow",// class name indiciating that a row is to be attached to the its parent
cssInfoBlock:"tablesorter-infoOnly",// don't sort tbody with this class name (only one class name allowed here!)
cssNoSort:"tablesorter-noSort",// class name added to element inside header; clicking on it won't cause a sort
cssIgnoreRow:"tablesorter-ignoreRow",// header row to ignore; cells within this row will not be added to c.$headers
cssIcon:"tablesorter-icon",// if this class does not exist, the {icon} will not be added from the headerTemplate
cssIconNone:"",// class name added to the icon when there is no column sort
cssIconAsc:"",// class name added to the icon when the column has an ascending sort
cssIconDesc:"",// class name added to the icon when the column has a descending sort
// *** events
pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",
// *** selectors
selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",// jQuery selector of content within selectorHeaders that is clickable to trigger a sort
selectorRemove:".remove-me",
// *** advanced
debug:!1,
// *** Internal variables
headerList:[],empties:{},strings:{},parsers:[]},
// internal css classes - these will ALWAYS be added to
// the table and MUST only contain one class name - fixes #381
css:{table:"tablesorter",cssHasChild:"tablesorter-hasChildRow",childRow:"tablesorter-childRow",colgroup:"tablesorter-colgroup",header:"tablesorter-header",headerRow:"tablesorter-headerRow",headerIn:"tablesorter-header-inner",icon:"tablesorter-icon",processing:"tablesorter-processing",sortAsc:"tablesorter-headerAsc",sortDesc:"tablesorter-headerDesc",sortNone:"tablesorter-headerUnSorted"},
// labels applied to sortable headers for accessibility (aria) support
language:{sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",nextAsc:"activate to apply an ascending sort",nextDesc:"activate to apply a descending sort",nextNone:"activate to remove the sort"},regex:{templateContent:/\{content\}/g,templateIcon:/\{icon\}/g,templateName:/\{name\}/i,spaces:/\s+/g,nonWord:/\W/g,formElements:/(input|select|button|textarea)/i,
// *** sort functions ***
// regex used in natural sort
// chunk/tokenize numbers & letters
chunk:/(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,
// replace chunks @ ends
chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i,
// *** formatFloat ***
comma:/,/g,digitNonUS:/[\s|\.]/g,digitNegativeTest:/^\s*\([.\d]+\)/,digitNegativeReplace:/^\s*\(([.\d]+)\)/,
// *** isDigit ***
digitTest:/^[\-+(]?\d+[)]?$/,digitReplace:/[,.'"\s]/g},
// digit sort text location; keeping max+/- for backwards compatibility
string:{max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,"null":0,top:!0,bottom:!1},
// These methods can be applied on table.config instance
instanceMethods:{},/*
*/
setup:function(c,d){
// if no thead or tbody, or tablesorter is already present, quit
if(!c||!c.tHead||0===c.tBodies.length||c.hasInitialized===!0)return void(d.debug&&(c.hasInitialized?console.warn("Stopping initialization. Tablesorter has already been initialized"):console.error("Stopping initialization! No table, thead or tbody")));var e="",f=a(c),g=a.metadata;
// initialization flag
c.hasInitialized=!1,
// table is being processed flag
c.isProcessing=!0,
// make sure to store the config object
c.config=d,
// save the settings where they read
a.data(c,"tablesorter",d),d.debug&&(console[console.group?"group":"log"]("Initializing tablesorter"),a.data(c,"startoveralltimer",new Date)),
// removing this in version 3 (only supports jQuery 1.7+)
d.supportsDataObject=function(a){return a[0]=parseInt(a[0],10),a[0]>1||1===a[0]&&parseInt(a[1],10)>=4}(a.fn.jquery.split(".")),
// ensure case insensitivity
d.emptyTo=d.emptyTo.toLowerCase(),d.stringTo=d.stringTo.toLowerCase(),d.last={sortList:[],clickedIndex:-1},
// add table theme class only if there isn't already one there
/tablesorter\-/.test(f.attr("class"))||(e=""!==d.theme?" tablesorter-"+d.theme:""),d.table=c,d.$table=f.addClass(b.css.table+" "+d.tableClass+e).attr("role","grid"),d.$headers=f.find(d.selectorHeaders),
// give the table a unique id, which will be used in namespace binding
d.namespace?d.namespace="."+d.namespace.replace(b.regex.nonWord,""):d.namespace=".tablesorter"+Math.random().toString(16).slice(2),d.$table.children().children("tr").attr("role","row"),d.$tbodies=f.children("tbody:not(."+d.cssInfoBlock+")").attr({"aria-live":"polite","aria-relevant":"all"}),d.$table.children("caption").length&&(e=d.$table.children("caption")[0],e.id||(e.id=d.namespace.slice(1)+"caption"),d.$table.attr("aria-labelledby",e.id)),d.widgetInit={},// keep a list of initialized widgets
// change textExtraction via data-attribute
d.textExtraction=d.$table.attr("data-text-extraction")||d.textExtraction||"basic",
// build headers
b.buildHeaders(d),
// fixate columns if the users supplies the fixedWidth option
// do this after theme has been applied
b.fixColumnWidth(c),
// add widgets from class name
b.addWidgetFromClass(c),
// add widget options before parsing (e.g. grouping widget has parser settings)
b.applyWidgetOptions(c),
// try to auto detect column type, and store in tables config
b.setupParsers(d),
// start total row count at zero
d.totalRows=0,
// build the cache for the tbody cells
// delayInit will delay building the cache until the user starts a sort
d.delayInit||b.buildCache(d),
// bind all header events and methods
b.bindEvents(c,d.$headers,!0),b.bindMethods(d),
// get sort list from jQuery data or metadata
// in jQuery < 1.4, an error occurs when calling $table.data()
d.supportsDataObject&&"undefined"!=typeof f.data().sortlist?d.sortList=f.data().sortlist:g&&f.metadata()&&f.metadata().sortlist&&(d.sortList=f.metadata().sortlist),
// apply widget init code
b.applyWidget(c,!0),
// if user has supplied a sort list to constructor
d.sortList.length>0?b.sortOn(d,d.sortList,{},!d.initWidgets):(b.setHeadersCss(d),d.initWidgets&&
// apply widget format
b.applyWidget(c,!1)),
// show processesing icon
d.showProcessing&&f.unbind("sortBegin"+d.namespace+" sortEnd"+d.namespace).bind("sortBegin"+d.namespace+" sortEnd"+d.namespace,function(a){clearTimeout(d.processTimer),b.isProcessing(c),"sortBegin"===a.type&&(d.processTimer=setTimeout(function(){b.isProcessing(c,!0)},500))}),
// initialized
c.hasInitialized=!0,c.isProcessing=!1,d.debug&&(console.log("Overall initialization time: "+b.benchmark(a.data(c,"startoveralltimer"))),d.debug&&console.groupEnd&&console.groupEnd()),f.trigger("tablesorter-initialized",c),"function"==typeof d.initialized&&d.initialized(c)},bindMethods:function(c){var d=c.$table,e=c.namespace,f="sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(e+" ");
// apply easy methods that trigger bound events
d.unbind(f.replace(b.regex.spaces," ")).bind("sortReset"+e,function(a,c){a.stopPropagation(),
// using this.config to ensure functions are getting a non-cached version of the config
b.sortReset(this.config,c)}).bind("updateAll"+e,function(a,c,d){a.stopPropagation(),b.updateAll(this.config,c,d)}).bind("update"+e+" updateRows"+e,function(a,c,d){a.stopPropagation(),b.update(this.config,c,d)}).bind("updateHeaders"+e,function(a,c){a.stopPropagation(),b.updateHeaders(this.config,c)}).bind("updateCell"+e,function(a,c,d,e){a.stopPropagation(),b.updateCell(this.config,c,d,e)}).bind("addRows"+e,function(a,c,d,e){a.stopPropagation(),b.addRows(this.config,c,d,e)}).bind("updateComplete"+e,function(){this.isUpdating=!1}).bind("sorton"+e,function(a,c,d,e){a.stopPropagation(),b.sortOn(this.config,c,d,e)}).bind("appendCache"+e,function(c,d,e){c.stopPropagation(),b.appendCache(this.config,e),a.isFunction(d)&&d(this)}).bind("updateCache"+e,function(a,c,d){a.stopPropagation(),b.updateCache(this.config,c,d)}).bind("applyWidgetId"+e,function(a,c){a.stopPropagation(),b.getWidgetById(c).format(this,this.config,this.config.widgetOptions)}).bind("applyWidgets"+e,function(a,c){a.stopPropagation(),
// apply widgets
b.applyWidget(this,c)}).bind("refreshWidgets"+e,function(a,c,d){a.stopPropagation(),b.refreshWidgets(this,c,d)}).bind("destroy"+e,function(a,c,d){a.stopPropagation(),b.destroy(this,c,d)}).bind("resetToLoadState"+e,function(d){d.stopPropagation(),
// remove all widgets
b.removeWidget(this,!0,!1),c=a.extend(!0,b.defaults,c.originalSettings),this.hasInitialized=!1,b.setup(this,c)})},bindEvents:function(c,d,e){c=a(c)[0];var f,g=c.config,h=g.namespace,i=null;e!==!0&&(d.addClass(h.slice(1)+"_extra_headers"),f=a.fn.closest?d.closest("table")[0]:d.parents("table")[0],f&&"TABLE"===f.nodeName&&f!==c&&a(f).addClass(h.slice(1)+"_extra_table")),f=(g.pointerDown+" "+g.pointerUp+" "+g.pointerClick+" sort keyup ").replace(b.regex.spaces," ").split(" ").join(h+" "),d.find(g.selectorSort).add(d.filter(g.selectorSort)).unbind(f).bind(f,function(c,e){var f,h,j,k=a(c.target),l=" "+c.type+" ";if(!(1!==(c.which||c.button)&&!l.match(" "+g.pointerClick+" | sort | keyup ")||" keyup "===l&&13!==c.which||l.match(" "+g.pointerClick+" ")&&"undefined"!=typeof c.which||l.match(" "+g.pointerUp+" ")&&i!==c.target&&e!==!0)){if(l.match(" "+g.pointerDown+" "))return i=c.target,j=k.jquery.split("."),void("1"===j[0]&&j[1]<4&&c.preventDefault());if(i=null,b.regex.formElements.test(c.target.nodeName)||k.hasClass(g.cssNoSort)||k.parents("."+g.cssNoSort).length>0||k.parents("button").length>0)return!g.cancelSelection;g.delayInit&&b.isEmptyObject(g.cache)&&b.buildCache(g),f=a.fn.closest?a(this).closest("th, td"):/TH|TD/.test(this.nodeName)?a(this):a(this).parents("th, td"),j=d.index(f),g.last.clickedIndex=0>j?f.attr("data-column"):j,h=g.$headers[g.last.clickedIndex],h&&!h.sortDisabled&&b.initSort(g,h,c)}}),g.cancelSelection&&d.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})},buildHeaders:function(c){var d,e,f,g;for(c.headerList=[],c.headerContent=[],c.sortVars=[],c.debug&&(f=new Date),
// children tr in tfoot - see issue #196 & #547
c.columns=b.computeColumnIndex(c.$table.children("thead, tfoot").children("tr")),e=c.cssIcon?'<i class="'+(c.cssIcon===b.css.icon?b.css.icon:c.cssIcon+" "+b.css.icon)+'"></i>':"",c.$headers=a(a.map(c.$table.find(c.selectorHeaders),function(d,f){var g,h,i,j,k,l=a(d);if(!l.parent().hasClass(c.cssIgnoreRow))return g=b.getColumnData(c.table,c.headers,f,!0),c.headerContent[f]=l.html(),""===c.headerTemplate||l.find("."+b.css.headerIn).length||(j=c.headerTemplate.replace(b.regex.templateContent,l.html()).replace(b.regex.templateIcon,l.find("."+b.css.icon).length?"":e),c.onRenderTemplate&&(h=c.onRenderTemplate.apply(l,[f,j]),h&&"string"==typeof h&&(j=h)),l.html('<div class="'+b.css.headerIn+'">'+j+"</div>")),c.onRenderHeader&&c.onRenderHeader.apply(l,[f,c,c.$table]),i=parseInt(l.attr("data-column"),10),d.column=i,k=b.getData(l,g,"sortInitialOrder")||c.sortInitialOrder,c.sortVars[i]={count:-1,order:b.formatSortingOrder(k)?[1,0,2]:[0,1,2],lockedOrder:!1},k=b.getData(l,g,"lockedOrder")||!1,"undefined"!=typeof k&&k!==!1&&(c.sortVars[i].lockedOrder=!0,c.sortVars[i].order=b.formatSortingOrder(k)?[1,1,1]:[0,0,0]),c.headerList[f]=d,l.addClass(b.css.header+" "+c.cssHeader).parent().addClass(b.css.headerRow+" "+c.cssHeaderRow).attr("role","row"),c.tabIndex&&l.attr("tabindex",0),d})),c.$headerIndexed=[],g=0;g<c.columns;g++)
// colspan in header making a column undefined
b.isEmptyObject(c.sortVars[g])&&(c.sortVars[g]={}),d=c.$headers.filter('[data-column="'+g+'"]'),c.$headerIndexed[g]=d.length?d.not(".sorter-false").length?d.not(".sorter-false").filter(":last"):d.filter(":last"):a();c.$table.find(c.selectorHeaders).attr({scope:"col",role:"columnheader"}),
// enable/disable sorting
b.updateHeader(c),c.debug&&(console.log("Built headers:"+b.benchmark(f)),console.log(c.$headers))},
// Use it to add a set of methods to table.config which will be available for all tables.
// This should be done before table initialization
addInstanceMethods:function(c){a.extend(b.instanceMethods,c)},/*
*/
setupParsers:function(a,c){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=a.table,s=0,t={};if(
// update table bodies in case we start with an empty table
a.$tbodies=a.$table.children("tbody:not(."+a.cssInfoBlock+")"),p="undefined"==typeof c?a.$tbodies:c,q=p.length,0===q)return a.debug?console.warn("Warning: *Empty table!* Not building a parser cache"):"";for(a.debug&&(o=new Date,console[console.group?"group":"log"]("Detecting parsers for each column")),e={extractors:[],parsers:[]};q>s;){if(d=p[s].rows,d.length)for(h=0,g=a.columns,i=0;g>i;i++)j=a.$headerIndexed[h],j&&j.length&&(k=b.getColumnData(r,a.headers,h),n=b.getParserById(b.getData(j,k,"extractor")),m=b.getParserById(b.getData(j,k,"sorter")),l="false"===b.getData(j,k,"parser"),a.empties[h]=(b.getData(j,k,"empty")||a.emptyTo||(a.emptyToBottom?"bottom":"top")).toLowerCase(),a.strings[h]=(b.getData(j,k,"string")||a.stringTo||"max").toLowerCase(),l&&(m=b.getParserById("no-parser")),n||(n=!1),m||(m=b.detectParserForColumn(a,d,-1,h)),a.debug&&(t["("+h+") "+j.text()]={parser:m.id,extractor:n?n.id:"none",string:a.strings[h],empty:a.empties[h]}),e.parsers[h]=m,e.extractors[h]=n,f=j[0].colSpan-1,f>0&&(h+=f,g+=f)),h++;s+=e.parsers.length?q:1}a.debug&&(b.isEmptyObject(t)?console.warn(" No parsers detected!"):console[console.table?"table":"log"](t),console.log("Completed detecting parsers"+b.benchmark(o)),console.groupEnd&&console.groupEnd()),a.parsers=e.parsers,a.extractors=e.extractors},addParser:function(a){var c,d=b.parsers.length,e=!0;for(c=0;d>c;c++)b.parsers[c].id.toLowerCase()===a.id.toLowerCase()&&(e=!1);e&&b.parsers.push(a)},getParserById:function(a){/*jshint eqeqeq:false */
if("false"==a)return!1;var c,d=b.parsers.length;for(c=0;d>c;c++)if(b.parsers[c].id.toLowerCase()===a.toString().toLowerCase())return b.parsers[c];return!1},detectParserForColumn:function(c,d,e,f){for(var g,h,i=b.parsers.length,j=!1,k="",l=!0;""===k&&l;)e++,d[e]?(j=d[e].cells[f],k=b.getElementText(c,j,f),h=a(j),c.debug&&console.log("Checking if value was empty on row "+e+", column: "+f+': "'+k+'"')):l=!1;for(;--i>=0;)
// ignore the default text parser because it will always be true
if(g=b.parsers[i],g&&"text"!==g.id&&g.is&&g.is(k,c.table,j,h))return g;
// nothing found, return the generic parser (text)
return b.getParserById("text")},getElementText:function(c,d,e){if(!d)return"";var f,g=c.textExtraction||"",
// node could be a jquery object
// http://jsperf.com/jquery-vs-instanceof-jquery/2
h=d.jquery?d:a(d);
// check data-attribute first when set to 'basic'; don't use node.innerText - it's really slow!
// http://www.kellegous.com/j/2013/02/27/innertext-vs-textcontent/
return"string"==typeof g?"basic"===g&&"undefined"!=typeof(f=h.attr(c.textAttribute))?a.trim(f):a.trim(d.textContent||h.text()):"function"==typeof g?a.trim(g(h[0],c.table,e)):"function"==typeof(f=b.getColumnData(c.table,g,e))?a.trim(f(h[0],c.table,e)):a.trim(h[0].textContent||h.text())},
// centralized function to extract/parse cell contents
getParsedText:function(a,c,d,e){"undefined"==typeof e&&(e=b.getElementText(a,c,d));
// if no parser, make sure to return the txt
var f=""+e,g=a.parsers[d],h=a.extractors[d];
// do extract before parsing, if there is one
// allow parsing if the string is empty, previously parsing would change it to zero,
// in case the parser needs to extract data from the table cell attributes
// make sure txt is a string (extractor may have converted it)
return g&&(h&&"function"==typeof h.format&&(e=h.format(e,a.table,c,d)),f="no-parser"===g.id?"":g.format(""+e,a.table,c,d),a.ignoreCase&&"string"==typeof f&&(f=f.toLowerCase())),f},/*
*/
buildCache:function(c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z=c.table,A=c.parsers;
// if no parsers found, return - it's an empty table.
if(
// update tbody variable
c.$tbodies=c.$table.children("tbody:not(."+c.cssInfoBlock+")"),l="undefined"==typeof e?c.$tbodies:e,c.cache={},c.totalRows=0,!A)return c.debug?console.warn("Warning: *Empty table!* Not building a cache"):"";for(c.debug&&(q=new Date),
// processing icon
c.showProcessing&&b.isProcessing(z,!0),k=0;k<l.length;k++){for(u=[],f=c.cache[k]={normalized:[]},r=l[k]&&l[k].rows.length||0,i=0;r>i;++i)
// if this is a child row, add it to the last row's children and continue to the next row
// ignore child row class, if it is the first row
if(s={
// order: original row order #
// $row : jQuery Object[]
child:[],// child row text (filter widget)
raw:[]},m=a(l[k].rows[i]),n=[],m.hasClass(c.cssChildRow)&&0!==i)for(y=f.normalized.length-1,t=f.normalized[y][c.columns],t.$row=t.$row.add(m),m.prev().hasClass(c.cssChildRow)||m.prev().addClass(b.css.cssHasChild),o=m.children("th, td"),y=t.child.length,t.child[y]=[],w=0,x=c.columns,j=0;x>j;j++)p=o[j],p&&(t.child[y][j]=b.getParsedText(c,p,j),v=o[j].colSpan-1,v>0&&(w+=v,x+=v)),w++;else{for(s.$row=m,s.order=i,w=0,x=c.columns,j=0;x>j;++j)p=m[0].cells[j],"undefined"==typeof A[w]?c.debug&&console.warn("No parser found for column "+j+"; cell:",p,"does it have a header?"):p&&(g=b.getElementText(c,p,w),s.raw[w]=g,h=b.getParsedText(c,p,w,g),n[w]=h,"numeric"===(A[w].type||"").toLowerCase()&&(u[w]=Math.max(Math.abs(h)||0,u[w]||0)),v=p.colSpan-1,v>0&&(w+=v,x+=v)),w++;
// ensure rowData is always in the same location (after the last column)
n[c.columns]=s,f.normalized.push(n)}f.colMax=u,
// total up rows, not including child rows
c.totalRows+=f.normalized.length}c.showProcessing&&b.isProcessing(z),c.debug&&console.log("Building cache for "+r+" rows"+b.benchmark(q)),a.isFunction(d)&&d(z)},getColumnText:function(c,d,e,f){c=a(c)[0];var g,h,i,j,k,l,m,n,o,p,q="function"==typeof e,r="all"===d,s={raw:[],parsed:[],$cell:[]},t=c.config;if(!b.isEmptyObject(t)){for(k=t.$tbodies.length,g=0;k>g;g++)for(i=t.cache[g].normalized,l=i.length,h=0;l>h;h++)j=i[h],(!f||j[t.columns].$row.is(f))&&(p=!0,n=r?j.slice(0,t.columns):j[d],j=j[t.columns],m=r?j.raw:j.raw[d],o=r?j.$row.children():j.$row.children().eq(d),q&&(p=e({tbodyIndex:g,rowIndex:h,parsed:n,raw:m,$row:j.$row,$cell:o})),p!==!1&&(s.parsed.push(n),s.raw.push(m),s.$cell.push(o)));
// return everything
return s}t.debug&&console.warn("No cache found - aborting getColumnText function!")},/*
*/
setHeadersCss:function(c){var d,e,f,g,h,i,j,k,l=c.sortList,m=l.length,n=b.css.sortNone+" "+c.cssNone,o=[b.css.sortAsc+" "+c.cssAsc,b.css.sortDesc+" "+c.cssDesc],p=[c.cssIconAsc,c.cssIconDesc,c.cssIconNone],q=["ascending","descending"],
// find the footer
r=c.$table.find("tfoot tr").children().add(a(c.namespace+"_extra_headers")).removeClass(o.join(" "));for(
// remove all header information
c.$headers.removeClass(o.join(" ")).addClass(n).attr("aria-sort","none").find("."+b.css.icon).removeClass(p.join(" ")).addClass(p[2]),f=0;m>f;f++)
// direction = 2 means reset!
if(2!==l[f][1]&&(d=c.$headers.filter(function(d,e){for(
// only include headers that are in the sortList (this includes colspans)
var f=!0,g=a(e),h=parseInt(g.attr("data-column"),10),i=h+e.colSpan;i>h;h++)f=f?b.isValueInArray(h,c.sortList)>-1:!1;return f}),d=d.not(".sorter-false").filter('[data-column="'+l[f][0]+'"]'+(1===m?":last":"")),d.length)){for(g=0;g<d.length;g++)d[g].sortDisabled||d.eq(g).removeClass(n).addClass(o[l[f][1]]).attr("aria-sort",q[l[f][1]]).find("."+b.css.icon).removeClass(p[2]).addClass(p[l[f][1]]);
// add sorted class to footer & extra headers, if they exist
r.length&&r.filter('[data-column="'+l[f][0]+'"]').removeClass(n).addClass(o[l[f][1]])}for(m=c.$headers.length,r=c.$headers.not(".sorter-false"),f=0;m>f;f++)h=r.eq(f),h.length&&(e=r[f],g=parseInt(h.attr("data-column"),10),i=c.sortVars[g].order[(c.sortVars[g].count+1)%(c.sortReset?3:2)],k=h.hasClass(b.css.sortAsc)?"sortAsc":h.hasClass(b.css.sortDesc)?"sortDesc":"sortNone",j=a.trim(h.text())+": "+b.language[k]+b.language[0===i?"nextAsc":1===i?"nextDesc":"nextNone"],h.attr("aria-label",j))},updateHeader:function(a){var c,d,e,f,g=a.table,h=a.$headers.length;for(c=0;h>c;c++)e=a.$headers.eq(c),f=b.getColumnData(g,a.headers,c,!0),d="false"===b.getData(e,f,"sorter")||"false"===b.getData(e,f,"parser"),e[0].sortDisabled=d,e[d?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+d),a.tabIndex&&(d?e.removeAttr("tabindex"):e.attr("tabindex","0")),g.id&&(d?e.removeAttr("aria-controls"):e.attr("aria-controls",g.id))},updateHeaderSortCount:function(b,c){var d,e,f,g,h,i,j,k,l=c||b.sortList,m=l.length;for(b.sortList=[],g=0;m>g;g++)
// prevents error if sorton array is wrong
if(j=l[g],d=parseInt(j[0],10),d<b.columns){
// 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext
switch(k=b.sortVars[d].order,e=(""+j[1]).match(/^(1|d|s|o|n)/),e=e?e[0]:""){case"1":case"d":// descending
e=1;break;case"s":// same direction (as primary column)
// if primary sort is set to 's', make it ascending
e=h||0;break;case"o":i=k[(h||0)%(b.sortReset?3:2)],
// opposite of primary column; but resets if primary resets
e=0===i?1:1===i?0:2;break;case"n":e=k[++b.sortVars[d].count%(b.sortReset?3:2)];break;default:// ascending
e=0}h=0===g?e:h,f=[d,parseInt(e,10)||0],b.sortList.push(f),e=a.inArray(f[1],k),// fixes issue #167
b.sortVars[d].count=e>=0?e:f[1]%(b.sortReset?3:2)}},updateAll:function(a,c,d){var e=a.table;e.isUpdating=!0,b.refreshWidgets(e,!0,!0),b.buildHeaders(a),b.bindEvents(e,a.$headers,!0),b.bindMethods(a),b.commonUpdate(a,c,d)},update:function(a,c,d){var e=a.table;e.isUpdating=!0,
// update sorting (if enabled/disabled)
b.updateHeader(a),b.commonUpdate(a,c,d)},
// simple header update - see #989
updateHeaders:function(a,c){a.table.isUpdating=!0,b.buildHeaders(a),b.bindEvents(a.table,a.$headers,!0),b.resortComplete(a,c)},updateCell:function(c,d,e,f){c.table.isUpdating=!0,c.$table.find(c.selectorRemove).remove();
// get position from the dom
var g,h,i,j,k,l,m=c.$tbodies,n=a(d),
// update cache - format: function( s, table, cell, cellIndex )
// no closest in jQuery v1.2.6
o=m.index(a.fn.closest?n.closest("tbody"):n.parents("tbody").filter(":first")),p=c.cache[o],q=a.fn.closest?n.closest("tr"):n.parents("tr").filter(":first");// in case cell is a jQuery object
// tbody may not exist if update is initialized while tbody is removed for processing
if(d=n[0],m.length&&o>=0){if(i=m.eq(o).find("tr").index(q),k=p.normalized[i],l=q[0].cells.length,l!==c.columns)for(j=0,g=!1,h=0;l>h;h++)g||q[0].cells[h]===d?g=!0:j+=q[0].cells[h].colSpan;else j=n.index();g=b.getElementText(c,d,j),// raw
k[c.columns].raw[j]=g,g=b.getParsedText(c,d,j,g),k[j]=g,// parsed
k[c.columns].$row=q,"numeric"===(c.parsers[j].type||"").toLowerCase()&&(
// update column max value (ignore sign)
p.colMax[j]=Math.max(Math.abs(g)||0,p.colMax[j]||0)),g="undefined"!==e?e:c.resort,g!==!1?
// widgets will be reapplied
b.checkResort(c,g,f):
// don't reapply widgets is resort is false, just in case it causes
// problems with element focus
b.resortComplete(c,f)}},addRows:function(c,d,e,f){var g,h,i,j,k,l,m,n,o,p,q,r,
// allow passing a row string if only one non-info tbody exists in the table
s="string"==typeof d&&1===c.$tbodies.length&&/<tr/.test(d||""),t=c.table;if(s)d=a(d),c.$tbodies.append(d);else if(!(d&&d instanceof jQuery&&(a.fn.closest?d.closest("table")[0]:d.parents("table")[0])===c.table))return c.debug&&console.error("addRows method requires (1) a jQuery selector reference to rows that have already been added to the table, or (2) row HTML string to be added to a table with only one tbody"),!1;if(t.isUpdating=!0,b.isEmptyObject(c.cache))
// empty table, do an update instead - fixes #450
b.updateHeader(c),b.commonUpdate(c,e,f);else{
// add each row
for(k=d.filter("tr").attr("role","row").length,i=c.$tbodies.index(d.parents("tbody").filter(":first")),c.parsers&&c.parsers.length||b.setupParsers(c),j=0;k>j;j++){
// add each cell
for(n=0,m=d[j].cells.length,p=[],o={child:[],raw:[],$row:d.eq(j),order:c.cache[i].normalized.length},l=0;m>l;l++)q=d[j].cells[l],g=b.getElementText(c,q,n),o.raw[n]=g,h=b.getParsedText(c,q,n,g),p[n]=h,"numeric"===(c.parsers[n].type||"").toLowerCase()&&(c.cache[i].colMax[n]=Math.max(Math.abs(h)||0,c.cache[i].colMax[n]||0)),r=q.colSpan-1,r>0&&(n+=r),n++;
// add the row data to the end
p[c.columns]=o,
// update cache
c.cache[i].normalized.push(p)}
// resort using current settings
b.checkResort(c,e,f)}},updateCache:function(a,c,d){
// rebuild parsers
a.parsers&&a.parsers.length||b.setupParsers(a,d),
// rebuild the cache map
b.buildCache(a,c,d)},
// init flag (true) used by pager plugin to prevent widget application
// renamed from appendToTable
appendCache:function(a,c){var d,e,f,g,h,i,j,k=a.table,l=a.widgetOptions,m=a.$tbodies,n=[],o=a.cache;
// empty table - fixes #206/#346
if(b.isEmptyObject(o))
// run pager appender in case the table was just emptied
return a.appender?a.appender(k,n):k.isUpdating?a.$table.trigger("updateComplete",k):"";for(a.debug&&(j=new Date),i=0;i<m.length;i++)if(f=m.eq(i),f.length){for(g=b.processTbody(k,f,!0),d=o[i].normalized,e=d.length,h=0;e>h;h++)n.push(d[h][a.columns].$row),
// removeRows used by the pager plugin; don't render if using ajax - fixes #411
a.appender&&(!a.pager||a.pager.removeRows&&l.pager_removeRows||a.pager.ajax)||g.append(d[h][a.columns].$row);
// restore tbody
b.processTbody(k,g,!1)}a.appender&&a.appender(k,n),a.debug&&console.log("Rebuilt table"+b.benchmark(j)),
// apply table widgets; but not before ajax completes
c||a.appender||b.applyWidget(k),k.isUpdating&&a.$table.trigger("updateComplete",k)},commonUpdate:function(a,c,d){
// remove rows/elements before update
a.$table.find(a.selectorRemove).remove(),
// rebuild parsers
b.setupParsers(a),
// rebuild the cache map
b.buildCache(a),b.checkResort(a,c,d)},/*
*/
initSort:function(c,d,e){if(c.table.isUpdating)
// let any updates complete before initializing a sort
return setTimeout(function(){b.initSort(c,d,e)},50);var f,g,h,i,j,k,l,m=!e[c.sortMultiSortKey],n=c.table,o=c.$headers.length,
// get current column index
p=parseInt(a(d).attr("data-column"),10),q=c.sortVars[p].order;
// reset all sorts on non-current column - issue #30
if(
// Only call sortStart if sorting is enabled
c.$table.trigger("sortStart",n),
// get current column sort order
c.sortVars[p].count=e[c.sortResetKey]?2:(c.sortVars[p].count+1)%(c.sortReset?3:2),c.sortRestart)for(k=d,h=0;o>h;h++)l=c.$headers.eq(h),l[0]===k||!m&&l.is("."+b.css.sortDesc+",."+b.css.sortAsc)||(c.sortVars[p].count=-1);
// user only wants to sort on one column
if(m){if(
// flush the sort list
c.sortList=[],c.last.sortList=[],null!==c.sortForce)for(f=c.sortForce,g=0;g<f.length;g++)f[g][0]!==p&&c.sortList.push(f[g]);if(i=q[c.sortVars[p].count],2>i&&(c.sortList.push([p,i]),d.colSpan>1))for(g=1;g<d.colSpan;g++)c.sortList.push([p+g,i]),
// update count on columns in colSpan
c.sortVars[p+g].count=a.inArray(i,q)}else
// the user has clicked on an already sorted column
if(
// get rid of the sortAppend before adding more - fixes issue #115 & #523
c.sortList=a.extend([],c.last.sortList),b.isValueInArray(p,c.sortList)>=0)
// reverse the sorting direction
for(g=0;g<c.sortList.length;g++)k=c.sortList[g],k[0]===p&&(k[1]=q[c.sortVars[p].count],2===k[1]&&(c.sortList.splice(g,1),c.sortVars[p].count=-1));else if(i=q[c.sortVars[p].count],2>i&&(c.sortList.push([p,i]),d.colSpan>1))for(g=1;g<d.colSpan;g++)c.sortList.push([p+g,i]),
// update count on columns in colSpan
c.sortVars[p+g].count=a.inArray(i,q);if(
// save sort before applying sortAppend
c.last.sortList=a.extend([],c.sortList),c.sortList.length&&c.sortAppend&&(f=a.isArray(c.sortAppend)?c.sortAppend:c.sortAppend[c.sortList[0][0]],!b.isEmptyObject(f)))for(g=0;g<f.length;g++)if(f[g][0]!==p&&b.isValueInArray(f[g][0],c.sortList)<0){if(i=f[g][1],j=(""+i).match(/^(a|d|s|o|n)/))switch(k=c.sortList[0][1],j[0]){case"d":i=1;break;case"s":i=k;break;case"o":i=0===k?1:0;break;case"n":i=(k+1)%(c.sortReset?3:2);break;default:i=0}c.sortList.push([f[g][0],i])}
// sortBegin event triggered immediately before the sort
c.$table.trigger("sortBegin",n),
// setTimeout needed so the processing icon shows up
setTimeout(function(){
// set css for headers
b.setHeadersCss(c),b.multisort(c),b.appendCache(c),c.$table.trigger("sortEnd",n)},1)},
// sort multiple columns
multisort:function(a){/*jshint loopfunc:true */
var c,d,e,f,g=a.table,h=0,i=a.textSorter||"",j=a.sortList,k=j.length,l=a.$tbodies.length;if(!a.serverSideSorting&&!b.isEmptyObject(a.cache)){for(a.debug&&(d=new Date),c=0;l>c;c++)e=a.cache[c].colMax,f=a.cache[c].normalized,f.sort(function(c,d){var f,l,m,n,o,p,q;for(f=0;k>f;f++){if(m=j[f][0],n=j[f][1],h=0===n,a.sortStable&&c[m]===d[m]&&1===k)return c[a.columns].order-d[a.columns].order;if(l=/n/i.test(b.getSortType(a.parsers,m)),l&&a.strings[m]?(l="boolean"==typeof b.string[a.strings[m]]?(h?1:-1)*(b.string[a.strings[m]]?-1:1):a.strings[m]?b.string[a.strings[m]]||0:0,o=a.numberSorter?a.numberSorter(c[m],d[m],h,e[m],g):b["sortNumeric"+(h?"Asc":"Desc")](c[m],d[m],l,e[m],m,a)):(p=h?c:d,q=h?d:c,o="function"==typeof i?i(p[m],q[m],h,m,g):"object"==typeof i&&i.hasOwnProperty(m)?i[m](p[m],q[m],h,m,g):b["sortNatural"+(h?"Asc":"Desc")](c[m],d[m],m,a)),o)return o}return c[a.columns].order-d[a.columns].order});a.debug&&console.log("Applying sort "+j.toString()+b.benchmark(d))}},resortComplete:function(b,c){b.table.isUpdating&&b.$table.trigger("updateComplete",b.table),a.isFunction(c)&&c(b.table)},checkResort:function(c,d,e){var f=a.isArray(d)?d:c.sortList,
// if no resort parameter is passed, fallback to config.resort (true by default)
g="undefined"==typeof d?c.resort:d;
// don't try to resort if the table is still processing
// this will catch spamming of the updateCell method
g===!1||c.serverSideSorting||c.table.isProcessing?(b.resortComplete(c,e),b.applyWidget(c.table,!1)):f.length?b.sortOn(c,f,function(){b.resortComplete(c,e)},!0):b.sortReset(c,function(){b.resortComplete(c,e),b.applyWidget(c.table,!1)})},sortOn:function(c,d,e,f){var g=c.table;c.$table.trigger("sortStart",g),
// update header count index
b.updateHeaderSortCount(c,d),
// set css for headers
b.setHeadersCss(c),
// fixes #346
c.delayInit&&b.isEmptyObject(c.cache)&&b.buildCache(c),c.$table.trigger("sortBegin",g),
// sort the table and append it to the dom
b.multisort(c),b.appendCache(c,f),c.$table.trigger("sortEnd",g),b.applyWidget(g),a.isFunction(e)&&e(g)},sortReset:function(c,d){c.sortList=[],b.setHeadersCss(c),b.multisort(c),b.appendCache(c),a.isFunction(d)&&d(c.table)},getSortType:function(a,b){return a&&a[b]?a[b].type||"":""},formatSortingOrder:function(a){
// look for 'd' in 'desc' order; return true
return/^d/i.test(a)||1===a},
// Natural sort - https://github.com/overset/javascript-natural-sort (date sorting removed)
// this function will only accept strings, or you'll see 'TypeError: undefined is not a function'
// I could add a = a.toString(); b = b.toString(); but it'll slow down the sort overall
sortNatural:function(a,c){if(a===c)return 0;var d,e,f,g,h,i,j=b.regex;
// first try and sort Hex codes
if(j.hex.test(c)){if(d=parseInt(a.match(j.hex),16),e=parseInt(c.match(j.hex),16),e>d)return-1;if(d>e)return 1}
// natural sorting through split numeric strings and default strings
for(d=a.replace(j.chunk,"\\0$1\\0").replace(j.chunks,"").split("\\0"),e=c.replace(j.chunk,"\\0$1\\0").replace(j.chunks,"").split("\\0"),i=Math.max(d.length,e.length),h=0;i>h;h++){
// handle numeric vs string comparison - number < string - (Kyle Adams)
if(f=isNaN(d[h])?d[h]||0:parseFloat(d[h])||0,g=isNaN(e[h])?e[h]||0:parseFloat(e[h])||0,isNaN(f)!==isNaN(g))return isNaN(f)?1:-1;if(
// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
typeof f!=typeof g&&(f+="",g+=""),g>f)return-1;if(f>g)return 1}return 0},sortNaturalAsc:function(a,c,d,e){if(a===c)return 0;var f=b.string[e.empties[d]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:-f||-1:""===c&&0!==f?"boolean"==typeof f?f?1:-1:f||1:b.sortNatural(a,c)},sortNaturalDesc:function(a,c,d,e){if(a===c)return 0;var f=b.string[e.empties[d]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:f||1:""===c&&0!==f?"boolean"==typeof f?f?1:-1:-f||-1:b.sortNatural(c,a)},
// basic alphabetical sort
sortText:function(a,b){return a>b?1:b>a?-1:0},
// return text string value by adding up ascii value
// so the text is somewhat sorted when using a digital sort
// this is NOT an alphanumeric sort
getTextValue:function(a,b,c){if(c){
// make sure the text value is greater than the max numerical value (max)
var d,e=a?a.length:0,f=c+b;for(d=0;e>d;d++)f+=a.charCodeAt(d);return b*f}return 0},sortNumericAsc:function(a,c,d,e,f,g){if(a===c)return 0;var h=b.string[g.empties[f]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:-h||-1:""===c&&0!==h?"boolean"==typeof h?h?1:-1:h||1:(isNaN(a)&&(a=b.getTextValue(a,d,e)),isNaN(c)&&(c=b.getTextValue(c,d,e)),a-c)},sortNumericDesc:function(a,c,d,e,f,g){if(a===c)return 0;var h=b.string[g.empties[f]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:h||1:""===c&&0!==h?"boolean"==typeof h?h?1:-1:-h||-1:(isNaN(a)&&(a=b.getTextValue(a,d,e)),isNaN(c)&&(c=b.getTextValue(c,d,e)),c-a)},sortNumeric:function(a,b){return a-b},/*
*/
addWidget:function(a){b.widgets.push(a)},hasWidget:function(b,c){return b=a(b),b.length&&b[0].config&&b[0].config.widgetInit[c]||!1},getWidgetById:function(a){var c,d,e=b.widgets.length;for(c=0;e>c;c++)if(d=b.widgets[c],d&&d.id&&d.id.toLowerCase()===a.toLowerCase())return d},applyWidgetOptions:function(c){var d,e,f=c.config,g=f.widgets.length;if(g)for(d=0;g>d;d++)e=b.getWidgetById(f.widgets[d]),e&&e.options&&(f.widgetOptions=a.extend(!0,{},e.options,f.widgetOptions))},addWidgetFromClass:function(a){var c,d,e=a.config,
// look for widgets to apply from table class
// stop using \b otherwise this matches 'ui-widget-content' & adds 'content' widget
f="\\s"+e.widgetClass.replace(b.regex.templateName,"([\\w-]+)")+"\\s",g=new RegExp(f,"g"),
// extract out the widget id from the table class (widget id's can include dashes)
h=(" "+e.table.className+" ").match(g);if(h)for(c=h.length,d=0;c>d;d++)e.widgets.push(h[d].replace(g,"$1"))},applyWidget:function(c,d,e){c=a(c)[0];// in case this is called externally
var f,g,h,i,j,k,l,m,n=c.config,o=[];
// prevent numerous consecutive widget applications
if(d===!1||!c.hasInitialized||!c.isApplyingWidgets&&!c.isUpdating){if(n.debug&&(l=new Date),b.addWidgetFromClass(c),n.widgets.length){
// build widget array & add priority as needed
for(c.isApplyingWidgets=!0,
// ensure unique widget ids
n.widgets=a.grep(n.widgets,function(b,c){return a.inArray(b,n.widgets)===c}),h=n.widgets||[],g=h.length,f=0;g>f;f++)i=b.getWidgetById(h[f]),i&&i.id&&(i.priority||(i.priority=10),o[f]=i);for(
// sort widgets by priority
o.sort(function(a,b){return a.priority<b.priority?-1:a.priority===b.priority?0:1}),g=o.length,n.debug&&console[console.group?"group":"log"]("Start "+(d?"initializing":"applying")+" widgets"),f=0;g>f;f++)i=o[f],i&&(j=i.id,k=!1,n.debug&&(m=new Date),(d||!n.widgetInit[j])&&(n.widgetInit[j]=!0,c.hasInitialized&&b.applyWidgetOptions(c),"function"==typeof i.init&&(k=!0,n.debug&&console[console.group?"group":"log"]("Initializing "+j+" widget"),i.init(c,i,c.config,c.config.widgetOptions))),d||"function"!=typeof i.format||(k=!0,n.debug&&console[console.group?"group":"log"]("Updating "+j+" widget"),i.format(c,c.config,c.config.widgetOptions,!1)),n.debug&&k&&(console.log("Completed "+(d?"initializing ":"applying ")+j+" widget"+b.benchmark(m)),console.groupEnd&&console.groupEnd()));n.debug&&console.groupEnd&&console.groupEnd(),
// callback executed on init only
d||"function"!=typeof e||e(c)}setTimeout(function(){c.isApplyingWidgets=!1,a.data(c,"lastWidgetApplication",new Date),n.$table.trigger("tablesorter-ready")},0),n.debug&&(i=n.widgets.length,console.log("Completed "+(d===!0?"initializing ":"applying ")+i+" widget"+(1!==i?"s":"")+b.benchmark(l)))}},removeWidget:function(c,d,e){c=a(c)[0];var f,g,h,i,j=c.config;
// if name === true, add all widgets from $.tablesorter.widgets
if(d===!0)for(d=[],i=b.widgets.length,h=0;i>h;h++)g=b.widgets[h],g&&g.id&&d.push(g.id);else
// name can be either an array of widgets names,
// or a space/comma separated list of widget names
d=(a.isArray(d)?d.join(","):d||"").toLowerCase().split(/[\s,]+/);for(i=d.length,f=0;i>f;f++)g=b.getWidgetById(d[f]),h=a.inArray(d[f],j.widgets),g&&g.remove&&(j.debug&&console.log((e?"Refreshing":"Removing")+' "'+d[f]+'" widget'),g.remove(c,j,j.widgetOptions,e),j.widgetInit[d[f]]=!1),h>=0&&e!==!0&&j.widgets.splice(h,1)},refreshWidgets:function(c,d,e){c=a(c)[0];// see issue #243
var f,g,h=c.config,i=h.widgets,j=b.widgets,k=j.length,l=[],m=function(b){a(b).trigger("refreshComplete")};
// remove widgets not defined in config.widgets, unless doAll is true
for(f=0;k>f;f++)g=j[f],g&&g.id&&(d||a.inArray(g.id,i)<0)&&l.push(g.id);b.removeWidget(c,l.join(","),!0),e!==!0?(
// call widget init if
b.applyWidget(c,d||!1,m),d&&
// apply widget format
b.applyWidget(c,!1,m)):m(c)},/*
*/
benchmark:function(a){return" ( "+((new Date).getTime()-a.getTime())+"ms )"},
// deprecated ts.log
log:function(){console.log(arguments)},
// $.isEmptyObject from jQuery v1.4
isEmptyObject:function(a){/*jshint forin: false */
for(var b in a)return!1;return!0},isValueInArray:function(a,b){var c,d=b&&b.length||0;for(c=0;d>c;c++)if(b[c][0]===a)return c;return-1},formatFloat:function(c,d){if("string"!=typeof c||""===c)return c;
// allow using formatFloat without a table; defaults to US number format
var e,f=d&&d.config?d.config.usNumberFormat!==!1:"undefined"!=typeof d?d:!0;
// return the text instead of zero
// US Format - 1,234,567.89 -> 1234567.89
// make (#) into a negative number -> (10) = -10
return c=f?c.replace(b.regex.comma,""):c.replace(b.regex.digitNonUS,"").replace(b.regex.comma,"."),b.regex.digitNegativeTest.test(c)&&(c=c.replace(b.regex.digitNegativeReplace,"-$1")),e=parseFloat(c),isNaN(e)?a.trim(c):e},isDigit:function(a){
// replace all unwanted chars and match
return isNaN(a)?b.regex.digitTest.test(a.toString().replace(b.regex.digitReplace,"")):""!==a},
// computeTableHeaderCellIndexes from:
// http://www.javascripttoolbox.com/lib/table/examples.php
// http://www.javascripttoolbox.com/temp/table_cellindex.html
computeColumnIndex:function(b){var c,d,e,f,g,h,i,j,k,l,m,n,o=[],p=[];for(c=0;c<b.length;c++)for(i=b[c].cells,d=0;d<i.length;d++){
// Find first available column in the first row
for(h=i[d],g=a(h),j=h.parentNode.rowIndex,k=j+"-"+g.index(),l=h.rowSpan||1,m=h.colSpan||1,"undefined"==typeof o[j]&&(o[j]=[]),e=0;e<o[j].length+1;e++)if("undefined"==typeof o[j][e]){n=e;break}for(
// add data-column (setAttribute = IE8+)
h.setAttribute?h.setAttribute("data-column",n):g.attr("data-column",n),e=j;j+l>e;e++)for("undefined"==typeof o[e]&&(o[e]=[]),p=o[e],f=n;n+m>f;f++)p[f]="x"}return p.length},
// automatically add a colgroup with col elements set to a percentage width
fixColumnWidth:function(c){c=a(c)[0];var d,e,f,g,h,i=c.config,j=i.$table.children("colgroup");if(
// remove plugin-added colgroup, in case we need to refresh the widths
j.length&&j.hasClass(b.css.colgroup)&&j.remove(),i.widthFixed&&0===i.$table.children("colgroup").length){for(j=a('<colgroup class="'+b.css.colgroup+'">'),d=i.$table.width(),f=i.$tbodies.find("tr:first").children(":visible"),g=f.length,h=0;g>h;h++)e=parseInt(f.eq(h).width()/d*1e3,10)/10+"%",j.append(a("<col>").css("width",e));i.$table.prepend(j)}},
// get sorter, string, empty, etc options for each column from
// jQuery data, metadata, header option or header class name ('sorter-false')
// priority = jQuery data > meta > headers option > header class name
getData:function(b,c,d){var e,f,g="",h=a(b);
// 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder'
// 'data-sort-initial-order' is assigned to 'sortInitialOrder'
// include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser'
return h.length?(e=a.metadata?h.metadata():!1,f=" "+(h.attr("class")||""),"undefined"!=typeof h.data(d)||"undefined"!=typeof h.data(d.toLowerCase())?g+=h.data(d)||h.data(d.toLowerCase()):e&&"undefined"!=typeof e[d]?g+=e[d]:c&&"undefined"!=typeof c[d]?g+=c[d]:" "!==f&&f.match(" "+d+"-")&&(g=f.match(new RegExp("\\s"+d+"-([\\w-]+)"))[1]||""),a.trim(g)):""},getColumnData:function(b,c,d,e,f){if("undefined"!=typeof c&&null!==c){b=a(b)[0];var g,h,i=b.config,j=f||i.$headers,
// c.$headerIndexed is not defined initially
k=i.$headerIndexed&&i.$headerIndexed[d]||j.filter('[data-column="'+d+'"]:last');if(c[d])return e?c[d]:c[j.index(k)];for(h in c)if("string"==typeof h&&(g=k.filter(h).add(k.find(h)),g.length))return c[h]}},
// *** Process table ***
// add processing indicator
isProcessing:function(c,d,e){c=a(c);var f=c[0].config,
// default to all headers
g=e||c.find("."+b.css.header);d?(
// don't use sortList if custom $ths used
"undefined"!=typeof e&&f.sortList.length>0&&(
// get headers from the sortList
g=g.filter(function(){
// get data-column from attr to keep compatibility with jQuery 1.2.6
return this.sortDisabled?!1:b.isValueInArray(parseFloat(a(this).attr("data-column")),f.sortList)>=0})),c.add(g).addClass(b.css.processing+" "+f.cssProcessing)):c.add(g).removeClass(b.css.processing+" "+f.cssProcessing)},
// detach tbody but save the position
// don't use tbody because there are portions that look for a tbody index (updateCell)
processTbody:function(b,c,d){if(b=a(b)[0],d)return b.isProcessing=!0,c.before('<colgroup class="tablesorter-savemyplace"/>'),a.fn.detach?c.detach():c.remove();var e=a(b).find("colgroup.tablesorter-savemyplace");c.insertAfter(e),e.remove(),b.isProcessing=!1},clearTableBody:function(b){a(b)[0].config.$tbodies.children().detach()},
// used when replacing accented characters during sorting
characterEquivalents:{a:"áàâãäąå",// áàâãäąå
A:"ÁÀÂÃÄĄÅ",// ÁÀÂÃÄĄÅ
c:"çćč",// çćč
C:"ÇĆČ",// ÇĆČ
e:"éèêëěę",// éèêëěę
E:"ÉÈÊËĚĘ",// ÉÈÊËĚĘ
i:"íìİîïı",// íìİîïı
I:"ÍÌİÎÏ",// ÍÌİÎÏ
o:"óòôõöō",// óòôõöō
O:"ÓÒÔÕÖŌ",// ÓÒÔÕÖŌ
ss:"ß",// ß (s sharp)
SS:"ẞ",// ẞ (Capital sharp s)
u:"úùûüů",// úùûüů
U:"ÚÙÛÜŮ"},replaceAccents:function(a){var c,d="[",e=b.characterEquivalents;if(!b.characterRegex){b.characterRegexArray={};for(c in e)"string"==typeof c&&(d+=e[c],b.characterRegexArray[c]=new RegExp("["+e[c]+"]","g"));b.characterRegex=new RegExp(d+"]")}if(b.characterRegex.test(a))for(c in e)"string"==typeof c&&(a=a.replace(b.characterRegexArray[c],c));return a},
// restore headers
restoreHeaders:function(c){var d,e,f=a(c)[0].config,g=f.$table.find(f.selectorHeaders),h=g.length;
// don't use c.$headers here in case header cells were swapped
for(d=0;h>d;d++)e=g.eq(d),e.find("."+b.css.headerIn).length&&e.html(f.headerContent[d])},destroy:function(c,d,e){if(c=a(c)[0],c.hasInitialized){
// remove all widgets
b.removeWidget(c,!0,!1);var f,g=a(c),h=c.config,i=h.debug,j=g.find("thead:first"),k=j.find("tr."+b.css.headerRow).removeClass(b.css.headerRow+" "+h.cssHeaderRow),l=g.find("tfoot:first > tr").children("th, td");d===!1&&a.inArray("uitheme",h.widgets)>=0&&(
// reapply uitheme classes, in case we want to maintain appearance
g.trigger("applyWidgetId",["uitheme"]),g.trigger("applyWidgetId",["zebra"])),
// remove widget added rows, just in case
j.find("tr").not(k).remove(),
// disable tablesorter
f="sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave keypress "+"sortBegin sortEnd resetToLoadState ".split(" ").join(h.namespace+" "),g.removeData("tablesorter").unbind(f.replace(b.regex.spaces," ")),h.$headers.add(l).removeClass([b.css.header,h.cssHeader,h.cssAsc,h.cssDesc,b.css.sortAsc,b.css.sortDesc,b.css.sortNone].join(" ")).removeAttr("data-column").removeAttr("aria-label").attr("aria-disabled","true"),k.find(h.selectorSort).unbind("mousedown mouseup keypress ".split(" ").join(h.namespace+" ").replace(b.regex.spaces," ")),b.restoreHeaders(c),g.toggleClass(b.css.table+" "+h.tableClass+" tablesorter-"+h.theme,d===!1),
// clear flag in case the plugin is initialized again
c.hasInitialized=!1,delete c.config.cache,"function"==typeof e&&e(c),i&&console.log("tablesorter has been removed")}}};a.fn.tablesorter=function(c){return this.each(function(){var d=this,
// merge & extend config options
e=a.extend(!0,{},b.defaults,c,b.instanceMethods);
// save initial settings
e.originalSettings=c,
// create a table from data (build table widget)
!d.hasInitialized&&b.buildTable&&"TABLE"!==this.nodeName?
// return the table (in case the original target is the table's container)
b.buildTable(d,e):b.setup(d,e)})},
// set up debug logs
window.console&&window.console.log||(
// access $.tablesorter.logs for browsers that don't have a console...
b.logs=[],/*jshint -W020 */
console={},console.log=console.warn=console.error=console.table=function(){var a=arguments.length>1?arguments:arguments[0];b.logs.push({date:Date.now(),log:a})}),
// add default parsers
b.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"}),b.addParser({id:"text",is:function(){return!0},format:function(c,d){var e=d.config;return c&&(c=a.trim(e.ignoreCase?c.toLocaleLowerCase():c),c=e.sortLocaleCompare?b.replaceAccents(c):c),c},type:"text"}),b.regex.nondigit=/[^\w,. \-()]/g,b.addParser({id:"digit",is:function(a){return b.isDigit(a)},format:function(c,d){var e=b.formatFloat((c||"").replace(b.regex.nondigit,""),d);return c&&"number"==typeof e?e:c?a.trim(c&&d.config.ignoreCase?c.toLocaleLowerCase():c):c},type:"numeric"}),b.regex.currencyReplace=/[+\-,. ]/g,b.regex.currencyTest=/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/,b.addParser({id:"currency",is:function(a){
// test for £$€¤¥¢
return a=(a||"").replace(b.regex.currencyReplace,""),b.regex.currencyTest.test(a)},format:function(c,d){var e=b.formatFloat((c||"").replace(b.regex.nondigit,""),d);return c&&"number"==typeof e?e:c?a.trim(c&&d.config.ignoreCase?c.toLocaleLowerCase():c):c},type:"numeric"}),
// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
// now, this regex can be updated before initialization
b.regex.urlProtocolTest=/^(https?|ftp|file):\/\//,b.regex.urlProtocolReplace=/(https?|ftp|file):\/\//,b.addParser({id:"url",is:function(a){return b.regex.urlProtocolTest.test(a)},format:function(c){return c?a.trim(c.replace(b.regex.urlProtocolReplace,"")):c},parsed:!0,// filter widget flag
type:"text"}),b.regex.dash=/-/g,b.regex.isoDate=/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/,b.addParser({id:"isoDate",is:function(a){return b.regex.isoDate.test(a)},format:function(a,c){var d=a?new Date(a.replace(b.regex.dash,"/")):a;return d instanceof Date&&isFinite(d)?d.getTime():a},type:"numeric"}),b.regex.percent=/%/g,b.regex.percentTest=/(\d\s*?%|%\s*?\d)/,b.addParser({id:"percent",is:function(a){return b.regex.percentTest.test(a)&&a.length<15},format:function(a,c){return a?b.formatFloat(a.replace(b.regex.percent,""),c):a},type:"numeric"}),
// added image parser to core v2.17.9
b.addParser({id:"image",is:function(a,b,c,d){return d.find("img").length>0},format:function(b,c,d){return a(d).find("img").attr(c.config.imgAttr||"alt")||b},parsed:!0,// filter widget flag
type:"text"}),b.regex.dateReplace=/(\S)([AP]M)$/i,// used by usLongDate & time parser
b.regex.usLongDateTest1=/^[A-Z]{3,10}\.?\s+\d{1,2},?\s+(\d{4})(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?$/i,b.regex.usLongDateTest2=/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i,b.addParser({id:"usLongDate",is:function(a){
// two digit years are not allowed cross-browser
// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
return b.regex.usLongDateTest1.test(a)||b.regex.usLongDateTest2.test(a)},format:function(a,c){var d=a?new Date(a.replace(b.regex.dateReplace,"$1 $2")):a;return d instanceof Date&&isFinite(d)?d.getTime():a},type:"numeric"}),
// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
b.regex.shortDateTest=/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/,
// escaped "-" because JSHint in Firefox was showing it as an error
b.regex.shortDateReplace=/[\-.,]/g,
// XXY covers MDY & DMY formats
b.regex.shortDateXXY=/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,b.regex.shortDateYMD=/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,b.addParser({id:"shortDate",// 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
is:function(a){return a=(a||"").replace(b.regex.spaces," ").replace(b.regex.shortDateReplace,"/"),b.regex.shortDateTest.test(a)},format:function(a,c,d,e){if(a){var f,g,h=c.config,i=h.$headerIndexed[e],j=i.length&&i[0].dateFormat||b.getData(i,b.getColumnData(c,h.headers,e),"dateFormat")||h.dateFormat;return g=a.replace(b.regex.spaces," ").replace(b.regex.shortDateReplace,"/"),"mmddyyyy"===j?g=g.replace(b.regex.shortDateXXY,"$3/$1/$2"):"ddmmyyyy"===j?g=g.replace(b.regex.shortDateXXY,"$3/$2/$1"):"yyyymmdd"===j&&(g=g.replace(b.regex.shortDateYMD,"$1/$2/$3")),f=new Date(g),f instanceof Date&&isFinite(f)?f.getTime():a}return a},type:"numeric"}),b.regex.timeTest=/^(([0-2]?\d:[0-5]\d)|([0-1]?\d:[0-5]\d\s?([AP]M)))$/i,b.addParser({id:"time",is:function(a){return b.regex.timeTest.test(a)},format:function(a,c){var d=a?new Date("2000/01/01 "+a.replace(b.regex.dateReplace,"$1 $2")):a;return d instanceof Date&&isFinite(d)?d.getTime():a},type:"numeric"}),b.addParser({id:"metadata",is:function(){return!1},format:function(b,c,d){var e=c.config,f=e.parserMetadataName?e.parserMetadataName:"sortValue";return a(d).metadata()[f]},type:"numeric"}),/*
*/
// add default widgets
b.addWidget({id:"zebra",priority:90,format:function(b,c,d){var e,f,g,h,i,j,k,l=new RegExp(c.cssChildRow,"i"),m=c.$tbodies.add(a(c.namespace+"_extra_table").children("tbody:not(."+c.cssInfoBlock+")"));for(i=0;i<m.length;i++)for(g=0,e=m.eq(i).children("tr:visible").not(c.selectorRemove),k=e.length,j=0;k>j;j++)f=e.eq(j),l.test(f[0].className)||g++,h=g%2===0,f.removeClass(d.zebra[h?1:0]).addClass(d.zebra[h?0:1])},remove:function(a,c,d,e){if(!e){var f,g,h=c.$tbodies,i=(d.zebra||["even","odd"]).join(" ");for(f=0;f<h.length;f++)g=b.processTbody(a,h.eq(f),!0),g.children().removeClass(i),b.processTbody(a,g,!1)}}})}(jQuery),function(a,b,c){"use strict";var d=a.tablesorter||{};
// *** Store data in local storage, with a cookie fallback ***
/* IE7 needs JSON library for JSON.stringify - (http://caniuse.com/#search=json)
if you need it, then include https://github.com/douglascrockford/JSON-js
$.parseJSON is not available is jQuery versions older than 1.4.1, using older
versions will only allow storing information for one page at a time
// *** Save data (JSON format only) ***
// val must be valid JSON... use http://jsonlint.com/ to ensure it is valid
var val = { "mywidget" : "data1" }; // valid JSON uses double quotes
// $.tablesorter.storage(table, key, val);
$.tablesorter.storage(table, 'tablesorter-mywidget', val);
// *** Get data: $.tablesorter.storage(table, key); ***
v = $.tablesorter.storage(table, 'tablesorter-mywidget');
// val may be empty, so also check for your data
val = (v && v.hasOwnProperty('mywidget')) ? v.mywidget : '';
alert(val); // 'data1' if saved, or '' if not
*/
d.storage=function(d,e,f,g){d=a(d)[0];var h,i,j,k=!1,l={},m=d.config,n=m&&m.widgetOptions,o=g&&g.useSessionStorage||n&&n.storage_useSessionStorage?"sessionStorage":"localStorage",p=a(d),
// id from (1) options ID, (2) table 'data-table-group' attribute, (3) widgetOptions.storage_tableId,
// (4) table ID, then (5) table index
q=g&&g.id||p.attr(g&&g.group||n&&n.storage_group||"data-table-group")||n&&n.storage_tableId||d.id||a(".tablesorter").index(p),
// url from (1) options url, (2) table 'data-table-page' attribute, (3) widgetOptions.storage_fixedUrl,
// (4) table.config.fixedUrl (deprecated), then (5) window location path
r=g&&g.url||p.attr(g&&g.page||n&&n.storage_page||"data-table-page")||n&&n.storage_fixedUrl||m&&m.fixedUrl||b.location.pathname;
// https://gist.github.com/paulirish/5558557
if(o in b)try{b[o].setItem("_tmptest","temp"),k=!0,b[o].removeItem("_tmptest")}catch(s){m&&m.debug&&console.warn(o+" is not supported in this browser")}
// allow value to be an empty string too
// *** get value ***
// old browser, using cookies
// add one to get from the key to the value
// allow value to be an empty string too
// add unique identifiers = url pathname > table ID/index on page > data
// *** set value ***
// 365 days
return a.parseJSON&&(k?l=a.parseJSON(b[o][e]||"null")||{}:(i=c.cookie.split(/[;\s|=]/),h=a.inArray(e,i)+1,l=0!==h?a.parseJSON(i[h]||"null")||{}:{})),(f||""===f)&&b.JSON&&JSON.hasOwnProperty("stringify")?(l[r]||(l[r]={}),l[r][q]=f,k?b[o][e]=JSON.stringify(l):(j=new Date,j.setTime(j.getTime()+31536e6),c.cookie=e+"="+JSON.stringify(l).replace(/\"/g,'"')+"; expires="+j.toGMTString()+"; path=/"),void 0):l&&l[r]?l[r][q]:""}}(jQuery,window,document),function(a){"use strict";var b=a.tablesorter||{};b.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",
// header class names
header:"bootstrap-header",// give the header a gradient background (theme.bootstrap_2.css)
sortNone:"",sortAsc:"",sortDesc:"",active:"",// applied when column is sorted
hover:"",// custom css required - a defined bootstrap style may not override other classes
// icon class names
icons:"",// add 'icon-white' to make them white; this icon class is added to the <i> in the header
iconSortNone:"bootstrap-icon-unsorted",// class name added to icon when column is not sorted
iconSortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",// class name added to icon when column has ascending sort
iconSortDesc:"icon-chevron-down glyphicon glyphicon-chevron-down",// class name added to icon when column has descending sort
filterRow:"",// filter row class
footerRow:"",footerCells:"",even:"",// even row zebra striping
odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",// table classes
caption:"ui-widget-content",
// header class names
header:"ui-widget-header ui-corner-all ui-state-default",// header classes
sortNone:"",sortAsc:"",sortDesc:"",active:"ui-state-active",// applied when column is sorted
hover:"ui-state-hover",// hover class
// icon class names
icons:"ui-icon",// icon class added to the <i> in the header
iconSortNone:"ui-icon-carat-2-n-s",// class name added to icon when column is not sorted
iconSortAsc:"ui-icon-carat-1-n",// class name added to icon when column has ascending sort
iconSortDesc:"ui-icon-carat-1-s",// class name added to icon when column has descending sort
filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",// even row zebra striping
odd:"ui-state-default"}},a.extend(b.css,{wrapper:"tablesorter-wrapper"}),b.addWidget({id:"uitheme",priority:10,format:function(c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r=b.themes,s=d.$table.add(a(d.namespace+"_extra_table")),t=d.$headers.add(a(d.namespace+"_extra_headers")),u=d.theme||"jui",v=r[u]||{},w=a.trim([v.sortNone,v.sortDesc,v.sortAsc,v.active].join(" ")),x=a.trim([v.iconSortNone,v.iconSortDesc,v.iconSortAsc].join(" "));for(d.debug&&(i=new Date),
// initialization code - run once
s.hasClass("tablesorter-"+u)&&d.theme===d.appliedTheme&&e.uitheme_applied||(e.uitheme_applied=!0,n=r[d.appliedTheme]||{},q=!a.isEmptyObject(n),o=q?[n.sortNone,n.sortDesc,n.sortAsc,n.active].join(" "):"",p=q?[n.iconSortNone,n.iconSortDesc,n.iconSortAsc].join(" "):"",q&&(e.zebra[0]=a.trim(" "+e.zebra[0].replace(" "+n.even,"")),e.zebra[1]=a.trim(" "+e.zebra[1].replace(" "+n.odd,"")),d.$tbodies.children().removeClass([n.even,n.odd].join(" "))),v.even&&(e.zebra[0]+=" "+v.even),v.odd&&(e.zebra[1]+=" "+v.odd),s.children("caption").removeClass(n.caption||"").addClass(v.caption),l=s.removeClass((d.appliedTheme?"tablesorter-"+(d.appliedTheme||""):"")+" "+(n.table||"")).addClass("tablesorter-"+u+" "+(v.table||"")).children("tfoot"),d.appliedTheme=d.theme,l.length&&l.children("tr").removeClass(n.footerRow||"").addClass(v.footerRow).children("th, td").removeClass(n.footerCells||"").addClass(v.footerCells),t.removeClass((q?[n.header,n.hover,o].join(" "):"")||"").addClass(v.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(b){a(this)["mouseenter"===b.type?"addClass":"removeClass"](v.hover||"")}),t.each(function(){var c=a(this);c.find("."+b.css.wrapper).length||c.wrapInner('<div class="'+b.css.wrapper+'" style="position:relative;height:100%;width:100%"></div>')}),d.cssIcon&&t.find("."+b.css.icon).removeClass(q?[n.icons,p].join(" "):"").addClass(v.icons||""),s.hasClass("hasFilters")&&s.children("thead").children("."+b.css.filterRow).removeClass(q?n.filterRow||"":"").addClass(v.filterRow||"")),f=0;f<d.columns;f++)j=d.$headers.add(a(d.namespace+"_extra_headers")).not(".sorter-false").filter('[data-column="'+f+'"]'),k=b.css.icon?j.find("."+b.css.icon):a(),m=t.not(".sorter-false").filter('[data-column="'+f+'"]:last'),m.length&&(j.removeClass(w),k.removeClass(x),m[0].sortDisabled?k.removeClass(v.icons||""):(g=v.sortNone,h=v.iconSortNone,m.hasClass(b.css.sortAsc)?(g=[v.sortAsc,v.active].join(" "),h=v.iconSortAsc):m.hasClass(b.css.sortDesc)&&(g=[v.sortDesc,v.active].join(" "),h=v.iconSortDesc),j.addClass(g),k.addClass(h||"")));d.debug&&console.log("Applying "+u+" theme"+b.benchmark(i))},remove:function(a,c,d,e){if(d.uitheme_applied){var f=c.$table,g=c.appliedTheme||"jui",h=b.themes[g]||b.themes.jui,i=f.children("thead").children(),j=h.sortNone+" "+h.sortDesc+" "+h.sortAsc,k=h.iconSortNone+" "+h.iconSortDesc+" "+h.iconSortAsc;f.removeClass("tablesorter-"+g+" "+h.table),d.uitheme_applied=!1,e||(f.find(b.css.header).removeClass(h.header),i.unbind("mouseenter.tsuitheme mouseleave.tsuitheme").removeClass(h.hover+" "+j+" "+h.active).filter("."+b.css.filterRow).removeClass(h.filterRow),i.find("."+b.css.icon).removeClass(h.icons+" "+k))}}})}(jQuery),function(a){"use strict";var b=a.tablesorter||{};b.addWidget({id:"columns",priority:30,options:{columns:["primary","secondary","tertiary"]},format:function(c,d,e){var f,g,h,i,j,k,l,m,n=d.$table,o=d.$tbodies,p=d.sortList,q=p.length,
// removed c.widgetColumns support
r=e&&e.columns||["primary","secondary","tertiary"],s=r.length-1;
// check if there is a sort (on initialization there may not be one)
for(l=r.join(" "),g=0;g<o.length;g++)f=b.processTbody(c,o.eq(g),!0),h=f.children("tr"),h.each(function(){if(j=a(this),"none"!==this.style.display&&(k=j.children().removeClass(l),p&&p[0]&&(k.eq(p[0][0]).addClass(r[0]),q>1)))for(m=1;q>m;m++)k.eq(p[m][0]).addClass(r[m]||r[s])}),b.processTbody(c,f,!1);if(i=e.columns_thead!==!1?["thead tr"]:[],e.columns_tfoot!==!1&&i.push("tfoot tr"),i.length&&(h=n.find(i.join(",")).children().removeClass(l),q))for(m=0;q>m;m++)
// add primary. secondary, tertiary, etc sort column classes
h.filter('[data-column="'+p[m][0]+'"]').addClass(r[m]||r[s])},remove:function(c,d,e){var f,g,h=d.$tbodies,i=(e.columns||["primary","secondary","tertiary"]).join(" ");for(d.$headers.removeClass(i),d.$table.children("tfoot").children("tr").children("th, td").removeClass(i),f=0;f<h.length;f++)g=b.processTbody(c,h.eq(f),!0),g.children("tr").each(function(){a(this).children().removeClass(i)}),b.processTbody(c,g,!1)}})}(jQuery),function(a){"use strict";var b,c=a.tablesorter||{},d=c.css;a.extend(d,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",filterDisabled:"disabled",filterRowHide:"hideme"}),c.addWidget({id:"filter",priority:50,options:{filter_childRows:!1,// if true, filter includes child row content in the search
filter_childByColumn:!1,// ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
filter_childWithSibs:!0,// if true, include matching child row siblings
filter_columnFilters:!0,// if true, a filter will be added to the top of each table column
filter_columnAnyMatch:!0,// if true, allows using '#:{query}' in AnyMatch searches ( column:query )
filter_cellFilter:"",// css class name added to the filter cell ( string or array )
filter_cssFilter:"",// css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
filter_defaultFilter:{},// add a default column filter type '~{query}' to make fuzzy searches default; '{q1} AND {q2}' to make all searches use a logical AND.
filter_excludeFilter:{},// filters to exclude, per column
filter_external:"",// jQuery selector string ( or jQuery object ) of external filters
filter_filteredRow:"filtered",// class added to filtered rows; needed by pager plugin
filter_formatter:null,// add custom filter elements to the filter row
filter_functions:null,// add custom filter functions using this option
filter_hideEmpty:!0,// hide filter row when table is empty
filter_hideFilters:!1,// collapse filter row when mouse leaves the area
filter_ignoreCase:!0,// if true, make all searches case-insensitive
filter_liveSearch:!0,// if true, search column content while the user types ( with a delay )
filter_onlyAvail:"filter-onlyAvail",// a header with a select dropdown & this class name will only show available ( visible ) options within the drop down
filter_placeholder:{search:"",select:""},// default placeholder text ( overridden by any header 'data-placeholder' setting )
filter_reset:null,// jQuery selector string of an element used to reset the filters
filter_saveFilters:!1,// Use the $.tablesorter.storage utility to save the most recent filters
filter_searchDelay:300,// typing delay in milliseconds before starting a search
filter_searchFiltered:!0,// allow searching through already filtered rows in special circumstances; will speed up searching in large tables if true
filter_selectSource:null,// include a function to return an array of values to be added to the column filter select
filter_startsWith:!1,// if true, filter start from the beginning of the cell contents
filter_useParsedData:!1,// filter all data using parsed content
filter_serversideFiltering:!1,// if true, must perform server-side filtering b/c client-side filtering is disabled, but the ui and events will still be used.
filter_defaultAttrib:"data-value",// data attribute in the header cell that contains the default filter value
filter_selectSourceSeparator:"|"},format:function(a,c,d){c.$table.hasClass("hasFilters")||b.init(a,c,d)},remove:function(b,e,f,g){var h,i,j=e.$table,k=e.$tbodies,l="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(e.namespace+"filter ");if(j.removeClass("hasFilters").unbind(l.replace(c.regex.spaces," ")).find("."+d.filterRow).remove(),!g){for(h=0;h<k.length;h++)i=c.processTbody(b,k.eq(h),!0),i.children().removeClass(f.filter_filteredRow).show(),c.processTbody(b,i,!1);f.filter_reset&&a(document).undelegate(f.filter_reset,"click"+e.namespace+"filter")}}}),b=c.filter={
// regex used in filter 'check' functions - not for general use and not documented
regex:{regex:/^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/,// regex to test for regex
child:/tablesorter-childRow/,// child row class name; this gets updated in the script
filtered:/filtered/,// filtered (hidden) row class name; updated in the script
type:/undefined|number/,// check type
exact:/(^[\"\'=]+)|([\"\'=]+$)/g,// exact match (allow '==')
operators:/[<>=]/g,// replace operators
query:"(q|query)",// replace filter queries
wild01:/\?/g,// wild card match 0 or 1
wild0More:/\*/g,// wild care match 0 or more
quote:/\"/g,isNeg1:/(>=?\s*-\d)/,isNeg2:/(<=?\s*\d)/},
// function( c, data ) { }
// c = table.config
// data.$row = jQuery object of the row currently being processed
// data.$cells = jQuery object of all cells within the current row
// data.filters = array of filters for all columns ( some may be undefined )
// data.filter = filter for the current column
// data.iFilter = same as data.filter, except lowercase ( if wo.filter_ignoreCase is true )
// data.exact = table cell text ( or parsed data if column parser enabled; may be a number & not a string )
// data.iExact = same as data.exact, except lowercase ( if wo.filter_ignoreCase is true; may be a number & not a string )
// data.cache = table cell text from cache, so it has been parsed ( & in all lower case if c.ignoreCase is true )
// data.cacheArray = An array of parsed content from each table cell in the row being processed
// data.index = column index; table = table element ( DOM )
// data.parsed = array ( by column ) of boolean values ( from filter_useParsedData or 'filter-parsed' class )
types:{or:function(c,d,e){if(b.regex.orTest.test(d.iFilter)||b.regex.orSplit.test(d.filter)){var f,g,h,i,
// duplicate data but split filter
j=a.extend({},d),k=d.index,l=d.parsed[k],m=d.filter.split(b.regex.orSplit),n=d.iFilter.split(b.regex.orSplit),o=m.length;for(f=0;o>f;f++){j.nestedFilters=!0,j.filter=""+(b.parseFilter(c,m[f],k,l)||""),j.iFilter=""+(b.parseFilter(c,n[f],k,l)||""),h="("+(b.parseFilter(c,j.filter,k,l)||"")+")";try{if(i=new RegExp(d.isMatch?h:"^"+h+"$",c.widgetOptions.filter_ignoreCase?"i":""),g=i.test(j.exact)||b.processTypes(c,j,e))return g}catch(p){return null}}
// may be null from processing types
return g||!1}return null},
// Look for an AND or && operator ( logical and )
and:function(c,d,e){if(b.regex.andTest.test(d.filter)){var f,g,h,i,j,
// duplicate data but split filter
k=a.extend({},d),l=d.index,m=d.parsed[l],n=d.filter.split(b.regex.andSplit),o=d.iFilter.split(b.regex.andSplit),p=n.length;for(f=0;p>f;f++){k.nestedFilters=!0,k.filter=""+(b.parseFilter(c,n[f],l,m)||""),k.iFilter=""+(b.parseFilter(c,o[f],l,m)||""),i=("("+(b.parseFilter(c,k.filter,l,m)||"")+")").replace(b.regex.wild01,"\\S{1}").replace(b.regex.wild0More,"\\S*");try{
// use try/catch just in case RegExp is invalid
j=new RegExp(d.isMatch?i:"^"+i+"$",c.widgetOptions.filter_ignoreCase?"i":""),
// look for an exact match with the 'and' unless the 'filter-match' class is found
h=j.test(k.exact)||b.processTypes(c,k,e),g=0===f?h:g&&h}catch(q){return null}}
// may be null from processing types
return g||!1}return null},
// Look for regex
regex:function(a,c){if(b.regex.regex.test(c.filter)){var d,
// cache regex per column for optimal speed
e=c.filter_regexCache[c.index]||b.regex.regex.exec(c.filter),f=e instanceof RegExp;try{f||(
// force case insensitive search if ignoreCase option set?
// if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
c.filter_regexCache[c.index]=e=new RegExp(e[1],e[2])),d=e.test(c.exact)}catch(g){d=!1}return d}return null},
// Look for operators >, >=, < or <=
operators:function(d,e){
// ignore empty strings... because '' < 10 is true
if(b.regex.operTest.test(e.iFilter)&&""!==e.iExact){var f,g,h,i=d.table,j=e.index,k=e.parsed[j],l=c.formatFloat(e.iFilter.replace(b.regex.operators,""),i),m=d.parsers[j],n=l;
// parse filter value in case we're comparing numbers ( dates )
// iExact may be numeric - see issue #149;
// check if cached is defined, because sometimes j goes out of range? ( numeric columns )
// keep showing all rows if nothing follows the operator
return(k||"numeric"===m.type)&&(h=a.trim(""+e.iFilter.replace(b.regex.operators,"")),g=b.parseFilter(d,h,j,!0),l="number"!=typeof g||""===g||isNaN(g)?l:g),!k&&"numeric"!==m.type||isNaN(l)||"undefined"==typeof e.cache?(h=isNaN(e.iExact)?e.iExact.replace(c.regex.nondigit,""):e.iExact,f=c.formatFloat(h,i)):f=e.cache,b.regex.gtTest.test(e.iFilter)?g=b.regex.gteTest.test(e.iFilter)?f>=l:f>l:b.regex.ltTest.test(e.iFilter)&&(g=b.regex.lteTest.test(e.iFilter)?l>=f:l>f),g||""!==n||(g=!0),g}return null},
// Look for a not match
notMatch:function(c,d){if(b.regex.notTest.test(d.iFilter)){var e,f=d.iFilter.replace("!",""),g=b.parseFilter(c,f,d.index,d.parsed[d.index])||"";
// look for exact not matches - see #628
return b.regex.exact.test(g)?(g=g.replace(b.regex.exact,""),""===g?!0:a.trim(g)!==d.iExact):(e=d.iExact.search(a.trim(g)),""===g?!0:!(c.widgetOptions.filter_startsWith?0===e:e>=0))}return null},
// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
exact:function(c,d){/*jshint eqeqeq:false */
if(b.regex.exact.test(d.iFilter)){var e=d.iFilter.replace(b.regex.exact,""),f=b.parseFilter(c,e,d.index,d.parsed[d.index])||"";return d.anyMatch?a.inArray(f,d.rowArray)>=0:f==d.iExact}return null},
// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
range:function(a,d){if(b.regex.toTest.test(d.iFilter)){var e,f,g,h,i=a.table,j=d.index,k=d.parsed[j],
// make sure the dash is for a range and not indicating a negative number
l=d.iFilter.split(b.regex.toSplit);
// parse filter value in case we're comparing numbers ( dates )
return f=l[0].replace(c.regex.nondigit,"")||"",g=c.formatFloat(b.parseFilter(a,f,j,k),i),f=l[1].replace(c.regex.nondigit,"")||"",h=c.formatFloat(b.parseFilter(a,f,j,k),i),(k||"numeric"===a.parsers[j].type)&&(e=a.parsers[j].format(""+l[0],i,a.$headers.eq(j),j),g=""===e||isNaN(e)?g:e,e=a.parsers[j].format(""+l[1],i,a.$headers.eq(j),j),h=""===e||isNaN(e)?h:e),!k&&"numeric"!==a.parsers[j].type||isNaN(g)||isNaN(h)?(f=isNaN(d.iExact)?d.iExact.replace(c.regex.nondigit,""):d.iExact,e=c.formatFloat(f,i)):e=d.cache,g>h&&(f=g,g=h,h=f),e>=g&&h>=e||""===g||""===h}return null},
// Look for wild card: ? = single, * = multiple, or | = logical OR
wild:function(a,c){if(b.regex.wildOrTest.test(c.iFilter)){var d=c.index,e=c.parsed[d],f=""+(b.parseFilter(a,c.iFilter,d,e)||"");
// look for an exact match with the 'or' unless the 'filter-match' class is found
!b.regex.wildTest.test(f)&&c.nestedFilters&&(f=c.isMatch?f:"^("+f+")$");
// parsing the filter may not work properly when using wildcards =/
try{return new RegExp(f.replace(b.regex.wild01,"\\S{1}").replace(b.regex.wild0More,"\\S*"),a.widgetOptions.filter_ignoreCase?"i":"").test(c.exact)}catch(g){return null}}return null},
// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
fuzzy:function(a,c){if(b.regex.fuzzyTest.test(c.iFilter)){var d,e=0,f=c.iExact.length,g=c.iFilter.slice(1),h=b.parseFilter(a,g,c.index,c.parsed[c.index])||"";for(d=0;f>d;d++)c.iExact[d]===h[e]&&(e+=1);return e===h.length?!0:!1}return null}},init:function(e,f,g){
// filter language options
c.language=a.extend(!0,{},{to:"to",or:"or",and:"and"},c.language);var h,i,j,k,l,m,n,o,p,q=b.regex;if(f.$table.addClass("hasFilters"),
// define timers so using clearTimeout won't cause an undefined error
g.filter_searchTimer=null,g.filter_initTimer=null,g.filter_formatterCount=0,g.filter_formatterInit=[],g.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',g.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',n="\\{"+b.regex.query+"\\}",a.extend(q,{child:new RegExp(f.cssChildRow),filtered:new RegExp(g.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+c.language.or+"|-|"+c.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+c.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+c.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+c.language.and+"|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+c.language.and+"|&&)\\s+)","gi"),orTest:/\|/,orSplit:new RegExp("(?:\\s+(?:"+c.language.or+")\\s+|\\|)","gi"),iQuery:new RegExp(n,"i"),igQuery:new RegExp(n,"ig"),operTest:/^[<>]=?/,gtTest:/>/,gteTest:/>=/,ltTest:/</,lteTest:/<=/,notTest:/^\!/,wildOrTest:/[\?\*\|]/,wildTest:/\?\*/,fuzzyTest:/^~/,exactTest:/[=\"\|!]/}),n=f.$headers.filter(".filter-false, .parser-false").length,g.filter_columnFilters!==!1&&n!==f.$headers.length&&b.buildRow(e,f,g),j="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(f.namespace+"filter "),f.$table.bind(j,function(c,h){return n=g.filter_hideEmpty&&a.isEmptyObject(f.cache)&&!(f.delayInit&&"appendCache"===c.type),f.$table.find("."+d.filterRow).toggleClass(g.filter_filteredRow,n),/(search|filter)/.test(c.type)||(c.stopPropagation(),b.buildDefault(e,!0)),"filterReset"===c.type?(f.$table.find("."+d.filter).add(g.filter_$externalFilters).val(""),b.searching(e,[])):"filterEnd"===c.type?b.buildDefault(e,!0):(h="search"===c.type?h:"updateComplete"===c.type?f.$table.data("lastSearch"):"",/(update|add)/.test(c.type)&&"updateComplete"!==c.type&&(f.lastCombinedFilter=null,f.lastSearch=[]),b.searching(e,h,!0)),!1}),g.filter_reset&&(g.filter_reset instanceof a?g.filter_reset.click(function(){f.$table.trigger("filterReset")}):a(g.filter_reset).length&&a(document).undelegate(g.filter_reset,"click"+f.namespace+"filter").delegate(g.filter_reset,"click"+f.namespace+"filter",function(){f.$table.trigger("filterReset")})),g.filter_functions)for(l=0;l<f.columns;l++)if(o=c.getColumnData(e,g.filter_functions,l))if(k=f.$headerIndexed[l].removeClass("filter-select"),p=!(k.hasClass("filter-false")||k.hasClass("parser-false")),h="",o===!0&&p)b.buildSelect(e,l);else if("object"==typeof o&&p){
// add custom drop down list
for(i in o)"string"==typeof i&&(h+=""===h?'<option value="">'+(k.data("placeholder")||k.attr("data-placeholder")||g.filter_placeholder.select||"")+"</option>":"",n=i,j=i,i.indexOf(g.filter_selectSourceSeparator)>=0&&(n=i.split(g.filter_selectSourceSeparator),j=n[1],n=n[0]),h+="<option "+(j===n?"":'data-function-name="'+i+'" ')+'value="'+n+'">'+j+"</option>");f.$table.find("thead").find("select."+d.filter+'[data-column="'+l+'"]').append(h),j=g.filter_selectSource,o="function"==typeof j?!0:c.getColumnData(e,j,l),o&&
// updating so the extra options are appended
b.buildSelect(f.table,l,"",!0,k.hasClass(g.filter_onlyAvail))}
// not really updating, but if the column has both the 'filter-select' class &
// filter_functions set to true, it would append the same options twice.
b.buildDefault(e,!0),b.bindSearch(e,f.$table.find("."+d.filter),!0),g.filter_external&&b.bindSearch(e,g.filter_external),g.filter_hideFilters&&b.hideFilters(f),
// show processing icon
f.showProcessing&&(j="filterStart filterEnd ".split(" ").join(f.namespace+"filter "),f.$table.unbind(j.replace(c.regex.spaces," ")).bind(j,function(b,g){k=g?f.$table.find("."+d.header).filter("[data-column]").filter(function(){return""!==g[a(this).data("column")]}):"",c.isProcessing(e,"filterStart"===b.type,g?k:"")})),
// set filtered rows count ( intially unfiltered )
f.filteredRows=f.totalRows,j="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(f.namespace+"filter "),f.$table.unbind(j.replace(c.regex.spaces," ")).bind(j,function(){var a=this.config.widgetOptions;m=b.setDefaults(e,f,a)||[],m.length&&(f.delayInit&&""===m.join("")||c.setFilters(e,m,!0)),f.$table.trigger("filterFomatterUpdate"),setTimeout(function(){a.filter_initialized||b.filterInitComplete(f)},100)}),f.pager&&f.pager.initialized&&!g.filter_initialized&&(f.$table.trigger("filterFomatterUpdate"),setTimeout(function(){b.filterInitComplete(f)},100))},
// $cell parameter, but not the config, is passed to the filter_formatters,
// so we have to work with it instead
formatterUpdated:function(a,b){
// prevent error if $cell is undefined - see #1056
var c=a&&a.closest("table")[0].config.widgetOptions;c&&!c.filter_initialized&&(
// add updates by column since this function
// may be called numerous times before initialization
c.filter_formatterInit[b]=1)},filterInitComplete:function(c){var d,e,f=c.widgetOptions,g=0,h=function(){f.filter_initialized=!0,c.$table.trigger("filterInit",c),b.findRows(c.table,c.$table.data("lastSearch")||[])};if(a.isEmptyObject(f.filter_formatter))h();else{for(e=f.filter_formatterInit.length,d=0;e>d;d++)1===f.filter_formatterInit[d]&&g++;clearTimeout(f.filter_initTimer),f.filter_initialized||g!==f.filter_formatterCount?f.filter_initialized||(
// fall back in case a filter_formatter doesn't call
// $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off
f.filter_initTimer=setTimeout(function(){h()},500)):
// filter widget initialized
h()}},
// encode or decode filters for storage; see #1026
processFilters:function(a,b){var c,d=b?encodeURIComponent:decodeURIComponent,e=a.length;for(c=0;e>c;c++)a[c]=d(a[c]);return a},setDefaults:function(d,e,f){var g,h,i,j,k,
// get current ( default ) filters
l=c.getFilters(d)||[];
// if no filters saved, then check default settings
if(f.filter_saveFilters&&c.storage&&(h=c.storage(d,"tablesorter-filters")||[],g=a.isArray(h),g&&""===h.join("")||!g||(l=b.processFilters(h))),""===l.join(""))for(k=e.$headers.add(f.filter_$externalFilters).filter("["+f.filter_defaultAttrib+"]"),i=0;i<=e.columns;i++)j=i===e.columns?"all":i,l[i]=k.filter('[data-column="'+j+'"]').attr(f.filter_defaultAttrib)||l[i]||"";return e.$table.data("lastSearch",l),l},parseFilter:function(a,b,c,d){return d?a.parsers[c].format(b,a.table,[],c):b},buildRow:function(b,e,f){var g,h,i,j,k,l,m,n,o,
// c.columns defined in computeThIndexes()
p=f.filter_cellFilter,q=e.columns,r=a.isArray(p),s='<tr role="row" class="'+d.filterRow+" "+e.cssIgnoreRow+'">';for(i=0;q>i;i++)e.$headerIndexed[i].length&&(s+='<td data-column="'+i+'"',o=e.$headerIndexed[i]&&e.$headerIndexed[i][0].colSpan||0,o>1&&(s+=' colspan="'+o+'"'),s+=r?p[i]?' class="'+p[i]+'"':"":""!==p?' class="'+p+'"':"",s+="></td>");
// build each filter input
for(e.$filters=a(s+="</tr>").appendTo(e.$table.children("thead").eq(0)).children("td"),i=0;q>i;i++)l=!1,j=e.$headerIndexed[i],j&&j.length&&(g=e.$filters.filter('[data-column="'+i+'"]'),n=c.getColumnData(b,f.filter_functions,i),k=f.filter_functions&&n&&"function"!=typeof n||j.hasClass("filter-select"),h=c.getColumnData(b,e.headers,i),l="false"===c.getData(j[0],h,"filter")||"false"===c.getData(j[0],h,"parser"),k?s=a("<select>").appendTo(g):(n=c.getColumnData(b,f.filter_formatter,i),n?(f.filter_formatterCount++,s=n(g,i),s&&0===s.length&&(s=g.children("input")),s&&(0===s.parent().length||s.parent().length&&s.parent()[0]!==g[0])&&g.append(s)):s=a('<input type="search">').appendTo(g),s&&(o=j.data("placeholder")||j.attr("data-placeholder")||f.filter_placeholder.search||"",s.attr("placeholder",o))),s&&(m=(a.isArray(f.filter_cssFilter)?"undefined"!=typeof f.filter_cssFilter[i]?f.filter_cssFilter[i]||"":"":f.filter_cssFilter)||"",s.addClass(d.filter+" "+m).attr("data-column",i),l&&(s.attr("placeholder","").addClass(d.filterDisabled)[0].disabled=!0)))},bindSearch:function(d,e,f){// allow passing a selector string
if(d=a(d)[0],e=a(e),e.length){var g,h=d.config,i=h.widgetOptions,j=h.namespace+"filter",k=i.filter_$externalFilters;f!==!0&&(g=i.filter_anyColumnSelector+","+i.filter_multipleColumnSelector,i.filter_$anyMatch=e.filter(g),k&&k.length?i.filter_$externalFilters=i.filter_$externalFilters.add(e):i.filter_$externalFilters=e,c.setFilters(d,h.$table.data("lastSearch")||[],f===!1)),
// unbind events
g="keypress keyup search change ".split(" ").join(j+" "),e.attr("data-lastSearchTime",(new Date).getTime()).unbind(g.replace(c.regex.spaces," ")).bind("keyup"+j,function(c){
// emulate what webkit does.... escape clears the filter
if(a(this).attr("data-lastSearchTime",(new Date).getTime()),27===c.which)this.value="";else{if(i.filter_liveSearch===!1)return;if(""!==this.value&&("number"==typeof i.filter_liveSearch&&this.value.length<i.filter_liveSearch||13!==c.which&&8!==c.which&&(c.which<32||c.which>=37&&c.which<=40)))return}
// change event = no delay; last true flag tells getFilters to skip newest timed input
b.searching(d,!0,!0)}).bind("search change keypress ".split(" ").join(j+" "),function(c){
// don't get cached data, in case data-column changes dynamically
var e=parseInt(a(this).attr("data-column"),10);
// don't allow 'change' event to process if the input value is the same - fixes #685
i.filter_initialized&&(13===c.which||"search"===c.type||"change"===c.type&&this.value!==h.lastSearch[e])&&(c.preventDefault(),
// init search with no delay
a(this).attr("data-lastSearchTime",(new Date).getTime()),b.searching(d,!1,!0))})}},searching:function(a,c,d){var e=a.config.widgetOptions;clearTimeout(e.filter_searchTimer),"undefined"==typeof c||c===!0?
// delay filtering
e.filter_searchTimer=setTimeout(function(){b.checkFilters(a,c,d)},e.filter_liveSearch?e.filter_searchDelay:10):
// skip delay
b.checkFilters(a,c,d)},checkFilters:function(e,f,g){var h=e.config,i=h.widgetOptions,j=a.isArray(f),k=j?f:c.getFilters(e,!0),l=(k||[]).join("");// combined filter values
// prevent errors if delay init is set
// combined filter values
// prevent errors if delay init is set
// update cache if delayInit set & pager has initialized ( after user initiates a search )
// add filter array back into inputs
// show/hide filter row as needed
// return if the last search is the same; but filter === false when updating the search
// see example-widget-filter.html filter toggle buttons
// force filter refresh
// give it time for the processing icon to kick in
return a.isEmptyObject(h.cache)?void(h.delayInit&&h.pager&&h.pager.initialized&&c.updateCache(h,function(){b.checkFilters(e,!1,g)})):(j&&(c.setFilters(e,k,!1,g!==!0),i.filter_initialized||(h.lastCombinedFilter="")),i.filter_hideFilters&&h.$table.find("."+d.filterRow).trigger(""===l?"mouseleave":"mouseenter"),h.lastCombinedFilter!==l||f===!1?(f===!1&&(h.lastCombinedFilter=null,h.lastSearch=[]),i.filter_initialized&&h.$table.trigger("filterStart",[k]),h.showProcessing?void setTimeout(function(){return b.findRows(e,k,l),!1},30):(b.findRows(e,k,l),!1)):void 0)},hideFilters:function(b,e){var f,g=(e||b.$table).find("."+d.filterRow).addClass(d.filterRowHide);g.bind("mouseenter mouseleave",function(c){
// save event object - http://bugs.jquery.com/ticket/12140
var e=c,g=a(this);clearTimeout(f),f=setTimeout(function(){/enter|over/.test(e.type)?g.removeClass(d.filterRowHide):
// don't hide if input has focus
// $( ':focus' ) needs jQuery 1.6+
a(document.activeElement).closest("tr")[0]!==g[0]&&""===b.lastCombinedFilter&&g.addClass(d.filterRowHide)},200)}).find("input, select").bind("focus blur",function(e){var g=e,h=a(this).closest("tr");clearTimeout(f),f=setTimeout(function(){clearTimeout(f),
// don't hide row if any filter has a value
""===c.getFilters(b.$table).join("")&&h.toggleClass(d.filterRowHide,"focus"!==g.type)},200)})},defaultFilter:function(c,d){if(""===c)return c;var e=b.regex.iQuery,f=d.match(b.regex.igQuery).length,g=f>1?a.trim(c).split(/\s/):[a.trim(c)],h=g.length-1,i=0,j=d;
// replace all {query} with query words...
// if query = 'Bob', then convert mask from '!{query}' to '!Bob'
// if query = 'Bob Joe Frank', then convert mask '{q} OR {q}' to 'Bob OR Joe OR Frank'
for(1>h&&f>1&&(
// only one 'word' in query but mask has >1 slots
g[1]=g[0]);e.test(j);)j=j.replace(e,g[i++]||""),e.test(j)&&h>i&&""!==(g[i]||"")&&(j=d.replace(e,j));return j},getLatestSearch:function(b){return b?b.sort(function(b,c){return a(c).attr("data-lastSearchTime")-a(b).attr("data-lastSearchTime")}):b||a()},multipleColumns:function(c,d){
// look for multiple columns '1-3,4-6,8' in data-column
var e,f,g,h,i,j,k,l,m,n=c.widgetOptions,
// only target 'all' column inputs on initialization
// & don't target 'all' column inputs if they don't exist
o=n.filter_initialized||!d.filter(n.filter_anyColumnSelector).length,p=[],q=a.trim(b.getLatestSearch(d).attr("data-column")||"");if(/^[0-9]+$/.test(q))return parseInt(q,10);
// process column range
if(o&&/-/.test(q))for(f=q.match(/(\d+)\s*-\s*(\d+)/g),m=f.length,l=0;m>l;l++){for(g=f[l].split(/\s*-\s*/),h=parseInt(g[0],10)||0,i=parseInt(g[1],10)||c.columns-1,h>i&&(e=h,h=i,i=e),i>=c.columns&&(i=c.columns-1);i>=h;h++)p.push(h);
// remove processed range from val
q=q.replace(f[l],"")}
// process single columns
if(o&&/,/.test(q))for(j=q.split(/\s*,\s*/),m=j.length,k=0;m>k;k++)""!==j[k]&&(l=parseInt(j[k],10),l<c.columns&&p.push(l));
// return all columns
if(!p.length)for(l=0;l<c.columns;l++)p.push(l);return p},processTypes:function(c,d,e){var f,g=null,h=null;for(f in b.types)a.inArray(f,e.excludeMatch)<0&&null===h&&(h=b.types[f](c,d,e),null!==h&&(g=h));return g},processRow:function(d,e,f){var g,h,i,j,k,l,m,n=b.regex,o=d.widgetOptions,p=!0,
// if wo.filter_$anyMatch data-column attribute is changed dynamically
// we don't want to do an "anyMatch" search on one column using data
// for the entire row - see #998
q=o.filter_$anyMatch&&o.filter_$anyMatch.length?
// look for multiple columns '1-3,4-6,8'
b.multipleColumns(d,o.filter_$anyMatch):[];if(e.$cells=e.$row.children(),e.anyMatchFlag&&q.length>1){if(e.anyMatch=!0,e.isMatch=!0,e.rowArray=e.$cells.map(function(b){return a.inArray(b,q)>-1?(e.parsed[b]?m=e.cacheArray[b]:(m=e.rawArray[b],m=a.trim(o.filter_ignoreCase?m.toLowerCase():m),d.sortLocaleCompare&&(m=c.replaceAccents(m))),m):void 0}).get(),e.filter=e.anyMatchFilter,e.iFilter=e.iAnyMatchFilter,e.exact=e.rowArray.join(" "),e.iExact=o.filter_ignoreCase?e.exact.toLowerCase():e.exact,e.cache=e.cacheArray.slice(0,-1).join(" "),f.excludeMatch=f.noAnyMatch,j=b.processTypes(d,e,f),null!==j)p=j;else if(o.filter_startsWith)for(p=!1,
// data.rowArray may not contain all columns
q=Math.min(d.columns,e.rowArray.length);!p&&q>0;)q--,p=p||0===e.rowArray[q].indexOf(e.iFilter);else p=(e.iExact+e.childRowText).indexOf(e.iFilter)>=0;
// no other filters to process
if(e.anyMatch=!1,e.filters.join("")===e.filter)return p}for(q=0;q<d.columns;q++)e.filter=e.filters[q],e.index=q,
// filter types to exclude, per column
f.excludeMatch=f.excludeFilter[q],
// ignore if filter is empty or disabled
e.filter&&(e.cache=e.cacheArray[q],
// check if column data should be from the cell or from parsed data
o.filter_useParsedData||e.parsed[q]?e.exact=e.cache:(h=e.rawArray[q]||"",e.exact=d.sortLocaleCompare?c.replaceAccents(h):h),e.iExact=!n.type.test(typeof e.exact)&&o.filter_ignoreCase?e.exact.toLowerCase():e.exact,e.isMatch=d.$headerIndexed[e.index].hasClass("filter-match"),h=p,l=o.filter_columnFilters?d.$filters.add(d.$externalFilters).filter('[data-column="'+q+'"]').find("select option:selected").attr("data-function-name")||"":"",d.sortLocaleCompare&&(e.filter=c.replaceAccents(e.filter)),i=!0,o.filter_defaultFilter&&n.iQuery.test(f.defaultColFilter[q])&&(e.filter=b.defaultFilter(e.filter,f.defaultColFilter[q]),i=!1),e.iFilter=o.filter_ignoreCase?(e.filter||"").toLowerCase():e.filter,k=f.functions[q],g=d.$headerIndexed[q].hasClass("filter-select"),j=null,(k||g&&i)&&(k===!0||g?j=e.isMatch?(""+e.iExact).search(e.iFilter)>=0:e.filter===e.exact:"function"==typeof k?j=k(e.exact,e.cache,e.filter,q,e.$row,d,e):"function"==typeof k[l||e.filter]&&(m=l||e.filter,j=k[m](e.exact,e.cache,e.filter,q,e.$row,d,e))),null===j?(j=b.processTypes(d,e,f),null!==j?h=j:(m=(e.iExact+e.childRowText).indexOf(b.parseFilter(d,e.iFilter,q,e.parsed[q])),h=!o.filter_startsWith&&m>=0||o.filter_startsWith&&0===m)):h=j,p=h?p:!1);return p},findRows:function(d,e,f){if(d.config.lastCombinedFilter!==f&&d.config.widgetOptions.filter_initialized){var g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E=a.extend([],e),F=b.regex,G=d.config,H=G.widgetOptions,
// data object passed to filters; anyMatch is a flag for the filters
I={anyMatch:!1,filters:e,
// regex filter type cache
filter_regexCache:[]},J={
// anyMatch really screws up with these types of filters
noAnyMatch:["range","notMatch","operators"],
// cache filter variables that use ts.getColumnData in the main loop
functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:c.getColumnData(d,H.filter_defaultFilter,G.columns,!0)||""};for(
// parse columns after formatter, in case the class is added at that point
I.parsed=G.$headers.map(function(b){
// force parsing if parser type is numeric
// getData won't return 'parsed' if other 'filter-' class names exist
// ( e.g. <th class="filter-select filter-parsed"> )
return G.parsers&&G.parsers[b]&&G.parsers[b].parsed||c.getData&&"parsed"===c.getData(G.$headerIndexed[b],c.getColumnData(d,G.headers,b),"filter")||a(this).hasClass("filter-parsed")}).get(),o=0;o<G.columns;o++)J.functions[o]=c.getColumnData(d,H.filter_functions,o),J.defaultColFilter[o]=c.getColumnData(d,H.filter_defaultFilter,o)||"",J.excludeFilter[o]=(c.getColumnData(d,H.filter_excludeFilter,o,!0)||"").split(/\s+/);for(G.debug&&(console.log("Filter: Starting filter widget search",e),u=new Date),
// filtered rows count
G.filteredRows=0,G.totalRows=0,f=(E||[]).join(""),m=0;m<G.$tbodies.length;m++){if(n=c.processTbody(d,G.$tbodies.eq(m),!0),o=G.columns,h=G.cache[m].normalized,j=a(a.map(h,function(a){return a[o].$row.get()})),""===f||H.filter_serversideFiltering)j.removeClass(H.filter_filteredRow).not("."+G.cssChildRow).css("display","");else{if(j=j.not("."+G.cssChildRow),g=j.length,(H.filter_$anyMatch&&H.filter_$anyMatch.length||"undefined"!=typeof e[G.columns])&&(I.anyMatchFlag=!0,I.anyMatchFilter=""+(e[G.columns]||H.filter_$anyMatch&&b.getLatestSearch(H.filter_$anyMatch).val()||""),H.filter_columnAnyMatch)){for(z=I.anyMatchFilter.split(F.andSplit),A=!1,w=0;w<z.length;w++)B=z[w].split(":"),B.length>1&&(C=parseInt(B[0],10)-1,C>=0&&C<G.columns&&(e[C]=B[1],z.splice(w,1),w--,A=!0));A&&(I.anyMatchFilter=z.join(" && "))}if(y=H.filter_searchFiltered,r=G.lastSearch||G.$table.data("lastSearch")||[],y)
// cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669
for(w=0;o+1>w;w++)v=e[w]||"",y||(w=o),y=y&&r.length&&0===v.indexOf(r[w]||"")&&!F.alreadyFiltered.test(v)&&!F.exactTest.test(v)&&!(F.isNeg1.test(v)||F.isNeg2.test(v))&&!(""!==v&&G.$filters&&G.$filters.filter('[data-column="'+w+'"]').find("select").length&&!G.$headerIndexed[w].hasClass("filter-match"));
// loop through the rows
for(x=j.not("."+H.filter_filteredRow).length,y&&0===x&&(y=!1),G.debug&&console.log("Filter: Searching through "+(y&&g>x?x:"all")+" rows"),I.anyMatchFlag&&(G.sortLocaleCompare&&(I.anyMatchFilter=c.replaceAccents(I.anyMatchFilter)),H.filter_defaultFilter&&F.iQuery.test(J.defaultAnyFilter)&&(I.anyMatchFilter=b.defaultFilter(I.anyMatchFilter,J.defaultAnyFilter),y=!1),I.iAnyMatchFilter=H.filter_ignoreCase&&G.ignoreCase?I.anyMatchFilter.toLowerCase():I.anyMatchFilter),l=0;g>l;l++)
// skip child rows & already filtered rows
if(D=j[l].className,p=l&&F.child.test(D),!(p||y&&F.filtered.test(D))){if(I.$row=j.eq(l),I.cacheArray=h[l],i=I.cacheArray[G.columns],I.rawArray=i.raw,I.childRowText="",!H.filter_childByColumn){
// so, if 'table.config.widgetOptions.filter_childRows' is true and there is
// a match anywhere in the child row, then it will make the row visible
// checked here so the option can be changed dynamically
for(D="",q=i.child,w=0;w<q.length;w++)D+=" "+q[w].join(" ")||"";I.childRowText=H.filter_childRows?H.filter_ignoreCase?D.toLowerCase():D:""}if(s=!1,t=b.processRow(G,I,J),k=i.$row,v=t?!0:!1,q=i.$row.filter(":gt( 0 )"),H.filter_childRows&&q.length){if(H.filter_childByColumn)
// cycle through each child row
for(H.filter_childWithSibs||(
// hide all child rows
q.addClass(H.filter_filteredRow),
// if only showing resulting child row, only include parent
k=k.eq(0)),w=0;w<q.length;w++)I.$row=q.eq(w),I.cacheArray=i.child[w],I.rawArray=I.cacheArray,v=b.processRow(G,I,J),s=s||v,!H.filter_childWithSibs&&v&&q.eq(w).removeClass(H.filter_filteredRow);
// keep parent row match even if no child matches... see #1020
s=s||t}else s=v;k.toggleClass(H.filter_filteredRow,!s)[0].display=s?"":"none"}}G.filteredRows+=j.not("."+H.filter_filteredRow).length,G.totalRows+=j.length,c.processTbody(d,n,!1)}G.lastCombinedFilter=f,// save last search
// don't save 'filters' directly since it may have altered ( AnyMatch column searches )
G.lastSearch=E,G.$table.data("lastSearch",E),H.filter_saveFilters&&c.storage&&c.storage(d,"tablesorter-filters",b.processFilters(E,!0)),G.debug&&console.log("Completed filter widget search"+c.benchmark(u)),H.filter_initialized&&G.$table.trigger("filterEnd",G),setTimeout(function(){c.applyWidget(G.table)},0)}},getOptionSource:function(d,e,f){d=a(d)[0];var g=d.config,h=g.widgetOptions,i=!1,j=h.filter_selectSource,k=g.$table.data("lastSearch")||[],l="function"==typeof j?!0:c.getColumnData(d,j,e);
// filter select source option
if(f&&""!==k[e]&&(f=!1),l===!0)
// OVERALL source
i=j(d,e,f);else{if(l instanceof a||"string"===a.type(l)&&l.indexOf("</option>")>=0)
// selectSource is a jQuery object or string of options
return l;a.isArray(l)?i=l:"object"===a.type(j)&&l&&(
// custom select source function for a SPECIFIC COLUMN
i=l(d,e,f))}
// fall back to original method
return i===!1&&(i=b.getOptions(d,e,f)),b.processOptions(d,e,i)},processOptions:function(b,d,e){if(!a.isArray(e))return!1;b=a(b)[0];var f,g,h,i,j=b.config,k="undefined"!=typeof d&&null!==d&&d>=0&&d<j.columns,l=[];if(e=a.grep(e,function(b,c){return a.inArray(b,e)===c}),k&&j.$headerIndexed[d].hasClass("filter-select-nosort"))
// unsorted select options
return e;
// parse select option values
for(i=e.length,h=0;i>h;h++)g=e[h],l.push({t:g,p:k&&j.parsers&&j.parsers.length&&j.parsers[d].format(g,b,[],d)||g});for(f=j.textSorter||"",l.sort(function(a,e){var g=a.p.toString(),h=e.p.toString();return k&&"function"==typeof f?f(g,h,!0,d,b):k&&"object"==typeof f&&f.hasOwnProperty(d)?f[d](g,h,!0,d,b):c.sortNatural?c.sortNatural(g,h):!0}),e=[],i=l.length,h=0;i>h;h++)e.push(l[h].t);return e},getOptions:function(b,d,e){b=a(b)[0];var f,g,h,i,j,k,l,m,n=b.config,o=n.widgetOptions,p=[];for(g=0;g<n.$tbodies.length;g++)
// loop through the rows
for(j=n.cache[g],h=n.cache[g].normalized.length,f=0;h>f;f++)
// check if has class filtered
if(i=j.row?j.row[f]:j.normalized[f][n.columns].$row[0],!e||!i.className.match(o.filter_filteredRow))
// get non-normalized cell content
if(o.filter_useParsedData||n.parsers[d].parsed||n.$headerIndexed[d].hasClass("filter-parsed")){
// child row parsed data
if(p.push(""+j.normalized[f][d]),o.filter_childRows&&o.filter_childByColumn)for(m=j.normalized[f][n.columns].$row.length-1,k=0;m>k;k++)p.push(""+j.normalized[f][n.columns].child[k][d])}else
// child row unparsed data
if(
// get raw cached data instead of content directly from the cells
p.push(j.normalized[f][n.columns].raw[d]),o.filter_childRows&&o.filter_childByColumn)for(m=j.normalized[f][n.columns].$row.length,k=1;m>k;k++)l=j.normalized[f][n.columns].$row.eq(k).children().eq(d),p.push(""+c.getElementText(n,l,d));return p},buildSelect:function(c,e,f,g,h){if(c=a(c)[0],e=parseInt(e,10),c.config.cache&&!a.isEmptyObject(c.config.cache)){var i,j,k,l,m,n,o=c.config,p=o.widgetOptions,q=o.$headerIndexed[e],
// t.data( 'placeholder' ) won't work in jQuery older than 1.4.3
r='<option value="">'+(q.data("placeholder")||q.attr("data-placeholder")||p.filter_placeholder.select||"")+"</option>",
// Get curent filter value
s=o.$table.find("thead").find("select."+d.filter+'[data-column="'+e+'"]').val();if(
// nothing included in arry ( external source ), so get the options from
// filter_selectSource or column data
("undefined"==typeof f||""===f)&&(f=b.getOptionSource(c,e,h)),a.isArray(f)){
// build option list
for(i=0;i<f.length;i++)k=f[i]=(""+f[i]).replace(b.regex.quote,"&quot;"),j=k,k.indexOf(p.filter_selectSourceSeparator)>=0&&(l=k.split(p.filter_selectSourceSeparator),j=l[0],k=l[1]),r+=""!==f[i]?"<option "+(j===k?"":'data-function-name="'+f[i]+'" ')+'value="'+j+'">'+k+"</option>":"";
// clear arry so it doesn't get appended twice
f=[]}
// update all selects in the same column ( clone thead in sticky headers &
// any external selects ) - fixes 473
m=(o.$filters?o.$filters:o.$table.children("thead")).find("."+d.filter),p.filter_$externalFilters&&(m=m&&m.length?m.add(p.filter_$externalFilters):p.filter_$externalFilters),n=m.filter('select[data-column="'+e+'"]'),
// make sure there is a select there!
n.length&&(n[g?"html":"append"](r),a.isArray(f)||
// append options if arry is provided externally as a string or jQuery object
// options ( default value ) was already added
n.append(f).val(s),n.val(s))}},buildDefault:function(a,d){var e,f,g,h=a.config,i=h.widgetOptions,j=h.columns;
// build default select dropdown
for(e=0;j>e;e++)f=h.$headerIndexed[e],g=!(f.hasClass("filter-false")||f.hasClass("parser-false")),(f.hasClass("filter-select")||c.getColumnData(a,i.filter_functions,e)===!0)&&g&&b.buildSelect(a,e,"",d,f.hasClass(i.filter_onlyAvail))}},c.getFilters=function(c,e,f,g){var h,i,j,k,l=!1,m=c?a(c)[0].config:"",n=m?m.widgetOptions:"";if(e!==!0&&n&&!n.filter_columnFilters||a.isArray(f)&&f.join("")===m.lastCombinedFilter)return a(c).data("lastSearch");if(m&&(m.$filters&&(i=m.$filters.find("."+d.filter)),n.filter_$externalFilters&&(i=i&&i.length?i.add(n.filter_$externalFilters):n.filter_$externalFilters),i&&i.length))for(l=f||[],h=0;h<m.columns+1;h++)k=h===m.columns?n.filter_anyColumnSelector+","+n.filter_multipleColumnSelector:'[data-column="'+h+'"]',j=i.filter(k),j.length&&(j=b.getLatestSearch(j),a.isArray(f)?(g&&j.length>1&&(j=j.slice(1)),h===m.columns&&(k=j.filter(n.filter_anyColumnSelector),j=k.length?k:j),j.val(f[h]).trigger("change"+m.namespace)):(l[h]=j.val()||"",h===m.columns?j.slice(1).filter('[data-column*="'+j.attr("data-column")+'"]').val(l[h]):j.slice(1).val(l[h])),h===m.columns&&j.length&&(n.filter_$anyMatch=j));return 0===l.length&&(l=!1),l},c.setFilters=function(d,e,f,g){var h=d?a(d)[0].config:"",i=c.getFilters(d,!0,e,g);return h&&f&&(h.lastCombinedFilter=null,h.lastSearch=[],b.searching(h.table,e,g),h.$table.trigger("filterFomatterUpdate")),!!i}}(jQuery),function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{sticky:"tablesorter-stickyHeader",// stickyHeader
stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),
// Add a resize event to table headers
c.addHeaderResizeEvent=function(b,c,d){// make sure we're using a dom element
if(b=a(b)[0],b.config){var e={timer:250},f=a.extend({},e,d),g=b.config,h=g.widgetOptions,i=function(a){var b,c,d,e,f,i,j=g.$headers.length;for(h.resize_flag=!0,c=[],b=0;j>b;b++)d=g.$headers.eq(b),e=d.data("savedSizes")||[0,0],f=d[0].offsetWidth,i=d[0].offsetHeight,(f!==e[0]||i!==e[1])&&(d.data("savedSizes",[f,i]),c.push(d[0]));c.length&&a!==!1&&g.$table.trigger("resize",[c]),h.resize_flag=!1};return i(!1),clearInterval(h.resize_timer),c?(h.resize_flag=!1,!1):void(h.resize_timer=setInterval(function(){h.resize_flag||i()},f.timer))}},
// Sticky headers based on this awesome article:
// http://css-tricks.com/13465-persistent-headers/
// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
// **************************
c.addWidget({id:"stickyHeaders",priority:60,// sticky widget must be initialized after the filter widget!
options:{stickyHeaders:"",// extra class name added to the sticky header row
stickyHeaders_attachTo:null,// jQuery selector or object to attach sticky header to
stickyHeaders_xScroll:null,// jQuery selector or object to monitor horizontal scroll position (defaults: xScroll > attachTo > window)
stickyHeaders_yScroll:null,// jQuery selector or object to monitor vertical scroll position (defaults: yScroll > attachTo > window)
stickyHeaders_offset:0,// number or jquery selector targeting the position:fixed element
stickyHeaders_filteredToTop:!0,// scroll table top into view after filtering
stickyHeaders_cloneId:"-sticky",// added to table ID, if it exists
stickyHeaders_addResizeEvent:!0,// trigger 'resize' event on headers
stickyHeaders_includeCaption:!0,// if false and a caption exist, it won't be included in the sticky header
stickyHeaders_zIndex:2},format:function(d,e,f){
// filter widget doesn't initialize on an empty table. Fixes #449
if(!(e.$table.hasClass("hasStickyHeaders")||a.inArray("filter",e.widgets)>=0&&!e.$table.hasClass("hasFilters"))){var g,h,i,j,k=e.$table,
// add position: relative to attach element, hopefully it won't cause trouble.
l=a(f.stickyHeaders_attachTo),m=e.namespace+"stickyheaders ",
// element to watch for the scroll event
n=a(f.stickyHeaders_yScroll||f.stickyHeaders_attachTo||b),o=a(f.stickyHeaders_xScroll||f.stickyHeaders_attachTo||b),p=k.children("thead:first"),q=p.children("tr").not(".sticky-false").children(),r=k.children("tfoot"),s=isNaN(f.stickyHeaders_offset)?a(f.stickyHeaders_offset):"",t=s.length?s.height()||0:parseInt(f.stickyHeaders_offset,10)||0,
// is this table nested? If so, find parent sticky header wrapper (div, not table)
u=k.parent().closest("."+c.css.table).hasClass("hasStickyHeaders")?k.parent().closest("table.tablesorter")[0].config.widgetOptions.$sticky.parent():[],v=u.length?u.height():0,
// clone table, then wrap to make sticky header
w=f.$sticky=k.clone().addClass("containsStickyHeaders "+c.css.sticky+" "+f.stickyHeaders+" "+e.namespace.slice(1)+"_extra_table").wrap('<div class="'+c.css.stickyWrap+'">'),x=w.parent().addClass(c.css.stickyHide).css({position:l.length?"absolute":"fixed",padding:parseInt(w.parent().parent().css("padding-left"),10),top:t+v,left:0,visibility:"hidden",zIndex:f.stickyHeaders_zIndex||2}),y=w.children("thead:first"),z="",A=0,B=function(a,c){var d,e,f,g,h,i=a.filter(":visible"),j=i.length;for(d=0;j>d;d++)g=c.filter(":visible").eq(d),h=i.eq(d),"border-box"===h.css("box-sizing")?e=h.outerWidth():"collapse"===g.css("border-collapse")?b.getComputedStyle?e=parseFloat(b.getComputedStyle(h[0],null).width):(f=parseFloat(h.css("border-width")),e=h.outerWidth()-parseFloat(h.css("padding-left"))-parseFloat(h.css("padding-right"))-f):e=h.width(),g.css({width:e,"min-width":e,"max-width":e})},C=function(){t=s.length?s.height()||0:parseInt(f.stickyHeaders_offset,10)||0,A=0,x.css({left:l.length?parseInt(l.css("padding-left"),10)||0:k.offset().left-parseInt(k.css("margin-left"),10)-o.scrollLeft()-A,width:k.outerWidth()}),B(k,w),B(q,j)},D=function(b){if(k.is(":visible")){// fixes #278
// Detect nested tables - fixes #724
v=u.length?u.offset().top-n.scrollTop()+u.height():0;var d=k.offset(),e=a.isWindow(n[0]),// $.isWindow needs jQuery 1.4.3
f=a.isWindow(o[0]),
// scrollTop = ( $attach.length ? $attach.offset().top : $yScroll.scrollTop() ) + stickyOffset + nestedStickyTop,
g=(l.length?e?n.scrollTop():n.offset().top:n.scrollTop())+t+v,h=k.height()-(x.height()+(r.height()||0)),i=g>d.top&&g<d.top+h?"visible":"hidden",j={visibility:i};l.length&&(j.top=e?g-l.offset().top:l.scrollTop()),f&&(
// adjust when scrolling horizontally - fixes issue #143
j.left=k.offset().left-parseInt(k.css("margin-left"),10)-o.scrollLeft()-A),u.length&&(j.top=(j.top||0)+t+v),x.removeClass(c.css.stickyVis+" "+c.css.stickyHide).addClass("visible"===i?c.css.stickyVis:c.css.stickyHide).css(j),(i!==z||b)&&(
// make sure the column widths match
C(),z=i)}};
// onRenderHeader is defined, we need to do something about it (fixes #641)
if(
// only add a position relative if a position isn't already defined
l.length&&!l.css("position")&&l.css("position","relative"),
// fix clone ID, if it exists - fixes #271
w.attr("id")&&(w[0].id+=f.stickyHeaders_cloneId),
// clear out cloned table, except for sticky header
// include caption & filter row (fixes #126 & #249) - don't remove cells to get correct cell indexing
w.find("thead:gt(0), tr.sticky-false").hide(),w.find("tbody, tfoot").remove(),w.find("caption").toggle(f.stickyHeaders_includeCaption),j=y.children().children(),w.css({height:0,width:0,margin:0}),j.find("."+c.css.resizer).remove(),k.addClass("hasStickyHeaders").bind("pagerComplete"+m,function(){C()}),c.bindEvents(d,y.children().children("."+c.css.header)),k.after(x),e.onRenderHeader)for(i=y.children("tr").children(),h=i.length,g=0;h>g;g++)
// send second parameter
e.onRenderHeader.apply(i.eq(g),[g,e,w]);
// make it sticky!
o.add(n).unbind("scroll resize ".split(" ").join(m).replace(/\s+/g," ")).bind("scroll resize ".split(" ").join(m),function(a){D("resize"===a.type)}),e.$table.unbind("stickyHeadersUpdate"+m).bind("stickyHeadersUpdate"+m,function(){D(!0)}),f.stickyHeaders_addResizeEvent&&c.addHeaderResizeEvent(d),
// look for filter widget
k.hasClass("hasFilters")&&f.filter_columnFilters&&(
// scroll table into view after filtering, if sticky header is active - #482
k.bind("filterEnd"+m,function(){
// $(':focus') needs jQuery 1.6+
var d=a(document.activeElement).closest("td"),g=d.parent().children().index(d);
// only scroll if sticky header is active
x.hasClass(c.css.stickyVis)&&f.stickyHeaders_filteredToTop&&(
// scroll to original table (not sticky clone)
b.scrollTo(0,k.position().top),
// give same input/select focus; check if c.$filters exists; fixes #594
g>=0&&e.$filters&&e.$filters.eq(g).find("a, select, input").filter(":visible").focus())}),c.filter.bindSearch(k,j.find("."+c.css.filter)),
// support hideFilters
f.filter_hideFilters&&c.filter.hideFilters(e,w)),k.trigger("stickyHeadersInit")}},remove:function(d,e,f){var g=e.namespace+"stickyheaders ";e.$table.removeClass("hasStickyHeaders").unbind("pagerComplete filterEnd stickyHeadersUpdate ".split(" ").join(g).replace(/\s+/g," ")).next("."+c.css.stickyWrap).remove(),f.$sticky&&f.$sticky.length&&f.$sticky.remove(),// remove cloned table
a(b).add(f.stickyHeaders_xScroll).add(f.stickyHeaders_yScroll).add(f.stickyHeaders_attachTo).unbind("scroll resize ".split(" ").join(g).replace(/\s+/g," ")),c.addHeaderResizeEvent(d,!1)}})}(jQuery,window),function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{resizableContainer:"tablesorter-resizable-container",resizableHandle:"tablesorter-resizable-handle",resizableNoSelect:"tablesorter-disableSelection",resizableStorage:"tablesorter-resizable"}),
// Add extra scroller css
a(function(){var b="<style>body."+c.css.resizableNoSelect+" { -ms-user-select: none; -moz-user-select: -moz-none;-khtml-user-select: none; -webkit-user-select: none; user-select: none; }."+c.css.resizableContainer+" { position: relative; height: 1px; }."+c.css.resizableHandle+" { position: absolute; display: inline-block; width: 8px;top: 1px; cursor: ew-resize; z-index: 3; user-select: none; -moz-user-select: none; }</style>";a(b).appendTo("body")}),c.resizable={init:function(b,d){if(!b.$table.hasClass("hasResizable")){b.$table.addClass("hasResizable");var e,f,g,h,i,j=b.$table,k=j.parent(),l=parseInt(j.css("margin-top"),10),
// internal variables
m=d.resizable_vars={useStorage:c.storage&&d.resizable!==!1,$wrap:k,mouseXPosition:0,$target:null,$next:null,overflow:"auto"===k.css("overflow")||"scroll"===k.css("overflow")||"auto"===k.css("overflow-x")||"scroll"===k.css("overflow-x"),storedSizes:[]};
// add container
for(
// set default widths
c.resizableReset(b.table,!0),
// now get measurements!
m.tableWidth=j.width(),
// attempt to autodetect
m.fullWidth=Math.abs(k.width()-m.tableWidth)<20,/*
// Hacky method to determine if table width is set to 'auto'
// http://stackoverflow.com/a/20892048/145346
if ( !vars.fullWidth ) {
tmp = $table.width();
$header = $table.wrap('<span>').parent(); // temp variable
storedSizes = parseInt( $table.css( 'margin-left' ), 10 ) || 0;
$table.css( 'margin-left', storedSizes + 50 );
vars.tableWidth = $header.width() > tmp ? 'auto' : tmp;
$table.css( 'margin-left', storedSizes ? storedSizes : '' );
$header = null;
$table.unwrap('<span>');
}
*/
m.useStorage&&m.overflow&&(
// save table width
c.storage(b.table,"tablesorter-table-original-css-width",m.tableWidth),i=c.storage(b.table,"tablesorter-table-resized-width")||"auto",c.resizable.setWidth(j,i,!0)),d.resizable_vars.storedSizes=h=(m.useStorage?c.storage(b.table,c.css.resizableStorage):[])||[],c.resizable.setWidths(b,d,h),c.resizable.updateStoredSizes(b,d),d.$resizable_container=a('<div class="'+c.css.resizableContainer+'">').css({top:l}).insertBefore(j),g=0;g<b.columns;g++)f=b.$headerIndexed[g],i=c.getColumnData(b.table,b.headers,g),e="false"===c.getData(f,i,"resizable"),e||a('<div class="'+c.css.resizableHandle+'">').appendTo(d.$resizable_container).attr({"data-column":g,unselectable:"on"}).data("header",f).bind("selectstart",!1);j.one("tablesorter-initialized",function(){c.resizable.setHandlePosition(b,d),c.resizable.bindings(this.config,this.config.widgetOptions)})}},updateStoredSizes:function(a,b){var c,d,e=a.columns,f=b.resizable_vars;for(f.storedSizes=[],c=0;e>c;c++)d=a.$headerIndexed[c],f.storedSizes[c]=d.is(":visible")?d.width():0},setWidth:function(a,b,c){
// overflow tables need min & max width set as well
a.css({width:b,"min-width":c?b:"","max-width":c?b:""})},setWidths:function(b,d,e){var f,g,h=d.resizable_vars,i=a(b.namespace+"_extra_headers"),j=b.$table.children("colgroup").children("col");
// process only if table ID or url match
if(e=e||h.storedSizes||[],e.length){for(f=0;f<b.columns;f++)
// set saved resizable widths
c.resizable.setWidth(b.$headerIndexed[f],e[f],h.overflow),i.length&&(g=i.eq(f).add(j.eq(f)),c.resizable.setWidth(g,e[f],h.overflow));g=a(b.namespace+"_extra_table"),g.length&&!c.hasWidget(b.table,"scroller")&&c.resizable.setWidth(g,b.$table.outerWidth(),h.overflow)}},setHandlePosition:function(b,d){var e,f=c.hasWidget(b.table,"scroller"),g=b.$table.height(),h=d.$resizable_container.children(),i=Math.floor(h.width()/2);f&&(g=0,b.$table.closest("."+c.css.scrollerWrap).children().each(function(){var b=a(this);g+=b.filter('[style*="height"]').length?b.height():b.children("table").height()})),e=b.$table.position().left,h.each(function(){var c=a(this),f=parseInt(c.attr("data-column"),10),h=b.columns-1,j=c.data("header");j&&(j.is(":visible")?(h>f||f===h&&d.resizable_addLastColumn)&&c.css({display:"inline-block",height:g,left:j.position().left-e+j.outerWidth()-i}):c.hide())})},
// prevent text selection while dragging resize bar
toggleTextSelection:function(b,d){var e=b.namespace+"tsresize";b.widgetOptions.resizable_vars.disabled=d,a("body").toggleClass(c.css.resizableNoSelect,d),d?a("body").attr("unselectable","on").bind("selectstart"+e,!1):a("body").removeAttr("unselectable").unbind("selectstart"+e)},bindings:function(d,e){var f=d.namespace+"tsresize";e.$resizable_container.children().bind("mousedown",function(b){
// save header cell and mouse position
var f,g=e.resizable_vars,h=a(d.namespace+"_extra_headers"),i=a(b.target).data("header");f=parseInt(i.attr("data-column"),10),g.$target=i=i.add(h.filter('[data-column="'+f+'"]')),g.target=f,g.$next=b.shiftKey||e.resizable_targetLast?i.parent().children().not(".resizable-false").filter(":last"):i.nextAll(":not(.resizable-false)").eq(0),f=parseInt(g.$next.attr("data-column"),10),g.$next=g.$next.add(h.filter('[data-column="'+f+'"]')),g.next=f,g.mouseXPosition=b.pageX,c.resizable.updateStoredSizes(d,e),c.resizable.toggleTextSelection(d,!0)}),a(document).bind("mousemove"+f,function(a){var b=e.resizable_vars;
// ignore mousemove if no mousedown
b.disabled&&0!==b.mouseXPosition&&b.$target&&(e.resizable_throttle?(clearTimeout(b.timer),b.timer=setTimeout(function(){c.resizable.mouseMove(d,e,a)},isNaN(e.resizable_throttle)?5:e.resizable_throttle)):c.resizable.mouseMove(d,e,a))}).bind("mouseup"+f,function(){e.resizable_vars.disabled&&(c.resizable.toggleTextSelection(d,!1),c.resizable.stopResize(d,e),c.resizable.setHandlePosition(d,e))}),
// resizeEnd event triggered by scroller widget
a(b).bind("resize"+f+" resizeEnd"+f,function(){c.resizable.setHandlePosition(d,e)}),
// right click to reset columns to default widths
d.$table.bind("columnUpdate"+f,function(){c.resizable.setHandlePosition(d,e)}).find("thead:first").add(a(d.namespace+"_extra_table").find("thead:first")).bind("contextmenu"+f,function(){
// $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
var a=0===e.resizable_vars.storedSizes.length;return c.resizableReset(d.table),c.resizable.setHandlePosition(d,e),e.resizable_vars.storedSizes=[],a})},mouseMove:function(b,d,e){if(0!==d.resizable_vars.mouseXPosition&&d.resizable_vars.$target){
// resize columns
var f,g=0,h=d.resizable_vars,i=h.$next,j=h.storedSizes[h.target],k=e.pageX-h.mouseXPosition;if(h.overflow){if(j+k>0){
// update the entire table width
for(h.storedSizes[h.target]+=k,c.resizable.setWidth(h.$target,h.storedSizes[h.target],!0),f=0;f<b.columns;f++)g+=h.storedSizes[f];c.resizable.setWidth(b.$table.add(a(b.namespace+"_extra_table")),g)}i.length||(
// if expanding right-most column, scroll the wrapper
h.$wrap[0].scrollLeft=b.$table.width())}else h.fullWidth?(h.storedSizes[h.target]+=k,h.storedSizes[h.next]-=k,c.resizable.setWidths(b,d)):(h.storedSizes[h.target]+=k,c.resizable.setWidths(b,d));h.mouseXPosition=e.pageX,
// dynamically update sticky header widths
b.$table.trigger("stickyHeadersUpdate")}},stopResize:function(a,b){var d=b.resizable_vars;c.resizable.updateStoredSizes(a,b),d.useStorage&&(
// save all column widths
c.storage(a.table,c.css.resizableStorage,d.storedSizes),c.storage(a.table,"tablesorter-table-resized-width",a.$table.width())),d.mouseXPosition=0,d.$target=d.$next=null,
// will update stickyHeaders, just in case, see #912
a.$table.trigger("stickyHeadersUpdate")}},
// this widget saves the column widths if
// $.tablesorter.storage function is included
// **************************
c.addWidget({id:"resizable",priority:40,options:{resizable:!0,// save column widths to storage
resizable_addLastColumn:!1,resizable_widths:[],resizable_throttle:!1,// set to true (5ms) or any number 0-10 range
resizable_targetLast:!1,resizable_fullWidth:null},init:function(a,b,d,e){c.resizable.init(d,e)},remove:function(b,d,e,f){if(e.$resizable_container){var g=d.namespace+"tsresize";d.$table.add(a(d.namespace+"_extra_table")).removeClass("hasResizable").children("thead").unbind("contextmenu"+g),e.$resizable_container.remove(),c.resizable.toggleTextSelection(d,!1),c.resizableReset(b,f),a(document).unbind("mousemove"+g+" mouseup"+g)}}}),c.resizableReset=function(b,d){a(b).each(function(){var a,e,f=this.config,g=f&&f.widgetOptions,h=g.resizable_vars;if(b&&f&&f.$headerIndexed.length){for(
// restore the initial table width
h.overflow&&h.tableWidth&&(c.resizable.setWidth(f.$table,h.tableWidth,!0),h.useStorage&&c.storage(b,"tablesorter-table-resized-width","auto")),a=0;a<f.columns;a++)e=f.$headerIndexed[a],g.resizable_widths&&g.resizable_widths[a]?c.resizable.setWidth(e,g.resizable_widths[a],h.overflow):e.hasClass("resizable-false")||c.resizable.setWidth(e,"",h.overflow);
// reset stickyHeader widths
f.$table.trigger("stickyHeadersUpdate"),c.storage&&!d&&c.storage(this,c.css.resizableStorage,{})}})}}(jQuery,window),function(a){"use strict";var b=a.tablesorter||{};
// this widget saves the last sort only if the
// saveSort widget option is true AND the
// $.tablesorter.storage function is included
// **************************
b.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(a,b,c,d){
// run widget format before all other widgets are applied to the table
b.format(a,c,d,!0)},format:function(c,d,e,f){var g,h,i=d.$table,j=e.saveSort!==!1,// make saveSort active/inactive; default to true
k={sortList:d.sortList};d.debug&&(h=new Date),i.hasClass("hasSaveSort")?j&&c.hasInitialized&&b.storage&&(b.storage(c,"tablesorter-savesort",k),d.debug&&console.log("saveSort widget: Saving last sort: "+d.sortList+b.benchmark(h))):(
// set table sort on initial run of the widget
i.addClass("hasSaveSort"),k="",b.storage&&(g=b.storage(c,"tablesorter-savesort"),k=g&&g.hasOwnProperty("sortList")&&a.isArray(g.sortList)?g.sortList:"",d.debug&&console.log('saveSort: Last sort loaded: "'+k+'"'+b.benchmark(h)),i.bind("saveSortReset",function(a){a.stopPropagation(),b.storage(c,"tablesorter-savesort","")})),f&&k&&k.length>0?d.sortList=k:c.hasInitialized&&k&&k.length>0&&b.sortOn(d,k))},remove:function(a,c){c.$table.removeClass("hasSaveSort"),
// clear storage
b.storage&&b.storage(a,"tablesorter-savesort","")}})}(jQuery),a.tablesorter});