diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/dragtable.mod.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/dragtable.mod.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..56d2f42eb6236e2b182949ebe7676d7969d0bd58
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/dragtable.mod.min.css
@@ -0,0 +1 @@
+.dragtable-sortable{list-style-type:none;margin:0;padding:0;-moz-user-select:none;z-index:10}.dragtable-sortable li{margin:0;padding:0;float:left;font-size:1em}.dragtable-sortable table{margin-top:0}.dragtable-sortable td,.dragtable-sortable th{border-left:0}.dragtable-sortable li:first-child td,.dragtable-sortable li:first-child th{border-left:1px solid #CCC}.ui-sortable-helper{opacity:.7;filter:alpha(opacity=70)}.ui-sortable-placeholder{-moz-box-shadow:4px 5px 4px rgba(0,0,0,.2) inset;-webkit-box-shadow:4px 5px 4px rgba(0,0,0,.2) inset;box-shadow:4px 5px 4px rgba(0,0,0,.2) inset;border-bottom:1px solid rgba(0,0,0,.2);border-top:1px solid rgba(0,0,0,.2);visibility:visible!important;background:#EFEFEF}.ui-sortable-placeholder *{opacity:0;visibility:hidden}.table-handle,.table-handle-disabled{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyIiBoZWlnaHQ9IjEzIj48cmVjdCBzdHlsZT0iZmlsbDojMzMzO2ZpbGwtb3BhY2l0eTouODsiIHdpZHRoPSIxIiBoZWlnaHQ9IjEiIHg9IjEiIHk9IjIiLz4JPHJlY3Qgc3R5bGU9ImZpbGw6IzMzMztmaWxsLW9wYWNpdHk6Ljg7IiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4PSIxIiB5PSI0Ii8+CTxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iNiIvPjxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iOCIvPjxyZWN0IHN0eWxlPSJmaWxsOiMzMzM7ZmlsbC1vcGFjaXR5Oi44OyIgd2lkdGg9IjEiIGhlaWdodD0iMSIgeD0iMSIgeT0iMTAiLz48L3N2Zz4=);background-repeat:repeat-x;height:13px;margin:0 1px;cursor:move}.table-handle-disabled{opacity:0;cursor:not-allowed}.dragtable-sortable table{margin-bottom:0}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/filter.formatter.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/filter.formatter.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..eba8cc043d59e9cd42ae5746559f6d6e4a0e4a6b
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/filter.formatter.min.css
@@ -0,0 +1 @@
+.tablesorter .tablesorter-filter-row td{text-align:center;font-size:.9em;font-weight:400}.tablesorter .ui-slider,.tablesorter input.range{width:90%;margin:2px auto;font-size:.8em}.tablesorter .ui-slider{top:12px}.tablesorter .ui-slider .ui-slider-handle{width:.9em;height:.9em}.tablesorter .ui-datepicker{font-size:.8em}.tablesorter .ui-slider-horizontal{height:.5em}.tablesorter .value-popup:after{content:attr(data-value);position:absolute;bottom:14px;left:-7px;min-width:18px;height:12px;background-color:#444;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#999));background-image:-webkit-linear-gradient(top,#444,#999);background-image:-moz-linear-gradient(top,#444,#999);background-image:-o-linear-gradient(top,#444,#999);background-image:linear-gradient(to bottom,#444,#999);-webkit-border-radius:3px;border-radius:3px;-webkit-background-clip:padding-box;background-clip:padding-box;-webkit-box-shadow:0 0 4px 0 #777;box-shadow:0 0 4px 0 #777;border:1px solid #444;color:#fff;font:1em/1.1em Arial,Sans-Serif;padding:1px;text-align:center}.tablesorter .button,.tablesorter .button label{-webkit-border-radius:25px;-moz-border-radius:25px}.tablesorter .value-popup:before{content:"";position:absolute;width:0;height:0;border-top:8px solid #777;border-left:8px solid transparent;border-right:8px solid transparent;top:-8px;left:50%;margin-left:-8px;margin-top:-1px}.tablesorter .dateFrom,.tablesorter .dateTo{width:80px;margin:2px 5px}.tablesorter .button{width:14px;height:14px;background:#fcfff4;background:-webkit-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:-moz-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:-o-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:-ms-linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);background:linear-gradient(top,#fcfff4 0,#dfe5d7 40%,#b3bead 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#fcfff4', endColorstr='#b3bead', GradientType=0 );margin:1px 5px 1px 1px;border-radius:25px;-webkit-box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);-moz-box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);position:relative;top:3px;display:inline-block}.tablesorter .button label{cursor:pointer;position:absolute;width:10px;height:10px;border-radius:25px;left:2px;top:2px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,1);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,1);box-shadow:inset 0 1px 1px rgba(0,0,0,.5),0 1px 0 rgba(255,255,255,1);background:#45484d;background:-webkit-linear-gradient(top,#222 0,#45484d 100%);background:-moz-linear-gradient(top,#222 0,#45484d 100%);background:-o-linear-gradient(top,#222 0,#45484d 100%);background:-ms-linear-gradient(top,#222 0,#45484d 100%);background:linear-gradient(top,#222 0,#45484d 100%);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#222', endColorstr='#45484d', GradientType=0 )}.tablesorter .button label:after{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";filter:alpha(opacity=0);opacity:0;content:'';position:absolute;width:8px;height:8px;background:#55f;background:-webkit-linear-gradient(top,#aaf 0,#55f 100%);background:-moz-linear-gradient(top,#aaf 0,#55f 100%);background:-o-linear-gradient(top,#aaf 0,#55f 100%);background:-ms-linear-gradient(top,#aaf 0,#55f 100%);background:linear-gradient(top,#aaf 0,#55f 100%);-webkit-border-radius:25px;-moz-border-radius:25px;border-radius:25px;top:1px;left:1px;-webkit-box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);-moz-box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5);box-shadow:inset 0 1px 1px #fff,0 1px 3px rgba(0,0,0,.5)}.tablesorter .button label:hover::after{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=30)";filter:alpha(opacity=30);opacity:.3}.tablesorter .button input[type=checkbox]{visibility:hidden}.tablesorter .button input[type=checkbox]:checked+label:after{-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";filter:alpha(opacity=100);opacity:1}.tablesorter .colorpicker{width:30px;height:18px}.tablesorter .ui-spinner-input{width:100px;height:18px}.tablesorter .currentColor,.tablesorter .ui-spinner,.tablesorter input.number{position:relative}.tablesorter .tablesorter-filter-row.hideme td *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/black-asc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/black-asc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..730533fa3570dd4805cec70fe2630e85a2e1b863
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/black-asc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/black-desc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/black-desc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..4c3b61020bb4d707e41e94fbf2b6ebe5d0c87f6b
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/black-desc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/black-unsorted.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/black-unsorted.gif
new file mode 100644
index 0000000000000000000000000000000000000000..5647f658329230706ec09c5e3c24fae39d225a04
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/black-unsorted.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/bootstrap-black-unsorted.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/bootstrap-black-unsorted.png
new file mode 100644
index 0000000000000000000000000000000000000000..3190f29accc3207a2f840733addbd8d284459361
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/bootstrap-black-unsorted.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/bootstrap-white-unsorted.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/bootstrap-white-unsorted.png
new file mode 100644
index 0000000000000000000000000000000000000000..368c66dd7399b1b7455a6d38017b4c0df3ba9759
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/bootstrap-white-unsorted.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dragtable-handle.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dragtable-handle.png
new file mode 100644
index 0000000000000000000000000000000000000000..52a1a5659382b287828bdb8c0f56158a9f342824
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dragtable-handle.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dragtable-handle.svg b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dragtable-handle.svg
new file mode 100644
index 0000000000000000000000000000000000000000..041ec1ded8c2f7a17e267e4f816bc06dd7d29c55
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dragtable-handle.svg
@@ -0,0 +1,7 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="2" height="13">
+	<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="2"/>
+	<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="4"/>
+	<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="6"/>
+	<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="8"/>
+	<rect style="fill:#333;fill-opacity:.8;" width="1" height="1" x="1" y="10"/>
+</svg>
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-asc-hovered.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-asc-hovered.png
new file mode 100644
index 0000000000000000000000000000000000000000..4e625e028c315576b4bf47140074ef5a7af2d8f7
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-asc-hovered.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-asc.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-asc.png
new file mode 100644
index 0000000000000000000000000000000000000000..7b6615bc49d1e874cf626a9fac4754e2f15696a8
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-asc.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-desc-hovered.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-desc-hovered.png
new file mode 100644
index 0000000000000000000000000000000000000000..806707dddb0b21cae6cddea0a4acdddd20393058
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-desc-hovered.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-desc.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-desc.png
new file mode 100644
index 0000000000000000000000000000000000000000..868a37ccc935c40ec378c3a73b75ea97aa9ef9d4
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/dropbox-desc.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/first.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/first.png
new file mode 100644
index 0000000000000000000000000000000000000000..7e505d68e3ba4d8aed703db339b33d8a29ff9034
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/first.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-asc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-asc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..4cfba09507af83ef6db36d4eb1adcc75e2fa3954
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-asc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-desc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-desc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..4f8817650dc07236f0f884cb826413ceeba2e1e6
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-desc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-header.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-header.gif
new file mode 100644
index 0000000000000000000000000000000000000000..cc746b70a390d3c1e60dd0839aafaefdb56ffa5c
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-header.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-unsorted.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-unsorted.gif
new file mode 100644
index 0000000000000000000000000000000000000000..0afe2c021cc7dccbb3af311f09496b51864737ca
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/green-unsorted.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/ice-asc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/ice-asc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..0961d9aafb17fa754d4ce5048c638cfb4db3b40d
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/ice-asc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/ice-desc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/ice-desc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..0330fccaabc2e17a7e67f4962aa4f89c8557ba4f
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/ice-desc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/ice-unsorted.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/ice-unsorted.gif
new file mode 100644
index 0000000000000000000000000000000000000000..c1afde558ea67f6f47148bb4e25f39abafd87799
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/ice-unsorted.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/last.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/last.png
new file mode 100644
index 0000000000000000000000000000000000000000..41e248ccc5e15522fee21f1a363de72f7988b3de
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/last.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/loading.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/loading.gif
new file mode 100644
index 0000000000000000000000000000000000000000..72054717b5f0d94a0582b3eb9032c71cb9296553
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/loading.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-black-asc.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-black-asc.png
new file mode 100644
index 0000000000000000000000000000000000000000..61c4f8018b2f198b91d595c26b7dbb9eb24a602c
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-black-asc.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-black-desc.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-black-desc.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc2188c6091bc2e17267df12130876c8f3a34384
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-black-desc.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-loading.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-loading.gif
new file mode 100644
index 0000000000000000000000000000000000000000..ae274c6c12de1a8b5fb237336e5208d2d269f0ad
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-loading.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-unsorted.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-unsorted.png
new file mode 100644
index 0000000000000000000000000000000000000000..e67ab2a69c4c0b9b90c7c4b1adc782b568c51b9c
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-unsorted.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-white-asc.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-white-asc.png
new file mode 100644
index 0000000000000000000000000000000000000000..a850fbf1a985ce0039c6ca8907d1b96ec0981abe
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-white-asc.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-white-desc.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-white-desc.png
new file mode 100644
index 0000000000000000000000000000000000000000..fc05607ef3a2334361b0ba3911f0aa7a3ff7038e
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/metro-white-desc.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/next.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/next.png
new file mode 100644
index 0000000000000000000000000000000000000000..aebf14d9ef7d8a71607a71ead039b56df9520e7b
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/next.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/prev.png b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/prev.png
new file mode 100644
index 0000000000000000000000000000000000000000..7d1d049e9c0cf58d2a270cdb1d2afa846debc10d
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/prev.png differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/white-asc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/white-asc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..2173b0a0596a3faa5d8f9236c385c325fa6227ad
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/white-asc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/white-desc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/white-desc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..7109c3ea161794feeae8c95a0fc5aa728e371f37
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/white-desc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/images/white-unsorted.gif b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/white-unsorted.gif
new file mode 100644
index 0000000000000000000000000000000000000000..9bfc3459c766d019f057f0557b0abf21319ff46e
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/css/images/white-unsorted.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/jquery.tablesorter.pager.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/jquery.tablesorter.pager.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..9d87fe3fc2de180f0b7e832451aa5bf72f5c7eb9
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/jquery.tablesorter.pager.min.css
@@ -0,0 +1 @@
+.tablesorter-pager{padding:5px}td.tablesorter-pager{background-color:#e6eeee;margin:0}.tablesorter-pager img{vertical-align:middle;margin-right:2px;cursor:pointer}.tablesorter-pager .pagedisplay{padding:0 5px;width:auto;white-space:nowrap;text-align:center}.tablesorter-pager select{margin:0;padding:0}.tablesorter-pager.disabled{display:none}.tablesorter-pager .disabled{opacity:.5;filter:alpha(opacity=50);cursor:default}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/less/bootstrap.less b/smash/web/static/AdminLTE/plugins/tablesorter/css/less/bootstrap.less
new file mode 100644
index 0000000000000000000000000000000000000000..32264fcd4f3d19679f1eadd6228c079699c6b16d
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/less/bootstrap.less
@@ -0,0 +1,328 @@
+/* Tablesorter Custom Bootstrap LESS Theme by Rob Garrison
+
+To create your own theme, modify the code below and run it through
+a LESS compiler, like this one: http://leafo.net/lessphp/editor.html
+or download less.js from http://lesscss.org/
+
+Test out these customization files live
+ Basic LESS Theme : http://codepen.io/Mottie/pen/eqBbn
+ Bootstrap LESS   : http://codepen.io/Mottie/pen/Ltzpi
+ Metro LESS Style : http://codepen.io/Mottie/pen/gCslk
+ Basic SCSS       : http://codepen.io/Mottie/pen/LbXdNR
+
+*/
+
+/*** theme ***/
+@theme                 : tablesorter-bootstrap;
+
+/*** fonts ***/
+@tableHeaderFont       : 14px bold Arial, Sans-serif;
+@tableBodyFont         : 14px "Helvetica Neue", Helvetica, Arial, sans-serif;
+
+/*** color definitions ***/
+/* for best results, only change the hue (240),
+   leave the saturation (60%) and luminosity (80%) alone
+   pick the color from here: http://hslpicker.com/#99E699 */
+@headerBackground      : hsl(240, 60%, 80%);
+@borderAndBackground   : #cdcdcd;
+@overallBorder         : @borderAndBackground 1px solid;
+@headerTextColor       : #000;
+
+@bodyBackground        : #fff;
+@bodyTextColor         : #000;
+
+@headerAsc             : darken(spin(@headerBackground, 5), 10%); /* darken(@headerBackground, 10%); */
+@headerDesc            : lighten(spin(@headerBackground, -5), 10%); /* desaturate(@headerAsc, 5%); */
+
+@captionBackground     : #fff; /* it might be best to match the document body background color here */
+@errorBackground       : #e6bf99; /* ajax error message (added to thead) */
+
+@filterCellBackground  : #eee;
+@filterElementTextColor: #333;
+@filterElementBkgd     : #fff;
+@filterElementBorder   : 1px solid #bbb;
+@filterTransitionTime  : 0.1s;
+@filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */
+
+@overallPadding        : 4px;
+/* 20px should be slightly wider than the icon width to avoid overlap */
+@headerPadding         : 4px 20px 4px 4px;
+@headerMargin          : 0 0 18px;
+
+/* url(icons/loading.gif); */
+@processingIcon        : url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=');
+
+/* zebra striping */
+.allRows {
+	background-color: @bodyBackground;
+	color: @bodyTextColor;
+}
+.evenRows {
+	background-color: lighten(@headerBackground, 35%);
+}
+.oddRows {
+	background-color: lighten(@headerBackground, 18%);
+}
+
+/* hovered rows */
+.oddHovered {
+	background-color: desaturate(@headerBackground, 60%);
+}
+.evenHovered {
+	background-color: lighten( desaturate(@headerBackground, 60%), 10% );
+}
+
+/* Columns widget */
+@primaryOdd    : spin(@headerBackground, 10); /* saturate( darken( desaturate(@headerBackground, 10%), 10% ), 30%); */
+@primaryEven   : lighten( @primaryOdd, 10% );
+@secondaryOdd  : @primaryEven;
+@secondaryEven : lighten( @primaryEven, 5% );
+@tertiaryOdd   : @secondaryEven;
+@tertiaryEven  : lighten( @secondaryEven, 5% );
+
+/* Filter widget transition */
+.filterWidgetTransition {
+	-webkit-transition: line-height @filterTransitionTime ease;
+	-moz-transition: line-height @filterTransitionTime ease;
+	-o-transition: line-height @filterTransitionTime ease;
+	transition: line-height @filterTransitionTime ease;
+}
+
+/*** icon block ***/
+.iconPosition {
+	font-size: 11px;
+	position: absolute;
+	right: 2px;
+	top: 50%;
+	margin-top: -7px; /* half the icon height; older IE doesn't like this */
+	width: 14px;
+	height: 14px;
+	background-repeat: no-repeat;
+	line-height: 14px;
+}
+
+/* black */
+@unsortedBlack : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAA20lEQVR4AWJABpKSkoxALCstLb0aUAsZaCAMhVEY6B0amx8YZWDDEDSBa2AGe7XeIiAAClYwVGBvsAcIllsf/mvcC9DgOOd8h90fxWvngVEUbZIkuWRZZlE8eQjcisgZMM9zi+LJ6ZfwegmWZflZDugdHMfxTcGqql7TNBlUB/QObtv2VBSFrev6OY7jngzFk9OT/fn73fWYpqnlXNyXDMWT0zuYx/Bvel9ej+LJ6R08DMOu67q7DkTkrSA5vYPneV71fX/QASdTkJwezhs0TfMARn0wMDDGXEPgF4oijqwM5YjNAAAAAElFTkSuQmCC);
+
+/* white */
+@unsortedWhite : url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAAe0lEQVR4AbXQoRWDMBiF0Sh2QLAAQ8SxJGugWSA6A2STW1PxTsnB9cnkfuYvv8OGC1t5G3Y0QMP+Bm857keAdQIzWBP3+Bw4MADQE18B6/etRnCV/w9nnGuLezfAmXhABGtAGIkruvk6auIFRwQJDywllsEAjCecB20GP59BQQ+gtlRLAAAAAElFTkSuQmCC);
+
+/* automatically choose the correct arrow/text color */
+.headerText (@a) when (lightness(@a) >= 50%) {
+	color: @headerTextColor;
+}
+.headerText (@a) when (lightness(@a) < 50%) {
+	color: lighten(@headerTextColor, 90%);
+}
+.unsorted (@a) when (lightness(@a) >= 50%) {
+	background-image: @unsortedBlack;
+	color: @headerTextColor;
+}
+.unsorted (@a) when (lightness(@a) < 50%) {
+	background-image: @unsortedWhite;
+	color: lighten(@headerTextColor, 90%);
+}
+
+/* variable theme name - requires less.js 1.3+;
+   or just replace (!".@{theme}") with the contents of @theme
+*/
+.@{theme} {
+	font: @tableBodyFont;
+	background-color: @borderAndBackground;
+	width: 100%;
+
+	/* style th's outside of the thead */
+	th, thead td {
+		font: @tableHeaderFont;
+		font-weight: bold;
+		background-color: @headerBackground;
+		.headerText(@headerBackground);
+		border-collapse: collapse;
+		margin: @headerMargin;
+		padding: @overallPadding;
+	}
+
+	tbody td, tfoot th, tfoot td {
+		padding: @overallPadding;
+		vertical-align: top;
+	}
+
+	/* style header */
+	.tablesorter-header {
+		cursor: pointer;
+	}
+
+	.tablesorter-header-inner {
+		position: relative;
+		padding: @headerPadding;
+	}
+
+	/* bootstrap uses <i> for icons */
+	.tablesorter-header-inner i.tablesorter-icon {
+		.iconPosition
+	}
+
+	.tablesorter-header.sorter-false {
+		cursor: default;
+
+		i.tablesorter-icon {
+			display: none;
+		}
+		.tablesorter-header-inner {
+			padding: @overallPadding;
+		}
+	}
+
+	.tablesorter-headerAsc {
+		background-color: @headerAsc;
+	}
+
+	.tablesorter-headerDesc {
+		background-color: @headerDesc;
+	}
+
+	.bootstrap-icon-unsorted {
+		.unsorted(@headerBackground);
+	}
+
+
+	/* tfoot */
+	tfoot .tablesorter-headerAsc,
+	tfoot .tablesorter-headerDesc {
+		/* remove sort arrows from footer */
+		background-image: none;
+	}
+
+	/* optional disabled input styling */
+	.disabled {
+		opacity: 0.5;
+		filter: alpha(opacity=50);
+		cursor: not-allowed;
+	}
+
+	/* body */
+	tbody {
+
+		td {
+			.allRows;
+			padding: @overallPadding;
+			vertical-align: top;
+		}
+
+		/* Zebra Widget - row alternating colors */
+		tr.odd > td {
+			.oddRows;
+		}
+		tr.even > td {
+			.evenRows;
+		}
+
+	}
+
+	/* hovered row colors
+	you'll need to add additional lines for
+	rows with more than 2 child rows
+	*/
+	tbody > tr.hover > td,
+	tbody > tr:hover > td,
+	tbody > tr:hover + tr.tablesorter-childRow > td,
+	tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td,
+	tbody > tr.even.hover > td,
+	tbody > tr.even:hover > td,
+	tbody > tr.even:hover + tr.tablesorter-childRow > td,
+	tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+		.evenHovered;
+	}
+	tbody > tr.odd.hover > td,
+	tbody > tr.odd:hover > td,
+	tbody > tr.odd:hover + tr.tablesorter-childRow > td,
+	tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+		.oddHovered;
+	}
+
+	/* table processing indicator - indeterminate spinner */
+	.tablesorter-processing {
+		background-image: @processingIcon;
+		background-position: center center;
+		background-repeat: no-repeat;
+	}
+
+	/* Column Widget - column sort colors */
+	tr.odd td.primary {
+		background-color: @primaryOdd;
+	}
+	td.primary, tr.even td.primary {
+		background-color: @primaryEven;
+	}
+	tr.odd td.secondary {
+		background-color: @secondaryOdd;
+	}
+	td.secondary, tr.even td.secondary {
+		background-color: @secondaryEven;
+	}
+	tr.odd td.tertiary {
+		background-color: @tertiaryOdd;
+	}
+	td.tertiary, tr.even td.tertiary {
+		background-color: @tertiaryEven;
+	}
+
+	/* caption (non-theme matching) */
+	caption {
+		background-color: @captionBackground ;
+	}
+
+	/* filter widget */
+	.tablesorter-filter-row input,
+	.tablesorter-filter-row select{
+		width: 98%;
+		margin: 0;
+		padding: @overallPadding;
+		color: @filterElementTextColor;
+		background-color: @filterElementBkgd;
+		border: @filterElementBorder;
+		-webkit-box-sizing: border-box;
+		-moz-box-sizing: border-box;
+		box-sizing: border-box;
+		.filterWidgetTransition;
+	}
+	.tablesorter-filter-row {
+		background-color: @filterCellBackground;
+	}
+	.tablesorter-filter-row td {
+		text-align: center;
+		background-color: @filterCellBackground;
+		line-height: normal;
+		text-align: center; /* center the input */
+		.filterWidgetTransition;
+	}
+	/* hidden filter row */
+	.tablesorter-filter-row.hideme td {
+		padding: @filterRowHiddenHeight / 2;
+		margin: 0;
+		line-height: 0;
+		cursor: pointer;
+	}
+	.tablesorter-filter-row.hideme * {
+		height: 1px;
+		min-height: 0;
+		border: 0;
+		padding: 0;
+		margin: 0;
+		/* don't use visibility: hidden because it disables tabbing */
+		opacity: 0;
+		filter: alpha(opacity=0);
+	}
+	/* rows hidden by filtering (needed for child rows) */
+	.filtered {
+		display: none;
+	}
+
+	/* ajax error row */
+	.tablesorter-errorRow td {
+		text-align: center;
+		cursor: pointer;
+		background-color: @errorBackground;
+	}
+
+}
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/less/metro.less b/smash/web/static/AdminLTE/plugins/tablesorter/css/less/metro.less
new file mode 100644
index 0000000000000000000000000000000000000000..f0423d34869814d4dbe45644d38ca271217b61cf
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/less/metro.less
@@ -0,0 +1,358 @@
+/* Tablesorter Custom Metro LESS Theme by Rob Garrison
+
+To create your own theme, modify the code below and run it through
+a LESS compiler, like this one: http://leafo.net/lessphp/editor.html
+or download less.js from http://lesscss.org/
+
+Test out these customization files live
+ Basic LESS Theme : http://codepen.io/Mottie/pen/eqBbn
+ Bootstrap LESS   : http://codepen.io/Mottie/pen/Ltzpi
+ Metro LESS Style : http://codepen.io/Mottie/pen/gCslk
+ Basic SCSS       : http://codepen.io/Mottie/pen/LbXdNR
+
+*/
+
+/*** theme ***/
+@theme                 : tablesorter-metro;
+
+/*** fonts ***/
+@tableHeaderFont       : 14px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif;
+@tableBodyFont         : 14px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif;
+
+/*** color definitions ***/
+/* for best results, only change the hue (120),
+   leave the saturation (60%) and luminosity (75%) alone
+   pick the color from here: http://hslpicker.com/#825a2b
+
+  Inspired by http://www.jtable.org/ metro themes:
+    Blue:        hsl(212, 86%, 35%)
+    Brown        hsl(32, 50%, 30%)
+    Crimson      hsl(0, 100%, 38%)
+    Dark Grey    hsl(0, 0%, 27%)
+    Dark Orange  hsl(13, 70%, 51%)
+    Green        hsl(120, 100%, 32%)
+    Light Gray   hsl(0, 0%, 44%)
+    Pink         hsl(297, 100%, 33%)
+    Purple       hsl(257, 51%, 48%)
+    Red          hsl(5, 100%, 40%)
+
+ */
+@headerBackground      : hsl(32, 50%, 30%);
+@borderAndBackground   : #cdcdcd;
+@headerTextColor       : #eee;
+
+@bodyBackground        : #fff;
+@bodyTextColor         : #000;
+
+@captionBackground     : #fff; /* it might be best to match the document body background color here */
+@errorBackground       : #e6bf99; /* ajax error message (added to thead) */
+
+@filterCellBackground  : #eee;
+@filterElementTextColor: #333;
+@filterElementBkgd     : #fff;
+@filterElementBorder   : 1px solid #bbb;
+@filterTransitionTime  : 0.1s;
+@filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */
+
+@overallPadding        : 4px;
+/* 20px should be slightly wider than the icon width to avoid overlap */
+@headerPadding         : 4px 20px 4px 4px;
+
+/* url(icons/loading.gif); */
+@processingIcon : url('data:image/gif;base64,R0lGODlhEAAQAPIAAP///1VVVdbW1oCAgFVVVZaWlqurq7a2tiH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAADMwi63P4wyklrE2MIOggZnAdOmGYJRbExwroUmcG2LmDEwnHQLVsYOd2mBzkYDAdKa+dIAAAh+QQJCgAAACwAAAAAEAAQAAADNAi63P5OjCEgG4QMu7DmikRxQlFUYDEZIGBMRVsaqHwctXXf7WEYB4Ag1xjihkMZsiUkKhIAIfkECQoAAAAsAAAAABAAEAAAAzYIujIjK8pByJDMlFYvBoVjHA70GU7xSUJhmKtwHPAKzLO9HMaoKwJZ7Rf8AYPDDzKpZBqfvwQAIfkECQoAAAAsAAAAABAAEAAAAzMIumIlK8oyhpHsnFZfhYumCYUhDAQxRIdhHBGqRoKw0R8DYlJd8z0fMDgsGo/IpHI5TAAAIfkECQoAAAAsAAAAABAAEAAAAzIIunInK0rnZBTwGPNMgQwmdsNgXGJUlIWEuR5oWUIpz8pAEAMe6TwfwyYsGo/IpFKSAAAh+QQJCgAAACwAAAAAEAAQAAADMwi6IMKQORfjdOe82p4wGccc4CEuQradylesojEMBgsUc2G7sDX3lQGBMLAJibufbSlKAAAh+QQJCgAAACwAAAAAEAAQAAADMgi63P7wCRHZnFVdmgHu2nFwlWCI3WGc3TSWhUFGxTAUkGCbtgENBMJAEJsxgMLWzpEAACH5BAkKAAAALAAAAAAQABAAAAMyCLrc/jDKSatlQtScKdceCAjDII7HcQ4EMTCpyrCuUBjCYRgHVtqlAiB1YhiCnlsRkAAAOwAAAAAAAAAAAA==');
+
+/* zebra striping */
+.allRows {
+	background-color: @bodyBackground;
+	color: @bodyTextColor;
+}
+.evenRows {
+	background-color: lighten( desaturate(@headerBackground, 80%), 70%);
+	color: @bodyTextColor;
+}
+.oddRows {
+	background-color: lighten( desaturate(@headerBackground, 80%), 50%);
+}
+
+/* hovered rows */
+.oddHovered {
+	background-color: lighten( desaturate(@headerBackground, 50%), 40%);
+	color: @bodyTextColor;
+}
+.evenHovered {
+	background-color: lighten( desaturate(@headerBackground, 50%), 30%);
+	color: @bodyTextColor;
+}
+
+/* Columns widget */
+@primaryOdd    : lighten( spin(@headerBackground, 10), 40%);
+@primaryEven   : lighten( @primaryOdd, 8% );
+@secondaryOdd  : @primaryEven;
+@secondaryEven : lighten( @primaryEven, 8% );
+@tertiaryOdd   : @secondaryEven;
+@tertiaryEven  : lighten( @secondaryEven, 8% );
+
+/* Filter widget transition */
+.filterWidgetTransition {
+	-webkit-transition: line-height @filterTransitionTime ease;
+	-moz-transition: line-height @filterTransitionTime ease;
+	-o-transition: line-height @filterTransitionTime ease;
+	transition: line-height @filterTransitionTime ease;
+}
+
+/*** Arrows ***/
+@arrowPosition : right 5px center;
+
+/* black */
+@unsortedBlack : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt0UjBAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC);
+@sortAscBlack  : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt0UjBAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC);
+@sortDescBlack : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAALVBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADBoCg+AAAADnRSTlMAMiweCQITTvDctZZqaTlM310AAABcSURBVAjXY2BgYEtgAAFHERDJqigUAKSYBQUNgFSioKAYAwOLIBA4MASBKFUGQxAlzAAF+94BwWuGKBC1lIFl3rt3Lx0YGCzevWsGSjK9e6cAUlT3HKyW9wADAwDRrBiDy6bKzwAAAABJRU5ErkJggg==);
+
+/* white */
+@unsortedWhite : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAElBMVEUAAADu7u7u7u7u7u7u7u7u7u7yb344AAAABnRSTlMAMhIHKyAHBrhHAAAATElEQVQI12NgYGBSYAABQ2Ew5SgCIlkFBQOAlKKgoBADA7MgEBgwsIAoB4ZAECXKAAFQHkg9WIejoCBIv4mgoDOQYgZpAxkDNARqEQBTkAYuMZEHPgAAAABJRU5ErkJggg==);
+@sortAscWhite  : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAHlBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u4+jEeEAAAACXRSTlMAMwkqFV7roCD4hW+/AAAAWUlEQVQI1y3MrQ5AABSG4Xd+Rj0jiDabjKZxB6qqaarGNRh27tY5myd8b/uAeML1l2+wPqUlUd0ss+oNoZqG2rOwe15+p5iC1HNAK5IBlUjnZyIlZsxx0QAfzokSZgp96u4AAAAASUVORK5CYII=);
+@sortDescWhite : url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAJ1BMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u4RJgHSAAAADHRSTlMAMiweCQITaU7olrlu2HdvAAAAXElEQVQI12NgYGBLYAABRxEQyaooFACkmAUFDYBUoqCgGAMDiyAQODAEgShVBkMQJcwABWvOAMEphmgQtZWBZc6ZMycdGBhszpw5DJRkOnNGAaSo5wRYLXsBAwMAi4YWQHRX4F0AAAAASUVORK5CYII=);
+
+/* automatically choose the correct arrow/text color */
+.headerText (@a) when (lightness(@a) >= 50%) {
+	color: @headerTextColor;
+}
+.headerText (@a) when (lightness(@a) < 50%) {
+	color: lighten(@headerTextColor, 90%);
+}
+.unsorted (@a) when (lightness(@a) >= 50%) {
+	background-image: @unsortedBlack;
+}
+.unsorted (@a) when (lightness(@a) < 50%) {
+	background-image: @unsortedWhite;
+}
+.sortAsc (@a) when (lightness(@a) >= 50%) {
+	background-image: @sortAscBlack;
+}
+.sortAsc (@a) when (lightness(@a) < 50%) {
+	background-image: @sortAscWhite;
+}
+.sortDesc (@a) when (lightness(@a) >= 50%) {
+	background-image: @sortDescBlack;
+}
+.sortDesc (@a) when (lightness(@a) < 50%) {
+	background-image: @sortDescWhite;
+}
+
+/* variable theme name - requires less.js 1.3+;
+   or just replace (!".@{theme}") with the contents of @theme
+*/
+.@{theme} {
+	font: @tableBodyFont;
+	background-color: @borderAndBackground;
+	margin: 10px 0 15px;
+	width: 100%;
+	text-align: left;
+	border-spacing: 0;
+	border: 0;
+
+	th, td {
+		border: 0;
+	}
+
+	/* style th's outside of the thead */
+	th, thead td {
+		font: @tableHeaderFont;
+		font-weight: bold;
+		background-color: @headerBackground;
+		color: @headerTextColor;
+		.headerText(@headerBackground);
+		border-collapse: collapse;
+		padding: @overallPadding;
+	}
+
+  .dark-row th, .dark-row td, caption.dark-row {
+    background-color: darken( @headerBackground, 10% );
+  }
+
+	tbody td, tfoot th, tfoot td {
+		padding: @overallPadding;
+		vertical-align: top;
+	}
+
+	/* style header */
+	.tablesorter-header {
+		.unsorted(@headerBackground);
+		background-repeat: no-repeat;
+		background-position: @arrowPosition;
+		cursor: pointer;
+		white-space: normal;
+	}
+
+	.tablesorter-header-inner {
+		padding: @headerPadding;
+	}
+
+	.tablesorter-header.sorter-false {
+		background-image: none;
+		cursor: default;
+		padding: @overallPadding;
+	}
+
+	.tablesorter-headerAsc {
+		.sortAsc(@headerBackground);
+	}
+
+	.tablesorter-headerDesc {
+		.sortDesc(@headerBackground);
+	}
+
+	/* tfoot */
+	tfoot .tablesorter-headerAsc,
+	tfoot .tablesorter-headerDesc {
+		/* remove sort arrows from footer */
+		background-image: none;
+	}
+
+	/* optional disabled input styling */
+	.disabled {
+		opacity: 0.5;
+		filter: alpha(opacity=50);
+		cursor: not-allowed;
+	}
+
+	/* body */
+	tbody {
+
+		td {
+			.allRows;
+			padding: @overallPadding;
+			vertical-align: top;
+		}
+
+		/* Zebra Widget - row alternating colors */
+		tr.odd > td {
+			.oddRows;
+		}
+		tr.even > td {
+			.evenRows;
+		}
+
+	}
+
+	/* hovered row colors
+	you'll need to add additional lines for
+	rows with more than 2 child rows
+	*/
+	tbody > tr.hover > td,
+	tbody > tr:hover > td,
+	tbody > tr:hover + tr.tablesorter-childRow > td,
+	tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td,
+	tbody > tr.even.hover > td,
+	tbody > tr.even:hover > td,
+	tbody > tr.even:hover + tr.tablesorter-childRow > td,
+	tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+		.evenHovered;
+	}
+	tbody > tr.odd.hover > td,
+	tbody > tr.odd:hover > td,
+	tbody > tr.odd:hover + tr.tablesorter-childRow > td,
+	tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+		.oddHovered;
+	}
+
+	/* table processing indicator - indeterminate spinner */
+	.tablesorter-processing {
+		background-image: @processingIcon;
+		background-position: center center;
+		background-repeat: no-repeat;
+	}
+
+	/* pager */
+	div.tablesorter-pager {
+		button {
+			background-color: lighten( @headerBackground, 7% );
+			color: @headerTextColor;
+			border: lighten( @headerBackground, 15% ) 1px solid;
+			cursor: pointer;
+		}
+		button:hover {
+			background-color: lighten( @headerBackground, 15% );
+		}
+	}
+
+	/* Column Widget - column sort colors */
+	tr.odd td.primary {
+		background-color: @primaryOdd;
+	}
+	td.primary, tr.even td.primary {
+		background-color: @primaryEven;
+	}
+	tr.odd td.secondary {
+		background-color: @secondaryOdd;
+	}
+	td.secondary, tr.even td.secondary {
+		background-color: @secondaryEven;
+	}
+	tr.odd td.tertiary {
+		background-color: @tertiaryOdd;
+	}
+	td.tertiary, tr.even td.tertiary {
+		background-color: @tertiaryEven;
+	}
+
+	/* caption (non-theme matching) */
+	caption {
+		background-color: @captionBackground ;
+	}
+
+	/* filter widget */
+	.tablesorter-filter-row input,
+	.tablesorter-filter-row select{
+		width: 98%;
+		height: auto;
+		margin: 0;
+		padding: @overallPadding;
+		color: @filterElementTextColor;
+		background-color: @filterElementBkgd;
+		border: @filterElementBorder;
+		-webkit-box-sizing: border-box;
+		-moz-box-sizing: border-box;
+		box-sizing: border-box;
+		.filterWidgetTransition;
+	}
+	.tablesorter-filter-row {
+		background-color: @filterCellBackground;
+	}
+	.tablesorter-filter-row td {
+		text-align: center;
+		background-color: @filterCellBackground;
+		line-height: normal;
+		text-align: center; /* center the input */
+		.filterWidgetTransition;
+	}
+	/* hidden filter row */
+	.tablesorter-filter-row.hideme td {
+		padding: @filterRowHiddenHeight / 2;
+		margin: 0;
+		line-height: 0;
+		cursor: pointer;
+	}
+	.tablesorter-filter-row.hideme * {
+		height: 1px;
+		min-height: 0;
+		border: 0;
+		padding: 0;
+		margin: 0;
+		/* don't use visibility: hidden because it disables tabbing */
+		opacity: 0;
+		filter: alpha(opacity=0);
+	}
+	/* rows hidden by filtering (needed for child rows) */
+	.filtered {
+		display: none;
+	}
+
+	/* ajax error row */
+	.tablesorter-errorRow td {
+		text-align: center;
+		cursor: pointer;
+		background-color: @errorBackground;
+	}
+
+}
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/less/theme.less b/smash/web/static/AdminLTE/plugins/tablesorter/css/less/theme.less
new file mode 100644
index 0000000000000000000000000000000000000000..e645227a76b49adc74091bbf7c58c9e35bbb6076
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/less/theme.less
@@ -0,0 +1,330 @@
+/* Tablesorter Custom LESS Theme by Rob Garrison
+
+ To create your own theme, modify the code below and run it through
+ a LESS compiler, like this one: http://leafo.net/lessphp/editor.html
+ or download less.js from http://lesscss.org/
+
+Test out these custom less files live
+ Basic Theme : http://codepen.io/Mottie/pen/eqBbn
+ Bootstrap   : http://codepen.io/Mottie/pen/Ltzpi
+ Metro Style : http://codepen.io/Mottie/pen/gCslk
+ Basic SCSS  : http://codepen.io/Mottie/pen/LbXdNR
+
+ */
+
+/*** theme ***/
+@theme                 : tablesorter-custom;
+
+/*** fonts ***/
+@tableHeaderFont       : 11px 'trebuchet ms', verdana, arial;
+@tableBodyFont         : 11px 'trebuchet ms', verdana, arial;
+
+/*** color definitions ***/
+/* for best results, only change the hue (120),
+   leave the saturation (60%) and luminosity (75%) alone
+   pick the color from here: http://hslpicker.com/#99E699 */
+@headerBackground      : hsl(120, 60%, 75%);
+@borderAndBackground   : #cdcdcd;
+@overallBorder         : @borderAndBackground 1px solid;
+@headerTextColor       : #000;
+
+@bodyBackground        : #fff;
+@bodyTextColor         : #000;
+
+@headerAsc             : darken(spin(@headerBackground, 5), 10%); /* darken(@headerBackground, 10%); */
+@headerDesc            : lighten(spin(@headerBackground, -5), 10%); /* desaturate(@headerAsc, 5%); */
+
+@captionBackground     : #fff; /* it might be best to match the document body background color here */
+@errorBackground       : #e6bf99; /* ajax error message (added to thead) */
+
+@filterCellBackground  : #eee;
+@filterElementTextColor: #333;
+@filterElementBkgd     : #fff;
+@filterElementBorder   : 1px solid #bbb;
+@filterTransitionTime  : 0.1s;
+@filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */
+
+@overallPadding        : 4px;
+/* 20px should be slightly wider than the icon width to avoid overlap */
+@headerPadding         : 4px 20px 4px 4px;
+
+/* url(icons/loading.gif); */
+@processingIcon        : url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=');
+
+/* zebra striping */
+.allRows {
+	background-color: @bodyBackground;
+	color: @bodyTextColor;
+}
+.evenRows {
+	background-color: lighten(@headerBackground, 40%);
+	color: @bodyTextColor;
+}
+.oddRows {
+	background-color: lighten(@headerBackground, 20%);
+}
+
+/* hovered rows */
+.oddHovered {
+	background-color: desaturate(@headerBackground, 60%);
+	color: @bodyTextColor;
+}
+.evenHovered {
+	background-color: lighten( desaturate(@headerBackground, 60%), 10% );
+	color: @bodyTextColor;
+}
+
+/* Columns widget */
+@primaryOdd    : spin(@headerBackground, 10); /* saturate( darken( desaturate(@headerBackground, 10%), 10% ), 30%); */
+@primaryEven   : lighten( @primaryOdd, 10% );
+@secondaryOdd  : @primaryEven;
+@secondaryEven : lighten( @primaryEven, 5% );
+@tertiaryOdd   : @secondaryEven;
+@tertiaryEven  : lighten( @secondaryEven, 5% );
+
+/* Filter widget transition */
+.filterWidgetTransition {
+	-webkit-transition: line-height @filterTransitionTime ease;
+	-moz-transition: line-height @filterTransitionTime ease;
+	-o-transition: line-height @filterTransitionTime ease;
+	transition: line-height @filterTransitionTime ease;
+}
+
+/*** Arrows ***/
+@arrowPosition : right 5px center;
+
+/* black */
+@unsortedBlack : url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
+@sortAscBlack  : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
+@sortDescBlack : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
+
+/* white */
+@unsortedWhite : url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
+@sortAscWhite  : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
+@sortDescWhite : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
+
+/* automatically choose the correct arrow/text color */
+.headerText (@a) when (lightness(@a) >= 50%) {
+	color: @headerTextColor;
+}
+.headerText (@a) when (lightness(@a) < 50%) {
+	color: lighten(@headerTextColor, 90%);
+}
+.unsorted (@a) when (lightness(@a) >= 50%) {
+	background-image: @unsortedBlack;
+}
+.unsorted (@a) when (lightness(@a) < 50%) {
+	background-image: @unsortedWhite;
+}
+.sortAsc (@a) when (lightness(@a) >= 50%) {
+	background-image: @sortAscBlack;
+}
+.sortAsc (@a) when (lightness(@a) < 50%) {
+	background-image: @sortAscWhite;
+}
+.sortDesc (@a) when (lightness(@a) >= 50%) {
+	background-image: @sortDescBlack;
+}
+.sortDesc (@a) when (lightness(@a) < 50%) {
+	background-image: @sortDescWhite;
+}
+
+/* variable theme name - requires less.js 1.3+;
+   or just replace (!".@{theme}") with the contents of @theme
+ */
+.@{theme} {
+	font: @tableBodyFont;
+	background-color: @borderAndBackground;
+	margin: 10px 0 15px;
+	width: 100%;
+	text-align: left;
+	border-spacing: 0;
+	border: @overallBorder;
+	border-width: 1px 0 0 1px;
+
+	th, td {
+		border: @overallBorder;
+		border-width: 0 1px 1px 0;
+	}
+
+	/* style th's outside of the thead */
+	th, thead td {
+		font: @tableHeaderFont;
+		font-weight: bold;
+		background-color: @headerBackground;
+		.headerText(@headerBackground);
+		border-collapse: collapse;
+		padding: @overallPadding;
+	}
+
+	tbody td, tfoot th, tfoot td {
+		padding: @overallPadding;
+		vertical-align: top;
+	}
+
+	/* style header */
+	.tablesorter-header {
+		.unsorted(@headerBackground);
+		background-repeat: no-repeat;
+		background-position: @arrowPosition;
+		padding: @headerPadding;
+		cursor: pointer;
+	}
+
+	.tablesorter-header.sorter-false {
+		background-image: none;
+		cursor: default;
+		padding: @overallPadding;
+	}
+
+	.tablesorter-headerAsc {
+		background-color: @headerAsc;
+		.sortAsc(@headerBackground);
+	}
+
+	.tablesorter-headerDesc {
+		background-color: @headerDesc;
+		.sortDesc(@headerBackground);
+	}
+
+	/* tfoot */
+	tfoot .tablesorter-headerAsc,
+	tfoot .tablesorter-headerDesc {
+		/* remove sort arrows from footer */
+		background-image: none;
+	}
+
+	/* optional disabled input styling */
+	.disabled {
+		opacity: 0.5;
+		filter: alpha(opacity=50);
+		cursor: not-allowed;
+	}
+
+	/* body */
+	tbody {
+
+		td {
+			.allRows;
+			padding: @overallPadding;
+			vertical-align: top;
+		}
+
+		/* Zebra Widget - row alternating colors */
+		tr.odd > td {
+			.oddRows;
+		}
+		tr.even > td {
+			.evenRows;
+		}
+
+	}
+
+	/* hovered row colors
+	   you'll need to add additional lines for
+	   rows with more than 2 child rows
+	*/
+	tbody > tr.hover td,
+	tbody > tr:hover td,
+	tbody > tr:hover + tr.tablesorter-childRow > td,
+	tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td,
+	tbody > tr.even.hover > td,
+	tbody > tr.even:hover > td,
+	tbody > tr.even:hover + tr.tablesorter-childRow > td,
+	tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+		.evenHovered;
+	}
+	tbody > tr.odd.hover > td,
+	tbody > tr.odd:hover > td,
+	tbody > tr.odd:hover + tr.tablesorter-childRow > td,
+	tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+		.oddHovered;
+	}
+
+	/* table processing indicator - indeterminate spinner */
+	.tablesorter-processing {
+		background-image: @processingIcon;
+		background-position: center center;
+		background-repeat: no-repeat;
+	}
+
+	/* Column Widget - column sort colors */
+	tr.odd td.primary {
+		background-color: @primaryOdd;
+	}
+	td.primary, tr.even td.primary {
+		background-color: @primaryEven;
+	}
+	tr.odd td.secondary {
+		background-color: @secondaryOdd;
+	}
+	td.secondary, tr.even td.secondary {
+		background-color: @secondaryEven;
+	}
+	tr.odd td.tertiary {
+		background-color: @tertiaryOdd;
+	}
+	td.tertiary, tr.even td.tertiary {
+		background-color: @tertiaryEven;
+	}
+
+	/* caption (non-theme matching) */
+	caption {
+		background-color: @captionBackground ;
+	}
+
+	/* filter widget */
+	.tablesorter-filter-row input,
+	.tablesorter-filter-row select {
+		width: 98%;
+		height: auto;
+		margin: 0;
+		padding: @overallPadding;
+		color: @filterElementTextColor;
+		background-color: @filterElementBkgd;
+		border: @filterElementBorder;
+		-webkit-box-sizing: border-box;
+		-moz-box-sizing: border-box;
+		box-sizing: border-box;
+		.filterWidgetTransition;
+	}
+	.tablesorter-filter-row {
+		background-color: @filterCellBackground;
+	}
+	.tablesorter-filter-row td {
+		text-align: center;
+		background-color: @filterCellBackground;
+		line-height: normal;
+		text-align: center; /* center the input */
+		.filterWidgetTransition;
+	}
+	/* hidden filter row */
+	.tablesorter-filter-row.hideme td {
+		padding: @filterRowHiddenHeight / 2;
+		margin: 0;
+		line-height: 0;
+		cursor: pointer;
+	}
+	.tablesorter-filter-row.hideme * {
+		height: 1px;
+		min-height: 0;
+		border: 0;
+		padding: 0;
+		margin: 0;
+		/* don't use visibility: hidden because it disables tabbing */
+		opacity: 0;
+		filter: alpha(opacity=0);
+	}
+	/* rows hidden by filtering (needed for child rows) */
+	.filtered {
+		display: none;
+	}
+
+	/* ajax error row */
+	.tablesorter-errorRow td {
+		text-align: center;
+		cursor: pointer;
+		background-color: @errorBackground;
+	}
+
+}
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/scss/theme.scss b/smash/web/static/AdminLTE/plugins/tablesorter/css/scss/theme.scss
new file mode 100644
index 0000000000000000000000000000000000000000..f8a940c76dee57796f0eadd0264d3cdbc8c9b5d3
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/scss/theme.scss
@@ -0,0 +1,327 @@
+/* Tablesorter Custom SCSS Theme by Dan Feidt (https://github.com/HongPong)
+ Converted from Custom LESS Theme by Rob Garrison
+
+ To create your own theme, modify the code below and run it through
+ a SCSS compiler, like this one: http://beautifytools.com/scss-compiler.php
+ or download sass.js from https://github.com/medialize/sass.js
+
+Test out these customization files live
+ Basic LESS Theme : http://codepen.io/Mottie/pen/eqBbn
+ Bootstrap LESS   : http://codepen.io/Mottie/pen/Ltzpi
+ Metro LESS Style : http://codepen.io/Mottie/pen/gCslk
+ Basic SCSS       : http://codepen.io/Mottie/pen/LbXdNR
+
+ */
+
+/*** theme ***/
+$theme                 : tablesorter-custom;
+
+/*** fonts ***/
+$tableHeaderFont       : 11px 'trebuchet ms', verdana, arial;
+$tableBodyFont         : 11px 'trebuchet ms', verdana, arial;
+
+/*** color definitions ***/
+/* for best results, only change the hue (120),
+   leave the saturation (60%) and luminosity (75%) alone
+   pick the color from here: http://hslpicker.com/#99E699 */
+$headerBackground      : hsl(0, 60%, 75%);
+$borderAndBackground   : #cdcdcd;
+$overallBorder         : $borderAndBackground 1px solid;
+$headerTextColor       : #000;
+
+$bodyBackground        : #fff;
+$bodyTextColor         : #000;
+
+$headerAsc             : darken(adjust-hue($headerBackground, 5), 10%); /* darken($headerBackground, 10%); */
+$headerDesc            : lighten(adjust-hue($headerBackground, -5), 10%); /* desaturate($headerAsc, 5%); */
+
+$captionBackground     : #fff; /* it might be best to match the document body background color here */
+$errorBackground       : #e6bf99; /* ajax error message (added to thead) */
+
+$filterCellBackground  : #eee;
+$filterElementTextColor: #333;
+$filterElementBkgd     : #fff;
+$filterElementBorder   : 1px solid #bbb;
+$filterTransitionTime  : 0.1s;
+$filterRowHiddenHeight : 4px; /* becomes height using padding (so it's divided by 2) */
+
+$overallPadding        : 4px;
+/* 20px should be slightly wider than the icon width to avoid overlap */
+$headerPadding         : 4px 20px 4px 4px;
+
+/* url(icons/loading.gif); */
+$processingIcon        : url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=');
+
+/* zebra striping */
+@mixin allRows {
+	background-color: $bodyBackground;
+	color: $bodyTextColor;
+}
+@mixin evenRows {
+	background-color: lighten($headerBackground, 40%);
+	color: $bodyTextColor;
+}
+@mixin oddRows {
+	background-color: lighten($headerBackground, 20%);
+}
+
+/* hovered rows */
+@mixin oddHovered {
+	background-color: desaturate($headerBackground, 60%);
+	color: $bodyTextColor;
+}
+@mixin evenHovered {
+	background-color: lighten( desaturate($headerBackground, 60%), 10% );
+	color: $bodyTextColor;
+}
+
+/* Columns widget */
+$primaryOdd    : adjust-hue($headerBackground, 10); /* saturate( darken( desaturate($headerBackground, 10%), 10% ), 30%); */
+$primaryEven   : lighten( $primaryOdd, 10% );
+$secondaryOdd  : $primaryEven;
+$secondaryEven : lighten( $primaryEven, 5% );
+$tertiaryOdd   : $secondaryEven;
+$tertiaryEven  : lighten( $secondaryEven, 5% );
+
+/* Filter widget transition */
+@mixin filterWidgetTransition {
+	-webkit-transition: line-height $filterTransitionTime ease;
+	-moz-transition: line-height $filterTransitionTime ease;
+	-o-transition: line-height $filterTransitionTime ease;
+	transition: line-height $filterTransitionTime ease;
+}
+
+/*** Arrows ***/
+$arrowPosition : right 5px center;
+
+/* black */
+$unsortedBlack : url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
+$sortAscBlack  : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
+$sortDescBlack : url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
+
+/* white */
+$unsortedWhite : url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
+$sortAscWhite  : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
+$sortDescWhite : url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
+
+/* automatically choose the correct arrow/text color */
+@function set-lightness($a, $b) {
+	@if (lightness($headerBackground) >= 50) {
+		@return $a;
+	} @else {
+		@return $b;
+	}
+}
+@mixin headerText {
+	color: set-lightness($headerTextColor, lighten($headerTextColor, 90%));
+}
+
+@mixin unsorted {
+	background-image: set-lightness($unsortedBlack, $unsortedWhite);
+}
+@mixin sortAsc {
+	background-image: set-lightness($sortAscBlack, $sortAscWhite);
+}
+@mixin sortDesc {
+	background-image: set-lightness($sortDescBlack, $sortDescWhite);
+}
+
+/* variable theme name - requires less.js 1.3+;
+   or just replace (!".#{$theme}") with the contents of $theme
+ */
+.#{$theme} {
+	font: $tableBodyFont;
+	background-color: $borderAndBackground;
+	margin: 10px 0 15px;
+	width: 100%;
+	text-align: left;
+	border-spacing: 0;
+	border: $overallBorder;
+	border-width: 1px 0 0 1px;
+
+	th, td {
+		border: $overallBorder;
+		border-width: 0 1px 1px 0;
+	}
+
+	/* style th's outside of the thead */
+	th, thead td {
+		font: $tableHeaderFont;
+		font-weight: bold;
+		background-color: $headerBackground;
+		@include headerText;
+		border-collapse: collapse;
+		padding: $overallPadding;
+	}
+
+	tbody td, tfoot th, tfoot td {
+		padding: $overallPadding;
+		vertical-align: top;
+	}
+
+	/* style header */
+	.tablesorter-header {
+		@include unsorted;
+		background-repeat: no-repeat;
+		background-position: $arrowPosition;
+		padding: $headerPadding;
+		cursor: pointer;
+	}
+
+	.tablesorter-header.sorter-false {
+		background-image: none;
+		cursor: default;
+		padding: $overallPadding;
+	}
+
+	.tablesorter-headerAsc {
+		background-color: $headerAsc;
+		@include sortAsc;
+	}
+
+	.tablesorter-headerDesc {
+		background-color: $headerDesc;
+		@include sortDesc;
+	}
+
+	/* tfoot */
+	tfoot .tablesorter-headerAsc,
+	tfoot .tablesorter-headerDesc {
+		/* remove sort arrows from footer */
+		background-image: none;
+	}
+
+	/* optional disabled input styling */
+	.disabled {
+		opacity: 0.5;
+		filter: alpha(opacity=50);
+		cursor: not-allowed;
+	}
+
+	/* body */
+	tbody {
+
+		td {
+			@include allRows;
+			padding: $overallPadding;
+			vertical-align: top;
+		}
+
+		/* Zebra Widget - row alternating colors */
+		tr.odd > td {
+			@include oddRows;
+		}
+		tr.even > td {
+			@include evenRows;
+		}
+
+	}
+
+	/* hovered row colors
+	   you'll need to add additional lines for
+	   rows with more than 2 child rows
+	*/
+	tbody > tr.hover td,
+	tbody > tr:hover td,
+	tbody > tr:hover + tr.tablesorter-childRow > td,
+	tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td,
+	tbody > tr.even.hover > td,
+	tbody > tr.even:hover > td,
+	tbody > tr.even:hover + tr.tablesorter-childRow > td,
+	tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+		@include evenHovered;
+	}
+	tbody > tr.odd.hover > td,
+	tbody > tr.odd:hover > td,
+	tbody > tr.odd:hover + tr.tablesorter-childRow > td,
+	tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+		@include oddHovered;
+	}
+
+	/* table processing indicator - indeterminate spinner */
+	.tablesorter-processing {
+		background-image: $processingIcon;
+		background-position: center center;
+		background-repeat: no-repeat;
+	}
+
+	/* Column Widget - column sort colors */
+	tr.odd td.primary {
+		background-color: $primaryOdd;
+	}
+	td.primary, tr.even td.primary {
+		background-color: $primaryEven;
+	}
+	tr.odd td.secondary {
+		background-color: $secondaryOdd;
+	}
+	td.secondary, tr.even td.secondary {
+		background-color: $secondaryEven;
+	}
+	tr.odd td.tertiary {
+		background-color: $tertiaryOdd;
+	}
+	td.tertiary, tr.even td.tertiary {
+		background-color: $tertiaryEven;
+	}
+
+	/* caption (non-theme matching) */
+	caption {
+		background-color: $captionBackground ;
+	}
+
+	/* filter widget */
+	.tablesorter-filter-row input,
+	.tablesorter-filter-row select {
+		width: 98%;
+		height: auto;
+		margin: 0;
+		padding: $overallPadding;
+		color: $filterElementTextColor;
+		background-color: $filterElementBkgd;
+		border: $filterElementBorder;
+		-webkit-box-sizing: border-box;
+		-moz-box-sizing: border-box;
+		box-sizing: border-box;
+		@include filterWidgetTransition;
+	}
+	.tablesorter-filter-row {
+		background-color: $filterCellBackground;
+	}
+	.tablesorter-filter-row td {
+		text-align: center;
+		background-color: $filterCellBackground;
+		line-height: normal;
+		text-align: center; /* center the input */
+		@include filterWidgetTransition;
+	}
+	/* hidden filter row */
+	.tablesorter-filter-row.hideme td {
+		padding: $filterRowHiddenHeight / 2;
+		margin: 0;
+		line-height: 0;
+		cursor: pointer;
+	}
+	.tablesorter-filter-row.hideme * {
+		height: 1px;
+		min-height: 0;
+		border: 0;
+		padding: 0;
+		margin: 0;
+		/* don't use visibility: hidden because it disables tabbing */
+		opacity: 0;
+		filter: alpha(opacity=0);
+	}
+	/* rows hidden by filtering (needed for child rows) */
+	.filtered {
+		display: none;
+	}
+
+	/* ajax error row */
+	.tablesorter-errorRow td {
+		text-align: center;
+		cursor: pointer;
+		background-color: $errorBackground;
+	}
+
+}
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.blackice.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.blackice.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..0d728c75668264c52b6b98bcb9db5240e20f8cf0
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.blackice.min.css
@@ -0,0 +1 @@
+.tablesorter-blackice{width:100%;margin-right:auto;margin-left:auto;font:11px/18px Arial,Sans-serif;text-align:left;background-color:#000;border-collapse:collapse;border-spacing:0}.tablesorter-blackice th,.tablesorter-blackice thead td{padding:4px;font:13px/20px Arial,Sans-serif;font-weight:700;color:#e5e5e5;text-align:left;text-shadow:0 1px 0 rgba(0,0,0,.7);background-color:#111;border:1px solid #232323}.tablesorter-blackice .header,.tablesorter-blackice .tablesorter-header{padding:4px 20px 4px 4px;cursor:pointer;background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-position:center right;background-repeat:no-repeat}.tablesorter-blackice .headerSortUp,.tablesorter-blackice .tablesorter-headerAsc,.tablesorter-blackice .tablesorter-headerSortUp{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);color:#fff}.tablesorter-blackice .headerSortDown,.tablesorter-blackice .tablesorter-headerDesc,.tablesorter-blackice .tablesorter-headerSortDown{color:#fff;background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7)}.tablesorter-blackice thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-blackice tfoot .tablesorter-headerAsc,.tablesorter-blackice tfoot .tablesorter-headerDesc,.tablesorter-blackice tfoot .tablesorter-headerSortDown,.tablesorter-blackice tfoot .tablesorter-headerSortUp{background-image:none}.tablesorter-blackice td{padding:4px;color:#ccc;vertical-align:top;background-color:#333;border:1px solid #232323}.tablesorter-blackice tbody>tr.even:hover>td,.tablesorter-blackice tbody>tr.hover>td,.tablesorter-blackice tbody>tr.odd:hover>td,.tablesorter-blackice tbody>tr:hover>td{background-color:#000}.tablesorter-blackice .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-blackice tr.odd>td{background-color:#333}.tablesorter-blackice tr.even>td{background-color:#393939}.tablesorter-blackice td.primary,.tablesorter-blackice tr.odd td.primary{background-color:#2f3a40}.tablesorter-blackice td.secondary,.tablesorter-blackice tr.even td.primary,.tablesorter-blackice tr.odd td.secondary{background-color:#3f4a50}.tablesorter-blackice td.tertiary,.tablesorter-blackice tr.even td.secondary,.tablesorter-blackice tr.odd td.tertiary{background-color:#4f5a60}.tablesorter-blackice tr.even td.tertiary{background-color:#5a646b}caption{background-color:#fff}.tablesorter-blackice .tablesorter-filter-row{background-color:#222}.tablesorter-blackice .tablesorter-filter-row td{background-color:#222;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-blackice .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-blackice .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-blackice .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-blackice input.tablesorter-filter,.tablesorter-blackice select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.blue.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.blue.css
new file mode 100644
index 0000000000000000000000000000000000000000..66d6e58cf945d7ed7ee163b7ee630f0e6e62c1c4
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.blue.css
@@ -0,0 +1,229 @@
+/*************
+  Blue Theme
+ *************/
+/* overall */
+.tablesorter-blue {
+	width: 100%;
+	background-color: #fff;
+	margin: 10px 0 15px;
+	text-align: left;
+	border-spacing: 0;
+	border: #cdcdcd 1px solid;
+	border-width: 1px 0 0 1px;
+}
+.tablesorter-blue th,
+.tablesorter-blue td {
+	border: #cdcdcd 1px solid;
+	border-width: 0 1px 1px 0;
+}
+
+/* header */
+.tablesorter-blue th,
+.tablesorter-blue thead td {
+	font: 12px/18px Arial, Sans-serif;
+	font-weight: bold;
+	color: #000;
+	background-color: #99bfe6;
+	border-collapse: collapse;
+	padding: 4px;
+	text-shadow: 0 1px 0 rgba(204, 204, 204, 0.7);
+}
+.tablesorter-blue tbody td,
+.tablesorter-blue tfoot th,
+.tablesorter-blue tfoot td {
+	padding: 4px;
+	vertical-align: top;
+}
+.tablesorter-blue .header,
+.tablesorter-blue .tablesorter-header {
+	/* black (unsorted) double arrow */
+	background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);
+	/* white (unsorted) double arrow */
+	/* background-image: url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==); */
+	/* image */
+	/* background-image: url(images/black-unsorted.gif); */
+	background-repeat: no-repeat;
+	background-position: center right;
+	padding: 4px 18px 4px 4px;
+	white-space: normal;
+	cursor: pointer;
+}
+.tablesorter-blue .headerSortUp,
+.tablesorter-blue .tablesorter-headerSortUp,
+.tablesorter-blue .tablesorter-headerAsc {
+	background-color: #9fbfdf;
+	/* black asc arrow */
+	background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);
+	/* white asc arrow */
+	/* background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7); */
+	/* image */
+	/* background-image: url(images/black-asc.gif); */
+}
+.tablesorter-blue .headerSortDown,
+.tablesorter-blue .tablesorter-headerSortDown,
+.tablesorter-blue .tablesorter-headerDesc {
+	background-color: #8cb3d9;
+	/* black desc arrow */
+	background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);
+	/* white desc arrow */
+	/* background-image: url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7); */
+	/* image */
+	/* background-image: url(images/black-desc.gif); */
+}
+.tablesorter-blue thead .sorter-false {
+	background-image: none;
+	cursor: default;
+	padding: 4px;
+}
+
+/* tfoot */
+.tablesorter-blue tfoot .tablesorter-headerSortUp,
+.tablesorter-blue tfoot .tablesorter-headerSortDown,
+.tablesorter-blue tfoot .tablesorter-headerAsc,
+.tablesorter-blue tfoot .tablesorter-headerDesc {
+	/* remove sort arrows from footer */
+	background-image: none;
+}
+
+/* tbody */
+.tablesorter-blue td {
+	color: #3d3d3d;
+	background-color: #fff;
+	padding: 4px;
+	vertical-align: top;
+}
+
+/* hovered row colors
+ you'll need to add additional lines for
+ rows with more than 2 child rows
+ */
+.tablesorter-blue tbody > tr.hover > td,
+.tablesorter-blue tbody > tr:hover > td,
+.tablesorter-blue tbody > tr:hover + tr.tablesorter-childRow > td,
+.tablesorter-blue tbody > tr:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td,
+.tablesorter-blue tbody > tr.even.hover > td,
+.tablesorter-blue tbody > tr.even:hover > td,
+.tablesorter-blue tbody > tr.even:hover + tr.tablesorter-childRow > td,
+.tablesorter-blue tbody > tr.even:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+	background-color: #d9d9d9;
+}
+.tablesorter-blue tbody > tr.odd.hover > td,
+.tablesorter-blue tbody > tr.odd:hover > td,
+.tablesorter-blue tbody > tr.odd:hover + tr.tablesorter-childRow > td,
+.tablesorter-blue tbody > tr.odd:hover + tr.tablesorter-childRow + tr.tablesorter-childRow > td {
+	background-color: #bfbfbf;
+}
+
+/* table processing indicator */
+.tablesorter-blue .tablesorter-processing {
+	background-position: center center !important;
+	background-repeat: no-repeat !important;
+	/* background-image: url(images/loading.gif) !important; */
+	background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=') !important;
+}
+
+/* Zebra Widget - row alternating colors */
+.tablesorter-blue tbody tr.odd > td {
+	background-color: #ebf2fa;
+}
+.tablesorter-blue tbody tr.even > td {
+	background-color: #fff;
+}
+
+/* Column Widget - column sort colors */
+.tablesorter-blue td.primary,
+.tablesorter-blue tr.odd td.primary {
+	background-color: #99b3e6;
+}
+.tablesorter-blue tr.even td.primary {
+	background-color: #c2d1f0;
+}
+.tablesorter-blue td.secondary,
+.tablesorter-blue tr.odd td.secondary {
+	background-color: #c2d1f0;
+}
+.tablesorter-blue tr.even td.secondary {
+	background-color: #d6e0f5;
+}
+.tablesorter-blue td.tertiary,
+.tablesorter-blue tr.odd td.tertiary {
+	background-color: #d6e0f5;
+}
+.tablesorter-blue tr.even td.tertiary {
+	background-color: #ebf0fa;
+}
+
+/* caption */
+caption {
+	background-color: #fff;
+}
+
+/* filter widget */
+.tablesorter-blue .tablesorter-filter-row {
+	background-color: #eee;
+}
+.tablesorter-blue .tablesorter-filter-row td {
+	background-color: #eee;
+	line-height: normal;
+	text-align: center; /* center the input */
+	-webkit-transition: line-height 0.1s ease;
+	-moz-transition: line-height 0.1s ease;
+	-o-transition: line-height 0.1s ease;
+	transition: line-height 0.1s ease;
+}
+/* optional disabled input styling */
+.tablesorter-blue .tablesorter-filter-row .disabled {
+	opacity: 0.5;
+	filter: alpha(opacity=50);
+	cursor: not-allowed;
+}
+/* hidden filter row */
+.tablesorter-blue .tablesorter-filter-row.hideme td {
+	/*** *********************************************** ***/
+	/*** change this padding to modify the thickness     ***/
+	/*** of the closed filter row (height = padding x 2) ***/
+	padding: 2px;
+	/*** *********************************************** ***/
+	margin: 0;
+	line-height: 0;
+	cursor: pointer;
+}
+.tablesorter-blue .tablesorter-filter-row.hideme * {
+	height: 1px;
+	min-height: 0;
+	border: 0;
+	padding: 0;
+	margin: 0;
+	/* don't use visibility: hidden because it disables tabbing */
+	opacity: 0;
+	filter: alpha(opacity=0);
+}
+/* filters */
+.tablesorter-blue input.tablesorter-filter,
+.tablesorter-blue select.tablesorter-filter {
+	width: 98%;
+	height: auto;
+	margin: 0;
+	padding: 4px;
+	background-color: #fff;
+	border: 1px solid #bbb;
+	color: #333;
+	-webkit-box-sizing: border-box;
+	-moz-box-sizing: border-box;
+	box-sizing: border-box;
+	-webkit-transition: height 0.1s ease;
+	-moz-transition: height 0.1s ease;
+	-o-transition: height 0.1s ease;
+	transition: height 0.1s ease;
+}
+/* rows hidden by filtering (needed for child rows) */
+.tablesorter .filtered {
+	display: none;
+}
+
+/* ajax error row */
+.tablesorter .tablesorter-errorRow td {
+	text-align: center;
+	cursor: pointer;
+	background-color: #e6bf99;
+}
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.blue.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.blue.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..8276861fbb38f46ce60ff2d390837d2803e8a523
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.blue.min.css
@@ -0,0 +1 @@
+.tablesorter-blue{width:100%;background-color:#fff;margin:10px 0 15px;text-align:left;border-spacing:0;border:1px solid #cdcdcd;border-width:1px 0 0 1px}.tablesorter-blue td,.tablesorter-blue th{border:1px solid #cdcdcd;border-width:0 1px 1px 0}.tablesorter-blue th,.tablesorter-blue thead td{font:12px/18px Arial,Sans-serif;font-weight:700;color:#000;background-color:#99bfe6;border-collapse:collapse;padding:4px;text-shadow:0 1px 0 rgba(204,204,204,.7)}.tablesorter-blue tbody td,.tablesorter-blue tfoot td,.tablesorter-blue tfoot th{padding:4px;vertical-align:top}.tablesorter-blue .header,.tablesorter-blue .tablesorter-header{background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-repeat:no-repeat;background-position:center right;padding:4px 18px 4px 4px;white-space:normal;cursor:pointer}.tablesorter-blue .headerSortUp,.tablesorter-blue .tablesorter-headerAsc,.tablesorter-blue .tablesorter-headerSortUp{background-color:#9fbfdf;background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7)}.tablesorter-blue .headerSortDown,.tablesorter-blue .tablesorter-headerDesc,.tablesorter-blue .tablesorter-headerSortDown{background-color:#8cb3d9;background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7)}.tablesorter-blue thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-blue tfoot .tablesorter-headerAsc,.tablesorter-blue tfoot .tablesorter-headerDesc,.tablesorter-blue tfoot .tablesorter-headerSortDown,.tablesorter-blue tfoot .tablesorter-headerSortUp{background-image:none}.tablesorter-blue td{color:#3d3d3d;background-color:#fff;padding:4px;vertical-align:top}.tablesorter-blue tbody>tr.even.hover>td,.tablesorter-blue tbody>tr.even:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr.even:hover+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr.even:hover>td,.tablesorter-blue tbody>tr.hover>td,.tablesorter-blue tbody>tr:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr:hover+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr:hover>td{background-color:#d9d9d9}.tablesorter-blue tbody>tr.odd.hover>td,.tablesorter-blue tbody>tr.odd:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr.odd:hover+tr.tablesorter-childRow>td,.tablesorter-blue tbody>tr.odd:hover>td{background-color:#bfbfbf}.tablesorter-blue .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-blue tbody tr.odd>td{background-color:#ebf2fa}.tablesorter-blue tbody tr.even>td{background-color:#fff}.tablesorter-blue td.primary,.tablesorter-blue tr.odd td.primary{background-color:#99b3e6}.tablesorter-blue td.secondary,.tablesorter-blue tr.even td.primary,.tablesorter-blue tr.odd td.secondary{background-color:#c2d1f0}.tablesorter-blue td.tertiary,.tablesorter-blue tr.even td.secondary,.tablesorter-blue tr.odd td.tertiary{background-color:#d6e0f5}.tablesorter-blue tr.even td.tertiary{background-color:#ebf0fa}caption{background-color:#fff}.tablesorter-blue .tablesorter-filter-row{background-color:#eee}.tablesorter-blue .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-blue .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-blue .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-blue .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-blue input.tablesorter-filter,.tablesorter-blue select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..ccceb521220f479bc526c6280f8e761600aa1072
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap.min.css
@@ -0,0 +1 @@
+.tablesorter-bootstrap{width:100%}.tablesorter-bootstrap tfoot td,.tablesorter-bootstrap tfoot th,.tablesorter-bootstrap thead td,.tablesorter-bootstrap thead th{font:14px/20px Arial,Sans-serif;font-weight:700;padding:4px;margin:0 0 18px;background-color:#eee}.tablesorter-bootstrap .tablesorter-header{cursor:pointer}.tablesorter-bootstrap .sorter-false{cursor:default}.tablesorter-bootstrap .tablesorter-header.sorter-false i.tablesorter-icon{display:none}.tablesorter-bootstrap .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-bootstrap .sorter-false .tablesorter-header-inner{padding:4px}.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon{font-size:11px;position:absolute;right:2px;top:50%;margin-top:-7px;width:14px;height:14px;background-repeat:no-repeat;line-height:14px;display:inline-block}.tablesorter-bootstrap .bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAA20lEQVR4AWJABpKSkoxALCstLb0aUAsZaCAMhVEY6B0amx8YZWDDEDSBa2AGe7XeIiAAClYwVGBvsAcIllsf/mvcC9DgOOd8h90fxWvngVEUbZIkuWRZZlE8eQjcisgZMM9zi+LJ6ZfwegmWZflZDugdHMfxTcGqql7TNBlUB/QObtv2VBSFrev6OY7jngzFk9OT/fn73fWYpqnlXNyXDMWT0zuYx/Bvel9ej+LJ6R08DMOu67q7DkTkrSA5vYPneV71fX/QASdTkJwezhs0TfMARn0wMDDGXEPgF4oijqwM5YjNAAAAAElFTkSuQmCC)}.tablesorter-bootstrap .icon-white.bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAAe0lEQVR4AbXQoRWDMBiF0Sh2QLAAQ8SxJGugWSA6A2STW1PxTsnB9cnkfuYvv8OGC1t5G3Y0QMP+Bm857keAdQIzWBP3+Bw4MADQE18B6/etRnCV/w9nnGuLezfAmXhABGtAGIkruvk6auIFRwQJDywllsEAjCecB20GP59BQQ+gtlRLAAAAAElFTkSuQmCC)}.tablesorter-bootstrap>tbody>tr.odd>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~tr.tablesorter-hasChildRow.odd~.tablesorter-childRow.odd>td{background-color:#f9f9f9}.tablesorter-bootstrap>tbody>tr.even:hover>td,.tablesorter-bootstrap>tbody>tr.hover>td,.tablesorter-bootstrap>tbody>tr.odd:hover>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~.tablesorter-childRow.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~.tablesorter-childRow.odd>td{background-color:#f5f5f5}.tablesorter-bootstrap>tbody>tr.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~tr.tablesorter-hasChildRow.even~.tablesorter-childRow.even>td{background-color:#fff}.tablesorter-bootstrap .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);background-position:center center!important;background-repeat:no-repeat!important}.tablesorter-bootstrap>tbody>tr.odd td.primary{background-color:#bfbfbf}.tablesorter-bootstrap>tbody>tr td.primary,.tablesorter-bootstrap>tbody>tr.even td.primary,.tablesorter-bootstrap>tbody>tr.odd td.secondary{background-color:#d9d9d9}.tablesorter-bootstrap>tbody>tr td.secondary,.tablesorter-bootstrap>tbody>tr.even td.secondary,.tablesorter-bootstrap>tbody>tr.odd td.tertiary{background-color:#e6e6e6}.tablesorter-bootstrap>tbody>tr td.tertiary,.tablesorter-bootstrap>tbody>tr.even td.tertiary{background-color:#f2f2f2}.caption{background-color:#fff}.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter{width:98%;margin:0;padding:4px 6px;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled{background-color:#eee;color:#555;cursor:not-allowed;border:1px solid #ccc;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.075) inset;box-sizing:border-box;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row{background-color:#efefef}.tablesorter-bootstrap .tablesorter-filter-row td{background-color:#efefef;line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-bootstrap .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-bootstrap .tablesorter-pager select{padding:4px 6px}.tablesorter-bootstrap .tablesorter-pager .pagedisplay{border:0}.tablesorter-bootstrap tfoot i{font-size:11px}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap_2.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap_2.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..8a6304db64e5d53433078902793d5f2663730448
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap_2.min.css
@@ -0,0 +1 @@
+.tablesorter-bootstrap{width:100%}.tablesorter-bootstrap .tablesorter-header,.tablesorter-bootstrap tfoot td,.tablesorter-bootstrap tfoot th{font:14px/20px Arial,Sans-serif;font-weight:700;position:relative;padding:8px;margin:0 0 18px;list-style:none;background-color:#FBFBFB;background-image:-moz-linear-gradient(top,#fff,#efefef);background-image:-ms-linear-gradient(top,#fff,#efefef);background-image:-webkit-gradient(linear,0 0,0 100%,from(white),to(#efefef));background-image:-webkit-linear-gradient(top,#fff,#efefef);background-image:-o-linear-gradient(top,#fff,#efefef);background-image:linear-gradient(to bottom,#fff,#efefef);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#efefef', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 1px 0 #fff;-moz-box-shadow:inset 0 1px 0 #fff;box-shadow:inset 0 1px 0 #fff}.tablesorter-bootstrap .tablesorter-header{cursor:pointer}.tablesorter-bootstrap .sorter-false{cursor:default}.tablesorter-bootstrap .tablesorter-header.sorter-false i.tablesorter-icon{display:none}.tablesorter-bootstrap .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-bootstrap .sorter-false .tablesorter-header-inner{padding:4px}.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon{position:absolute;right:2px;top:50%;margin-top:-7px;width:14px;height:14px;background-repeat:no-repeat;line-height:14px;display:inline-block}.tablesorter-bootstrap .bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAABGUlEQVR4AZWQAUfEYBzGC07fILfrbnfgqG1jmxliDitmYIaxb9Y3CEIEVHDaUGMfYF8gIyBqbd7eH7wWofB6/J7nN+x/IIRQbz6fH8p3slgsrkl4uv8QNU071XX9wTAMQcLTD6bi2WazubUsq3ddV5AwPftU1tbr9Z0UPhGDIHgjYXp2JS+Xy71t2wNCFEV113UxCdOzKznLshvf9z+SJHlp23ZHR8L07Er+6/u/LO96td1u3zmX/BmdjoTp2ZUchmHted4o/16sVqt7KR6TMD27kpumOc/z/EkOvWmaQp7rlYTp2ZU8juOsqqqLoij2UvhyHEeQMD27knl93x+VZXmZpukz9yVh+l+vMQzDrK7rXRzHjyQ83b8BlglBGLw1Kb4AAAAASUVORK5CYII=)}.tablesorter-bootstrap .icon-white.bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAAe0lEQVR4AbXQoRWDMBiF0Sh2QLAAQ8SxJGugWSA6A2STW1PxTsnB9cnkfuYvv8OGC1t5G3Y0QMP+Bm857keAdQIzWBP3+Bw4MADQE18B6/etRnCV/w9nnGuLezfAmXhABGtAGIkruvk6auIFRwQJDywllsEAjCecB20GP59BQQ+gtlRLAAAAAElFTkSuQmCC)}.tablesorter-bootstrap tr.odd>td{background-color:#f9f9f9}.tablesorter-bootstrap tbody>.even:hover>td,.tablesorter-bootstrap tbody>.odd:hover>td,.tablesorter-bootstrap tbody>tr.hover>td{background-color:#f5f5f5}.tablesorter-bootstrap tbody>tr.even>td{background-color:#fff}.tablesorter-bootstrap .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);position:absolute;z-index:1000}.tablesorter-bootstrap>tbody>tr.odd td.primary{background-color:#bfbfbf}.tablesorter-bootstrap>tbody>tr td.primary,.tablesorter-bootstrap>tbody>tr.even td.primary,.tablesorter-bootstrap>tbody>tr.odd td.secondary{background-color:#d9d9d9}.tablesorter-bootstrap>tbody>tr td.secondary,.tablesorter-bootstrap>tbody>tr.even td.secondary,.tablesorter-bootstrap>tbody>tr.odd td.tertiary{background-color:#e6e6e6}.tablesorter-bootstrap>tbody>tr td.tertiary,.tablesorter-bootstrap>tbody>tr.even td.tertiary{background-color:#f2f2f2}caption{background-color:#fff}.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter{height:28px;width:98%;margin:0;padding:4px 6px;background-color:#fff;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled{background-color:#eee;cursor:not-allowed}.tablesorter-bootstrap .tablesorter-filter-row{background-color:#ddd}.tablesorter-bootstrap .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-bootstrap tr.tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-bootstrap tr.tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-bootstrap .tablesorter-pager select{padding:4px 6px}.tablesorter-bootstrap .tablesorter-pager .pagedisplay{border:0}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap_3.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap_3.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..ccceb521220f479bc526c6280f8e761600aa1072
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap_3.min.css
@@ -0,0 +1 @@
+.tablesorter-bootstrap{width:100%}.tablesorter-bootstrap tfoot td,.tablesorter-bootstrap tfoot th,.tablesorter-bootstrap thead td,.tablesorter-bootstrap thead th{font:14px/20px Arial,Sans-serif;font-weight:700;padding:4px;margin:0 0 18px;background-color:#eee}.tablesorter-bootstrap .tablesorter-header{cursor:pointer}.tablesorter-bootstrap .sorter-false{cursor:default}.tablesorter-bootstrap .tablesorter-header.sorter-false i.tablesorter-icon{display:none}.tablesorter-bootstrap .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-bootstrap .sorter-false .tablesorter-header-inner{padding:4px}.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon{font-size:11px;position:absolute;right:2px;top:50%;margin-top:-7px;width:14px;height:14px;background-repeat:no-repeat;line-height:14px;display:inline-block}.tablesorter-bootstrap .bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAA20lEQVR4AWJABpKSkoxALCstLb0aUAsZaCAMhVEY6B0amx8YZWDDEDSBa2AGe7XeIiAAClYwVGBvsAcIllsf/mvcC9DgOOd8h90fxWvngVEUbZIkuWRZZlE8eQjcisgZMM9zi+LJ6ZfwegmWZflZDugdHMfxTcGqql7TNBlUB/QObtv2VBSFrev6OY7jngzFk9OT/fn73fWYpqnlXNyXDMWT0zuYx/Bvel9ej+LJ6R08DMOu67q7DkTkrSA5vYPneV71fX/QASdTkJwezhs0TfMARn0wMDDGXEPgF4oijqwM5YjNAAAAAElFTkSuQmCC)}.tablesorter-bootstrap .icon-white.bootstrap-icon-unsorted{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAAe0lEQVR4AbXQoRWDMBiF0Sh2QLAAQ8SxJGugWSA6A2STW1PxTsnB9cnkfuYvv8OGC1t5G3Y0QMP+Bm857keAdQIzWBP3+Bw4MADQE18B6/etRnCV/w9nnGuLezfAmXhABGtAGIkruvk6auIFRwQJDywllsEAjCecB20GP59BQQ+gtlRLAAAAAElFTkSuQmCC)}.tablesorter-bootstrap>tbody>tr.odd>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~tr.tablesorter-hasChildRow.odd~.tablesorter-childRow.odd>td{background-color:#f9f9f9}.tablesorter-bootstrap>tbody>tr.even:hover>td,.tablesorter-bootstrap>tbody>tr.hover>td,.tablesorter-bootstrap>tbody>tr.odd:hover>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~.tablesorter-childRow.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.odd:hover~.tablesorter-childRow.odd>td{background-color:#f5f5f5}.tablesorter-bootstrap>tbody>tr.even>td,.tablesorter-bootstrap>tbody>tr.tablesorter-hasChildRow.even:hover~tr.tablesorter-hasChildRow.even~.tablesorter-childRow.even>td{background-color:#fff}.tablesorter-bootstrap .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);background-position:center center!important;background-repeat:no-repeat!important}.tablesorter-bootstrap>tbody>tr.odd td.primary{background-color:#bfbfbf}.tablesorter-bootstrap>tbody>tr td.primary,.tablesorter-bootstrap>tbody>tr.even td.primary,.tablesorter-bootstrap>tbody>tr.odd td.secondary{background-color:#d9d9d9}.tablesorter-bootstrap>tbody>tr td.secondary,.tablesorter-bootstrap>tbody>tr.even td.secondary,.tablesorter-bootstrap>tbody>tr.odd td.tertiary{background-color:#e6e6e6}.tablesorter-bootstrap>tbody>tr td.tertiary,.tablesorter-bootstrap>tbody>tr.even td.tertiary{background-color:#f2f2f2}.caption{background-color:#fff}.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter{width:98%;margin:0;padding:4px 6px;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled{background-color:#eee;color:#555;cursor:not-allowed;border:1px solid #ccc;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.075) inset;box-sizing:border-box;transition:height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row{background-color:#efefef}.tablesorter-bootstrap .tablesorter-filter-row td{background-color:#efefef;line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-bootstrap .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-bootstrap .tablesorter-pager select{padding:4px 6px}.tablesorter-bootstrap .tablesorter-pager .pagedisplay{border:0}.tablesorter-bootstrap tfoot i{font-size:11px}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap_4.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap_4.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..a0d3836d5f459e731bfe8c6c96685ed17b494163
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.bootstrap_4.min.css
@@ -0,0 +1 @@
+.tablesorter-bootstrap{width:100%}.tablesorter-bootstrap tfoot td,.tablesorter-bootstrap tfoot th,.tablesorter-bootstrap thead td,.tablesorter-bootstrap thead th{font:14px/20px Arial,Sans-serif;font-weight:700;padding:4px;margin:0 0 18px}.tablesorter-bootstrap thead .tablesorter-header{background-position:right 5px center;background-repeat:no-repeat;cursor:pointer;white-space:normal}.tablesorter-bootstrap:not(.table-inverse) tfoot td,.tablesorter-bootstrap:not(.table-inverse) tfoot th,.tablesorter-bootstrap:not(.table-inverse) thead:not(.thead-inverse) .tablesorter-header{background-color:#eee}.tablesorter-bootstrap thead .sorter-false{cursor:default;background-image:none}.tablesorter-bootstrap .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-bootstrap .sorter-false .tablesorter-header-inner{padding:4px}.tablesorter-bootstrap thead .tablesorter-headerUnSorted:not(.sorter-false){background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE0IDIwIj48cGF0aCBkPSJNMTQgMTNsLTIuNS0yLjVMNyAxNWwtNC41LTQuNUwwIDEzbDcgN3pNMTQgNy41TDExLjUgMTAgNyA1LjUgMi41IDEwIDAgNy41bDctN3oiLz48L3N2Zz4=)}.tablesorter-bootstrap thead .tablesorter-headerAsc{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDE0IDE0Ij48cGF0aCBkPSJNMTQgOS41TDExLjUgMTIgNyA3LjUgMi41IDEyIDAgOS41bDctN3oiLz48L3N2Zz4=)}.tablesorter-bootstrap thead .tablesorter-headerDesc{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDE0IDE0Ij48cGF0aCBkPSJNMTQgNWwtMi41LTIuNS00LjUgNC41LTQuNS00LjVMMCA1IDcgMTJ6Ii8+PC9zdmc+)}.tablesorter-bootstrap thead.thead-inverse .tablesorter-headerUnSorted:not(.sorter-false),.tablesorter-bootstrap.table-inverse thead .tablesorter-headerUnSorted:not(.sorter-false){background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE0IDIwIj48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTQgMTNsLTIuNS0yLjVMNyAxNWwtNC41LTQuNUwwIDEzbDcgN3pNMTQgNy41TDExLjUgMTAgNyA1LjUgMi41IDEwIDAgNy41bDctN3oiLz48L3N2Zz4=)}.tablesorter-bootstrap thead.thead-inverse .tablesorter-headerAsc,.tablesorter-bootstrap.table-inverse thead .tablesorter-headerAsc{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDE0IDE0Ij48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTQgOS41TDExLjUgMTIgNyA3LjUgMi41IDEyIDAgOS41bDctN3oiLz48L3N2Zz4=)}.tablesorter-bootstrap thead.thead-inverse .tablesorter-headerDesc,.tablesorter-bootstrap.table-inverse thead .tablesorter-headerDesc{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDE0IDE0Ij48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMTQgNWwtMi41LTIuNS00LjUgNC41LTQuNS00LjVMMCA1IDcgMTJ6Ii8+PC9zdmc+)}.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.odd>td,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.tablesorter-hasChildRow.odd:hover~tr.tablesorter-hasChildRow.odd~.tablesorter-childRow.odd>td{background-color:#f9f9f9}.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.even:hover>td,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.hover>td,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.odd:hover>td,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.tablesorter-hasChildRow.even:hover~.tablesorter-childRow.even>td,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.tablesorter-hasChildRow.odd:hover~.tablesorter-childRow.odd>td{background-color:#f5f5f5}.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.even>td,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.tablesorter-hasChildRow.even:hover~tr.tablesorter-hasChildRow.even~.tablesorter-childRow.even>td{background-color:#fff}.tablesorter-bootstrap .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);background-position:center center!important;background-repeat:no-repeat!important}.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.odd td.primary{background-color:#bfbfbf}.tablesorter-bootstrap:not(.table-inverse)>tbody>tr td.primary,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.even td.primary,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.odd td.secondary{background-color:#d9d9d9}.tablesorter-bootstrap:not(.table-inverse)>tbody>tr td.secondary,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.even td.secondary,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.odd td.tertiary{background-color:#e6e6e6}.tablesorter-bootstrap:not(.table-inverse)>tbody>tr td.tertiary,.tablesorter-bootstrap:not(.table-inverse)>tbody>tr.even td.tertiary{background-color:#f2f2f2}.tablesorter-bootstrap:not(.table-inverse) .caption{background-color:#fff}.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter{width:98%;margin:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-bootstrap:not(.table-inverse) .tablesorter-filter-row{background-color:#efefef}.tablesorter-bootstrap:not(.table-inverse) .tablesorter-filter-row input.tablesorter-filter,.tablesorter-bootstrap:not(.table-inverse) .tablesorter-filter-row select.tablesorter-filter{color:#333}.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled{cursor:not-allowed;box-shadow:0 1px 1px rgba(0,0,0,.075) inset;box-sizing:border-box;transition:height .1s ease}.tablesorter-bootstrap:not(.table-inverse) .tablesorter-filter-row td{line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-bootstrap .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-bootstrap .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-bootstrap .tablesorter-pager .pagedisplay{border:0}.tablesorter:not(.table-inverse) .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.dark.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.dark.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..7b3801b58bc8adacfe4d39ceba4b21d14c763b9b
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.dark.min.css
@@ -0,0 +1 @@
+.tablesorter-dark,.tablesorter-dark tbody>tr.even:hover>td,.tablesorter-dark tbody>tr.hover>td,.tablesorter-dark tbody>tr.odd:hover>td,.tablesorter-dark tbody>tr:hover>td,.tablesorter-dark td{background-color:#000}.tablesorter-dark{width:100%;font:11px/18px Arial,Sans-serif;color:#ccc;text-align:left;border-spacing:0}.tablesorter-dark th,.tablesorter-dark thead td{padding:4px;font:12px/20px Arial,Sans-serif;font-weight:700;color:#fff;background-color:#000;border-collapse:collapse}.tablesorter-dark thead th{border-bottom:#333 2px solid}.tablesorter-dark .header,.tablesorter-dark .tablesorter-header{padding:4px 20px 4px 4px;cursor:pointer;background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-position:center right;background-repeat:no-repeat}.tablesorter-dark thead .headerSortUp,.tablesorter-dark thead .tablesorter-headerAsc,.tablesorter-dark thead .tablesorter-headerSortUp{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);border-bottom:#888 1px solid}.tablesorter-dark thead .headerSortDown,.tablesorter-dark thead .tablesorter-headerDesc,.tablesorter-dark thead .tablesorter-headerSortDown{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);border-bottom:#888 1px solid}.tablesorter-dark thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-dark tfoot .tablesorter-headerAsc,.tablesorter-dark tfoot .tablesorter-headerDesc,.tablesorter-dark tfoot .tablesorter-headerSortDown,.tablesorter-dark tfoot .tablesorter-headerSortUp{border-top:#888 1px solid;background-image:none}.tablesorter-dark td{padding:4px;border-bottom:#333 1px solid;color:#ccc}.tablesorter-dark .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-dark tr.odd>td{background-color:#202020}.tablesorter-dark tr.even>td{background-color:#101010}.tablesorter-dark td.primary,.tablesorter-dark tr.odd td.primary{background-color:#0a0a0a}.tablesorter-dark tr.even td.primary{background-color:#050505}.tablesorter-dark td.secondary,.tablesorter-dark tr.odd td.secondary{background-color:#0f0f0f}.tablesorter-dark tr.even td.secondary{background-color:#0a0a0a}.tablesorter-dark td.tertiary,.tablesorter-dark tr.odd td.tertiary{background-color:#191919}.tablesorter-dark tr.even td.tertiary{background-color:#0f0f0f}.tablesorter-dark .tablesorter-filter-row,caption{background-color:#202020}.tablesorter-dark .tablesorter-filter-row td{background-color:#202020;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-dark .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-dark .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-dark .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-dark input.tablesorter-filter,.tablesorter-dark select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#111;border:1px solid #222;color:#ddd;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.default.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.default.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..e60b0493488d39a096c4b3b1c21158cbcfe2b31e
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.default.min.css
@@ -0,0 +1 @@
+.tablesorter-default{width:100%;font:12px/18px Arial,Sans-serif;color:#333;background-color:#fff;border-spacing:0;margin:10px 0 15px;text-align:left}.tablesorter-default th,.tablesorter-default thead td{font-weight:700;color:#000;background-color:#fff;border-collapse:collapse;border-bottom:#ccc 2px solid;padding:0}.tablesorter-default tfoot td,.tablesorter-default tfoot th{border:0}.tablesorter-default .header,.tablesorter-default .tablesorter-header{background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-position:center right;background-repeat:no-repeat;cursor:pointer;white-space:normal;padding:4px 20px 4px 4px}.tablesorter-default thead .headerSortUp,.tablesorter-default thead .tablesorter-headerAsc,.tablesorter-default thead .tablesorter-headerSortUp{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7);border-bottom:#000 2px solid}.tablesorter-default thead .headerSortDown,.tablesorter-default thead .tablesorter-headerDesc,.tablesorter-default thead .tablesorter-headerSortDown{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAACMtMP///yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7);border-bottom:#000 2px solid}.tablesorter-default thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-default tfoot .tablesorter-headerAsc,.tablesorter-default tfoot .tablesorter-headerDesc,.tablesorter-default tfoot .tablesorter-headerSortDown,.tablesorter-default tfoot .tablesorter-headerSortUp{border-top:#000 2px solid}.tablesorter-default td{background-color:#fff;border-bottom:#ccc 1px solid;padding:4px;vertical-align:top}.tablesorter-default tbody>tr.even:hover>td,.tablesorter-default tbody>tr.hover>td,.tablesorter-default tbody>tr.odd:hover>td,.tablesorter-default tbody>tr:hover>td{background-color:#fff;color:#000}.tablesorter-default .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-default tr.odd>td{background-color:#dfdfdf}.tablesorter-default tr.even>td{background-color:#efefef}.tablesorter-default tr.odd td.primary{background-color:#bfbfbf}.tablesorter-default td.primary,.tablesorter-default tr.even td.primary,.tablesorter-default tr.odd td.secondary{background-color:#d9d9d9}.tablesorter-default td.secondary,.tablesorter-default tr.even td.secondary,.tablesorter-default tr.odd td.tertiary{background-color:#e6e6e6}.tablesorter-default td.tertiary,.tablesorter-default tr.even td.tertiary{background-color:#f2f2f2}caption{background-color:#fff}.tablesorter-default .tablesorter-filter-row{background-color:#eee}.tablesorter-default .tablesorter-filter-row td{background-color:#eee;border-bottom:#ccc 1px solid;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-default .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-default .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-default .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-default input.tablesorter-filter,.tablesorter-default select.tablesorter-filter{width:95%;height:auto;margin:4px auto;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.dropbox.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.dropbox.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..270e21ce363715c39835905cce337b480e45c182
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.dropbox.min.css
@@ -0,0 +1 @@
+.tablesorter-dropbox{width:100%;font:13px/32px "Open Sans","lucida grande","Segoe UI",arial,verdana,"lucida sans unicode",tahoma,sans-serif;color:#555;text-align:left;background-color:#fff;border-collapse:collapse;border-top:1px solid #82cffa;border-spacing:0}.tablesorter-dropbox tfoot td,.tablesorter-dropbox tfoot th,.tablesorter-dropbox th,.tablesorter-dropbox thead td{background-color:#f0f9ff;border-color:#82cffa #e7f2fb #96c4ea;border-style:solid;border-width:1px;padding:3px 6px;font-size:13px;font-weight:400;line-height:29px;color:#2281CF;text-align:left}.tablesorter-dropbox .header,.tablesorter-dropbox .tablesorter-headerRow,.tablesorter-dropbox thead tr{background-color:#f0f9ff;border-bottom:1px solid #96c4ea;box-shadow:0 1px 1px rgba(0,0,0,.12),0 0 0 #000 inset;white-space:normal}.tablesorter-dropbox .tablesorter-headerAsc,.tablesorter-dropbox .tablesorter-headerDesc,.tablesorter-dropbox .tablesorter-headerSortDown,.tablesorter-dropbox .tablesorter-headerSortUp{font-weight:600}.tablesorter-dropbox .tablesorter-header{cursor:pointer}.tablesorter-dropbox .tablesorter-header i.tablesorter-icon{width:9px;height:9px;padding:0 10px 0 4px;display:inline-block;background-position:center right;background-repeat:no-repeat;content:""}.tablesorter .filtered,.tablesorter-dropbox thead .sorter-false i.tablesorter-icon{display:none}.tablesorter-dropbox .tablesorter-headerAsc i.tablesorter-icon,.tablesorter-dropbox .tablesorter-headerSortUp i.tablesorter-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALhJREFUeNpi/P//PwMhwILMiexYx8bIxNTy/9+/muUVQb9g4kzIitg4edI4+YRLQTSyOCPMupjerUI8whK3OXgEhH58+fDuy9sXqkuKvd+hmMTOxdvCxS8sxMUvxACiQXwU6+Im7DDg5BNKY+fiY2BmYWMA0SA+SByuiJ2bbzIHrwAzMxsb0AGMDCAaxAeJg+SZ7wtaqfAISfQAdTIwMUM8ywhUyMTEzPD/71+5FXvPLWUkJpwAAgwAZqYvvHStbD4AAAAASUVORK5CYII=)}.tablesorter-dropbox .tablesorter-headerAsc:hover i.tablesorter-icon,.tablesorter-dropbox .tablesorter-headerSortUp:hover i.tablesorter-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALVJREFUeNpi/P//PwMhwILMCc+qZGNkYmr5/+9fzcpp7b9g4kzIitjYOdM4uXlLQTSyOCPMuqi8OiEefsHbHFzcQj++fX335eN71WWTmt6hmMTOwdXCycMnBDSJAUSD+CjWxRQ0GHBw86Sxc3AyMDOzMIBoEB8kDlfEzsk1mYOLByjPCnQAIwOIBvFB4iB55rsfmVS4+QV7QNYwMTNDHApUyMTExPDv/z+5Feu3L2UkJpwAAgwA244u+I9CleAAAAAASUVORK5CYII=)}.tablesorter-dropbox .tablesorter-headerDesc i.tablesorter-icon,.tablesorter-dropbox .tablesorter-headerSortDown i.tablesorter-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALdJREFUeNpi/P//PwMhwBLdtVGFhZ3zNhMzC4bkv79/GP78/K7KCDIpZ9mVw+xcfDaMTExwBf///WP4+e3TkSlROrZg7UxMLLns3HxnmFnZmGGK/v7+9ff3j2+5YHkQMSlC48Kv719m/f//D2IKkAbxQeJwRSDw4/OHmr+/fr0DqmAA0SA+TA6uaEq0zjugG+r//vkFcks9iA/3HbJvvn18O+vf379yP758mMXAoAAXZyQmnAACDADX316BiTFbMQAAAABJRU5ErkJggg==)}.tablesorter-dropbox .tablesorter-headerDesc:hover i.tablesorter-icon,.tablesorter-dropbox .tablesorter-headerSortDown:hover i.tablesorter-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAALNJREFUeNpi/P//PwMhwBJf3uP879e3PUzMzBiS//7+ZWBi43JhBJmU2z7nIzMzEx8jIyNcAUj8799/nyZXpvCzgARYuXjTWBkZVjCzIEz7++cvw+//DGkgNiPMTWVT1l5hZvynDTINbMp/pqtdOcE6IDkmmM5fv3/5//v37z9QBQOIBvFhcnBFEwoj7/5jZFnz9+8fBhAN4sN9h+ybH9++JrGxscr/+vE1CVmckZhwAggwANvlUyq5Dd1wAAAAAElFTkSuQmCC)}.tablesorter-dropbox thead .sorter-false{cursor:default}.tablesorter-dropbox td{padding:5px 6px;line-height:32px;color:#555;text-align:left;border-top:1px solid #edf1f5;border-bottom:1px solid #edf1f5}.tablesorter-dropbox tbody>tr.even:hover>td,.tablesorter-dropbox tbody>tr.hover>td,.tablesorter-dropbox tbody>tr.odd:hover>td,.tablesorter-dropbox tbody>tr:hover>td{background-color:rgba(230,245,255,.3);border-right:0;border-left:0;border-color:#c6d8e4;border-style:double}.tablesorter-dropbox .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-dropbox .tablesorter-filter-row,caption{background-color:#fff}.tablesorter-dropbox .tablesorter-filter-row td{background-color:#fff;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-dropbox .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-dropbox .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-dropbox .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-dropbox input.tablesorter-filter,.tablesorter-dropbox select.tablesorter-filter{width:98%;height:auto;margin:0;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.green.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.green.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..1bcbf539bf2ba14e702c22526fa737c68096f09d
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.green.min.css
@@ -0,0 +1 @@
+.tablesorter-green{width:100%;text-align:left;border-spacing:0;border:1px solid #cdcdcd;border-width:1px 0 0 1px}.tablesorter-green td,.tablesorter-green th{font:12px/18px Arial,Sans-serif;border:1px solid #cdcdcd;border-width:0 1px 1px 0}.tablesorter-green tfoot tr,.tablesorter-green thead tr .tablesorter-header{background-position:center center;background-repeat:repeat-x;background-image:url(data:image/gif;base64,R0lGODlhAQBkAOYAAN/e39XU1fX19tTU1eXm5uTl5ePk5OLj4+Hi4vX29fT19PP08/Lz8vHy8fDx8O/w7+7v7uzt7Orr6ufo5/T08/Pz8ufn5uLi4eDg39/f3t3d3Nzc29HR0NDQz8/Pzuvq6urp6eno6Ojn5+fm5tfW1tbV1dTT09PS0tLR0dHQ0NDPz/f39/b29vX19fT09PPz8/Ly8vHx8e/v7+7u7u3t7ezs7Ovr6+rq6unp6ejo6Ofn5+bm5uXl5eTk5OPj4+Li4uHh4eDg4N/f397e3t3d3dzc3Nvb29ra2tnZ2djY2NfX19XV1dPT09LS0tHR0dDQ0M/Pz8rKysXFxf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAFMALAAAAAABAGQAAAdegCsrLC0tLi+ILi6FCSwsCS0KkhQVDA0OMjM0NTYfICEiIzw9P0AYGUQaG0ZHSEoDTU9Qs08pTk1MSyRJR0VDQT8+PTw7Ojg3NTMyMTAvi4WOhC0vMTI1OT9GTlFSgQA7)}.tablesorter-green th,.tablesorter-green thead td{font-weight:700;border-right:#cdcdcd 1px solid;border-collapse:collapse;padding:6px}.tablesorter-green .header,.tablesorter-green .tablesorter-header-inner{background-position:5px center;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhEAAQAOYAAA5NDBBYDlWWUzRUM5DVjp7inJ/fnQ1ECiCsGhyYFxqKFRFdDhBXDQxCCiO8HSK2HCCqGh2aGByUFxuPFhqNFhmHFRZ2EhVvERRpEBBVDSS8HiGyHB+mGh6fGRuTFxiAFBd5Eww/Cgs5CRp7Fiu+JRx8GCy/JjHAKyynKCuhJzXCMDbCMDnDMyNuHz3EODy9N0LFPSl7JkvIRjycOFDKS1LKTVPLT1XLUFTCT17OWTBkLmbQYnDTbHXVcXnWdoXago/djGmUZ112XCJEIEdjRf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAEUALAAAAAAQABAAAAdlgEWCg4SFhoIvh4cVLECKhCMeJjwFj0UlEwgaMD4Gii0WFAkRHQ47BIY6IQAZDAwBCyAPOJa1toRBGBAwNTY3OT0/AoZCDQoOKi4yNDOKRCIfGycrKZYDBxIkKLZDFxy3RTHgloEAOw==);border-collapse:collapse;white-space:normal;cursor:pointer}.tablesorter-green thead .headerSortUp .tablesorter-header-inner,.tablesorter-green thead .tablesorter-headerAsc .tablesorter-header-inner,.tablesorter-green thead .tablesorter-headerSortUp .tablesorter-header-inner{background-image:url(data:image/gif;base64,R0lGODlhEAAQANUAAA5NDBBYDpDVjp7inJ/fnSCsGhyYFxFdDhBXDSO8HSK2HB2aGBuPFhqNFhmHFRZ2EhBVDSS8Hh6fGRuTFxd5Eww/Chp7Fhx8GCy/JjnDMyNuHzy9N0LFPVTCTzBkLmbQYnDTbHnWdo/djP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACMALAAAAAAQABAAAAY4wJFwSCwaj8ikcslMbpojR0bEtEwwoIHywihEOCECUvNoGBaSxEdg9FQAEAQicKAoOtC8fs8fBgEAOw==)}.tablesorter-green thead .headerSortDown .tablesorter-header-inner,.tablesorter-green thead .tablesorter-headerDesc .tablesorter-header-inner,.tablesorter-green thead .tablesorter-headerSortDown .tablesorter-header-inner{background-image:url(data:image/gif;base64,R0lGODlhEAAQANUAAFWWUzRUMw1EChqKFQxCCiO8HSCqGhyUFxVvERRpECGyHB+mGhiAFAs5CSu+JTHAKyynKCuhJzXCMDbCMD3EOELFPSl7JkvIRjycOFDKS1LKTVPLT1XLUF7OWXXVcYXagmmUZ112XCJEIEdjRf///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACQALAAAAAAQABAAAAY4QJJwSCwaj8ikcskkghKGimbD6Xg+AGOIMChIKJcMBjlqMBSPSUQZEBwcEKYIsWiSLPa8fs9HBgEAOw==)}.tablesorter-green td.tablesorter-header .tablesorter-header-inner,.tablesorter-green th.tablesorter-header .tablesorter-header-inner{padding-left:23px}.tablesorter-green thead .tablesorter-header.sorter-false .tablesorter-header-inner{background-image:none;cursor:default;padding-left:6px}.tablesorter-green tbody td,.tablesorter-green tfoot th{padding:6px;vertical-align:top}.tablesorter-green td{color:#3d3d3d;padding:6px}.tablesorter-green tbody>tr.even.hover>td,.tablesorter-green tbody>tr.even:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr.even:hover+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr.even:hover>td,.tablesorter-green tbody>tr.hover>td,.tablesorter-green tbody>tr:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr:hover+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr:hover>td{background-color:#d9d9d9}.tablesorter-green tbody>tr.odd.hover>td,.tablesorter-green tbody>tr.odd:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr.odd:hover+tr.tablesorter-childRow>td,.tablesorter-green tbody>tr.odd:hover>td{background-color:#bfbfbf}.tablesorter-green .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-green tr.odd>td{background-color:#ebfaeb}.tablesorter-green tr.even>td{background-color:#fff}.tablesorter-green td.primary,.tablesorter-green tr.odd td.primary{background-color:#99e6a6}.tablesorter-green td.secondary,.tablesorter-green tr.even td.primary,.tablesorter-green tr.odd td.secondary{background-color:#c2f0c9}.tablesorter-green td.tertiary,.tablesorter-green tr.even td.secondary,.tablesorter-green tr.odd td.tertiary{background-color:#d6f5db}.tablesorter-green tr.even td.tertiary{background-color:#ebfaed}caption{background-color:#fff}.tablesorter-green .tablesorter-filter-row{background-color:#eee}.tablesorter-green .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-green .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-green .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-green .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-green input.tablesorter-filter,.tablesorter-green select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.grey.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.grey.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..26290ffb8558c27d3fae672f43ec26cd92fa6c8d
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.grey.min.css
@@ -0,0 +1 @@
+.tablesorter .filtered,.tablesorter-grey thead .sorter-false i.tablesorter-icon{display:none}.tablesorter-grey{width:100%;margin:10px 0 15px;text-align:left;border-spacing:0;border-left:#555 1px solid}.tablesorter-grey th,.tablesorter-grey thead td{font:700 12px/18px Arial,Sans-serif;color:#c8c8c8;background-color:#3c3c3c;background-image:-moz-linear-gradient(top,#555,#3c3c3c);background-image:-ms-linear-gradient(top,#555,#3c3c3c);background-image:-webkit-gradient(linear,0 0,0 100%,from(#555),to(#3c3c3c));background-image:-webkit-linear-gradient(top,#555,#3c3c3c);background-image:-o-linear-gradient(top,#555,#3c3c3c);background-image:linear-gradient(to bottom,#555,#3c3c3c);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#555555', endColorstr='#3c3c3c', GradientType=0 );background-repeat:repeat-x;border-right:#555 1px solid;text-shadow:0 1px 0 rgba(128,128,128,.7);-webkit-box-shadow:inset 0 1px 0 #222;-moz-box-shadow:inset 0 1px 0 #222;box-shadow:inset 0 1px 0 #222;padding:4px}.tablesorter-grey .tablesorter-header-inner{position:relative;padding:4px 15px 4px 4px}.tablesorter-grey .header,.tablesorter-grey .tablesorter-header{cursor:pointer}.tablesorter-grey .header i,.tablesorter-grey .tablesorter-header i.tablesorter-icon{width:18px;height:10px;position:absolute;right:2px;top:50%;margin-top:-10px;background-image:url(data:image/gif;base64,R0lGODlhFQAJAIAAAP///////yH5BAEAAAEALAAAAAAVAAkAAAIXjI+AywnaYnhUMoqt3gZXPmVg94yJVQAAOw==);background-repeat:no-repeat;background-position:center right;padding:4px;white-space:normal}.tablesorter-grey th.headerSortDown,.tablesorter-grey th.headerSortUp,.tablesorter-grey th.tablesorter-headerSortDown,.tablesorter-grey th.tablesorter-headerSortUp{color:#ddd;background-color:#135185;background-image:-moz-linear-gradient(top,#195c93,#0e4776);background-image:-ms-linear-gradient(top,#195c93,#0e4776);background-image:-webkit-gradient(linear,0 0,0 100%,from(#195c93),to(#0e4776));background-image:-webkit-linear-gradient(top,#195c93,#0e4776);background-image:-o-linear-gradient(top,#195c93,#0e4776);background-image:linear-gradient(to bottom,#195c93,#0e4776);filter:progid:DXImageTransform.Microsoft.gradient( startColorstr='#195c93', endColorstr='#0e4776', GradientType=0 )}.tablesorter-grey .headerSortUp i.tablesorter-icon,.tablesorter-grey .tablesorter-headerAsc i.tablesorter-icon,.tablesorter-grey .tablesorter-headerSortUp i.tablesorter-icon{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjI8Bya2wnINUMopZAQA7)}.tablesorter-grey .headerSortDown i.tablesorter-icon,.tablesorter-grey .tablesorter-headerDesc i.tablesorter-icon,.tablesorter-grey .tablesorter-headerSortDown i.tablesorter-icon{background-image:url(data:image/gif;base64,R0lGODlhFQAEAIAAAP///////yH5BAEAAAEALAAAAAAVAAQAAAINjB+gC+jP2ptn0WskLQA7)}.tablesorter-grey thead .sorter-false{cursor:default}.tablesorter-grey tbody td,.tablesorter-grey tfoot td,.tablesorter-grey tfoot th{padding:4px;vertical-align:top;border-right:#555 1px solid}.tablesorter-grey tfoot td,.tablesorter-grey tfoot th{padding:8px}.tablesorter-grey td{color:#eee;background-color:#6d6d6d;padding:4px;vertical-align:top}.tablesorter-grey tbody>tr.even.hover>td,.tablesorter-grey tbody>tr.even:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr.even:hover+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr.even:hover>td,.tablesorter-grey tbody>tr.hover>td,.tablesorter-grey tbody>tr.odd.hover>td,.tablesorter-grey tbody>tr.odd:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr.odd:hover+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr.odd:hover>td,.tablesorter-grey tbody>tr:hover+tr.tablesorter-childRow+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr:hover+tr.tablesorter-childRow>td,.tablesorter-grey tbody>tr:hover>td{background-color:#134b78}.tablesorter-grey .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-grey tbody tr.odd>td{background-color:#5e5e5e}.tablesorter-grey tbody tr.even>td{background-color:#6d6d6d}.tablesorter-grey td.primary,.tablesorter-grey tr.odd td.primary{color:#ddd;background-color:#165388}.tablesorter-grey tr.even td.primary{color:#ddd;background-color:#195c93}.tablesorter-grey td.secondary,.tablesorter-grey tr.odd td.secondary{color:#ddd;background-color:#185C9A}.tablesorter-grey tr.even td.secondary{color:#ddd;background-color:#1D67A5}.tablesorter-grey td.tertiary,.tablesorter-grey tr.odd td.tertiary{color:#ddd;background-color:#1B67AD}.tablesorter-grey tr.even td.tertiary{color:#ddd;background-color:#2073B7}caption{background-color:#fff}.tablesorter-grey .tablesorter-filter-row{background-color:#3c3c3c}.tablesorter-grey .tablesorter-filter-row td{background-color:#3c3c3c;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-grey .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-grey .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-grey .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-grey input.tablesorter-filter,.tablesorter-grey select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#6d6d6d;border:1px solid #555;color:#ddd;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.ice.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.ice.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..add23f621b2d723599dc6b58b433b7b83ee8fb9a
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.ice.min.css
@@ -0,0 +1 @@
+.tablesorter-ice{width:100%;background-color:#fff;margin:10px 0 15px;text-align:left;border-spacing:0;border:1px solid #ccc;border-width:1px 0 0 1px}.tablesorter-ice td,.tablesorter-ice th{border:1px solid #ccc;border-width:0 1px 1px 0}.tablesorter-ice th,.tablesorter-ice thead td{font:12px/18px Arial,Sans-serif;color:#555;background-color:#f6f8f9;border-collapse:collapse;padding:4px;text-shadow:0 1px 0 rgba(255,255,255,.7)}.tablesorter-ice tbody td,.tablesorter-ice tfoot td,.tablesorter-ice tfoot th{padding:4px;vertical-align:top}.tablesorter-ice .header,.tablesorter-ice .tablesorter-header{background-color:#f6f8f9;background-position:center right;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhDAAMAMQAAAJEjAJCiwJBigJAiANFjgNGjgNEjQRIkQRHkANIkAVMlAVQmAZWnQZUnAdYoAhdpAhZoAlhqQlepQliqQppsApmrQxutgtutQtutAxwtwxwtg1yug1zugxtsw1yuP8A/yH5BAEAAB8ALAAAAAAMAAwAAAUx4Cd+3GiOW4ado2d9VMVm1xg9ptadTsP+QNZEcjoQTBDGCAFgLRSfQgCYMAiCn8EvBAA7);padding:4px 20px 4px 4px;white-space:normal;cursor:pointer}.tablesorter-ice .headerSortUp,.tablesorter-ice .tablesorter-headerAsc,.tablesorter-ice .tablesorter-headerSortUp{color:#333;background-color:#ebedee;background-position:center right;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhDAAMANUAAAJCiwNHkANFjgNEjQRIkQNJkQRMlARKkwRKkgVPlwZSmgdaogdYnwhfpghcowlhqgliqglgqAlgpwljqwporwpmrQplrAtsswtqsgtrsgtqsQxttAtvtQtttAxyuQxwtwxxtwxvtg10uw1zuQ1xuP8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACUALAAAAAAMAAwAAAY6wJKwJBoahyNQ6Dj0fDoZCpPEuWgqk4jxs8FQLI+Gg8Esm5kQydFQMC7IwkOAqUiUCAIzIjA4lwBlQQA7)}.tablesorter-ice .headerSortDown,.tablesorter-ice .tablesorter-headerDesc,.tablesorter-ice .tablesorter-headerSortDown{color:#333;background-color:#ebedee;background-position:center right;background-repeat:no-repeat;background-image:url(data:image/gif;base64,R0lGODlhDAAMANUAAAE/iAJBigNFjgNEjQNFjQNDiwRHkQRHjwNHjwROlgRMlQRMlARJkgRKkgZQmAVPlgZWnQZSmgZRmAdXoAdXnwdUnAdbogdZoQhbowlhqAlepglkrAliqQtstAtqsQxyugxyuQxwuAxxuAxxtwxwtgxvtQ10vA12vA10u/8A/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAACkALAAAAAAMAAwAAAY6wJQwdRoah6bP6DhEiVIdDxNEGm4yxlDpiJkwv2AmR2OhVCSJBsJ4gUQeCwOB6VAwBAXwYRAIpwBfQQA7)}.tablesorter-ice thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-ice tfoot .tablesorter-headerAsc,.tablesorter-ice tfoot .tablesorter-headerDesc,.tablesorter-ice tfoot .tablesorter-headerSortDown,.tablesorter-ice tfoot .tablesorter-headerSortUp{background-color:#ebedee}.tablesorter-ice td{color:#333}.tablesorter-ice tbody>tr.even:hover>td,.tablesorter-ice tbody>tr.hover>td,.tablesorter-ice tbody>tr.odd:hover>td,.tablesorter-ice tbody>tr:hover>td{background-color:#ebf2fa}.tablesorter-ice .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-ice tr.odd>td{background-color:#dfdfdf}.tablesorter-ice tr.even>td{background-color:#efefef}.tablesorter-ice td.primary,.tablesorter-ice tr.odd td.primary{background-color:#9ae5e5}.tablesorter-ice td.secondary,.tablesorter-ice tr.even td.primary,.tablesorter-ice tr.odd td.secondary{background-color:#c2f0f0}.tablesorter-ice td.tertiary,.tablesorter-ice tr.even td.secondary,.tablesorter-ice tr.odd td.tertiary{background-color:#d5f5f5}.tablesorter-ice tr.even td.tertiary{background-color:#ebfafa}.tablesorter-ice.containsStickyHeaders thead tr:nth-child(1) td,.tablesorter-ice.containsStickyHeaders thead tr:nth-child(1) th{border-top:#ccc 1px solid}caption{background-color:#fff}.tablesorter-ice .tablesorter-filter-row{background-color:#eee}.tablesorter-ice .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-ice .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-ice .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-ice .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-ice input.tablesorter-filter,.tablesorter-ice select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.jui.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.jui.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..8b24d87f91373ce0663c9d092300a37af79a7179
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.jui.min.css
@@ -0,0 +1 @@
+.tablesorter .filtered,.tablesorter-jui thead tr .sorter-false .ui-icon{display:none}.tablesorter-jui{width:100%;border-collapse:separate;border-spacing:2px;margin:10px 0 15px;padding:5px;font-size:.8em}.tablesorter-jui tfoot td,.tablesorter-jui tfoot th,.tablesorter-jui thead td,.tablesorter-jui thead th{position:relative;background-repeat:no-repeat;background-position:right center;font-weight:700!important;border-width:1px!important;text-align:left;padding:8px}.tablesorter-jui .header,.tablesorter-jui .tablesorter-header{cursor:pointer;white-space:normal}.tablesorter-jui .tablesorter-header-inner{padding-right:20px}.tablesorter-jui thead tr th .ui-icon{position:absolute;right:3px;top:50%;margin-top:-8px}.tablesorter-jui thead .sorter-false{cursor:default}.tablesorter-jui tfoot td,.tablesorter-jui tfoot th{font-weight:400!important;font-size:.9em;padding:2px}.tablesorter-jui td{padding:4px;vertical-align:top}.tablesorter-jui tbody>tr.hover>td,.tablesorter-jui tbody>tr:hover>td{opacity:.7;filter:alpha(opacity=70)}.tablesorter-jui .tablesorter-processing .tablesorter-header-inner{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-jui tr.ui-state-default{background-image:none;font-weight:400}.tablesorter-jui .tablesorter-processing{background-color:#ddd;background-color:rgba(255,255,255,.8)}.tablesorter-jui caption{border:0}.tablesorter-jui .tablesorter-filter-row{background-color:transparent}.tablesorter-jui .tablesorter-filter-row td{background-color:transparent;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-jui .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-jui .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-jui .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-jui input.tablesorter-filter,.tablesorter-jui select.tablesorter-filter{width:98%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.materialize.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.materialize.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..58249f46e97b1d90975f4ad222dc35d6d21a32dc
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.materialize.min.css
@@ -0,0 +1 @@
+.tablesorter-materialize{width:100%}.tablesorter-materialize tfoot td,.tablesorter-materialize tfoot th,.tablesorter-materialize thead td,.tablesorter-materialize thead th{font:14px/20px Arial,Sans-serif;font-weight:700;padding:4px;margin:0 0 18px;background-color:#eee}.tablesorter-materialize .tablesorter-header{cursor:pointer}.tablesorter-materialize .sorter-false{cursor:default}.tablesorter-materialize .tablesorter-header-inner{position:relative;padding:4px 18px 4px 4px}.tablesorter-materialize thead .tablesorter-header{background-repeat:no-repeat;background-position:center right;padding:4px 18px 4px 4px;white-space:normal;cursor:pointer}.tablesorter-materialize thead .tablesorter-headerUnSorted{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDI0IDE2Ij48cGF0aCBkPSJNMTUgOCAxIDggOCAwek0xNSA5IDEgOSA4IDE2eiIgZmlsbD0iIzIyMiIvPjwvc3ZnPg==)}.tablesorter-materialize thead .tablesorter-headerAsc{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDI0IDE2Ij48cGF0aCBkPSJNMTUgMTEgMSAxMSA4IDN6IiBmaWxsPSIjMjIyIi8+PC9zdmc+)}.tablesorter-materialize thead .tablesorter-headerDesc{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDI0IDE2Ij48cGF0aCBkPSJNMTUgNiAxIDYgOCAxM3oiIGZpbGw9IiMyMjIiLz48L3N2Zz4=)}.tablesorter-materialize-dark thead .tablesorter-headerUnSorted{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDI0IDE2Ij48cGF0aCBkPSJNMTUgOCAxIDggOCAwek0xNSA5IDEgOSA4IDE2eiIgZmlsbD0iI2ZmZiIvPjwvc3ZnPg==)}.tablesorter-materialize-dark thead .tablesorter-headerAsc{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDI0IDE2Ij48cGF0aCBkPSJNMTUgMTEgMSAxMSA4IDN6IiBmaWxsPSIjZmZmIi8+PC9zdmc+)}.tablesorter-materialize-dark thead .tablesorter-headerDesc{background-image:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxMiIgdmlld0JveD0iMCAwIDI0IDE2Ij48cGF0aCBkPSJNMTUgNiAxIDYgOCAxM3oiIGZpbGw9IiNmZmYiLz48L3N2Zz4=)}.tablesorter-materialize>tbody>tr.odd>td,.tablesorter-materialize>tbody>tr.tablesorter-hasChildRow.odd:hover~tr.tablesorter-hasChildRow.odd~.tablesorter-childRow.odd>td{background-color:#f9f9f9}.tablesorter-materialize>tbody>tr.even:hover>td,.tablesorter-materialize>tbody>tr.hover>td,.tablesorter-materialize>tbody>tr.odd:hover>td,.tablesorter-materialize>tbody>tr.tablesorter-hasChildRow.even:hover~.tablesorter-childRow.even>td,.tablesorter-materialize>tbody>tr.tablesorter-hasChildRow.odd:hover~.tablesorter-childRow.odd>td{background-color:#f5f5f5}.caption,.tablesorter-materialize>tbody>tr.even>td,.tablesorter-materialize>tbody>tr.tablesorter-hasChildRow.even:hover~tr.tablesorter-hasChildRow.even~.tablesorter-childRow.even>td{background-color:#fff}.tablesorter-materialize .tablesorter-processing{background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=);background-position:center center!important;background-repeat:no-repeat!important}.tablesorter-materialize .tablesorter-filter-row input.tablesorter-filter,.tablesorter-materialize .tablesorter-filter-row select.tablesorter-filter{width:98%;margin:0;padding:4px 6px;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter-materialize .tablesorter-filter-row .tablesorter-filter.disabled{background-color:#eee;color:#555;cursor:not-allowed;border:1px solid #ccc;border-radius:4px;box-shadow:0 1px 1px rgba(0,0,0,.075) inset;box-sizing:border-box;transition:height .1s ease}.tablesorter-materialize .tablesorter-filter-row{background-color:#efefef}.tablesorter-materialize .tablesorter-filter-row td{background-color:#efefef;line-height:normal;text-align:center;padding:4px 6px;vertical-align:middle;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-materialize .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0}.tablesorter-materialize .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter .filtered{display:none}.tablesorter-materialize .tablesorter-pager select{padding:4px 6px;display:inline-block;width:auto}.tablesorter-materialize .tablesorter-pager .pagedisplay{border:0}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.metro-dark.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.metro-dark.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..349f9d9833a67b372656afcc29bd4483f5a9cf1f
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/theme.metro-dark.min.css
@@ -0,0 +1 @@
+.tablesorter-metro-dark{width:100%;font:12px/18px 'Segoe UI Semilight','Open Sans',Verdana,Arial,Helvetica,sans-serif;color:#000;background-color:#333;border-spacing:0;margin:10px 0 15px;text-align:left}.tablesorter-metro-dark caption.dark-row,.tablesorter-metro-dark tr.dark-row td,.tablesorter-metro-dark tr.dark-row th{background-color:#222;color:#fff;padding:2px;text-align:left;font-size:14px}.tablesorter-metro-dark caption,.tablesorter-metro-dark tfoot td,.tablesorter-metro-dark tfoot th,.tablesorter-metro-dark th,.tablesorter-metro-dark thead td{font-weight:300;font-size:15px;color:#ddd;background-color:#333;padding:4px}.tablesorter-metro-dark .header,.tablesorter-metro-dark .tablesorter-header{background-image:url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAGFBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u5jNePWAAAACHRSTlMAMxIHKwEgMWD59H4AAABSSURBVAjXY2BgYFJgAAHzYhDJ6igSAKTYBAUTgJSioKAQAwNzoaCguAFDiCAQuDIkgigxBgiA8cJAVCpQt6AgSL+JoKAzA0gjUBsQqBcBCYhFAAE/CV4zeSzxAAAAAElFTkSuQmCC);background-position:right 5px center;background-repeat:no-repeat;cursor:pointer;white-space:normal}.tablesorter-metro-dark .tablesorter-header-inner{padding:0 18px 0 4px}.tablesorter-metro-dark thead .headerSortUp,.tablesorter-metro-dark thead .tablesorter-headerAsc,.tablesorter-metro-dark thead .tablesorter-headerSortUp{background-image:url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u5meJAOAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC)}.tablesorter-metro-dark thead .headerSortDown,.tablesorter-metro-dark thead .tablesorter-headerDesc,.tablesorter-metro-dark thead .tablesorter-headerSortDown{background-image:url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAALVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7i0NViAAAADnRSTlMAMiweCQITTvDctZZqaTlM310AAABcSURBVAjXY2BgYEtgAAFHERDJqigUAKSYBQUNgFSioKAYAwOLIBA4MASBKFUGQxAlzAAF+94BwWuGKBC1lIFl3rt3Lx0YGCzevWsGSjK9e6cAUlT3HKyW9wADAwDRrBiDy6bKzwAAAABJRU5ErkJggg==)}.tablesorter-metro-dark thead .sorter-false{background-image:none;cursor:default;padding:4px}.tablesorter-metro-dark td{background-color:#fff;padding:4px;vertical-align:top}.tablesorter-metro-dark tbody>tr.even:hover>td,.tablesorter-metro-dark tbody>tr.hover>td,.tablesorter-metro-dark tbody>tr.odd:hover>td,.tablesorter-metro-dark tbody>tr:hover>td{background-color:#bbb;color:#000}.tablesorter-metro-dark .tablesorter-processing{background-position:center center!important;background-repeat:no-repeat!important;background-image:url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=)!important}.tablesorter-metro-dark .tablesorter-pager button{background-color:#444;color:#eee;border:1px solid #555;cursor:pointer}.tablesorter-metro-dark .tablesorter-pager button:hover{background-color:#555}.tablesorter-metro-dark tr.odd>td{background-color:#eee}.tablesorter-metro-dark tr.even>td{background-color:#fff}.tablesorter-metro-dark tr.odd td.primary{background-color:#bfbfbf}.tablesorter-metro-dark td.primary,.tablesorter-metro-dark tr.even td.primary,.tablesorter-metro-dark tr.odd td.secondary{background-color:#d9d9d9}.tablesorter-metro-dark td.secondary,.tablesorter-metro-dark tr.even td.secondary,.tablesorter-metro-dark tr.odd td.tertiary{background-color:#e6e6e6}.tablesorter-metro-dark td.tertiary,.tablesorter-metro-dark tr.even td.tertiary{background-color:#f2f2f2}.tablesorter-metro-dark .tablesorter-filter-row{background-color:#eee}.tablesorter-metro-dark .tablesorter-filter-row td{background-color:#eee;line-height:normal;text-align:center;-webkit-transition:line-height .1s ease;-moz-transition:line-height .1s ease;-o-transition:line-height .1s ease;transition:line-height .1s ease}.tablesorter-metro-dark .tablesorter-filter-row .disabled{opacity:.5;filter:alpha(opacity=50);cursor:not-allowed}.tablesorter-metro-dark .tablesorter-filter-row.hideme td{padding:2px;margin:0;line-height:0;cursor:pointer}.tablesorter-metro-dark .tablesorter-filter-row.hideme *{height:1px;min-height:0;border:0;padding:0;margin:0;opacity:0;filter:alpha(opacity=0)}.tablesorter-metro-dark input.tablesorter-filter,.tablesorter-metro-dark select.tablesorter-filter{width:95%;height:auto;margin:0;padding:4px;background-color:#fff;border:1px solid #bbb;color:#333;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:height .1s ease;-moz-transition:height .1s ease;-o-transition:height .1s ease;transition:height .1s ease}.tablesorter .filtered{display:none}.tablesorter .tablesorter-errorRow td{text-align:center;cursor:pointer;background-color:#e6bf99}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/css/widget.grouping.min.css b/smash/web/static/AdminLTE/plugins/tablesorter/css/widget.grouping.min.css
new file mode 100644
index 0000000000000000000000000000000000000000..0beb435aa243e80353cd159056579246b090b462
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/css/widget.grouping.min.css
@@ -0,0 +1 @@
+tr.group-header td{background:#eee}.group-name{text-transform:uppercase;font-weight:700}.group-count{color:#999}.group-hidden{display:none!important}.group-header,.group-header td{user-select:none;-moz-user-select:none}tr.group-header td i{display:inline-block;width:0;height:0;border-top:4px solid transparent;border-bottom:4px solid #888;border-right:4px solid #888;border-left:4px solid transparent;margin-right:7px;user-select:none;-moz-user-select:none}tr.group-header.collapsed td i{border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #888;border-right:0;margin-right:10px}
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/jquery.dragtable.mod.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/jquery.dragtable.mod.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..b9f9af263097c7aae1dea8113b51538492c1d2c7
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/jquery.dragtable.mod.min.js
@@ -0,0 +1,3 @@
+/*! Dragtable Mod for TableSorter - updated 10/31/2015 (v2.24.0) */
+!function(a){"use strict";function b(){var b=a('<style id="__dragtable_disable_text_selection__" type="text/css">body { -ms-user-select:none;-moz-user-select:-moz-none;-khtml-user-select:none;-webkit-user-select:none;user-select:none; }</style>');a(document.head).append(b),a(document.body).attr("onselectstart","return false;").attr("unselectable","on"),window.getSelection?window.getSelection().removeAllRanges():document.selection.empty()}function c(){a("#__dragtable_disable_text_selection__").remove(),f?a(document.body).attr("onselectstart",f):a(document.body).removeAttr("onselectstart"),g?a(document.body).attr("unselectable",g):a(document.body).removeAttr("unselectable")}var d,e=a.tablesorter;e.dragtable={create:function(b){var c,d=b.originalTable.el,e=b.options.dragHandle.replace(".","");d.children("thead").children().children("th,td").each(function(){var d=a(this);d.find(b.options.dragHandle+",."+e+"-disabled").length||(c=!b.options.dragaccept||d.hasClass(b.options.dragaccept.replace(".","")),d.wrapInner('<div class="'+b.options.sortClass.replace(".","")+'"/>').prepend('<div class="'+e+(c?"":"-disabled")+'"></div>'))})},start:function(b){b=a(b)[0],b&&b.config&&(b.config.widgetOptions.dragtableLast={search:a(b).data("lastSearch"),order:e.dragtable.getOrder(b)})},update:function(b){var c,d,f,g=b.originalTable,h=g.el[0],i=a(h),j=h.config,k=j&&j.widgetOptions,l=g.startIndex-1,m=g.endIndex-1,n=e.dragtable.getOrder(h)||[],o=e.hasWidget(i,"filter")||!1,p=k&&k.dragtableLast||{},q=[];(p.order||[]).join("")!==n.join("")&&(j.sortList.length&&(d=a.extend(!0,[],j.sortList),a.each(n,function(a,b){f=e.isValueInArray(parseInt(b,10),d),b!==p.order[a]&&f>=0&&(j.sortList[f][0]=a)})),o&&a.each(p.search||[],function(a){q[a]=p.search[n[a]]}),c=!!e.hasWidget(j.$table,"editable")&&k.editable_columnsArray,c&&(j.widgetOptions.editable_columnsArray=e.dragtable.reindexArrayItem(c,l,m)),c=!!e.hasWidget(j.$table,"math")&&k.math_ignore,c&&(j.widgetOptions.math_ignore=e.dragtable.reindexArrayItem(c,l,m)),c=!!e.hasWidget(j.$table,"resizable")&&k.resizable_widths,c&&(k.resizable_widths=e.dragtable.moveArrayItem(c,l,m)),e.updateAll(j,!1,function(){o&&setTimeout(function(){j.lastCombinedFilter=null,j.$table.data("lastSearch",q),e.setFilters(i,q),a.isFunction(b.options.tablesorterComplete)&&b.options.tablesorterComplete(j.table)},10)}))},getOrder:function(b){return a(b).children("thead").children("."+e.css.headerRow).children().map(function(){return a(this).attr("data-column")}).get()||[]},startColumnMove:function(b){var c,d=b.el[0].config,e=b.startIndex-1,f=b.endIndex-1,g=d.columns-1,h=f!==g&&f<=e,i=d.$table.children().children("tr");d.debug&&console.log("Inserting column "+e+(h?" before":" after")+" column "+f),i.each(function(){c=a(this).children(),c.eq(e)[h?"insertBefore":"insertAfter"](c.eq(f))}),c=d.$table.children("colgroup").children(),c.eq(e)[h?"insertBefore":"insertAfter"](c.eq(f))},swapNodes:function(a,b){var c,d,e,f=a.length;for(c=0;c<f;c++)d=a[c].parentNode,e=a[c].nextSibling===b[c]?a[c]:a[c].nextSibling,b[c].parentNode.insertBefore(a[c],b[c]),d.insertBefore(b[c],e)},moveArrayItem:function(a,b,c){var e,f=a.length;if(c>=f)for(e=c-f;e--+1;)a.push(d);return a.splice(c,0,a.splice(b,1)[0]),a},reindexArrayItem:function(b,c,d){var e=a.inArray(d,b),f=a.inArray(c,b),g=(Math.max.apply(Math,b),[]);return e>=0&&f>=0?b:(a.each(b,function(a,b){d<c?b>=d?g.push(b+(b<c?1:0)):g.push(b):d>c&&(b===c?g.push(d):b<d&&b>=c?g.push(b-1):b<=d?g.push(b):b>c&&g.push(b+(b<d?0:1)))}),g.sort())}},/*! dragtable v2.0.14 Mod */
+a.widget("akottr.dragtable",{options:{revert:!1,dragHandle:".table-handle",maxMovingRows:40,excludeFooter:!1,onlyHeaderThreshold:100,dragaccept:null,persistState:null,restoreState:null,exact:!0,clickDelay:10,containment:null,cursor:"move",cursorAt:!1,distance:0,tolerance:"pointer",axis:"x",beforeStart:a.noop,beforeMoving:a.noop,beforeReorganize:a.noop,beforeStop:a.noop,tablesorterComplete:null,sortClass:".sorter"},originalTable:{el:null,selectedHandle:null,sortOrder:null,startIndex:0,endIndex:0},sortableTable:{el:a(),selectedHandle:a(),movingRow:a()},persistState:function(){var b=this;this.originalTable.el.find("th").each(function(a){""!==this.id&&(b.originalTable.sortOrder[this.id]=a)}),a.ajax({url:this.options.persistState,data:this.originalTable.sortOrder})},_restoreState:function(b){for(var c in b)c in b&&(this.originalTable.startIndex=a("#"+c).closest("th").prevAll().length+1,this.originalTable.endIndex=parseInt(b[c],10)+1,this._bubbleCols())},_bubbleCols:function(){e.dragtable.startColumnMove(this.originalTable)},_rearrangeTableBackroundProcessing:function(){var b=this;return function(){b._bubbleCols(),b.options.beforeStop(b.originalTable),b.sortableTable.el.remove(),c(),e.dragtable.update(b),a.isFunction(b.options.persistState)?b.options.persistState(b.originalTable):b.persistState()}},_rearrangeTable:function(){var a=this;return function(){a.originalTable.selectedHandle.removeClass("dragtable-handle-selected"),a.sortableTable.el.sortable("disable"),a.sortableTable.el.addClass("dragtable-disabled"),a.options.beforeReorganize(a.originalTable,a.sortableTable),a.originalTable.endIndex=a.sortableTable.movingRow.prevAll().length+1,setTimeout(a._rearrangeTableBackroundProcessing(),50)}},_generateSortable:function(c){c.cancelBubble?c.cancelBubble=!0:c.stopPropagation();for(var d=this,e=this.originalTable.el[0].attributes,f="",g=0;g<e.length;g++)(e[g].value||e[g].nodeValue)&&"id"!=e[g].nodeName&&"width"!=e[g].nodeName&&(f+=e[g].nodeName+'="'+(e[g].value||e[g].nodeValue)+'" ');var h=[],i=[];d.originalTable.el.children("thead, tbody").children("tr:visible").slice(0,d.options.maxMovingRow).each(function(){for(var b=this.attributes,c="",d=0;d<b.length;d++)(b[d].value||b[d].nodeValue)&&"id"!=b[d].nodeName&&(c+=" "+b[d].nodeName+'="'+(b[d].value||b[d].nodeValue)+'"');h.push(c),i.push(a(this).height())});var j=[],k=0,l=d.originalTable.el.children(),m=l.filter("thead").children("tr:visible"),n=l.filter("tbody").children("tr:visible");if(m.eq(0).children("th, td").filter(":visible").each(function(){var b=a(this).outerWidth();j.push(b),k+=b}),d.options.exact){var o=k-d.originalTable.el.outerWidth();j[0]-=o}k+=2;var p=0;l.filter("caption").each(function(){p+=a(this).outerHeight()});var q,r='<ul class="dragtable-sortable" style="position:absolute; width:'+k+'px;">',s=[],t=m.eq(0).children("th, td").length;for(g=0;g<t;g++){var u=m.children(":nth-child("+(g+1)+")");u.is(":visible")&&(q=0,s[g]='<li style="width:'+u.outerWidth()+'px;"><table '+f+">"+(p?'<caption style="height:'+p+'px;"></caption>':"")+"<thead>",m.each(function(a){s[g]+="<tr "+h[q++]+(i[a]?' style="height:'+i[a]+'px;"':"")+">"+u[a].outerHTML+"</tr>"}),s[g]+="</thead><tbody>",u=n.children(":nth-child("+(g+1)+")"),d.options.maxMovingRows>1&&(u=u.add(n.children(":nth-child("+(g+1)+")").slice(0,d.options.maxMovingRows-1))),u.each(function(a){s[g]+="<tr "+h[q++]+(i[a]?' style="height:'+i[a]+'px;"':"")+">"+this.outerHTML+"</tr>"}),s[g]+="</tbody>",d.options.excludeFooter||(s[g]+="<tfoot><tr "+h[q++]+">"+l.filter("tfoot").children("tr:visible").children()[g].outerHTML+"</tr></tfoot>"),s[g]+="</table></li>")}r+=s.join("")+"</ul>",this.sortableTable.el=this.originalTable.el.before(r).prev(),this.sortableTable.el.find("> li > table").each(function(b){a(this).css("width",j[b]+"px")}),this.sortableTable.selectedHandle=this.sortableTable.el.find("th .dragtable-handle-selected");var v=this.options.dragaccept?"li:has("+this.options.dragaccept+")":"li";this.sortableTable.el.sortable({items:v,stop:this._rearrangeTable(),revert:this.options.revert,tolerance:this.options.tolerance,containment:this.options.containment,cursor:this.options.cursor,cursorAt:this.options.cursorAt,distance:this.options.distance,axis:this.options.axis}),this.originalTable.startIndex=a(c.target).closest("th,td").prevAll().length+1,this.options.beforeMoving(this.originalTable,this.sortableTable),this.sortableTable.movingRow=this.sortableTable.el.children("li:nth-child("+this.originalTable.startIndex+")"),b(),this.sortableTable.movingRow.trigger(a.extend(a.Event(c.type),{which:1,clientX:c.clientX,clientY:c.clientY,pageX:c.pageX,pageY:c.pageY,screenX:c.screenX,screenY:c.screenY}));var w=this.sortableTable.el.find(".ui-sortable-placeholder");w.height()>0&&w.css("height",this.sortableTable.el.find(".ui-sortable-helper").height()),w.html('<div class="outer" style="height:100%;"><div class="inner" style="height:100%;"></div></div>')},bindTo:{},_create:function(){var b=this;b.originalTable={el:b.element,selectedHandle:a(),sortOrder:{},startIndex:0,endIndex:0},e.dragtable.create(b),b.bindTo="> thead > tr > "+(b.options.dragaccept||"th, td"),b.element.find(b.bindTo).find(b.options.dragHandle).length&&(b.bindTo+=" "+b.options.dragHandle),a.isFunction(b.options.restoreState)?b.options.restoreState(b.originalTable):b._restoreState(b.options.restoreState),b.originalTable.el.on("mousedown.dragtable",b.bindTo,function(c){1===c.which&&(e.dragtable.start(b.originalTable.el),b.options.beforeStart(b.originalTable)!==!1&&(clearTimeout(b.downTimer),b.downTimer=setTimeout(function(){b.originalTable.selectedHandle=a(b),b.originalTable.selectedHandle.addClass("dragtable-handle-selected"),b._generateSortable(c)},b.options.clickDelay)))}).on("mouseup.dragtable",b.options.dragHandle,function(){clearTimeout(b.downTimer)})},redraw:function(){this.destroy(),this._create()},destroy:function(){this.originalTable.el.off("mousedown.dragtable mouseup.dragtable",this.bindTo),a.Widget.prototype.destroy.apply(this,arguments)}});var f=a(document.body).attr("onselectstart"),g=a(document.body).attr("unselectable")}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/jquery.metadata.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/jquery.metadata.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..4a11db581445384c1bbf2812ce8ee8cdf4754a09
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/jquery.metadata.min.js
@@ -0,0 +1 @@
+!function($){$.extend({metadata:{defaults:{type:"class",name:"metadata",cre:/(\{.*\})/,single:"metadata"},setType:function(a,b){this.defaults.type=a,this.defaults.name=b},get:function(elem,opts){var data,m,e,attr,settings=$.extend({},this.defaults,opts);if(settings.single.length||(settings.single="metadata"),data=$.data(elem,settings.single))return data;if(data="{}","class"===settings.type)m=settings.cre.exec(elem.className),m&&(data=m[1]);else if("elem"===settings.type){if(!elem.getElementsByTagName)return;e=elem.getElementsByTagName(settings.name),e.length&&(data=$.trim(e[0].innerHTML))}else void 0!==elem.getAttribute&&(attr=elem.getAttribute(settings.name),attr&&(data=attr));return data.indexOf("{")<0&&(data="{"+data+"}"),data=eval("("+data+")"),$.data(elem,settings.single,data),data}}}),$.fn.metadata=function(a){return $.metadata.get(this[0],a)}}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/jquery.tablesorter.pager.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/jquery.tablesorter.pager.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..676810c2503d0be46ea5a047159ed144d2abfd7e
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/jquery.tablesorter.pager.min.js
@@ -0,0 +1,5 @@
+/*!
+* tablesorter (FORK) pager plugin
+* updated 1/6/2017 (v2.28.4)
+*/
+!function(a){"use strict";var b=a.tablesorter;a.extend({tablesorterPager:new function(){this.defaults={container:null,ajaxUrl:null,customAjaxUrl:function(a,b){return b},ajaxError:null,ajaxObject:{dataType:"json"},processAjaxOnInit:!0,ajaxProcessing:function(a){return[0,[],null]},output:"{startRow} to {endRow} of {totalRows} rows",updateArrows:!0,page:0,pageReset:0,size:10,maxOptionSize:20,savePages:!0,storageKey:"tablesorter-pager",fixedHeight:!1,countChildRows:!1,removeRows:!1,cssFirst:".first",cssPrev:".prev",cssNext:".next",cssLast:".last",cssGoto:".gotoPage",cssPageDisplay:".pagedisplay",cssPageSize:".pagesize",cssErrorRow:"tablesorter-errorRow",cssDisabled:"disabled",totalRows:0,totalPages:0,filteredRows:0,filteredPages:0,ajaxCounter:0,currentFilters:[],startRow:0,endRow:0,$size:null,last:{}};var c="filterInit filterStart filterEnd sortEnd disablePager enablePager destroyPager updateComplete pageSize pageSet pageAndSize pagerUpdate refreshComplete ",d=this,e=function(a,b,c){var d,e="addClass",f="removeClass",g=b.cssDisabled,h=!!c,i=h||0===b.page,j=t(a,b),k=h||b.page===j-1||0===j;b.updateArrows&&(d=b.$container.find(b.cssFirst+","+b.cssPrev),d[i?e:f](g),d.each(function(){this.ariaDisabled=i}),d=b.$container.find(b.cssNext+","+b.cssLast),d[k?e:f](g),d.each(function(){this.ariaDisabled=k}))},f=function(a,c){var d,e,f,g=a.config,h=g.$table.hasClass("hasFilters");if(h&&!c.ajax)if(b.isEmptyObject(g.cache))c.filteredRows=c.totalRows=g.$tbodies.eq(0).children("tr").not(c.countChildRows?"":"."+g.cssChildRow).length;else for(c.filteredRows=0,d=g.cache[0].normalized,f=d.length,e=0;e<f;e++)c.filteredRows+=c.regexRows.test(d[e][g.columns].$row[0].className)?0:1;else h||(c.filteredRows=c.totalRows)},g=function(c,d,g){if(!d.initializing){var j,k,l,m,n,o,p,q,r=c.config,s=r.namespace+"pager",w=u(d,d.size,"get");if("all"===w&&(w=d.totalRows),d.countChildRows&&(k[k.length]=r.cssChildRow),d.totalPages=Math.ceil(d.totalRows/w),r.totalRows=d.totalRows,v(c,d),f(c,d),r.filteredRows=d.filteredRows,d.filteredPages=Math.ceil(d.filteredRows/w)||0,t(c,d)>=0){if(k=w*d.page>d.filteredRows&&g,d.page=k?d.pageReset||0:d.page,d.startRow=k?w*d.page+1:0===d.filteredRows?0:w*d.page+1,d.endRow=Math.min(d.filteredRows,d.totalRows,w*(d.page+1)),l=d.$container.find(d.cssPageDisplay),"function"==typeof d.output?j=d.output(c,d):(q=l.attr("data-pager-output"+(d.filteredRows<d.totalRows?"-filtered":""))||d.output,j=(d.ajaxData&&d.ajaxData.output?d.ajaxData.output||q:q).replace(/\{page([\-+]\d+)?\}/gi,function(a,b){return d.totalPages?d.page+(b?parseInt(b,10):1):0}).replace(/\{\w+(\s*:\s*\w+)?\}/gi,function(a){var b,c,e=a.replace(/[{}\s]/g,""),f=e.split(":"),g=d.ajaxData,h=/(rows?|pages?)$/i.test(e)?0:"";return/(startRow|page)/.test(f[0])&&"input"===f[1]?(b=(""+("page"===f[0]?d.totalPages:d.totalRows)).length,c="page"===f[0]?d.page+1:d.startRow,'<input type="text" class="ts-'+f[0]+'" style="max-width:'+b+'em" value="'+c+'"/>'):f.length>1&&g&&g[f[0]]?g[f[0]][f[1]]:d[e]||(g?g[e]:h)||h})),m=d.$container.find(d.cssGoto),m.length){for(k="",p=h(c,d),o=p.length,n=0;n<o;n++)k+='<option value="'+p[n]+'">'+p[n]+"</option>";m.html(k).val(d.page+1)}l.length&&(l["INPUT"===l[0].nodeName?"val":"html"](j),l.find(".ts-startRow, .ts-page").unbind("change"+s).bind("change"+s,function(){var b=a(this).val(),c=a(this).hasClass("ts-startRow")?Math.floor(b/w)+1:b;r.$table.triggerHandler("pageSet"+s,[c])}))}e(c,d),i(c,d),d.initialized&&g!==!1&&(r.debug&&console.log("Pager: Triggering pagerComplete"),r.$table.triggerHandler("pagerComplete",d),d.savePages&&b.storage&&b.storage(c,d.storageKey,{page:d.page,size:w===d.totalRows?"all":w}))}},h=function(b,c){var d,e,f,g,h,i,j=t(b,c)||1,k=5*Math.ceil(j/c.maxOptionSize/5),l=j>c.maxOptionSize,m=c.page+1,n=k,o=j-k,p=[1],q=l?k:1;for(d=q;d<=j;)p[p.length]=d,d+=l?k:1;if(p[p.length]=j,l){for(f=[],e=Math.max(Math.floor(c.maxOptionSize/k)-1,5),n=m-e,n<1&&(n=1),o=m+e,o>j&&(o=j),d=n;d<=o;d++)f[f.length]=d;p=a.grep(p,function(b,c){return a.inArray(b,p)===c}),h=p.length,i=f.length,h-i>k/2&&h+i>c.maxOptionSize&&(g=Math.floor(h/2)-Math.floor(i/2),Array.prototype.splice.apply(p,[g,i])),p=p.concat(f)}return p=a.grep(p,function(b,c){return a.inArray(b,p)===c}).sort(function(a,b){return a-b})},i=function(b,c){var d,e,f=b.config,g=f.$tbodies.eq(0);g.find("tr.pagerSavedHeightSpacer").remove(),c.fixedHeight&&!c.isDisabled&&(e=a.data(b,"pagerSavedHeight"),e&&(d=e-g.height(),d>5&&a.data(b,"pagerLastSize")===c.size&&g.children("tr:visible").length<("all"===c.size?c.totalRows:c.size)&&g.append('<tr class="pagerSavedHeightSpacer '+f.selectorRemove.slice(1)+'" style="height:'+d+'px;"></tr>')))},j=function(b,c){var d,e=b.config,f=e.$tbodies.eq(0);f.find("tr.pagerSavedHeightSpacer").remove(),f.children("tr:visible").length||f.append('<tr class="pagerSavedHeightSpacer '+e.selectorRemove.slice(1)+'"><td>&nbsp</td></tr>'),d=f.children("tr").eq(0).height()*("all"===c.size?c.totalRows:c.size),a.data(b,"pagerSavedHeight",d),i(b,c),a.data(b,"pagerLastSize",c.size)},k=function(a,c){if(!c.ajaxUrl){var d,e=0,f=a.config,g=f.$tbodies.eq(0).children("tr"),h=g.length,i="all"===c.size?c.totalRows:c.size,j=c.page*i,k=j+i,l=0,m=0;for(c.cacheIndex=[],d=0;d<h;d++)c.regexFiltered.test(g[d].className)||(m===j&&g[d].className.match(f.cssChildRow)?g[d].style.display="none":(g[d].style.display=m>=j&&m<k?"":"none",l!==m&&m>=j&&m<k&&(c.cacheIndex[c.cacheIndex.length]=d,l=m),m+=g[d].className.match(f.cssChildRow+"|"+f.selectorRemove.slice(1))&&!c.countChildRows?0:1,m===k&&"none"!==g[d].style.display&&g[d].className.match(b.css.cssHasChild)&&(e=d)));if(e>0&&g[e].className.match(b.css.cssHasChild))for(;++e<h&&g[e].className.match(f.cssChildRow);)g[e].style.display=""}},l=function(b,c){var d=c.$container.find(c.cssPageSize);c.size=u(c,d.val(),"get"),d.val(c.size),a.data(b,"pagerLastSize",c.size),e(b,c),c.removeRows||(k(b,c),a(b).bind("sortEnd filterEnd ".split(" ").join(b.config.namespace+"pager "),function(){k(b,c)}))},m=function(c,d,e,f,h,i){if("function"==typeof e.ajaxProcessing){d.config.$tbodies.eq(0).empty();var j,k,l,m,n,o,p,q,r,s,t,v,w,x,y,z=d.config,A=z.$table,C="",D=e.ajaxProcessing(c,d,f)||[0,[]];A.find("thead th").length;if(b.showError(d),i)z.debug&&console.error("Pager: >> Ajax Error",f,h,i),b.showError(d,f,h,i),z.$tbodies.eq(0).children("tr").detach(),e.totalRows=0;else{if(a.isArray(D)?(l=isNaN(D[0])&&!isNaN(D[1]),w=D[l?1:0],e.totalRows=isNaN(w)?e.totalRows||0:w,z.totalRows=z.filteredRows=e.filteredRows=e.totalRows,t=0===e.totalRows?[]:D[l?0:1]||[],s=D[2]):(e.ajaxData=D,z.totalRows=e.totalRows=D.total,z.filteredRows=e.filteredRows="undefined"!=typeof D.filteredRows?D.filteredRows:D.total,s=D.headers,t=D.rows||[]),v=t&&t.length,t instanceof jQuery)e.processAjaxOnInit&&(z.$tbodies.eq(0).empty(),z.$tbodies.eq(0).append(t));else if(v){for(j=0;j<v;j++){for(C+="<tr>",k=0;k<t[j].length;k++)C+=/^\s*<td/.test(t[j][k])?a.trim(t[j][k]):"<td>"+t[j][k]+"</td>";C+="</tr>"}e.processAjaxOnInit&&z.$tbodies.eq(0).html(C)}if(e.processAjaxOnInit=!0,s)for(m=A.hasClass("hasStickyHeaders"),o=m?z.widgetOptions.$sticky.children("thead:first").children("tr:not(."+z.cssIgnoreRow+")").children():"",n=A.find("tfoot tr:first").children(),p=z.$headers.filter("th "),x=p.length,k=0;k<x;k++)q=p.eq(k),q.find("."+b.css.icon).length?(r=q.find("."+b.css.icon).clone(!0),q.find("."+b.css.headerIn).html(s[k]).append(r),m&&o.length&&(r=o.eq(k).find("."+b.css.icon).clone(!0),o.eq(k).find("."+b.css.headerIn).html(s[k]).append(r))):(q.find("."+b.css.headerIn).html(s[k]),m&&o.length&&(e.$container=e.$container.add(z.widgetOptions.$sticky),o.eq(k).find("."+b.css.headerIn).html(s[k]))),n.eq(k).html(s[k])}z.showProcessing&&b.isProcessing(d),y=u(e,e.size,"get"),e.totalPages="all"===y?1:Math.ceil(e.totalRows/y),e.last.totalRows=e.totalRows,e.last.currentFilters=e.currentFilters,e.last.sortList=(z.sortList||[]).join(","),g(d,e,!1),b.updateCache(z,function(){e.initialized&&setTimeout(function(){z.debug&&console.log("Pager: Triggering pagerChange"),A.triggerHandler("pagerChange",e),b.applyWidget(d),g(d,e,!0)},0)})}e.initialized||B(d,e)},n=function(c,d){var e,f=o(c,d),g=a(document),h=c.config,i=h.namespace+"pager";""!==f&&(h.showProcessing&&b.isProcessing(c,!0),g.bind("ajaxError"+i,function(a,b,e,f){m(null,c,d,b,e,f),g.unbind("ajaxError"+i)}),e=++d.ajaxCounter,d.last.ajaxUrl=f,d.ajaxObject.url=f,d.ajaxObject.success=function(a,b,f){e<d.ajaxCounter||(m(a,c,d,f),g.unbind("ajaxError"+i),"function"==typeof d.oldAjaxSuccess&&d.oldAjaxSuccess(a))},h.debug&&console.log("Pager: Ajax initialized",d.ajaxObject),a.ajax(d.ajaxObject))},o=function(b,c){var d,e,f=b.config,g=c.ajaxUrl?c.ajaxUrl.replace(/\{page([\-+]\d+)?\}/,function(a,b){return c.page+(b?parseInt(b,10):0)}).replace(/\{size\}/g,c.size):"",h=f.sortList,i=c.currentFilters||a(b).data("lastSearch")||[],j=g.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/),k=g.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/),l=[];if(j){for(j=j[1],e=h.length,d=0;d<e;d++)l[l.length]=j+"["+h[d][0]+"]="+h[d][1];g=g.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g,l.length?l.join("&"):j),l=[]}if(k){for(k=k[1],e=i.length,d=0;d<e;d++)i[d]&&(l[l.length]=k+"["+d+"]="+encodeURIComponent(i[d]));g=g.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g,l.length?l.join("&"):k),c.currentFilters=i}return"function"==typeof c.customAjaxUrl&&(g=c.customAjaxUrl(b,g)),f.debug&&console.log("Pager: Ajax url = "+g),g},p=function(c,d,e){var f,h,i,j,l=a(c),m=c.config,n=m.$table.hasClass("hasFilters"),o=d&&d.length||0,p="all"===e.size?e.totalRows:e.size,q=e.page*p;if(o<1)return void(m.debug&&console.warn("Pager: >> No rows for pager to render"));if(e.page>=e.totalPages&&y(c,e),e.cacheIndex=[],e.isDisabled=!1,e.initialized&&(m.debug&&console.log("Pager: Triggering pagerChange"),l.triggerHandler("pagerChange",e)),e.removeRows){for(b.clearTableBody(c),f=b.processTbody(c,m.$tbodies.eq(0),!0),h=n?0:q,i=n?0:q,j=0;j<p&&h<d.length;)n&&e.regexFiltered.test(d[h][0].className)||(i++,i>q&&j<=p&&(j++,e.cacheIndex[e.cacheIndex.length]=h,f.append(d[h]))),h++;b.processTbody(c,f,!1)}else k(c,e);g(c,e),c.isUpdating&&(m.debug&&console.log("Pager: Triggering updateComplete"),l.triggerHandler("updateComplete",[c,!0]))},q=function(c,d){var f,g,h;for(d.ajax?e(c,d,!0):(a.data(c,"pagerLastPage",d.page),a.data(c,"pagerLastSize",d.size),d.page=0,d.size="all",d.totalPages=1,a(c).addClass("pagerDisabled").removeAttr("aria-describedby").find("tr.pagerSavedHeightSpacer").remove(),p(c,c.config.rowsCopy,d),d.isDisabled=!0,b.applyWidget(c),c.config.debug&&console.log("Pager: Disabled")),g=d.$container.find(d.cssGoto+","+d.cssPageSize+", .ts-startRow, .ts-page"),h=g.length,f=0;f<h;f++)g.eq(f).addClass(d.cssDisabled)[0].disabled=!0,g[f].ariaDisabled=!0},r=function(a){var c=a.config,d=c.pager;b.updateCache(c,function(){var b,e=[],f=a.config.cache[0].normalized;for(d.totalRows=f.length,b=0;b<d.totalRows;b++)e[e.length]=f[b][c.columns].$row;c.rowsCopy=e,s(a,d,!0)})},s=function(c,d,e){if(!d.isDisabled){var g,h=c.config,i=a(c),j=d.last;return e!==!1&&d.initialized&&b.isEmptyObject(h.cache)?r(c):void(d.ajax&&b.hasWidget(c,"filter")&&!h.widgetOptions.filter_initialized||(v(c,d),f(c,d),j.currentFilters=""===(j.currentFilters||[]).join("")?[]:j.currentFilters,d.currentFilters=""===(d.currentFilters||[]).join("")?[]:d.currentFilters,j.page===d.page&&j.size===d.size&&j.totalRows===d.totalRows&&(j.currentFilters||[]).join(",")===(d.currentFilters||[]).join(",")&&(j.ajaxUrl||"")===(d.ajaxObject.url||"")&&(j.optAjaxUrl||"")===(d.ajaxUrl||"")&&j.sortList===(h.sortList||[]).join(",")||(h.debug&&console.log("Pager: Changing to page "+d.page),d.last={page:d.page,size:d.size,sortList:(h.sortList||[]).join(","),totalRows:d.totalRows,currentFilters:d.currentFilters||[],ajaxUrl:d.ajaxObject.url||"",optAjaxUrl:d.ajaxUrl||""},d.ajax?d.processAjaxOnInit||b.isEmptyObject(d.initialRows)?n(c,d):(d.processAjaxOnInit=!0,g=d.initialRows,d.totalRows="undefined"!=typeof g.total?g.total:h.debug?console.error("Pager: no initial total page set!")||0:0,d.filteredRows="undefined"!=typeof g.filtered?g.filtered:h.debug?console.error("Pager: no initial filtered page set!")||0:0,B(c,d)):d.ajax||p(c,h.rowsCopy,d),a.data(c,"pagerLastPage",d.page),d.initialized&&e!==!1&&(h.debug&&console.log("Pager: Triggering pageMoved"),i.triggerHandler("pageMoved",d),b.applyWidget(c),c.isUpdating&&(h.debug&&console.log("Pager: Triggering updateComplete"),i.triggerHandler("updateComplete",[c,!0]))))))}},t=function(a,c){return b.hasWidget(a,"filter")?Math.min(c.totalPages,c.filteredPages):c.totalPages},u=function(a,b,c){var d=parseInt(b,10)||a.size||a.settings.size||10;return a.initialized&&(/all/i.test(b)||d===a.totalRows)?"all":"get"===c?d:a.size},v=function(a,b){var c=t(a,b)-1;return b.page=parseInt(b.page,10),(b.page<0||isNaN(b.page))&&(b.page=0),b.page>c&&c>=0&&(b.page=c),b.page},w=function(b,c,d){d.size=u(d,c,"get"),d.$container.find(d.cssPageSize).val(u(d,d.size,"set")),a.data(b,"pagerLastPage",v(b,d)),a.data(b,"pagerLastSize",d.size),d.totalPages="all"===d.size?1:Math.ceil(d.totalRows/d.size),d.filteredPages="all"===d.size?1:Math.ceil(d.filteredRows/d.size),s(b,d)},x=function(a,b){b.page=0,s(a,b)},y=function(a,b){b.page=t(a,b)-1,s(a,b)},z=function(a,b){b.page++;var c=t(a,b)-1;b.page>=c&&(b.page=c),s(a,b)},A=function(a,b){b.page--,b.page<=0&&(b.page=0),s(a,b)},B=function(c,d){d.initialized=!0,d.initializing=!1,c.config.debug&&console.log("Pager: Triggering pagerInitialized"),a(c).triggerHandler("pagerInitialized",d),b.applyWidget(c),g(c,d)},C=function(b,c){var d=b.config;d.pager=a.extend(!0,{},a.tablesorterPager.defaults,c.settings),F(b,c.settings)},D=function(a,c){var d=a.config,e=d.namespace+"pager",f=[c.cssFirst,c.cssPrev,c.cssNext,c.cssLast,c.cssGoto,c.cssPageSize].join(",");q(a,c),c.$container.hide().find(f).unbind(e),d.appender=null,d.$table.unbind(e),b.storage&&b.storage(a,c.storageKey,""),delete d.pager,delete d.rowsCopy},E=function(c,d,e){var f,g,h,i=c.config;d.$container.find(d.cssGoto+","+d.cssPageSize+",.ts-startRow, .ts-page").removeClass(d.cssDisabled).removeAttr("disabled").each(function(){this.ariaDisabled=!1}),d.isDisabled=!1,d.page=a.data(c,"pagerLastPage")||d.page||0,h=d.$container.find(d.cssPageSize),g=h.find("option[selected]").val(),d.size=a.data(c,"pagerLastSize")||u(d,g,"get"),h.val(d.size),d.totalPages="all"===d.size?1:Math.ceil(t(c,d)/d.size),c.id&&!i.$table.attr("aria-describedby")&&(h=d.$container.find(d.cssPageDisplay),f=h.attr("id"),f||(f=c.id+"_pager_info",h.attr("id",f)),i.$table.attr("aria-describedby",f)),j(c,d),e&&(b.update(i),w(c,d.size,d),l(c,d),i.debug&&console.log("Pager: Enabled"))},F=function(e,f){var h,i,m,n,o=e.config,p=o.widgetOptions,t=o.pager=a.extend(!0,{},a.tablesorterPager.defaults,f),v=o.$table,B=o.namespace+"pager",F=t.$container=a(t.container).addClass("tablesorter-pager").show();t.settings=a.extend(!0,{},a.tablesorterPager.defaults,f),o.debug&&console.log("Pager: Initializing"),t.oldAjaxSuccess=t.oldAjaxSuccess||t.ajaxObject.success,o.appender=d.appender,t.initializing=!0,t.savePages&&b.storage&&(h=b.storage(e,t.storageKey)||{},t.page=isNaN(h.page)?t.page:h.page,t.size="all"===h.size?h.size:(isNaN(h.size)?t.size:h.size)||t.setSize||10,a.data(e,"pagerLastSize",t.size),F.find(t.cssPageSize).val(t.size)),t.regexRows=new RegExp("("+(p.filter_filteredRow||"filtered")+"|"+o.selectorRemove.slice(1)+"|"+o.cssChildRow+")"),t.regexFiltered=new RegExp(p.filter_filteredRow||"filtered"),v.unbind(c.split(" ").join(B+" ").replace(/\s+/g," ")).bind("filterInit filterStart ".split(" ").join(B+" "),function(b,c){t.currentFilters=a.isArray(c)?c:o.$table.data("lastSearch"),"filterStart"===b.type&&t.pageReset!==!1&&(o.lastCombinedFilter||"")!==(t.currentFilters||[]).join("")&&(t.page=t.pageReset)}).bind("filterEnd sortEnd ".split(" ").join(B+" "),function(){t.currentFilters=o.$table.data("lastSearch"),(t.initialized||t.initializing)&&(o.delayInit&&o.rowsCopy&&0===o.rowsCopy.length&&r(e),g(e,t,!1),s(e,t,!1),b.applyWidget(e))}).bind("disablePager"+B,function(a){a.stopPropagation(),q(e,t)}).bind("enablePager"+B,function(a){a.stopPropagation(),E(e,t,!0)}).bind("destroyPager"+B,function(a){a.stopPropagation(),D(e,t)}).bind("resetToLoadState"+B,function(a){a.stopPropagation(),C(e,t)}).bind("updateComplete"+B,function(a,b,c){if(a.stopPropagation(),b&&!c&&!t.ajax){var d=o.$tbodies.eq(0).children("tr").not(o.selectorRemove);t.totalRows=d.length-(t.countChildRows?0:d.filter("."+o.cssChildRow).length),t.totalPages="all"===t.size?1:Math.ceil(t.totalRows/t.size),d.length&&o.rowsCopy&&0===o.rowsCopy.length&&r(b),t.page>=t.totalPages&&y(b,t),k(b,t),j(b,t),g(b,t,!0)}}).bind("pageSize refreshComplete ".split(" ").join(B+" "),function(a,b){a.stopPropagation(),w(e,u(t,b,"get"),t),k(e,t),g(e,t,!1)}).bind("pageSet pagerUpdate ".split(" ").join(B+" "),function(a,b){a.stopPropagation(),"pagerUpdate"===a.type&&(b="undefined"==typeof b?t.page+1:b,t.last.page=!0),t.page=(parseInt(b,10)||1)-1,s(e,t,!0),g(e,t,!1)}).bind("pageAndSize"+B,function(a,b,c){a.stopPropagation(),t.page=(parseInt(b,10)||1)-1,w(e,u(t,c,"get"),t),s(e,t,!0),k(e,t),g(e,t,!1)}),i=[t.cssFirst,t.cssPrev,t.cssNext,t.cssLast],m=[x,A,z,y],o.debug&&!F.length&&console.warn("Pager: >> Container not found"),F.find(i.join(",")).attr("tabindex",0).unbind("click"+B).bind("click"+B,function(b){b.stopPropagation();var c,d=a(this),f=i.length;if(!d.hasClass(t.cssDisabled))for(c=0;c<f;c++)if(d.is(i[c])){m[c](e,t);break}}),n=F.find(t.cssGoto),n.length?n.unbind("change"+B).bind("change"+B,function(){t.page=a(this).val()-1,s(e,t,!0),g(e,t,!1)}):o.debug&&console.warn("Pager: >> Goto selector not found"),n=F.find(t.cssPageSize),n.length?(n.find("option").removeAttr("selected"),n.unbind("change"+B).bind("change"+B,function(){if(!a(this).hasClass(t.cssDisabled)){var b=a(this).val();t.$container.find(t.cssGoto).val(b),w(e,b,t),j(e,t)}return!1})):o.debug&&console.warn("Pager: >> Size selector not found"),t.initialized=!1,v.triggerHandler("pagerBeforeInitialized",t),E(e,t,!1),"string"==typeof t.ajaxUrl?(t.ajax=!0,o.widgetOptions.filter_serversideFiltering=!0,o.serverSideSorting=!0,s(e,t)):(t.ajax=!1,b.appendCache(o,!0),l(e,t)),t.ajax||t.initialized||(t.initializing=!1,t.initialized=!0,s(e,t),o.debug&&console.log("Pager: Triggering pagerInitialized"),o.$table.triggerHandler("pagerInitialized",t),o.widgetOptions.filter_initialized&&b.hasWidget(e,"filter")||g(e,t,!1)),o.widgetInit.pager=!0};d.appender=function(b,c){var d=b.config,e=d.pager;e.ajax||(d.rowsCopy=c,e.totalRows=e.countChildRows?d.$tbodies.eq(0).children("tr").length:c.length,e.size=a.data(b,"pagerLastSize")||e.size||e.settings.size||10,e.totalPages="all"===e.size?1:Math.ceil(e.totalRows/e.size),p(b,c,e),g(b,e,!1))},d.construct=function(a){return this.each(function(){this.config&&this.hasInitialized&&F(this,a)})}}}),b.showError=function(b,c,d,e){var f,g=a(b),h=g[0].config,i=h&&h.widgetOptions,j=h.pager&&h.pager.cssErrorRow||i&&i.pager_css&&i.pager_css.errorRow||"tablesorter-errorRow",k=typeof c,l=!0,m="",n=function(){h.$table.find("thead").find("."+j).remove()};if(!g.length)return void console.error("tablesorter showError: no table parameter passed");if("function"==typeof h.pager.ajaxError){if(l=h.pager.ajaxError(h,c,d,e),l===!1)return n();m=l}else if("function"==typeof i.pager_ajaxError){if(l=i.pager_ajaxError(h,c,d,e),l===!1)return n();m=l}if(""===m)if("object"===k)m=0===c.status?"Not connected, verify Network":404===c.status?"Requested page not found [404]":500===c.status?"Internal Server Error [500]":"parsererror"===e?"Requested JSON parse failed":"timeout"===e?"Time out error":"abort"===e?"Ajax Request aborted":"Uncaught error: "+c.statusText+" ["+c.status+"]";else{if("string"!==k)return n();m=c}f=a(/tr\>/.test(m)?m:'<tr><td colspan="'+h.columns+'">'+m+"</td></tr>").click(function(){a(this).remove()}).appendTo(h.$table.find("thead:first")).addClass(j+" "+h.selectorRemove.slice(1)).attr({role:"alert","aria-live":"assertive"})},a.fn.extend({tablesorterPager:a.tablesorterPager.construct})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/semver-mod.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/semver-mod.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..1f2740f40152ab2ad59660b63da546793f095a24
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/extras/semver-mod.min.js
@@ -0,0 +1,2 @@
+/*! Modified semver.js for node.js (v4.3.3, 3/27/2015) */
+!function(){function a(a,b){if(a instanceof d)return a;if("string"!=typeof a)return null;if(a.length>U)return null;var c=b?W[la]:W[ia];if(!c.test(a))return null;try{return new d(a,b)}catch(a){return null}}function b(b,c){var d=a(b,c);return d?d.version:null}function c(b,c){var d=a(b.trim().replace(/^[=v]+/,""),c);return d?d.version:null}function d(a,b){if(a instanceof d){if(a.loose===b)return a;a=a.version}else if("string"!=typeof a)throw new TypeError("Invalid Version: "+a);if(a.length>U)throw new TypeError("version is longer than "+U+" characters");if(!(this instanceof d))return new d(a,b);R("SemVer",a,b),this.loose=b;var c=a.trim().match(b?W[la]:W[ia]);if(!c)throw new TypeError("Invalid Version: "+a);if(this.raw=a,this.major=+c[1],this.minor=+c[2],this.patch=+c[3],this.major>V||this.major<0)throw new TypeError("Invalid major version");if(this.minor>V||this.minor<0)throw new TypeError("Invalid minor version");if(this.patch>V||this.patch<0)throw new TypeError("Invalid patch version");c[4]?this.prerelease=c[4].split(".").map(function(a){if(/^[0-9]+$/.test(a)){var b=+a;if(b>=0&&b<V)return b}return a}):this.prerelease=[],this.build=c[5]?c[5].split("."):[],this.format()}function e(a,b,c,e){"string"==typeof c&&(e=c,c=void 0);try{return new d(a,c).inc(b,e).version}catch(a){return null}}function f(b,c){if(s(b,c))return null;var d=a(b),e=a(c);if(d.prerelease.length||e.prerelease.length){for(var f in d)if(("major"===f||"minor"===f||"patch"===f)&&d[f]!==e[f])return"pre"+f;return"prerelease"}for(var f in d)if(("major"===f||"minor"===f||"patch"===f)&&d[f]!==e[f])return f}function g(a,b){var c=La.test(a),d=La.test(b);return c&&d&&(a=+a,b=+b),c&&!d?-1:d&&!c?1:a<b?-1:a>b?1:0}function h(a,b){return g(b,a)}function i(a,b){return new d(a,b).major}function j(a,b){return new d(a,b).minor}function k(a,b){return new d(a,b).patch}function l(a,b,c){return new d(a,c).compare(b)}function m(a,b){return l(a,b,!0)}function n(a,b,c){return l(b,a,c)}function o(a,b){return a.sort(function(a,c){return T.compare(a,c,b)})}function p(a,b){return a.sort(function(a,c){return T.rcompare(a,c,b)})}function q(a,b,c){return l(a,b,c)>0}function r(a,b,c){return l(a,b,c)<0}function s(a,b,c){return 0===l(a,b,c)}function t(a,b,c){return 0!==l(a,b,c)}function u(a,b,c){return l(a,b,c)>=0}function v(a,b,c){return l(a,b,c)<=0}function w(a,b,c,d){var e;switch(b){case"===":"object"==typeof a&&(a=a.version),"object"==typeof c&&(c=c.version),e=a===c;break;case"!==":"object"==typeof a&&(a=a.version),"object"==typeof c&&(c=c.version),e=a!==c;break;case"":case"=":case"==":e=s(a,c,d);break;case"!=":e=t(a,c,d);break;case">":e=q(a,c,d);break;case">=":e=u(a,c,d);break;case"<":e=r(a,c,d);break;case"<=":e=v(a,c,d);break;default:throw new TypeError("Invalid operator: "+b)}return e}function x(a,b){if(a instanceof x){if(a.loose===b)return a;a=a.value}return this instanceof x?(R("comparator",a,b),this.loose=b,this.parse(a),this.semver===Ma?this.value="":this.value=this.operator+this.semver.version,void R("comp",this)):new x(a,b)}function y(a,b){if(a instanceof y&&a.loose===b)return a;if(!(this instanceof y))return new y(a,b);if(this.loose=b,this.raw=a,this.set=a.split(/\s*\|\|\s*/).map(function(a){return this.parseRange(a.trim())},this).filter(function(a){return a.length}),!this.set.length)throw new TypeError("Invalid SemVer Range: "+a);this.format()}function z(a,b){return new y(a,b).set.map(function(a){return a.map(function(a){return a.value}).join(" ").trim().split(" ")})}function A(a,b){return R("comp",a),a=E(a,b),R("caret",a),a=C(a,b),R("tildes",a),a=G(a,b),R("xrange",a),a=I(a,b),R("stars",a),a}function B(a){return!a||"x"===a.toLowerCase()||"*"===a}function C(a,b){return a.trim().split(/\s+/).map(function(a){return D(a,b)}).join(" ")}function D(a,b){var c=b?W[xa]:W[wa];return a.replace(c,function(b,c,d,e,f){R("tilde",a,b,c,d,e,f);var g;return B(c)?g="":B(d)?g=">="+c+".0.0 <"+(+c+1)+".0.0":B(e)?g=">="+c+"."+d+".0 <"+c+"."+(+d+1)+".0":f?(R("replaceTilde pr",f),"-"!==f.charAt(0)&&(f="-"+f),g=">="+c+"."+d+"."+e+f+" <"+c+"."+(+d+1)+".0"):g=">="+c+"."+d+"."+e+" <"+c+"."+(+d+1)+".0",R("tilde return",g),g})}function E(a,b){return a.trim().split(/\s+/).map(function(a){return F(a,b)}).join(" ")}function F(a,b){R("caret",a,b);var c=b?W[Ca]:W[Ba];return a.replace(c,function(b,c,d,e,f){R("caret",a,b,c,d,e,f);var g;return B(c)?g="":B(d)?g=">="+c+".0.0 <"+(+c+1)+".0.0":B(e)?g="0"===c?">="+c+"."+d+".0 <"+c+"."+(+d+1)+".0":">="+c+"."+d+".0 <"+(+c+1)+".0.0":f?(R("replaceCaret pr",f),"-"!==f.charAt(0)&&(f="-"+f),g="0"===c?"0"===d?">="+c+"."+d+"."+e+f+" <"+c+"."+d+"."+(+e+1):">="+c+"."+d+"."+e+f+" <"+c+"."+(+d+1)+".0":">="+c+"."+d+"."+e+f+" <"+(+c+1)+".0.0"):(R("no pr"),g="0"===c?"0"===d?">="+c+"."+d+"."+e+" <"+c+"."+d+"."+(+e+1):">="+c+"."+d+"."+e+" <"+c+"."+(+d+1)+".0":">="+c+"."+d+"."+e+" <"+(+c+1)+".0.0"),R("caret return",g),g})}function G(a,b){return R("replaceXRanges",a,b),a.split(/\s+/).map(function(a){return H(a,b)}).join(" ")}function H(a,b){a=a.trim();var c=b?W[sa]:W[ra];return a.replace(c,function(b,c,d,e,f,g){R("xRange",a,b,c,d,e,f,g);var h=B(d),i=h||B(e),j=i||B(f),k=j;return"="===c&&k&&(c=""),h?b=">"===c||"<"===c?"<0.0.0":"*":c&&k?(i&&(e=0),j&&(f=0),">"===c?(c=">=",i?(d=+d+1,e=0,f=0):j&&(e=+e+1,f=0)):"<="===c&&(c="<",i?d=+d+1:e=+e+1),b=c+d+"."+e+"."+f):i?b=">="+d+".0.0 <"+(+d+1)+".0.0":j&&(b=">="+d+"."+e+".0 <"+d+"."+(+e+1)+".0"),R("xRange return",b),b})}function I(a,b){return R("replaceStars",a,b),a.trim().replace(W[Ja],"")}function J(a,b,c,d,e,f,g,h,i,j,k,l,m){return b=B(c)?"":B(d)?">="+c+".0.0":B(e)?">="+c+"."+d+".0":">="+b,h=B(i)?"":B(j)?"<"+(+i+1)+".0.0":B(k)?"<"+i+"."+(+j+1)+".0":l?"<="+i+"."+j+"."+k+"-"+l:"<="+h,(b+" "+h).trim()}function K(a,b){for(var c=0;c<a.length;c++)if(!a[c].test(b))return!1;if(b.prerelease.length){for(var c=0;c<a.length;c++){if(R(a[c].semver),a[c].semver===Ma)return!0;if(a[c].semver.prerelease.length>0){var d=a[c].semver;if(d.major===b.major&&d.minor===b.minor&&d.patch===b.patch)return!0}}return!1}return!0}function L(a,b,c){try{b=new y(b,c)}catch(a){return!1}return b.test(a)}function M(a,b,c){return a.filter(function(a){return L(a,b,c)}).sort(function(a,b){return n(a,b,c)})[0]||null}function N(a,b){try{return new y(a,b).range||"*"}catch(a){return null}}function O(a,b,c){return Q(a,b,"<",c)}function P(a,b,c){return Q(a,b,">",c)}function Q(a,b,c,e){a=new d(a,e),b=new y(b,e);var f,g,h,i,j;switch(c){case">":f=q,g=v,h=r,i=">",j=">=";break;case"<":f=r,g=u,h=q,i="<",j="<=";break;default:throw new TypeError('Must provide a hilo val of "<" or ">"')}if(L(a,b,e))return!1;for(var k=0;k<b.set.length;++k){var l=b.set[k],m=null,n=null;if(l.forEach(function(a){m=m||a,n=n||a,f(a.semver,m.semver,e)?m=a:h(a.semver,n.semver,e)&&(n=a)}),m.operator===i||m.operator===j)return!1;if((!n.operator||n.operator===i)&&g(a,n.semver))return!1;if(n.operator===j&&h(a,n.semver))return!1}return!0}var R,S={exports:{}},T=S.exports=d;R="object"==typeof process&&process.env&&process.env.NODE_DEBUG&&/\bsemver\b/i.test(process.env.NODE_DEBUG)?function(){var a=Array.prototype.slice.call(arguments,0);a.unshift("SEMVER"),console.log.apply(console,a)}:function(){},T.SEMVER_SPEC_VERSION="2.0.0";var U=256,V=Number.MAX_SAFE_INTEGER||9007199254740991,W=T.re=[],X=T.src=[],Y=0,Z=Y++;X[Z]="0|[1-9]\\d*";var $=Y++;X[$]="[0-9]+";var _=Y++;X[_]="\\d*[a-zA-Z-][a-zA-Z0-9-]*";var aa=Y++;X[aa]="("+X[Z]+")\\.("+X[Z]+")\\.("+X[Z]+")";var ba=Y++;X[ba]="("+X[$]+")\\.("+X[$]+")\\.("+X[$]+")";var ca=Y++;X[ca]="(?:"+X[Z]+"|"+X[_]+")";var da=Y++;X[da]="(?:"+X[$]+"|"+X[_]+")";var ea=Y++;X[ea]="(?:-("+X[ca]+"(?:\\."+X[ca]+")*))";var fa=Y++;X[fa]="(?:-?("+X[da]+"(?:\\."+X[da]+")*))";var ga=Y++;X[ga]="[0-9A-Za-z-]+";var ha=Y++;X[ha]="(?:\\+("+X[ga]+"(?:\\."+X[ga]+")*))";var ia=Y++,ja="v?"+X[aa]+X[ea]+"?"+X[ha]+"?";X[ia]="^"+ja+"$";var ka="[v=\\s]*"+X[ba]+X[fa]+"?"+X[ha]+"?",la=Y++;X[la]="^"+ka+"$";var ma=Y++;X[ma]="((?:<|>)?=?)";var na=Y++;X[na]=X[$]+"|x|X|\\*";var oa=Y++;X[oa]=X[Z]+"|x|X|\\*";var pa=Y++;X[pa]="[v=\\s]*("+X[oa]+")(?:\\.("+X[oa]+")(?:\\.("+X[oa]+")(?:"+X[ea]+")?"+X[ha]+"?)?)?";var qa=Y++;X[qa]="[v=\\s]*("+X[na]+")(?:\\.("+X[na]+")(?:\\.("+X[na]+")(?:"+X[fa]+")?"+X[ha]+"?)?)?";var ra=Y++;X[ra]="^"+X[ma]+"\\s*"+X[pa]+"$";var sa=Y++;X[sa]="^"+X[ma]+"\\s*"+X[qa]+"$";var ta=Y++;X[ta]="(?:~>?)";var ua=Y++;X[ua]="(\\s*)"+X[ta]+"\\s+",W[ua]=new RegExp(X[ua],"g");var va="$1~",wa=Y++;X[wa]="^"+X[ta]+X[pa]+"$";var xa=Y++;X[xa]="^"+X[ta]+X[qa]+"$";var ya=Y++;X[ya]="(?:\\^)";var za=Y++;X[za]="(\\s*)"+X[ya]+"\\s+",W[za]=new RegExp(X[za],"g");var Aa="$1^",Ba=Y++;X[Ba]="^"+X[ya]+X[pa]+"$";var Ca=Y++;X[Ca]="^"+X[ya]+X[qa]+"$";var Da=Y++;X[Da]="^"+X[ma]+"\\s*("+ka+")$|^$";var Ea=Y++;X[Ea]="^"+X[ma]+"\\s*("+ja+")$|^$";var Fa=Y++;X[Fa]="(\\s*)"+X[ma]+"\\s*("+ka+"|"+X[pa]+")",W[Fa]=new RegExp(X[Fa],"g");var Ga="$1$2$3",Ha=Y++;X[Ha]="^\\s*("+X[pa]+")\\s+-\\s+("+X[pa]+")\\s*$";var Ia=Y++;X[Ia]="^\\s*("+X[qa]+")\\s+-\\s+("+X[qa]+")\\s*$";var Ja=Y++;X[Ja]="(<|>)?=?\\s*\\*";for(var Ka=0;Ka<Y;Ka++)R(Ka,X[Ka]),W[Ka]||(W[Ka]=new RegExp(X[Ka]));T.parse=a,T.valid=b,T.clean=c,window.semver=T.SemVer=d,d.prototype.format=function(){return this.version=this.major+"."+this.minor+"."+this.patch,this.prerelease.length&&(this.version+="-"+this.prerelease.join(".")),this.version},d.prototype.inspect=function(){return'<SemVer "'+this+'">'},d.prototype.toString=function(){return this.version},d.prototype.compare=function(a){return R("SemVer.compare",this.version,this.loose,a),a instanceof d||(a=new d(a,this.loose)),this.compareMain(a)||this.comparePre(a)},d.prototype.compareMain=function(a){return a instanceof d||(a=new d(a,this.loose)),g(this.major,a.major)||g(this.minor,a.minor)||g(this.patch,a.patch)},d.prototype.comparePre=function(a){if(a instanceof d||(a=new d(a,this.loose)),this.prerelease.length&&!a.prerelease.length)return-1;if(!this.prerelease.length&&a.prerelease.length)return 1;if(!this.prerelease.length&&!a.prerelease.length)return 0;var b=0;do{var c=this.prerelease[b],e=a.prerelease[b];if(R("prerelease compare",b,c,e),void 0===c&&void 0===e)return 0;if(void 0===e)return 1;if(void 0===c)return-1;if(c!==e)return g(c,e)}while(++b)},d.prototype.inc=function(a,b){switch(a){case"premajor":this.prerelease.length=0,this.patch=0,this.minor=0,this.major++,this.inc("pre",b);break;case"preminor":this.prerelease.length=0,this.patch=0,this.minor++,this.inc("pre",b);break;case"prepatch":this.prerelease.length=0,this.inc("patch",b),this.inc("pre",b);break;case"prerelease":0===this.prerelease.length&&this.inc("patch",b),this.inc("pre",b);break;case"major":0===this.minor&&0===this.patch&&0!==this.prerelease.length||this.major++,this.minor=0,this.patch=0,this.prerelease=[];break;case"minor":0===this.patch&&0!==this.prerelease.length||this.minor++,this.patch=0,this.prerelease=[];break;case"patch":0===this.prerelease.length&&this.patch++,this.prerelease=[];break;case"pre":if(0===this.prerelease.length)this.prerelease=[0];else{for(var c=this.prerelease.length;--c>=0;)"number"==typeof this.prerelease[c]&&(this.prerelease[c]++,c=-2);c===-1&&this.prerelease.push(0)}b&&(this.prerelease[0]===b?isNaN(this.prerelease[1])&&(this.prerelease=[b,0]):this.prerelease=[b,0]);break;default:throw new Error("invalid increment argument: "+a)}return this.format(),this},T.inc=e,T.diff=f,T.compareIdentifiers=g;var La=/^[0-9]+$/;T.rcompareIdentifiers=h,T.major=i,T.minor=j,T.patch=k,T.compare=l,T.compareLoose=m,T.rcompare=n,T.sort=o,T.rsort=p,T.gt=q,T.lt=r,T.eq=s,T.neq=t,T.gte=u,T.lte=v,T.cmp=w,T.Comparator=x;var Ma={};x.prototype.parse=function(a){var b=this.loose?W[Da]:W[Ea],c=a.match(b);if(!c)throw new TypeError("Invalid comparator: "+a);this.operator=c[1],"="===this.operator&&(this.operator=""),c[2]?this.semver=new d(c[2],this.loose):this.semver=Ma},x.prototype.inspect=function(){return'<SemVer Comparator "'+this+'">'},x.prototype.toString=function(){return this.value},x.prototype.test=function(a){return R("Comparator.test",a,this.loose),this.semver===Ma||("string"==typeof a&&(a=new d(a,this.loose)),w(a,this.operator,this.semver,this.loose))},T.Range=y,y.prototype.inspect=function(){return'<SemVer Range "'+this.range+'">'},y.prototype.format=function(){return this.range=this.set.map(function(a){return a.join(" ").trim()}).join("||").trim(),this.range},y.prototype.toString=function(){return this.range},y.prototype.parseRange=function(a){var b=this.loose;a=a.trim(),R("range",a,b);var c=b?W[Ia]:W[Ha];a=a.replace(c,J),R("hyphen replace",a),a=a.replace(W[Fa],Ga),R("comparator trim",a,W[Fa]),a=a.replace(W[ua],va),a=a.replace(W[za],Aa),a=a.split(/\s+/).join(" ");var d=b?W[Da]:W[Ea],e=a.split(" ").map(function(a){return A(a,b)}).join(" ").split(/\s+/);return this.loose&&(e=e.filter(function(a){return!!a.match(d)})),e=e.map(function(a){return new x(a,b)})},T.toComparators=z,y.prototype.test=function(a){if(!a)return!1;"string"==typeof a&&(a=new d(a,this.loose));for(var b=0;b<this.set.length;b++)if(K(this.set[b],a))return!0;return!1},T.satisfies=L,T.maxSatisfying=M,T.validRange=N,T.ltr=O,T.gtr=P,T.outside=Q,"function"==typeof define&&define.amd&&define(T)}();
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.combined.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.combined.js
new file mode 100644
index 0000000000000000000000000000000000000000..1f96f997ae2caf603a32122ccd20cdf6d728b6a6
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.combined.js
@@ -0,0 +1,5838 @@
+/*! tablesorter (FORK) - updated 01-06-2017 (v2.28.4)*/
+/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
+(function(factory) {
+	if (typeof define === 'function' && define.amd) {
+		define(['jquery'], factory);
+	} else if (typeof module === 'object' && typeof module.exports === 'object') {
+		module.exports = factory(require('jquery'));
+	} else {
+		factory(jQuery);
+	}
+}(function(jQuery) {
+
+/*! TableSorter (FORK) v2.28.4 *//*
+* Client-side table sorting with ease!
+* @requires jQuery v1.2.6+
+*
+* Copyright (c) 2007 Christian Bach
+* fork maintained by Rob Garrison
+*
+* Examples and original docs at: http://tablesorter.com
+* Dual licensed under the MIT and GPL licenses:
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl.html
+*
+* @type jQuery
+* @name tablesorter (FORK)
+* @cat Plugins/Tablesorter
+* @author Christian Bach - christian.bach@polyester.se
+* @contributor Rob Garrison - https://github.com/Mottie/tablesorter
+* @docs (fork) - https://mottie.github.io/tablesorter/docs/
+*/
+/*jshint browser:true, jquery:true, unused:false, expr: true */
+;( function( $ ) {
+	'use strict';
+	var ts = $.tablesorter = {
+
+		version : '2.28.4',
+
+		parsers : [],
+		widgets : [],
+		defaults : {
+
+			// *** appearance
+			theme            : 'default',  // adds tablesorter-{theme} to the table for styling
+			widthFixed       : false,      // adds colgroup to fix widths of columns
+			showProcessing   : false,      // 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  : true,       // prevent text selection in the header
+			tabIndex         : true,       // 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   : true,       // false for German '1.234.567,89' or French '1 234 567,89'
+			delayInit        : false,      // if false, the parsed table contents will not update until the first sort
+			serverSideSorting: false,      // 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           : true,       // 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       : true,       // 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       : false,      // when sorting two rows with exactly the same content, the original sort order is maintained
+
+			sortInitialOrder : 'asc',      // sort direction on first click
+			sortLocaleCompare: false,      // replace equivalent character (accented characters)
+			sortReset        : false,      // third click on the header will reset column to default - unsorted
+			sortRestart      : false,      // 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
+			duplicateSpan    : true,       // colspan cells in the tbody will have duplicated content in the cache for each spanned column
+			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
+			initWidgets      : true,       // apply widgets on tablesorter initialization
+			widgetClass      : 'widget-{name}', // table class name template to match to include a widget
+			widgets          : [],         // method to add widgets, e.g. widgets: ['zebra']
+			widgetOptions    : {
+				zebra : [ 'even', 'odd' ]  // zebra widget alternating row class names
+			},
+
+			// *** 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 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            : false,
+
+			// *** Internal variables
+			headerList: [],
+			empties: {},
+			strings: {},
+			parsers: [],
+
+			// *** parser options for validator; values must be falsy!
+			globalize: 0,
+			imgAttr: 0
+
+			// removed: widgetZebra: { css: ['even', 'odd'] }
+
+		},
+
+		// 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, ',
+			sortDisabled : 'sorting is disabled',
+			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
+		string : {
+			max      : 1,
+			min      : -1,
+			emptymin : 1,
+			emptymax : -1,
+			zero     : 0,
+			none     : 0,
+			'null'   : 0,
+			top      : true,
+			bottom   : false
+		},
+
+		keyCodes : {
+			enter : 13
+		},
+
+		// placeholder date parser data (globalize)
+		dates : {},
+
+		// These methods can be applied on table.config instance
+		instanceMethods : {},
+
+		/*
+		▄█████ ██████ ██████ ██  ██ █████▄
+		▀█▄    ██▄▄     ██   ██  ██ ██▄▄██
+		   ▀█▄ ██▀▀     ██   ██  ██ ██▀▀▀
+		█████▀ ██████   ██   ▀████▀ ██
+		*/
+
+		setup : function( table, c ) {
+			// if no thead or tbody, or tablesorter is already present, quit
+			if ( !table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true ) {
+				if ( c.debug ) {
+					if ( table.hasInitialized ) {
+						console.warn( 'Stopping initialization. Tablesorter has already been initialized' );
+					} else {
+						console.error( 'Stopping initialization! No table, thead or tbody', table );
+					}
+				}
+				return;
+			}
+
+			var tmp = '',
+				$table = $( table ),
+				meta = $.metadata;
+			// initialization flag
+			table.hasInitialized = false;
+			// table is being processed flag
+			table.isProcessing = true;
+			// make sure to store the config object
+			table.config = c;
+			// save the settings where they read
+			$.data( table, 'tablesorter', c );
+			if ( c.debug ) {
+				console[ console.group ? 'group' : 'log' ]( 'Initializing tablesorter v' + ts.version );
+				$.data( table, 'startoveralltimer', new Date() );
+			}
+
+			// removing this in version 3 (only supports jQuery 1.7+)
+			c.supportsDataObject = ( function( version ) {
+				version[ 0 ] = parseInt( version[ 0 ], 10 );
+				return ( version[ 0 ] > 1 ) || ( version[ 0 ] === 1 && parseInt( version[ 1 ], 10 ) >= 4 );
+			})( $.fn.jquery.split( '.' ) );
+			// ensure case insensitivity
+			c.emptyTo = c.emptyTo.toLowerCase();
+			c.stringTo = c.stringTo.toLowerCase();
+			c.last = { sortList : [], clickedIndex : -1 };
+			// add table theme class only if there isn't already one there
+			if ( !/tablesorter\-/.test( $table.attr( 'class' ) ) ) {
+				tmp = ( c.theme !== '' ? ' tablesorter-' + c.theme : '' );
+			}
+			c.table = table;
+			c.$table = $table
+				.addClass( ts.css.table + ' ' + c.tableClass + tmp )
+				.attr( 'role', 'grid' );
+			c.$headers = $table.find( c.selectorHeaders );
+
+			// give the table a unique id, which will be used in namespace binding
+			if ( !c.namespace ) {
+				c.namespace = '.tablesorter' + Math.random().toString( 16 ).slice( 2 );
+			} else {
+				// make sure namespace starts with a period & doesn't have weird characters
+				c.namespace = '.' + c.namespace.replace( ts.regex.nonWord, '' );
+			}
+
+			c.$table.children().children( 'tr' ).attr( 'role', 'row' );
+			c.$tbodies = $table.children( 'tbody:not(.' + c.cssInfoBlock + ')' ).attr({
+				'aria-live' : 'polite',
+				'aria-relevant' : 'all'
+			});
+			if ( c.$table.children( 'caption' ).length ) {
+				tmp = c.$table.children( 'caption' )[ 0 ];
+				if ( !tmp.id ) { tmp.id = c.namespace.slice( 1 ) + 'caption'; }
+				c.$table.attr( 'aria-labelledby', tmp.id );
+			}
+			c.widgetInit = {}; // keep a list of initialized widgets
+			// change textExtraction via data-attribute
+			c.textExtraction = c.$table.attr( 'data-text-extraction' ) || c.textExtraction || 'basic';
+			// build headers
+			ts.buildHeaders( c );
+			// fixate columns if the users supplies the fixedWidth option
+			// do this after theme has been applied
+			ts.fixColumnWidth( table );
+			// add widgets from class name
+			ts.addWidgetFromClass( table );
+			// add widget options before parsing (e.g. grouping widget has parser settings)
+			ts.applyWidgetOptions( table );
+			// try to auto detect column type, and store in tables config
+			ts.setupParsers( c );
+			// start total row count at zero
+			c.totalRows = 0;
+			ts.validateOptions( c );
+			// build the cache for the tbody cells
+			// delayInit will delay building the cache until the user starts a sort
+			if ( !c.delayInit ) { ts.buildCache( c ); }
+			// bind all header events and methods
+			ts.bindEvents( table, c.$headers, true );
+			ts.bindMethods( c );
+			// get sort list from jQuery data or metadata
+			// in jQuery < 1.4, an error occurs when calling $table.data()
+			if ( c.supportsDataObject && typeof $table.data().sortlist !== 'undefined' ) {
+				c.sortList = $table.data().sortlist;
+			} else if ( meta && ( $table.metadata() && $table.metadata().sortlist ) ) {
+				c.sortList = $table.metadata().sortlist;
+			}
+			// apply widget init code
+			ts.applyWidget( table, true );
+			// if user has supplied a sort list to constructor
+			if ( c.sortList.length > 0 ) {
+				ts.sortOn( c, c.sortList, {}, !c.initWidgets );
+			} else {
+				ts.setHeadersCss( c );
+				if ( c.initWidgets ) {
+					// apply widget format
+					ts.applyWidget( table, false );
+				}
+			}
+
+			// show processesing icon
+			if ( c.showProcessing ) {
+				$table
+				.unbind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace )
+				.bind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace, function( e ) {
+					clearTimeout( c.timerProcessing );
+					ts.isProcessing( table );
+					if ( e.type === 'sortBegin' ) {
+						c.timerProcessing = setTimeout( function() {
+							ts.isProcessing( table, true );
+						}, 500 );
+					}
+				});
+			}
+
+			// initialized
+			table.hasInitialized = true;
+			table.isProcessing = false;
+			if ( c.debug ) {
+				console.log( 'Overall initialization time:' + ts.benchmark( $.data( table, 'startoveralltimer' ) ) );
+				if ( c.debug && console.groupEnd ) { console.groupEnd(); }
+			}
+			$table.triggerHandler( 'tablesorter-initialized', table );
+			if ( typeof c.initialized === 'function' ) {
+				c.initialized( table );
+			}
+		},
+
+		bindMethods : function( c ) {
+			var $table = c.$table,
+				namespace = c.namespace,
+				events = ( 'sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete ' +
+					'sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup ' +
+					'mouseleave ' ).split( ' ' )
+					.join( namespace + ' ' );
+			// apply easy methods that trigger bound events
+			$table
+			.unbind( events.replace( ts.regex.spaces, ' ' ) )
+			.bind( 'sortReset' + namespace, function( e, callback ) {
+				e.stopPropagation();
+				// using this.config to ensure functions are getting a non-cached version of the config
+				ts.sortReset( this.config, callback );
+			})
+			.bind( 'updateAll' + namespace, function( e, resort, callback ) {
+				e.stopPropagation();
+				ts.updateAll( this.config, resort, callback );
+			})
+			.bind( 'update' + namespace + ' updateRows' + namespace, function( e, resort, callback ) {
+				e.stopPropagation();
+				ts.update( this.config, resort, callback );
+			})
+			.bind( 'updateHeaders' + namespace, function( e, callback ) {
+				e.stopPropagation();
+				ts.updateHeaders( this.config, callback );
+			})
+			.bind( 'updateCell' + namespace, function( e, cell, resort, callback ) {
+				e.stopPropagation();
+				ts.updateCell( this.config, cell, resort, callback );
+			})
+			.bind( 'addRows' + namespace, function( e, $row, resort, callback ) {
+				e.stopPropagation();
+				ts.addRows( this.config, $row, resort, callback );
+			})
+			.bind( 'updateComplete' + namespace, function() {
+				this.isUpdating = false;
+			})
+			.bind( 'sorton' + namespace, function( e, list, callback, init ) {
+				e.stopPropagation();
+				ts.sortOn( this.config, list, callback, init );
+			})
+			.bind( 'appendCache' + namespace, function( e, callback, init ) {
+				e.stopPropagation();
+				ts.appendCache( this.config, init );
+				if ( $.isFunction( callback ) ) {
+					callback( this );
+				}
+			})
+			// $tbodies variable is used by the tbody sorting widget
+			.bind( 'updateCache' + namespace, function( e, callback, $tbodies ) {
+				e.stopPropagation();
+				ts.updateCache( this.config, callback, $tbodies );
+			})
+			.bind( 'applyWidgetId' + namespace, function( e, id ) {
+				e.stopPropagation();
+				ts.applyWidgetId( this, id );
+			})
+			.bind( 'applyWidgets' + namespace, function( e, init ) {
+				e.stopPropagation();
+				// apply widgets
+				ts.applyWidget( this, init );
+			})
+			.bind( 'refreshWidgets' + namespace, function( e, all, dontapply ) {
+				e.stopPropagation();
+				ts.refreshWidgets( this, all, dontapply );
+			})
+			.bind( 'removeWidget' + namespace, function( e, name, refreshing ) {
+				e.stopPropagation();
+				ts.removeWidget( this, name, refreshing );
+			})
+			.bind( 'destroy' + namespace, function( e, removeClasses, callback ) {
+				e.stopPropagation();
+				ts.destroy( this, removeClasses, callback );
+			})
+			.bind( 'resetToLoadState' + namespace, function( e ) {
+				e.stopPropagation();
+				// remove all widgets
+				ts.removeWidget( this, true, false );
+				var tmp = $.extend( true, {}, c.originalSettings );
+				// restore original settings; this clears out current settings, but does not clear
+				// values saved to storage.
+				c = $.extend( true, ts.defaults, tmp );
+				c.originalSettings = tmp;
+				this.hasInitialized = false;
+				// setup the entire table again
+				ts.setup( this, c );
+			});
+		},
+
+		bindEvents : function( table, $headers, core ) {
+			table = $( table )[ 0 ];
+			var tmp,
+				c = table.config,
+				namespace = c.namespace,
+				downTarget = null;
+			if ( core !== true ) {
+				$headers.addClass( namespace.slice( 1 ) + '_extra_headers' );
+				tmp = $.fn.closest ? $headers.closest( 'table' )[ 0 ] : $headers.parents( 'table' )[ 0 ];
+				if ( tmp && tmp.nodeName === 'TABLE' && tmp !== table ) {
+					$( tmp ).addClass( namespace.slice( 1 ) + '_extra_table' );
+				}
+			}
+			tmp = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
+				.replace( ts.regex.spaces, ' ' )
+				.split( ' ' )
+				.join( namespace + ' ' );
+			// apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
+			$headers
+			// http://stackoverflow.com/questions/5312849/jquery-find-self;
+			.find( c.selectorSort )
+			.add( $headers.filter( c.selectorSort ) )
+			.unbind( tmp )
+			.bind( tmp, function( e, external ) {
+				var $cell, cell, temp,
+					$target = $( e.target ),
+					// wrap event type in spaces, so the match doesn't trigger on inner words
+					type = ' ' + e.type + ' ';
+				// only recognize left clicks
+				if ( ( ( e.which || e.button ) !== 1 && !type.match( ' ' + c.pointerClick + ' | sort | keyup ' ) ) ||
+					// allow pressing enter
+					( type === ' keyup ' && e.which !== ts.keyCodes.enter ) ||
+					// allow triggering a click event (e.which is undefined) & ignore physical clicks
+					( type.match( ' ' + c.pointerClick + ' ' ) && typeof e.which !== 'undefined' ) ) {
+					return;
+				}
+				// ignore mouseup if mousedown wasn't on the same target
+				if ( type.match( ' ' + c.pointerUp + ' ' ) && downTarget !== e.target && external !== true ) {
+					return;
+				}
+				// set target on mousedown
+				if ( type.match( ' ' + c.pointerDown + ' ' ) ) {
+					downTarget = e.target;
+					// preventDefault needed or jQuery v1.3.2 and older throws an
+					// "Uncaught TypeError: handler.apply is not a function" error
+					temp = $target.jquery.split( '.' );
+					if ( temp[ 0 ] === '1' && temp[ 1 ] < 4 ) { e.preventDefault(); }
+					return;
+				}
+				downTarget = null;
+				// prevent sort being triggered on form elements
+				if ( ts.regex.formElements.test( e.target.nodeName ) ||
+					// nosort class name, or elements within a nosort container
+					$target.hasClass( c.cssNoSort ) || $target.parents( '.' + c.cssNoSort ).length > 0 ||
+					// elements within a button
+					$target.parents( 'button' ).length > 0 ) {
+					return !c.cancelSelection;
+				}
+				if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
+					ts.buildCache( c );
+				}
+				// jQuery v1.2.6 doesn't have closest()
+				$cell = $.fn.closest ? $( this ).closest( 'th, td' ) :
+					/TH|TD/.test( this.nodeName ) ? $( this ) : $( this ).parents( 'th, td' );
+				// reference original table headers and find the same cell
+				// don't use $headers or IE8 throws an error - see #987
+				temp = $headers.index( $cell );
+				c.last.clickedIndex = ( temp < 0 ) ? $cell.attr( 'data-column' ) : temp;
+				// use column index if $headers is undefined
+				cell = c.$headers[ c.last.clickedIndex ];
+				if ( cell && !cell.sortDisabled ) {
+					ts.initSort( c, cell, e );
+				}
+			});
+			if ( c.cancelSelection ) {
+				// cancel selection
+				$headers
+					.attr( 'unselectable', 'on' )
+					.bind( 'selectstart', false )
+					.css({
+						'user-select' : 'none',
+						'MozUserSelect' : 'none' // not needed for jQuery 1.8+
+					});
+			}
+		},
+
+		buildHeaders : function( c ) {
+			var $temp, icon, timer, indx;
+			c.headerList = [];
+			c.headerContent = [];
+			c.sortVars = [];
+			if ( c.debug ) {
+				timer = new Date();
+			}
+			// children tr in tfoot - see issue #196 & #547
+			// don't pass table.config to computeColumnIndex here - widgets (math) pass it to "quickly" index tbody cells
+			c.columns = ts.computeColumnIndex( c.$table.children( 'thead, tfoot' ).children( 'tr' ) );
+			// add icon if cssIcon option exists
+			icon = c.cssIcon ?
+				'<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' :
+				'';
+			// redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
+			c.$headers = $( $.map( c.$table.find( c.selectorHeaders ), function( elem, index ) {
+				var configHeaders, header, column, template, tmp,
+					$elem = $( elem );
+				// ignore cell (don't add it to c.$headers) if row has ignoreRow class
+				if ( $elem.parent().hasClass( c.cssIgnoreRow ) ) { return; }
+				// make sure to get header cell & not column indexed cell
+				configHeaders = ts.getColumnData( c.table, c.headers, index, true );
+				// save original header content
+				c.headerContent[ index ] = $elem.html();
+				// if headerTemplate is empty, don't reformat the header cell
+				if ( c.headerTemplate !== '' && !$elem.find( '.' + ts.css.headerIn ).length ) {
+					// set up header template
+					template = c.headerTemplate
+						.replace( ts.regex.templateContent, $elem.html() )
+						.replace( ts.regex.templateIcon, $elem.find( '.' + ts.css.icon ).length ? '' : icon );
+					if ( c.onRenderTemplate ) {
+						header = c.onRenderTemplate.apply( $elem, [ index, template ] );
+						// only change t if something is returned
+						if ( header && typeof header === 'string' ) {
+							template = header;
+						}
+					}
+					$elem.html( '<div class="' + ts.css.headerIn + '">' + template + '</div>' ); // faster than wrapInner
+				}
+				if ( c.onRenderHeader ) {
+					c.onRenderHeader.apply( $elem, [ index, c, c.$table ] );
+				}
+				column = parseInt( $elem.attr( 'data-column' ), 10 );
+				elem.column = column;
+				tmp = ts.getOrder( ts.getData( $elem, configHeaders, 'sortInitialOrder' ) || c.sortInitialOrder );
+				// this may get updated numerous times if there are multiple rows
+				c.sortVars[ column ] = {
+					count : -1, // set to -1 because clicking on the header automatically adds one
+					order:  tmp ?
+						( c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ] ) : // desc, asc, unsorted
+						( c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ] ),  // asc, desc, unsorted
+					lockedOrder : false
+				};
+				tmp = ts.getData( $elem, configHeaders, 'lockedOrder' ) || false;
+				if ( typeof tmp !== 'undefined' && tmp !== false ) {
+					c.sortVars[ column ].lockedOrder = true;
+					c.sortVars[ column ].order = ts.getOrder( tmp ) ? [ 1, 1 ] : [ 0, 0 ];
+				}
+				// add cell to headerList
+				c.headerList[ index ] = elem;
+				// add to parent in case there are multiple rows
+				$elem
+					.addClass( ts.css.header + ' ' + c.cssHeader )
+					.parent()
+					.addClass( ts.css.headerRow + ' ' + c.cssHeaderRow )
+					.attr( 'role', 'row' );
+				// allow keyboard cursor to focus on element
+				if ( c.tabIndex ) {
+					$elem.attr( 'tabindex', 0 );
+				}
+				return elem;
+			}) );
+			// cache headers per column
+			c.$headerIndexed = [];
+			for ( indx = 0; indx < c.columns; indx++ ) {
+				// colspan in header making a column undefined
+				if ( ts.isEmptyObject( c.sortVars[ indx ] ) ) {
+					c.sortVars[ indx ] = {};
+				}
+				$temp = c.$headers.filter( '[data-column="' + indx + '"]' );
+				// target sortable column cells, unless there are none, then use non-sortable cells
+				// .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6
+				c.$headerIndexed[ indx ] = $temp.length ?
+					$temp.not( '.sorter-false' ).length ?
+						$temp.not( '.sorter-false' ).filter( ':last' ) :
+						$temp.filter( ':last' ) :
+					$();
+			}
+			c.$table.find( c.selectorHeaders ).attr({
+				scope: 'col',
+				role : 'columnheader'
+			});
+			// enable/disable sorting
+			ts.updateHeader( c );
+			if ( c.debug ) {
+				console.log( 'Built headers:' + ts.benchmark( timer ) );
+				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( methods ) {
+			$.extend( ts.instanceMethods, methods );
+		},
+
+		/*
+		█████▄ ▄████▄ █████▄ ▄█████ ██████ █████▄ ▄█████
+		██▄▄██ ██▄▄██ ██▄▄██ ▀█▄    ██▄▄   ██▄▄██ ▀█▄
+		██▀▀▀  ██▀▀██ ██▀██     ▀█▄ ██▀▀   ██▀██     ▀█▄
+		██     ██  ██ ██  ██ █████▀ ██████ ██  ██ █████▀
+		*/
+		setupParsers : function( c, $tbodies ) {
+			var rows, list, span, max, colIndex, indx, header, configHeaders,
+				noParser, parser, extractor, time, tbody, len,
+				table = c.table,
+				tbodyIndex = 0,
+				debug = {};
+			// update table bodies in case we start with an empty table
+			c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
+			tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies;
+			len = tbody.length;
+			if ( len === 0 ) {
+				return c.debug ? console.warn( 'Warning: *Empty table!* Not building a parser cache' ) : '';
+			} else if ( c.debug ) {
+				time = new Date();
+				console[ console.group ? 'group' : 'log' ]( 'Detecting parsers for each column' );
+			}
+			list = {
+				extractors: [],
+				parsers: []
+			};
+			while ( tbodyIndex < len ) {
+				rows = tbody[ tbodyIndex ].rows;
+				if ( rows.length ) {
+					colIndex = 0;
+					max = c.columns;
+					for ( indx = 0; indx < max; indx++ ) {
+						header = c.$headerIndexed[ colIndex ];
+						if ( header && header.length ) {
+							// get column indexed table cell
+							configHeaders = ts.getColumnData( table, c.headers, colIndex );
+							// get column parser/extractor
+							extractor = ts.getParserById( ts.getData( header, configHeaders, 'extractor' ) );
+							parser = ts.getParserById( ts.getData( header, configHeaders, 'sorter' ) );
+							noParser = ts.getData( header, configHeaders, 'parser' ) === 'false';
+							// empty cells behaviour - keeping emptyToBottom for backwards compatibility
+							c.empties[colIndex] = (
+								ts.getData( header, configHeaders, 'empty' ) ||
+								c.emptyTo || ( c.emptyToBottom ? 'bottom' : 'top' ) ).toLowerCase();
+							// text strings behaviour in numerical sorts
+							c.strings[colIndex] = (
+								ts.getData( header, configHeaders, 'string' ) ||
+								c.stringTo ||
+								'max' ).toLowerCase();
+							if ( noParser ) {
+								parser = ts.getParserById( 'no-parser' );
+							}
+							if ( !extractor ) {
+								// For now, maybe detect someday
+								extractor = false;
+							}
+							if ( !parser ) {
+								parser = ts.detectParserForColumn( c, rows, -1, colIndex );
+							}
+							if ( c.debug ) {
+								debug[ '(' + colIndex + ') ' + header.text() ] = {
+									parser : parser.id,
+									extractor : extractor ? extractor.id : 'none',
+									string : c.strings[ colIndex ],
+									empty  : c.empties[ colIndex ]
+								};
+							}
+							list.parsers[ colIndex ] = parser;
+							list.extractors[ colIndex ] = extractor;
+							span = header[ 0 ].colSpan - 1;
+							if ( span > 0 ) {
+								colIndex += span;
+								max += span;
+								while ( span + 1 > 0 ) {
+									// set colspan columns to use the same parsers & extractors
+									list.parsers[ colIndex - span ] = parser;
+									list.extractors[ colIndex - span ] = extractor;
+									span--;
+								}
+							}
+						}
+						colIndex++;
+					}
+				}
+				tbodyIndex += ( list.parsers.length ) ? len : 1;
+			}
+			if ( c.debug ) {
+				if ( !ts.isEmptyObject( debug ) ) {
+					console[ console.table ? 'table' : 'log' ]( debug );
+				} else {
+					console.warn( '  No parsers detected!' );
+				}
+				console.log( 'Completed detecting parsers' + ts.benchmark( time ) );
+				if ( console.groupEnd ) { console.groupEnd(); }
+			}
+			c.parsers = list.parsers;
+			c.extractors = list.extractors;
+		},
+
+		addParser : function( parser ) {
+			var indx,
+				len = ts.parsers.length,
+				add = true;
+			for ( indx = 0; indx < len; indx++ ) {
+				if ( ts.parsers[ indx ].id.toLowerCase() === parser.id.toLowerCase() ) {
+					add = false;
+				}
+			}
+			if ( add ) {
+				ts.parsers[ ts.parsers.length ] = parser;
+			}
+		},
+
+		getParserById : function( name ) {
+			/*jshint eqeqeq:false */
+			if ( name == 'false' ) { return false; }
+			var indx,
+				len = ts.parsers.length;
+			for ( indx = 0; indx < len; indx++ ) {
+				if ( ts.parsers[ indx ].id.toLowerCase() === ( name.toString() ).toLowerCase() ) {
+					return ts.parsers[ indx ];
+				}
+			}
+			return false;
+		},
+
+		detectParserForColumn : function( c, rows, rowIndex, cellIndex ) {
+			var cur, $node, row,
+				indx = ts.parsers.length,
+				node = false,
+				nodeValue = '',
+				keepLooking = true;
+			while ( nodeValue === '' && keepLooking ) {
+				rowIndex++;
+				row = rows[ rowIndex ];
+				// stop looking after 50 empty rows
+				if ( row && rowIndex < 50 ) {
+					if ( row.className.indexOf( ts.cssIgnoreRow ) < 0 ) {
+						node = rows[ rowIndex ].cells[ cellIndex ];
+						nodeValue = ts.getElementText( c, node, cellIndex );
+						$node = $( node );
+						if ( c.debug ) {
+							console.log( 'Checking if value was empty on row ' + rowIndex + ', column: ' +
+								cellIndex + ': "' + nodeValue + '"' );
+						}
+					}
+				} else {
+					keepLooking = false;
+				}
+			}
+			while ( --indx >= 0 ) {
+				cur = ts.parsers[ indx ];
+				// ignore the default text parser because it will always be true
+				if ( cur && cur.id !== 'text' && cur.is && cur.is( nodeValue, c.table, node, $node ) ) {
+					return cur;
+				}
+			}
+			// nothing found, return the generic parser (text)
+			return ts.getParserById( 'text' );
+		},
+
+		getElementText : function( c, node, cellIndex ) {
+			if ( !node ) { return ''; }
+			var tmp,
+				extract = c.textExtraction || '',
+				// node could be a jquery object
+				// http://jsperf.com/jquery-vs-instanceof-jquery/2
+				$node = node.jquery ? node : $( node );
+			if ( typeof extract === 'string' ) {
+				// 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/
+				if ( extract === 'basic' && typeof ( tmp = $node.attr( c.textAttribute ) ) !== 'undefined' ) {
+					return $.trim( tmp );
+				}
+				return $.trim( node.textContent || $node.text() );
+			} else {
+				if ( typeof extract === 'function' ) {
+					return $.trim( extract( $node[ 0 ], c.table, cellIndex ) );
+				} else if ( typeof ( tmp = ts.getColumnData( c.table, extract, cellIndex ) ) === 'function' ) {
+					return $.trim( tmp( $node[ 0 ], c.table, cellIndex ) );
+				}
+			}
+			// fallback
+			return $.trim( $node[ 0 ].textContent || $node.text() );
+		},
+
+		// centralized function to extract/parse cell contents
+		getParsedText : function( c, cell, colIndex, txt ) {
+			if ( typeof txt === 'undefined' ) {
+				txt = ts.getElementText( c, cell, colIndex );
+			}
+			// if no parser, make sure to return the txt
+			var val = '' + txt,
+				parser = c.parsers[ colIndex ],
+				extractor = c.extractors[ colIndex ];
+			if ( parser ) {
+				// do extract before parsing, if there is one
+				if ( extractor && typeof extractor.format === 'function' ) {
+					txt = extractor.format( txt, c.table, cell, colIndex );
+				}
+				// 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
+				val = parser.id === 'no-parser' ? '' :
+					// make sure txt is a string (extractor may have converted it)
+					parser.format( '' + txt, c.table, cell, colIndex );
+				if ( c.ignoreCase && typeof val === 'string' ) {
+					val = val.toLowerCase();
+				}
+			}
+			return val;
+		},
+
+		/*
+		▄████▄ ▄████▄ ▄████▄ ██  ██ ██████
+		██  ▀▀ ██▄▄██ ██  ▀▀ ██▄▄██ ██▄▄
+		██  ▄▄ ██▀▀██ ██  ▄▄ ██▀▀██ ██▀▀
+		▀████▀ ██  ██ ▀████▀ ██  ██ ██████
+		*/
+		buildCache : function( c, callback, $tbodies ) {
+			var cache, val, txt, rowIndex, colIndex, tbodyIndex, $tbody, $row,
+				cols, $cells, cell, cacheTime, totalRows, rowData, prevRowData,
+				colMax, span, cacheIndex, hasParser, max, len, index,
+				table = c.table,
+				parsers = c.parsers;
+			// update tbody variable
+			c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
+			$tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies,
+			c.cache = {};
+			c.totalRows = 0;
+			// if no parsers found, return - it's an empty table.
+			if ( !parsers ) {
+				return c.debug ? console.warn( 'Warning: *Empty table!* Not building a cache' ) : '';
+			}
+			if ( c.debug ) {
+				cacheTime = new Date();
+			}
+			// processing icon
+			if ( c.showProcessing ) {
+				ts.isProcessing( table, true );
+			}
+			for ( tbodyIndex = 0; tbodyIndex < $tbody.length; tbodyIndex++ ) {
+				colMax = []; // column max value per tbody
+				cache = c.cache[ tbodyIndex ] = {
+					normalized: [] // array of normalized row data; last entry contains 'rowData' above
+					// colMax: #   // added at the end
+				};
+
+				totalRows = ( $tbody[ tbodyIndex ] && $tbody[ tbodyIndex ].rows.length ) || 0;
+				for ( rowIndex = 0; rowIndex < totalRows; ++rowIndex ) {
+					rowData = {
+						// order: original row order #
+						// $row : jQuery Object[]
+						child: [], // child row text (filter widget)
+						raw: []    // original row text
+					};
+					/** Add the table data to main data array */
+					$row = $( $tbody[ tbodyIndex ].rows[ rowIndex ] );
+					cols = [];
+					// ignore "remove-me" rows
+					if ( $row.hasClass( c.selectorRemove.slice(1) ) ) {
+						continue;
+					}
+					// 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 ( $row.hasClass( c.cssChildRow ) && rowIndex !== 0 ) {
+						len = cache.normalized.length - 1;
+						prevRowData = cache.normalized[ len ][ c.columns ];
+						prevRowData.$row = prevRowData.$row.add( $row );
+						// add 'hasChild' class name to parent row
+						if ( !$row.prev().hasClass( c.cssChildRow ) ) {
+							$row.prev().addClass( ts.css.cssHasChild );
+						}
+						// save child row content (un-parsed!)
+						$cells = $row.children( 'th, td' );
+						len = prevRowData.child.length;
+						prevRowData.child[ len ] = [];
+						// child row content does not account for colspans/rowspans; so indexing may be off
+						cacheIndex = 0;
+						max = c.columns;
+						for ( colIndex = 0; colIndex < max; colIndex++ ) {
+							cell = $cells[ colIndex ];
+							if ( cell ) {
+								prevRowData.child[ len ][ colIndex ] = ts.getParsedText( c, cell, colIndex );
+								span = $cells[ colIndex ].colSpan - 1;
+								if ( span > 0 ) {
+									cacheIndex += span;
+									max += span;
+								}
+							}
+							cacheIndex++;
+						}
+						// go to the next for loop
+						continue;
+					}
+					rowData.$row = $row;
+					rowData.order = rowIndex; // add original row position to rowCache
+					cacheIndex = 0;
+					max = c.columns;
+					for ( colIndex = 0; colIndex < max; ++colIndex ) {
+						cell = $row[ 0 ].cells[ colIndex ];
+						if ( cell && cacheIndex < c.columns ) {
+							hasParser = typeof parsers[ cacheIndex ] !== 'undefined';
+							if ( !hasParser && c.debug ) {
+								console.warn( 'No parser found for row: ' + rowIndex + ', column: ' + colIndex +
+									'; cell containing: "' + $(cell).text() + '"; does it have a header?' );
+							}
+							val = ts.getElementText( c, cell, cacheIndex );
+							rowData.raw[ cacheIndex ] = val; // save original row text
+							// save raw column text even if there is no parser set
+							txt = ts.getParsedText( c, cell, cacheIndex, val );
+							cols[ cacheIndex ] = txt;
+							if ( hasParser && ( parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
+								// determine column max value (ignore sign)
+								colMax[ cacheIndex ] = Math.max( Math.abs( txt ) || 0, colMax[ cacheIndex ] || 0 );
+							}
+							// allow colSpan in tbody
+							span = cell.colSpan - 1;
+							if ( span > 0 ) {
+								index = 0;
+								while ( index <= span ) {
+									// duplicate text (or not) to spanned columns
+									// instead of setting duplicate span to empty string, use textExtraction to try to get a value
+									// see http://stackoverflow.com/q/36449711/145346
+									txt = c.duplicateSpan || index === 0 ?
+										val :
+										typeof c.textExtraction !== 'string' ?
+											ts.getElementText( c, cell, cacheIndex + index ) || '' :
+											'';
+									rowData.raw[ cacheIndex + index ] = txt;
+									cols[ cacheIndex + index ] = txt;
+									index++;
+								}
+								cacheIndex += span;
+								max += span;
+							}
+						}
+						cacheIndex++;
+					}
+					// ensure rowData is always in the same location (after the last column)
+					cols[ c.columns ] = rowData;
+					cache.normalized[ cache.normalized.length ] = cols;
+				}
+				cache.colMax = colMax;
+				// total up rows, not including child rows
+				c.totalRows += cache.normalized.length;
+
+			}
+			if ( c.showProcessing ) {
+				ts.isProcessing( table ); // remove processing icon
+			}
+			if ( c.debug ) {
+				len = Math.min( 5, c.cache[ 0 ].normalized.length );
+				console[ console.group ? 'group' : 'log' ]( 'Building cache for ' + c.totalRows +
+					' rows (showing ' + len + ' rows in log) and ' + c.columns + ' columns' +
+					ts.benchmark( cacheTime ) );
+				val = {};
+				for ( colIndex = 0; colIndex < c.columns; colIndex++ ) {
+					for ( cacheIndex = 0; cacheIndex < len; cacheIndex++ ) {
+						if ( !val[ 'row: ' + cacheIndex ] ) {
+							val[ 'row: ' + cacheIndex ] = {};
+						}
+						val[ 'row: ' + cacheIndex ][ c.$headerIndexed[ colIndex ].text() ] =
+							c.cache[ 0 ].normalized[ cacheIndex ][ colIndex ];
+					}
+				}
+				console[ console.table ? 'table' : 'log' ]( val );
+				if ( console.groupEnd ) { console.groupEnd(); }
+			}
+			if ( $.isFunction( callback ) ) {
+				callback( table );
+			}
+		},
+
+		getColumnText : function( table, column, callback, rowFilter ) {
+			table = $( table )[0];
+			var tbodyIndex, rowIndex, cache, row, tbodyLen, rowLen, raw, parsed, $cell, result,
+				hasCallback = typeof callback === 'function',
+				allColumns = column === 'all',
+				data = { raw : [], parsed: [], $cell: [] },
+				c = table.config;
+			if ( ts.isEmptyObject( c ) ) {
+				if ( c.debug ) {
+					console.warn( 'No cache found - aborting getColumnText function!' );
+				}
+			} else {
+				tbodyLen = c.$tbodies.length;
+				for ( tbodyIndex = 0; tbodyIndex < tbodyLen; tbodyIndex++ ) {
+					cache = c.cache[ tbodyIndex ].normalized;
+					rowLen = cache.length;
+					for ( rowIndex = 0; rowIndex < rowLen; rowIndex++ ) {
+						row = cache[ rowIndex ];
+						if ( rowFilter && !row[ c.columns ].$row.is( rowFilter ) ) {
+							continue;
+						}
+						result = true;
+						parsed = ( allColumns ) ? row.slice( 0, c.columns ) : row[ column ];
+						row = row[ c.columns ];
+						raw = ( allColumns ) ? row.raw : row.raw[ column ];
+						$cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column );
+						if ( hasCallback ) {
+							result = callback({
+								tbodyIndex : tbodyIndex,
+								rowIndex : rowIndex,
+								parsed : parsed,
+								raw : raw,
+								$row : row.$row,
+								$cell : $cell
+							});
+						}
+						if ( result !== false ) {
+							data.parsed[ data.parsed.length ] = parsed;
+							data.raw[ data.raw.length ] = raw;
+							data.$cell[ data.$cell.length ] = $cell;
+						}
+					}
+				}
+				// return everything
+				return data;
+			}
+		},
+
+		/*
+		██  ██ █████▄ █████▄ ▄████▄ ██████ ██████
+		██  ██ ██▄▄██ ██  ██ ██▄▄██   ██   ██▄▄
+		██  ██ ██▀▀▀  ██  ██ ██▀▀██   ██   ██▀▀
+		▀████▀ ██     █████▀ ██  ██   ██   ██████
+		*/
+		setHeadersCss : function( c ) {
+			var $sorted, indx, column,
+				list = c.sortList,
+				len = list.length,
+				none = ts.css.sortNone + ' ' + c.cssNone,
+				css = [ ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc ],
+				cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ],
+				aria = [ 'ascending', 'descending' ],
+				// find the footer
+				$headers = c.$table
+					.find( 'tfoot tr' )
+					.children( 'td, th' )
+					.add( $( c.namespace + '_extra_headers' ) )
+					.removeClass( css.join( ' ' ) );
+			// remove all header information
+			c.$headers
+				.add( $( 'thead ' + c.namespace + '_extra_headers' ) )
+				.removeClass( css.join( ' ' ) )
+				.addClass( none )
+				.attr( 'aria-sort', 'none' )
+				.find( '.' + ts.css.icon )
+				.removeClass( cssIcon.join( ' ' ) )
+				.addClass( cssIcon[ 2 ] );
+			for ( indx = 0; indx < len; indx++ ) {
+				// direction = 2 means reset!
+				if ( list[ indx ][ 1 ] !== 2 ) {
+					// multicolumn sorting updating - see #1005
+					// .not(function(){}) needs jQuery 1.4
+					// filter(function(i, el){}) <- el is undefined in jQuery v1.2.6
+					$sorted = c.$headers.filter( function( i ) {
+						// only include headers that are in the sortList (this includes colspans)
+						var include = true,
+							$el = c.$headers.eq( i ),
+							col = parseInt( $el.attr( 'data-column' ), 10 ),
+							end = col + c.$headers[ i ].colSpan;
+						for ( ; col < end; col++ ) {
+							include = include ? include || ts.isValueInArray( col, c.sortList ) > -1 : false;
+						}
+						return include;
+					});
+
+					// choose the :last in case there are nested columns
+					$sorted = $sorted
+						.not( '.sorter-false' )
+						.filter( '[data-column="' + list[ indx ][ 0 ] + '"]' + ( len === 1 ? ':last' : '' ) );
+					if ( $sorted.length ) {
+						for ( column = 0; column < $sorted.length; column++ ) {
+							if ( !$sorted[ column ].sortDisabled ) {
+								$sorted
+									.eq( column )
+									.removeClass( none )
+									.addClass( css[ list[ indx ][ 1 ] ] )
+									.attr( 'aria-sort', aria[ list[ indx ][ 1 ] ] )
+									.find( '.' + ts.css.icon )
+									.removeClass( cssIcon[ 2 ] )
+									.addClass( cssIcon[ list[ indx ][ 1 ] ] );
+							}
+						}
+						// add sorted class to footer & extra headers, if they exist
+						if ( $headers.length ) {
+							$headers
+								.filter( '[data-column="' + list[ indx ][ 0 ] + '"]' )
+								.removeClass( none )
+								.addClass( css[ list[ indx ][ 1 ] ] );
+						}
+					}
+				}
+			}
+			// add verbose aria labels
+			len = c.$headers.length;
+			for ( indx = 0; indx < len; indx++ ) {
+				ts.setColumnAriaLabel( c, c.$headers.eq( indx ) );
+			}
+		},
+
+		// nextSort (optional), lets you disable next sort text
+		setColumnAriaLabel : function( c, $header, nextSort ) {
+			if ( $header.length ) {
+				var column = parseInt( $header.attr( 'data-column' ), 10 ),
+					vars = c.sortVars[ column ],
+					tmp = $header.hasClass( ts.css.sortAsc ) ?
+						'sortAsc' :
+						$header.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone',
+					txt = $.trim( $header.text() ) + ': ' + ts.language[ tmp ];
+				if ( $header.hasClass( 'sorter-false' ) || nextSort === false ) {
+					txt += ts.language.sortDisabled;
+				} else {
+					tmp = ( vars.count + 1 ) % vars.order.length;
+					nextSort = vars.order[ tmp ];
+					// if nextSort
+					txt += ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ];
+				}
+				$header.attr( 'aria-label', txt );
+			}
+		},
+
+		updateHeader : function( c ) {
+			var index, isDisabled, $header, col,
+				table = c.table,
+				len = c.$headers.length;
+			for ( index = 0; index < len; index++ ) {
+				$header = c.$headers.eq( index );
+				col = ts.getColumnData( table, c.headers, index, true );
+				// add 'sorter-false' class if 'parser-false' is set
+				isDisabled = ts.getData( $header, col, 'sorter' ) === 'false' || ts.getData( $header, col, 'parser' ) === 'false';
+				ts.setColumnSort( c, $header, isDisabled );
+			}
+		},
+
+		setColumnSort : function( c, $header, isDisabled ) {
+			var id = c.table.id;
+			$header[ 0 ].sortDisabled = isDisabled;
+			$header[ isDisabled ? 'addClass' : 'removeClass' ]( 'sorter-false' )
+				.attr( 'aria-disabled', '' + isDisabled );
+			// disable tab index on disabled cells
+			if ( c.tabIndex ) {
+				if ( isDisabled ) {
+					$header.removeAttr( 'tabindex' );
+				} else {
+					$header.attr( 'tabindex', '0' );
+				}
+			}
+			// aria-controls - requires table ID
+			if ( id ) {
+				if ( isDisabled ) {
+					$header.removeAttr( 'aria-controls' );
+				} else {
+					$header.attr( 'aria-controls', id );
+				}
+			}
+		},
+
+		updateHeaderSortCount : function( c, list ) {
+			var col, dir, group, indx, primary, temp, val, order,
+				sortList = list || c.sortList,
+				len = sortList.length;
+			c.sortList = [];
+			for ( indx = 0; indx < len; indx++ ) {
+				val = sortList[ indx ];
+				// ensure all sortList values are numeric - fixes #127
+				col = parseInt( val[ 0 ], 10 );
+				// prevents error if sorton array is wrong
+				if ( col < c.columns ) {
+
+					// set order if not already defined - due to colspan header without associated header cell
+					// adding this check prevents a javascript error
+					if ( !c.sortVars[ col ].order ) {
+						if ( ts.getOrder( c.sortInitialOrder ) ) {
+							order = c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ];
+						} else {
+							order = c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ];
+						}
+						c.sortVars[ col ].order = order;
+						c.sortVars[ col ].count = 0;
+					}
+
+					order = c.sortVars[ col ].order;
+					dir = ( '' + val[ 1 ] ).match( /^(1|d|s|o|n)/ );
+					dir = dir ? dir[ 0 ] : '';
+					// 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext
+					switch ( dir ) {
+						case '1' : case 'd' : // descending
+							dir = 1;
+							break;
+						case 's' : // same direction (as primary column)
+							// if primary sort is set to 's', make it ascending
+							dir = primary || 0;
+							break;
+						case 'o' :
+							temp = order[ ( primary || 0 ) % order.length ];
+							// opposite of primary column; but resets if primary resets
+							dir = temp === 0 ? 1 : temp === 1 ? 0 : 2;
+							break;
+						case 'n' :
+							dir = order[ ( ++c.sortVars[ col ].count ) % order.length ];
+							break;
+						default : // ascending
+							dir = 0;
+							break;
+					}
+					primary = indx === 0 ? dir : primary;
+					group = [ col, parseInt( dir, 10 ) || 0 ];
+					c.sortList[ c.sortList.length ] = group;
+					dir = $.inArray( group[ 1 ], order ); // fixes issue #167
+					c.sortVars[ col ].count = dir >= 0 ? dir : group[ 1 ] % order.length;
+				}
+			}
+		},
+
+		updateAll : function( c, resort, callback ) {
+			var table = c.table;
+			table.isUpdating = true;
+			ts.refreshWidgets( table, true, true );
+			ts.buildHeaders( c );
+			ts.bindEvents( table, c.$headers, true );
+			ts.bindMethods( c );
+			ts.commonUpdate( c, resort, callback );
+		},
+
+		update : function( c, resort, callback ) {
+			var table = c.table;
+			table.isUpdating = true;
+			// update sorting (if enabled/disabled)
+			ts.updateHeader( c );
+			ts.commonUpdate( c, resort, callback );
+		},
+
+		// simple header update - see #989
+		updateHeaders : function( c, callback ) {
+			c.table.isUpdating = true;
+			ts.buildHeaders( c );
+			ts.bindEvents( c.table, c.$headers, true );
+			ts.resortComplete( c, callback );
+		},
+
+		updateCell : function( c, cell, resort, callback ) {
+			if ( ts.isEmptyObject( c.cache ) ) {
+				// empty table, do an update instead - fixes #1099
+				ts.updateHeader( c );
+				ts.commonUpdate( c, resort, callback );
+				return;
+			}
+			c.table.isUpdating = true;
+			c.$table.find( c.selectorRemove ).remove();
+			// get position from the dom
+			var tmp, indx, row, icell, cache, len,
+				$tbodies = c.$tbodies,
+				$cell = $( cell ),
+				// update cache - format: function( s, table, cell, cellIndex )
+				// no closest in jQuery v1.2.6
+				tbodyIndex = $tbodies
+					.index( $.fn.closest ? $cell.closest( 'tbody' ) : $cell.parents( 'tbody' ).filter( ':first' ) ),
+				tbcache = c.cache[ tbodyIndex ],
+				$row = $.fn.closest ? $cell.closest( 'tr' ) : $cell.parents( 'tr' ).filter( ':first' );
+			cell = $cell[ 0 ]; // in case cell is a jQuery object
+			// tbody may not exist if update is initialized while tbody is removed for processing
+			if ( $tbodies.length && tbodyIndex >= 0 ) {
+				row = $tbodies.eq( tbodyIndex ).find( 'tr' ).index( $row );
+				cache = tbcache.normalized[ row ];
+				len = $row[ 0 ].cells.length;
+				if ( len !== c.columns ) {
+					// colspan in here somewhere!
+					icell = 0;
+					tmp = false;
+					for ( indx = 0; indx < len; indx++ ) {
+						if ( !tmp && $row[ 0 ].cells[ indx ] !== cell ) {
+							icell += $row[ 0 ].cells[ indx ].colSpan;
+						} else {
+							tmp = true;
+						}
+					}
+				} else {
+					icell = $cell.index();
+				}
+				tmp = ts.getElementText( c, cell, icell ); // raw
+				cache[ c.columns ].raw[ icell ] = tmp;
+				tmp = ts.getParsedText( c, cell, icell, tmp );
+				cache[ icell ] = tmp; // parsed
+				cache[ c.columns ].$row = $row;
+				if ( ( c.parsers[ icell ].type || '' ).toLowerCase() === 'numeric' ) {
+					// update column max value (ignore sign)
+					tbcache.colMax[ icell ] = Math.max( Math.abs( tmp ) || 0, tbcache.colMax[ icell ] || 0 );
+				}
+				tmp = resort !== 'undefined' ? resort : c.resort;
+				if ( tmp !== false ) {
+					// widgets will be reapplied
+					ts.checkResort( c, tmp, callback );
+				} else {
+					// don't reapply widgets is resort is false, just in case it causes
+					// problems with element focus
+					ts.resortComplete( c, callback );
+				}
+			} else {
+				if ( c.debug ) {
+					console.error( 'updateCell aborted, tbody missing or not within the indicated table' );
+				}
+				c.table.isUpdating = false;
+			}
+		},
+
+		addRows : function( c, $row, resort, callback ) {
+			var txt, val, tbodyIndex, rowIndex, rows, cellIndex, len, order,
+				cacheIndex, rowData, cells, cell, span,
+				// allow passing a row string if only one non-info tbody exists in the table
+				valid = typeof $row === 'string' && c.$tbodies.length === 1 && /<tr/.test( $row || '' ),
+				table = c.table;
+			if ( valid ) {
+				$row = $( $row );
+				c.$tbodies.append( $row );
+			} else if ( !$row ||
+				// row is a jQuery object?
+				!( $row instanceof jQuery ) ||
+				// row contained in the table?
+				( $.fn.closest ? $row.closest( 'table' )[ 0 ] : $row.parents( 'table' )[ 0 ] ) !== c.table ) {
+				if ( 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' );
+				}
+				return false;
+			}
+			table.isUpdating = true;
+			if ( ts.isEmptyObject( c.cache ) ) {
+				// empty table, do an update instead - fixes #450
+				ts.updateHeader( c );
+				ts.commonUpdate( c, resort, callback );
+			} else {
+				rows = $row.filter( 'tr' ).attr( 'role', 'row' ).length;
+				tbodyIndex = c.$tbodies.index( $row.parents( 'tbody' ).filter( ':first' ) );
+				// fixes adding rows to an empty table - see issue #179
+				if ( !( c.parsers && c.parsers.length ) ) {
+					ts.setupParsers( c );
+				}
+				// add each row
+				for ( rowIndex = 0; rowIndex < rows; rowIndex++ ) {
+					cacheIndex = 0;
+					len = $row[ rowIndex ].cells.length;
+					order = c.cache[ tbodyIndex ].normalized.length;
+					cells = [];
+					rowData = {
+						child : [],
+						raw : [],
+						$row : $row.eq( rowIndex ),
+						order : order
+					};
+					// add each cell
+					for ( cellIndex = 0; cellIndex < len; cellIndex++ ) {
+						cell = $row[ rowIndex ].cells[ cellIndex ];
+						txt = ts.getElementText( c, cell, cacheIndex );
+						rowData.raw[ cacheIndex ] = txt;
+						val = ts.getParsedText( c, cell, cacheIndex, txt );
+						cells[ cacheIndex ] = val;
+						if ( ( c.parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
+							// update column max value (ignore sign)
+							c.cache[ tbodyIndex ].colMax[ cacheIndex ] =
+								Math.max( Math.abs( val ) || 0, c.cache[ tbodyIndex ].colMax[ cacheIndex ] || 0 );
+						}
+						span = cell.colSpan - 1;
+						if ( span > 0 ) {
+							cacheIndex += span;
+						}
+						cacheIndex++;
+					}
+					// add the row data to the end
+					cells[ c.columns ] = rowData;
+					// update cache
+					c.cache[ tbodyIndex ].normalized[ order ] = cells;
+				}
+				// resort using current settings
+				ts.checkResort( c, resort, callback );
+			}
+		},
+
+		updateCache : function( c, callback, $tbodies ) {
+			// rebuild parsers
+			if ( !( c.parsers && c.parsers.length ) ) {
+				ts.setupParsers( c, $tbodies );
+			}
+			// rebuild the cache map
+			ts.buildCache( c, callback, $tbodies );
+		},
+
+		// init flag (true) used by pager plugin to prevent widget application
+		// renamed from appendToTable
+		appendCache : function( c, init ) {
+			var parsed, totalRows, $tbody, $curTbody, rowIndex, tbodyIndex, appendTime,
+				table = c.table,
+				wo = c.widgetOptions,
+				$tbodies = c.$tbodies,
+				rows = [],
+				cache = c.cache;
+			// empty table - fixes #206/#346
+			if ( ts.isEmptyObject( cache ) ) {
+				// run pager appender in case the table was just emptied
+				return c.appender ? c.appender( table, rows ) :
+					table.isUpdating ? c.$table.triggerHandler( 'updateComplete', table ) : ''; // Fixes #532
+			}
+			if ( c.debug ) {
+				appendTime = new Date();
+			}
+			for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = $tbodies.eq( tbodyIndex );
+				if ( $tbody.length ) {
+					// detach tbody for manipulation
+					$curTbody = ts.processTbody( table, $tbody, true );
+					parsed = cache[ tbodyIndex ].normalized;
+					totalRows = parsed.length;
+					for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) {
+						rows[rows.length] = parsed[ rowIndex ][ c.columns ].$row;
+						// removeRows used by the pager plugin; don't render if using ajax - fixes #411
+						if ( !c.appender || ( c.pager && ( !c.pager.removeRows || !wo.pager_removeRows ) && !c.pager.ajax ) ) {
+							$curTbody.append( parsed[ rowIndex ][ c.columns ].$row );
+						}
+					}
+					// restore tbody
+					ts.processTbody( table, $curTbody, false );
+				}
+			}
+			if ( c.appender ) {
+				c.appender( table, rows );
+			}
+			if ( c.debug ) {
+				console.log( 'Rebuilt table' + ts.benchmark( appendTime ) );
+			}
+			// apply table widgets; but not before ajax completes
+			if ( !init && !c.appender ) {
+				ts.applyWidget( table );
+			}
+			if ( table.isUpdating ) {
+				c.$table.triggerHandler( 'updateComplete', table );
+			}
+		},
+
+		commonUpdate : function( c, resort, callback ) {
+			// remove rows/elements before update
+			c.$table.find( c.selectorRemove ).remove();
+			// rebuild parsers
+			ts.setupParsers( c );
+			// rebuild the cache map
+			ts.buildCache( c );
+			ts.checkResort( c, resort, callback );
+		},
+
+		/*
+		▄█████ ▄████▄ █████▄ ██████ ██ █████▄ ▄████▄
+		▀█▄    ██  ██ ██▄▄██   ██   ██ ██  ██ ██ ▄▄▄
+		   ▀█▄ ██  ██ ██▀██    ██   ██ ██  ██ ██ ▀██
+		█████▀ ▀████▀ ██  ██   ██   ██ ██  ██ ▀████▀
+		*/
+		initSort : function( c, cell, event ) {
+			if ( c.table.isUpdating ) {
+				// let any updates complete before initializing a sort
+				return setTimeout( function(){
+					ts.initSort( c, cell, event );
+				}, 50 );
+			}
+
+			var arry, indx, headerIndx, dir, temp, tmp, $header,
+				notMultiSort = !event[ c.sortMultiSortKey ],
+				table = c.table,
+				len = c.$headers.length,
+				// get current column index
+				col = parseInt( $( cell ).attr( 'data-column' ), 10 ),
+				order = c.sortVars[ col ].order;
+
+			// Only call sortStart if sorting is enabled
+			c.$table.triggerHandler( 'sortStart', table );
+			// get current column sort order
+			tmp = ( c.sortVars[ col ].count + 1 ) % order.length;
+			c.sortVars[ col ].count = event[ c.sortResetKey ] ? 2 : tmp;
+			// reset all sorts on non-current column - issue #30
+			if ( c.sortRestart ) {
+				for ( headerIndx = 0; headerIndx < len; headerIndx++ ) {
+					$header = c.$headers.eq( headerIndx );
+					tmp = parseInt( $header.attr( 'data-column' ), 10 );
+					// only reset counts on columns that weren't just clicked on and if not included in a multisort
+					if ( col !== tmp && ( notMultiSort || $header.hasClass( ts.css.sortNone ) ) ) {
+						c.sortVars[ tmp ].count = -1;
+					}
+				}
+			}
+			// user only wants to sort on one column
+			if ( notMultiSort ) {
+				// flush the sort list
+				c.sortList = [];
+				c.last.sortList = [];
+				if ( c.sortForce !== null ) {
+					arry = c.sortForce;
+					for ( indx = 0; indx < arry.length; indx++ ) {
+						if ( arry[ indx ][ 0 ] !== col ) {
+							c.sortList[ c.sortList.length ] = arry[ indx ];
+						}
+					}
+				}
+				// add column to sort list
+				dir = order[ c.sortVars[ col ].count ];
+				if ( dir < 2 ) {
+					c.sortList[ c.sortList.length ] = [ col, dir ];
+					// add other columns if header spans across multiple
+					if ( cell.colSpan > 1 ) {
+						for ( indx = 1; indx < cell.colSpan; indx++ ) {
+							c.sortList[ c.sortList.length ] = [ col + indx, dir ];
+							// update count on columns in colSpan
+							c.sortVars[ col + indx ].count = $.inArray( dir, order );
+						}
+					}
+				}
+				// multi column sorting
+			} else {
+				// get rid of the sortAppend before adding more - fixes issue #115 & #523
+				c.sortList = $.extend( [], c.last.sortList );
+
+				// the user has clicked on an already sorted column
+				if ( ts.isValueInArray( col, c.sortList ) >= 0 ) {
+					// reverse the sorting direction
+					for ( indx = 0; indx < c.sortList.length; indx++ ) {
+						tmp = c.sortList[ indx ];
+						if ( tmp[ 0 ] === col ) {
+							// order.count seems to be incorrect when compared to cell.count
+							tmp[ 1 ] = order[ c.sortVars[ col ].count ];
+							if ( tmp[1] === 2 ) {
+								c.sortList.splice( indx, 1 );
+								c.sortVars[ col ].count = -1;
+							}
+						}
+					}
+				} else {
+					// add column to sort list array
+					dir = order[ c.sortVars[ col ].count ];
+					if ( dir < 2 ) {
+						c.sortList[ c.sortList.length ] = [ col, dir ];
+						// add other columns if header spans across multiple
+						if ( cell.colSpan > 1 ) {
+							for ( indx = 1; indx < cell.colSpan; indx++ ) {
+								c.sortList[ c.sortList.length ] = [ col + indx, dir ];
+								// update count on columns in colSpan
+								c.sortVars[ col + indx ].count = $.inArray( dir, order );
+							}
+						}
+					}
+				}
+			}
+			// save sort before applying sortAppend
+			c.last.sortList = $.extend( [], c.sortList );
+			if ( c.sortList.length && c.sortAppend ) {
+				arry = $.isArray( c.sortAppend ) ? c.sortAppend : c.sortAppend[ c.sortList[ 0 ][ 0 ] ];
+				if ( !ts.isEmptyObject( arry ) ) {
+					for ( indx = 0; indx < arry.length; indx++ ) {
+						if ( arry[ indx ][ 0 ] !== col && ts.isValueInArray( arry[ indx ][ 0 ], c.sortList ) < 0 ) {
+							dir = arry[ indx ][ 1 ];
+							temp = ( '' + dir ).match( /^(a|d|s|o|n)/ );
+							if ( temp ) {
+								tmp = c.sortList[ 0 ][ 1 ];
+								switch ( temp[ 0 ] ) {
+									case 'd' :
+										dir = 1;
+										break;
+									case 's' :
+										dir = tmp;
+										break;
+									case 'o' :
+										dir = tmp === 0 ? 1 : 0;
+										break;
+									case 'n' :
+										dir = ( tmp + 1 ) % order.length;
+										break;
+									default:
+										dir = 0;
+										break;
+								}
+							}
+							c.sortList[ c.sortList.length ] = [ arry[ indx ][ 0 ], dir ];
+						}
+					}
+				}
+			}
+			// sortBegin event triggered immediately before the sort
+			c.$table.triggerHandler( 'sortBegin', table );
+			// setTimeout needed so the processing icon shows up
+			setTimeout( function() {
+				// set css for headers
+				ts.setHeadersCss( c );
+				ts.multisort( c );
+				ts.appendCache( c );
+				c.$table.triggerHandler( 'sortBeforeEnd', table );
+				c.$table.triggerHandler( 'sortEnd', table );
+			}, 1 );
+		},
+
+		// sort multiple columns
+		multisort : function( c ) { /*jshint loopfunc:true */
+			var tbodyIndex, sortTime, colMax, rows, tmp,
+				table = c.table,
+				sorter = [],
+				dir = 0,
+				textSorter = c.textSorter || '',
+				sortList = c.sortList,
+				sortLen = sortList.length,
+				len = c.$tbodies.length;
+			if ( c.serverSideSorting || ts.isEmptyObject( c.cache ) ) {
+				// empty table - fixes #206/#346
+				return;
+			}
+			if ( c.debug ) { sortTime = new Date(); }
+			// cache textSorter to optimize speed
+			if ( typeof textSorter === 'object' ) {
+				colMax = c.columns;
+				while ( colMax-- ) {
+					tmp = ts.getColumnData( table, textSorter, colMax );
+					if ( typeof tmp === 'function' ) {
+						sorter[ colMax ] = tmp;
+					}
+				}
+			}
+			for ( tbodyIndex = 0; tbodyIndex < len; tbodyIndex++ ) {
+				colMax = c.cache[ tbodyIndex ].colMax;
+				rows = c.cache[ tbodyIndex ].normalized;
+
+				rows.sort( function( a, b ) {
+					var sortIndex, num, col, order, sort, x, y;
+					// rows is undefined here in IE, so don't use it!
+					for ( sortIndex = 0; sortIndex < sortLen; sortIndex++ ) {
+						col = sortList[ sortIndex ][ 0 ];
+						order = sortList[ sortIndex ][ 1 ];
+						// sort direction, true = asc, false = desc
+						dir = order === 0;
+
+						if ( c.sortStable && a[ col ] === b[ col ] && sortLen === 1 ) {
+							return a[ c.columns ].order - b[ c.columns ].order;
+						}
+
+						// fallback to natural sort since it is more robust
+						num = /n/i.test( ts.getSortType( c.parsers, col ) );
+						if ( num && c.strings[ col ] ) {
+							// sort strings in numerical columns
+							if ( typeof ( ts.string[ c.strings[ col ] ] ) === 'boolean' ) {
+								num = ( dir ? 1 : -1 ) * ( ts.string[ c.strings[ col ] ] ? -1 : 1 );
+							} else {
+								num = ( c.strings[ col ] ) ? ts.string[ c.strings[ col ] ] || 0 : 0;
+							}
+							// fall back to built-in numeric sort
+							// var sort = $.tablesorter['sort' + s]( a[col], b[col], dir, colMax[col], table );
+							sort = c.numberSorter ? c.numberSorter( a[ col ], b[ col ], dir, colMax[ col ], table ) :
+								ts[ 'sortNumeric' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ], b[ col ], num, colMax[ col ], col, c );
+						} else {
+							// set a & b depending on sort direction
+							x = dir ? a : b;
+							y = dir ? b : a;
+							// text sort function
+							if ( typeof textSorter === 'function' ) {
+								// custom OVERALL text sorter
+								sort = textSorter( x[ col ], y[ col ], dir, col, table );
+							} else if ( typeof sorter[ col ] === 'function' ) {
+								// custom text sorter for a SPECIFIC COLUMN
+								sort = sorter[ col ]( x[ col ], y[ col ], dir, col, table );
+							} else {
+								// fall back to natural sort
+								sort = ts[ 'sortNatural' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ], b[ col ], col, c );
+							}
+						}
+						if ( sort ) { return sort; }
+					}
+					return a[ c.columns ].order - b[ c.columns ].order;
+				});
+			}
+			if ( c.debug ) {
+				console.log( 'Applying sort ' + sortList.toString() + ts.benchmark( sortTime ) );
+			}
+		},
+
+		resortComplete : function( c, callback ) {
+			if ( c.table.isUpdating ) {
+				c.$table.triggerHandler( 'updateComplete', c.table );
+			}
+			if ( $.isFunction( callback ) ) {
+				callback( c.table );
+			}
+		},
+
+		checkResort : function( c, resort, callback ) {
+			var sortList = $.isArray( resort ) ? resort : c.sortList,
+				// if no resort parameter is passed, fallback to config.resort (true by default)
+				resrt = typeof resort === 'undefined' ? c.resort : resort;
+			// don't try to resort if the table is still processing
+			// this will catch spamming of the updateCell method
+			if ( resrt !== false && !c.serverSideSorting && !c.table.isProcessing ) {
+				if ( sortList.length ) {
+					ts.sortOn( c, sortList, function() {
+						ts.resortComplete( c, callback );
+					}, true );
+				} else {
+					ts.sortReset( c, function() {
+						ts.resortComplete( c, callback );
+						ts.applyWidget( c.table, false );
+					} );
+				}
+			} else {
+				ts.resortComplete( c, callback );
+				ts.applyWidget( c.table, false );
+			}
+		},
+
+		sortOn : function( c, list, callback, init ) {
+			var table = c.table;
+			c.$table.triggerHandler( 'sortStart', table );
+			// update header count index
+			ts.updateHeaderSortCount( c, list );
+			// set css for headers
+			ts.setHeadersCss( c );
+			// fixes #346
+			if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
+				ts.buildCache( c );
+			}
+			c.$table.triggerHandler( 'sortBegin', table );
+			// sort the table and append it to the dom
+			ts.multisort( c );
+			ts.appendCache( c, init );
+			c.$table.triggerHandler( 'sortBeforeEnd', table );
+			c.$table.triggerHandler( 'sortEnd', table );
+			ts.applyWidget( table );
+			if ( $.isFunction( callback ) ) {
+				callback( table );
+			}
+		},
+
+		sortReset : function( c, callback ) {
+			c.sortList = [];
+			ts.setHeadersCss( c );
+			ts.multisort( c );
+			ts.appendCache( c );
+			if ( $.isFunction( callback ) ) {
+				callback( c.table );
+			}
+		},
+
+		getSortType : function( parsers, column ) {
+			return ( parsers && parsers[ column ] ) ? parsers[ column ].type || '' : '';
+		},
+
+		getOrder : function( val ) {
+			// look for 'd' in 'desc' order; return true
+			return ( /^d/i.test( val ) || val === 1 );
+		},
+
+		// 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, b ) {
+			if ( a === b ) { return 0; }
+			var aNum, bNum, aFloat, bFloat, indx, max,
+				regex = ts.regex;
+			// first try and sort Hex codes
+			if ( regex.hex.test( b ) ) {
+				aNum = parseInt( ( a || '' ).match( regex.hex ), 16 );
+				bNum = parseInt( ( b || '' ).match( regex.hex ), 16 );
+				if ( aNum < bNum ) { return -1; }
+				if ( aNum > bNum ) { return 1; }
+			}
+			// chunk/tokenize
+			aNum = ( a || '' ).replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
+			bNum = ( b || '' ).replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
+			max = Math.max( aNum.length, bNum.length );
+			// natural sorting through split numeric strings and default strings
+			for ( indx = 0; indx < max; indx++ ) {
+				// find floats not starting with '0', string or 0 if not defined
+				aFloat = isNaN( aNum[ indx ] ) ? aNum[ indx ] || 0 : parseFloat( aNum[ indx ] ) || 0;
+				bFloat = isNaN( bNum[ indx ] ) ? bNum[ indx ] || 0 : parseFloat( bNum[ indx ] ) || 0;
+				// handle numeric vs string comparison - number < string - (Kyle Adams)
+				if ( isNaN( aFloat ) !== isNaN( bFloat ) ) { return isNaN( aFloat ) ? 1 : -1; }
+				// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
+				if ( typeof aFloat !== typeof bFloat ) {
+					aFloat += '';
+					bFloat += '';
+				}
+				if ( aFloat < bFloat ) { return -1; }
+				if ( aFloat > bFloat ) { return 1; }
+			}
+			return 0;
+		},
+
+		sortNaturalAsc : function( a, b, col, c ) {
+			if ( a === b ) { return 0; }
+			var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
+			if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
+			if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
+			return ts.sortNatural( a, b );
+		},
+
+		sortNaturalDesc : function( a, b, col, c ) {
+			if ( a === b ) { return 0; }
+			var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
+			if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
+			if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
+			return ts.sortNatural( b, a );
+		},
+
+		// basic alphabetical sort
+		sortText : function( a, b ) {
+			return a > b ? 1 : ( a < b ? -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( val, num, max ) {
+			if ( max ) {
+				// make sure the text value is greater than the max numerical value (max)
+				var indx,
+					len = val ? val.length : 0,
+					n = max + num;
+				for ( indx = 0; indx < len; indx++ ) {
+					n += val.charCodeAt( indx );
+				}
+				return num * n;
+			}
+			return 0;
+		},
+
+		sortNumericAsc : function( a, b, num, max, col, c ) {
+			if ( a === b ) { return 0; }
+			var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
+			if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
+			if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
+			if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
+			if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
+			return a - b;
+		},
+
+		sortNumericDesc : function( a, b, num, max, col, c ) {
+			if ( a === b ) { return 0; }
+			var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
+			if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
+			if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
+			if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
+			if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
+			return b - a;
+		},
+
+		sortNumeric : function( a, b ) {
+			return a - b;
+		},
+
+		/*
+		██ ██ ██ ██ █████▄ ▄████▄ ██████ ██████ ▄█████
+		██ ██ ██ ██ ██  ██ ██ ▄▄▄ ██▄▄     ██   ▀█▄
+		██ ██ ██ ██ ██  ██ ██ ▀██ ██▀▀     ██      ▀█▄
+		███████▀ ██ █████▀ ▀████▀ ██████   ██   █████▀
+		*/
+		addWidget : function( widget ) {
+			if ( widget.id && !ts.isEmptyObject( ts.getWidgetById( widget.id ) ) ) {
+				console.warn( '"' + widget.id + '" widget was loaded more than once!' );
+			}
+			ts.widgets[ ts.widgets.length ] = widget;
+		},
+
+		hasWidget : function( $table, name ) {
+			$table = $( $table );
+			return $table.length && $table[ 0 ].config && $table[ 0 ].config.widgetInit[ name ] || false;
+		},
+
+		getWidgetById : function( name ) {
+			var indx, widget,
+				len = ts.widgets.length;
+			for ( indx = 0; indx < len; indx++ ) {
+				widget = ts.widgets[ indx ];
+				if ( widget && widget.id && widget.id.toLowerCase() === name.toLowerCase() ) {
+					return widget;
+				}
+			}
+		},
+
+		applyWidgetOptions : function( table ) {
+			var indx, widget,
+				c = table.config,
+				len = c.widgets.length;
+			if ( len ) {
+				for ( indx = 0; indx < len; indx++ ) {
+					widget = ts.getWidgetById( c.widgets[ indx ] );
+					if ( widget && widget.options ) {
+						c.widgetOptions = $.extend( true, {}, widget.options, c.widgetOptions );
+						// add widgetOptions to defaults for option validator
+						$.extend( true, ts.defaults.widgetOptions, widget.options );
+					}
+				}
+			}
+		},
+
+		addWidgetFromClass : function( table ) {
+			var len, indx,
+				c = table.config,
+				// look for widgets to apply from table class
+				// don't match from 'ui-widget-content'; use \S instead of \w to include widgets
+				// with dashes in the name, e.g. "widget-test-2" extracts out "test-2"
+				regex = '^' + c.widgetClass.replace( ts.regex.templateName, '(\\S+)+' ) + '$',
+				widgetClass = new RegExp( regex, 'g' ),
+				// split up table class (widget id's can include dashes) - stop using match
+				// otherwise only one widget gets extracted, see #1109
+				widgets = ( table.className || '' ).split( ts.regex.spaces );
+			if ( widgets.length ) {
+				len = widgets.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					if ( widgets[ indx ].match( widgetClass ) ) {
+						c.widgets[ c.widgets.length ] = widgets[ indx ].replace( widgetClass, '$1' );
+					}
+				}
+			}
+		},
+
+		applyWidgetId : function( table, id, init ) {
+			table = $(table)[0];
+			var applied, time, name,
+				c = table.config,
+				wo = c.widgetOptions,
+				widget = ts.getWidgetById( id );
+			if ( widget ) {
+				name = widget.id;
+				applied = false;
+				// add widget name to option list so it gets reapplied after sorting, filtering, etc
+				if ( $.inArray( name, c.widgets ) < 0 ) {
+					c.widgets[ c.widgets.length ] = name;
+				}
+				if ( c.debug ) { time = new Date(); }
+
+				if ( init || !( c.widgetInit[ name ] ) ) {
+					// set init flag first to prevent calling init more than once (e.g. pager)
+					c.widgetInit[ name ] = true;
+					if ( table.hasInitialized ) {
+						// don't reapply widget options on tablesorter init
+						ts.applyWidgetOptions( table );
+					}
+					if ( typeof widget.init === 'function' ) {
+						applied = true;
+						if ( c.debug ) {
+							console[ console.group ? 'group' : 'log' ]( 'Initializing ' + name + ' widget' );
+						}
+						widget.init( table, widget, c, wo );
+					}
+				}
+				if ( !init && typeof widget.format === 'function' ) {
+					applied = true;
+					if ( c.debug ) {
+						console[ console.group ? 'group' : 'log' ]( 'Updating ' + name + ' widget' );
+					}
+					widget.format( table, c, wo, false );
+				}
+				if ( c.debug ) {
+					if ( applied ) {
+						console.log( 'Completed ' + ( init ? 'initializing ' : 'applying ' ) + name + ' widget' + ts.benchmark( time ) );
+						if ( console.groupEnd ) { console.groupEnd(); }
+					}
+				}
+			}
+		},
+
+		applyWidget : function( table, init, callback ) {
+			table = $( table )[ 0 ]; // in case this is called externally
+			var indx, len, names, widget, time,
+				c = table.config,
+				widgets = [];
+			// prevent numerous consecutive widget applications
+			if ( init !== false && table.hasInitialized && ( table.isApplyingWidgets || table.isUpdating ) ) {
+				return;
+			}
+			if ( c.debug ) { time = new Date(); }
+			ts.addWidgetFromClass( table );
+			// prevent "tablesorter-ready" from firing multiple times in a row
+			clearTimeout( c.timerReady );
+			if ( c.widgets.length ) {
+				table.isApplyingWidgets = true;
+				// ensure unique widget ids
+				c.widgets = $.grep( c.widgets, function( val, index ) {
+					return $.inArray( val, c.widgets ) === index;
+				});
+				names = c.widgets || [];
+				len = names.length;
+				// build widget array & add priority as needed
+				for ( indx = 0; indx < len; indx++ ) {
+					widget = ts.getWidgetById( names[ indx ] );
+					if ( widget && widget.id ) {
+						// set priority to 10 if not defined
+						if ( !widget.priority ) { widget.priority = 10; }
+						widgets[ indx ] = widget;
+					} else if ( c.debug ) {
+						console.warn( '"' + names[ indx ] + '" widget code does not exist!' );
+					}
+				}
+				// sort widgets by priority
+				widgets.sort( function( a, b ) {
+					return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1;
+				});
+				// add/update selected widgets
+				len = widgets.length;
+				if ( c.debug ) {
+					console[ console.group ? 'group' : 'log' ]( 'Start ' + ( init ? 'initializing' : 'applying' ) + ' widgets' );
+				}
+				for ( indx = 0; indx < len; indx++ ) {
+					widget = widgets[ indx ];
+					if ( widget && widget.id ) {
+						ts.applyWidgetId( table, widget.id, init );
+					}
+				}
+				if ( c.debug && console.groupEnd ) { console.groupEnd(); }
+				// callback executed on init only
+				if ( !init && typeof callback === 'function' ) {
+					callback( table );
+				}
+			}
+			c.timerReady = setTimeout( function() {
+				table.isApplyingWidgets = false;
+				$.data( table, 'lastWidgetApplication', new Date() );
+				c.$table.triggerHandler( 'tablesorter-ready' );
+			}, 10 );
+			if ( c.debug ) {
+				widget = c.widgets.length;
+				console.log( 'Completed ' +
+					( init === true ? 'initializing ' : 'applying ' ) + widget +
+					' widget' + ( widget !== 1 ? 's' : '' ) + ts.benchmark( time ) );
+			}
+		},
+
+		removeWidget : function( table, name, refreshing ) {
+			table = $( table )[ 0 ];
+			var index, widget, indx, len,
+				c = table.config;
+			// if name === true, add all widgets from $.tablesorter.widgets
+			if ( name === true ) {
+				name = [];
+				len = ts.widgets.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					widget = ts.widgets[ indx ];
+					if ( widget && widget.id ) {
+						name[ name.length ] = widget.id;
+					}
+				}
+			} else {
+				// name can be either an array of widgets names,
+				// or a space/comma separated list of widget names
+				name = ( $.isArray( name ) ? name.join( ',' ) : name || '' ).toLowerCase().split( /[\s,]+/ );
+			}
+			len = name.length;
+			for ( index = 0; index < len; index++ ) {
+				widget = ts.getWidgetById( name[ index ] );
+				indx = $.inArray( name[ index ], c.widgets );
+				// don't remove the widget from config.widget if refreshing
+				if ( indx >= 0 && refreshing !== true ) {
+					c.widgets.splice( indx, 1 );
+				}
+				if ( widget && widget.remove ) {
+					if ( c.debug ) {
+						console.log( ( refreshing ? 'Refreshing' : 'Removing' ) + ' "' + name[ index ] + '" widget' );
+					}
+					widget.remove( table, c, c.widgetOptions, refreshing );
+					c.widgetInit[ name[ index ] ] = false;
+				}
+			}
+		},
+
+		refreshWidgets : function( table, doAll, dontapply ) {
+			table = $( table )[ 0 ]; // see issue #243
+			var indx, widget,
+				c = table.config,
+				curWidgets = c.widgets,
+				widgets = ts.widgets,
+				len = widgets.length,
+				list = [],
+				callback = function( table ) {
+					$( table ).triggerHandler( 'refreshComplete' );
+				};
+			// remove widgets not defined in config.widgets, unless doAll is true
+			for ( indx = 0; indx < len; indx++ ) {
+				widget = widgets[ indx ];
+				if ( widget && widget.id && ( doAll || $.inArray( widget.id, curWidgets ) < 0 ) ) {
+					list[ list.length ] = widget.id;
+				}
+			}
+			ts.removeWidget( table, list.join( ',' ), true );
+			if ( dontapply !== true ) {
+				// call widget init if
+				ts.applyWidget( table, doAll || false, callback );
+				if ( doAll ) {
+					// apply widget format
+					ts.applyWidget( table, false, callback );
+				}
+			} else {
+				callback( table );
+			}
+		},
+
+		/*
+		██  ██ ██████ ██ ██     ██ ██████ ██ ██████ ▄█████
+		██  ██   ██   ██ ██     ██   ██   ██ ██▄▄   ▀█▄
+		██  ██   ██   ██ ██     ██   ██   ██ ██▀▀      ▀█▄
+		▀████▀   ██   ██ ██████ ██   ██   ██ ██████ █████▀
+		*/
+		benchmark : function( diff ) {
+			return ( ' (' + ( new Date().getTime() - diff.getTime() ) + ' ms)' );
+		},
+		// deprecated ts.log
+		log : function() {
+			console.log( arguments );
+		},
+
+		// $.isEmptyObject from jQuery v1.4
+		isEmptyObject : function( obj ) {
+			/*jshint forin: false */
+			for ( var name in obj ) {
+				return false;
+			}
+			return true;
+		},
+
+		isValueInArray : function( column, arry ) {
+			var indx,
+				len = arry && arry.length || 0;
+			for ( indx = 0; indx < len; indx++ ) {
+				if ( arry[ indx ][ 0 ] === column ) {
+					return indx;
+				}
+			}
+			return -1;
+		},
+
+		formatFloat : function( str, table ) {
+			if ( typeof str !== 'string' || str === '' ) { return str; }
+			// allow using formatFloat without a table; defaults to US number format
+			var num,
+				usFormat = table && table.config ? table.config.usNumberFormat !== false :
+					typeof table !== 'undefined' ? table : true;
+			if ( usFormat ) {
+				// US Format - 1,234,567.89 -> 1234567.89
+				str = str.replace( ts.regex.comma, '' );
+			} else {
+				// German Format = 1.234.567,89 -> 1234567.89
+				// French Format = 1 234 567,89 -> 1234567.89
+				str = str.replace( ts.regex.digitNonUS, '' ).replace( ts.regex.comma, '.' );
+			}
+			if ( ts.regex.digitNegativeTest.test( str ) ) {
+				// make (#) into a negative number -> (10) = -10
+				str = str.replace( ts.regex.digitNegativeReplace, '-$1' );
+			}
+			num = parseFloat( str );
+			// return the text instead of zero
+			return isNaN( num ) ? $.trim( str ) : num;
+		},
+
+		isDigit : function( str ) {
+			// replace all unwanted chars and match
+			return isNaN( str ) ?
+				ts.regex.digitTest.test( str.toString().replace( ts.regex.digitReplace, '' ) ) :
+				str !== '';
+		},
+
+		// computeTableHeaderCellIndexes from:
+		// http://www.javascripttoolbox.com/lib/table/examples.php
+		// http://www.javascripttoolbox.com/temp/table_cellindex.html
+		computeColumnIndex : function( $rows, c ) {
+			var i, j, k, l, cell, cells, rowIndex, rowSpan, colSpan, firstAvailCol,
+				// total columns has been calculated, use it to set the matrixrow
+				columns = c && c.columns || 0,
+				matrix = [],
+				matrixrow = new Array( columns );
+			for ( i = 0; i < $rows.length; i++ ) {
+				cells = $rows[ i ].cells;
+				for ( j = 0; j < cells.length; j++ ) {
+					cell = cells[ j ];
+					rowIndex = cell.parentNode.rowIndex;
+					rowSpan = cell.rowSpan || 1;
+					colSpan = cell.colSpan || 1;
+					if ( typeof matrix[ rowIndex ] === 'undefined' ) {
+						matrix[ rowIndex ] = [];
+					}
+					// Find first available column in the first row
+					for ( k = 0; k < matrix[ rowIndex ].length + 1; k++ ) {
+						if ( typeof matrix[ rowIndex ][ k ] === 'undefined' ) {
+							firstAvailCol = k;
+							break;
+						}
+					}
+					// jscs:disable disallowEmptyBlocks
+					if ( columns && cell.cellIndex === firstAvailCol ) {
+						// don't to anything
+					} else if ( cell.setAttribute ) {
+						// jscs:enable disallowEmptyBlocks
+						// add data-column (setAttribute = IE8+)
+						cell.setAttribute( 'data-column', firstAvailCol );
+					} else {
+						// remove once we drop support for IE7 - 1/12/2016
+						$( cell ).attr( 'data-column', firstAvailCol );
+					}
+					for ( k = rowIndex; k < rowIndex + rowSpan; k++ ) {
+						if ( typeof matrix[ k ] === 'undefined' ) {
+							matrix[ k ] = [];
+						}
+						matrixrow = matrix[ k ];
+						for ( l = firstAvailCol; l < firstAvailCol + colSpan; l++ ) {
+							matrixrow[ l ] = 'x';
+						}
+					}
+				}
+			}
+			return matrixrow.length;
+		},
+
+		// automatically add a colgroup with col elements set to a percentage width
+		fixColumnWidth : function( table ) {
+			table = $( table )[ 0 ];
+			var overallWidth, percent, $tbodies, len, index,
+				c = table.config,
+				$colgroup = c.$table.children( 'colgroup' );
+			// remove plugin-added colgroup, in case we need to refresh the widths
+			if ( $colgroup.length && $colgroup.hasClass( ts.css.colgroup ) ) {
+				$colgroup.remove();
+			}
+			if ( c.widthFixed && c.$table.children( 'colgroup' ).length === 0 ) {
+				$colgroup = $( '<colgroup class="' + ts.css.colgroup + '">' );
+				overallWidth = c.$table.width();
+				// only add col for visible columns - fixes #371
+				$tbodies = c.$tbodies.find( 'tr:first' ).children( ':visible' );
+				len = $tbodies.length;
+				for ( index = 0; index < len; index++ ) {
+					percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%';
+					$colgroup.append( $( '<col>' ).css( 'width', percent ) );
+				}
+				c.$table.prepend( $colgroup );
+			}
+		},
+
+		// 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( header, configHeader, key ) {
+			var meta, cl4ss,
+				val = '',
+				$header = $( header );
+			if ( !$header.length ) { return ''; }
+			meta = $.metadata ? $header.metadata() : false;
+			cl4ss = ' ' + ( $header.attr( 'class' ) || '' );
+			if ( typeof $header.data( key ) !== 'undefined' ||
+				typeof $header.data( key.toLowerCase() ) !== 'undefined' ) {
+				// 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder'
+				// 'data-sort-initial-order' is assigned to 'sortInitialOrder'
+				val += $header.data( key ) || $header.data( key.toLowerCase() );
+			} else if ( meta && typeof meta[ key ] !== 'undefined' ) {
+				val += meta[ key ];
+			} else if ( configHeader && typeof configHeader[ key ] !== 'undefined' ) {
+				val += configHeader[ key ];
+			} else if ( cl4ss !== ' ' && cl4ss.match( ' ' + key + '-' ) ) {
+				// include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser'
+				val = cl4ss.match( new RegExp( '\\s' + key + '-([\\w-]+)' ) )[ 1 ] || '';
+			}
+			return $.trim( val );
+		},
+
+		getColumnData : function( table, obj, indx, getCell, $headers ) {
+			if ( typeof obj !== 'object' || obj === null ) {
+				return obj;
+			}
+			table = $( table )[ 0 ];
+			var $header, key,
+				c = table.config,
+				$cells = ( $headers || c.$headers ),
+				// c.$headerIndexed is not defined initially
+				$cell = c.$headerIndexed && c.$headerIndexed[ indx ] ||
+					$cells.filter( '[data-column="' + indx + '"]:last' );
+			if ( typeof obj[ indx ] !== 'undefined' ) {
+				return getCell ? obj[ indx ] : obj[ $cells.index( $cell ) ];
+			}
+			for ( key in obj ) {
+				if ( typeof key === 'string' ) {
+					$header = $cell
+						// header cell with class/id
+						.filter( key )
+						// find elements within the header cell with cell/id
+						.add( $cell.find( key ) );
+					if ( $header.length ) {
+						return obj[ key ];
+					}
+				}
+			}
+			return;
+		},
+
+		// *** Process table ***
+		// add processing indicator
+		isProcessing : function( $table, toggle, $headers ) {
+			$table = $( $table );
+			var c = $table[ 0 ].config,
+				// default to all headers
+				$header = $headers || $table.find( '.' + ts.css.header );
+			if ( toggle ) {
+				// don't use sortList if custom $headers used
+				if ( typeof $headers !== 'undefined' && c.sortList.length > 0 ) {
+					// get headers from the sortList
+					$header = $header.filter( function() {
+						// get data-column from attr to keep compatibility with jQuery 1.2.6
+						return this.sortDisabled ?
+							false :
+							ts.isValueInArray( parseFloat( $( this ).attr( 'data-column' ) ), c.sortList ) >= 0;
+					});
+				}
+				$table.add( $header ).addClass( ts.css.processing + ' ' + c.cssProcessing );
+			} else {
+				$table.add( $header ).removeClass( ts.css.processing + ' ' + c.cssProcessing );
+			}
+		},
+
+		// detach tbody but save the position
+		// don't use tbody because there are portions that look for a tbody index (updateCell)
+		processTbody : function( table, $tb, getIt ) {
+			table = $( table )[ 0 ];
+			if ( getIt ) {
+				table.isProcessing = true;
+				$tb.before( '<colgroup class="tablesorter-savemyplace"/>' );
+				return $.fn.detach ? $tb.detach() : $tb.remove();
+			}
+			var holdr = $( table ).find( 'colgroup.tablesorter-savemyplace' );
+			$tb.insertAfter( holdr );
+			holdr.remove();
+			table.isProcessing = false;
+		},
+
+		clearTableBody : function( table ) {
+			$( table )[ 0 ].config.$tbodies.children().detach();
+		},
+
+		// used when replacing accented characters during sorting
+		characterEquivalents : {
+			'a' : '\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5', // áàâãäąå
+			'A' : '\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5', // ÁÀÂÃÄĄÅ
+			'c' : '\u00e7\u0107\u010d', // çćč
+			'C' : '\u00c7\u0106\u010c', // ÇĆČ
+			'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę
+			'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ
+			'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı
+			'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ
+			'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō
+			'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ
+			'ss': '\u00df', // ß (s sharp)
+			'SS': '\u1e9e', // ẞ (Capital sharp s)
+			'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů
+			'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ
+		},
+
+		replaceAccents : function( str ) {
+			var chr,
+				acc = '[',
+				eq = ts.characterEquivalents;
+			if ( !ts.characterRegex ) {
+				ts.characterRegexArray = {};
+				for ( chr in eq ) {
+					if ( typeof chr === 'string' ) {
+						acc += eq[ chr ];
+						ts.characterRegexArray[ chr ] = new RegExp( '[' + eq[ chr ] + ']', 'g' );
+					}
+				}
+				ts.characterRegex = new RegExp( acc + ']' );
+			}
+			if ( ts.characterRegex.test( str ) ) {
+				for ( chr in eq ) {
+					if ( typeof chr === 'string' ) {
+						str = str.replace( ts.characterRegexArray[ chr ], chr );
+					}
+				}
+			}
+			return str;
+		},
+
+		validateOptions : function( c ) {
+			var setting, setting2, typ, timer,
+				// ignore options containing an array
+				ignore = 'headers sortForce sortList sortAppend widgets'.split( ' ' ),
+				orig = c.originalSettings;
+			if ( orig ) {
+				if ( c.debug ) {
+					timer = new Date();
+				}
+				for ( setting in orig ) {
+					typ = typeof ts.defaults[setting];
+					if ( typ === 'undefined' ) {
+						console.warn( 'Tablesorter Warning! "table.config.' + setting + '" option not recognized' );
+					} else if ( typ === 'object' ) {
+						for ( setting2 in orig[setting] ) {
+							typ = ts.defaults[setting] && typeof ts.defaults[setting][setting2];
+							if ( $.inArray( setting, ignore ) < 0 && typ === 'undefined' ) {
+								console.warn( 'Tablesorter Warning! "table.config.' + setting + '.' + setting2 + '" option not recognized' );
+							}
+						}
+					}
+				}
+				if ( c.debug ) {
+					console.log( 'validate options time:' + ts.benchmark( timer ) );
+				}
+			}
+		},
+
+		// restore headers
+		restoreHeaders : function( table ) {
+			var index, $cell,
+				c = $( table )[ 0 ].config,
+				$headers = c.$table.find( c.selectorHeaders ),
+				len = $headers.length;
+			// don't use c.$headers here in case header cells were swapped
+			for ( index = 0; index < len; index++ ) {
+				$cell = $headers.eq( index );
+				// only restore header cells if it is wrapped
+				// because this is also used by the updateAll method
+				if ( $cell.find( '.' + ts.css.headerIn ).length ) {
+					$cell.html( c.headerContent[ index ] );
+				}
+			}
+		},
+
+		destroy : function( table, removeClasses, callback ) {
+			table = $( table )[ 0 ];
+			if ( !table.hasInitialized ) { return; }
+			// remove all widgets
+			ts.removeWidget( table, true, false );
+			var events,
+				$t = $( table ),
+				c = table.config,
+				debug = c.debug,
+				$h = $t.find( 'thead:first' ),
+				$r = $h.find( 'tr.' + ts.css.headerRow ).removeClass( ts.css.headerRow + ' ' + c.cssHeaderRow ),
+				$f = $t.find( 'tfoot:first > tr' ).children( 'th, td' );
+			if ( removeClasses === false && $.inArray( 'uitheme', c.widgets ) >= 0 ) {
+				// reapply uitheme classes, in case we want to maintain appearance
+				$t.triggerHandler( 'applyWidgetId', [ 'uitheme' ] );
+				$t.triggerHandler( 'applyWidgetId', [ 'zebra' ] );
+			}
+			// remove widget added rows, just in case
+			$h.find( 'tr' ).not( $r ).remove();
+			// disable tablesorter - not using .unbind( namespace ) because namespacing was
+			// added in jQuery v1.4.3 - see http://api.jquery.com/event.namespace/
+			events = 'sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton ' +
+				'appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave ' +
+				'keypress sortBegin sortEnd resetToLoadState '.split( ' ' )
+				.join( c.namespace + ' ' );
+			$t
+				.removeData( 'tablesorter' )
+				.unbind( events.replace( ts.regex.spaces, ' ' ) );
+			c.$headers
+				.add( $f )
+				.removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join( ' ' ) )
+				.removeAttr( 'data-column' )
+				.removeAttr( 'aria-label' )
+				.attr( 'aria-disabled', 'true' );
+			$r
+				.find( c.selectorSort )
+				.unbind( ( 'mousedown mouseup keypress '.split( ' ' ).join( c.namespace + ' ' ) ).replace( ts.regex.spaces, ' ' ) );
+			ts.restoreHeaders( table );
+			$t.toggleClass( ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false );
+			// clear flag in case the plugin is initialized again
+			table.hasInitialized = false;
+			delete table.config.cache;
+			if ( typeof callback === 'function' ) {
+				callback( table );
+			}
+			if ( debug ) {
+				console.log( 'tablesorter has been removed' );
+			}
+		}
+
+	};
+
+	$.fn.tablesorter = function( settings ) {
+		return this.each( function() {
+			var table = this,
+			// merge & extend config options
+			c = $.extend( true, {}, ts.defaults, settings, ts.instanceMethods );
+			// save initial settings
+			c.originalSettings = settings;
+			// create a table from data (build table widget)
+			if ( !table.hasInitialized && ts.buildTable && this.nodeName !== 'TABLE' ) {
+				// return the table (in case the original target is the table's container)
+				ts.buildTable( table, c );
+			} else {
+				ts.setup( table, c );
+			}
+		});
+	};
+
+	// set up debug logs
+	if ( !( window.console && window.console.log ) ) {
+		// access $.tablesorter.logs for browsers that don't have a console...
+		ts.logs = [];
+		/*jshint -W020 */
+		console = {};
+		console.log = console.warn = console.error = console.table = function() {
+			var arg = arguments.length > 1 ? arguments : arguments[0];
+			ts.logs[ ts.logs.length ] = { date: Date.now(), log: arg };
+		};
+	}
+
+	// add default parsers
+	ts.addParser({
+		id : 'no-parser',
+		is : function() {
+			return false;
+		},
+		format : function() {
+			return '';
+		},
+		type : 'text'
+	});
+
+	ts.addParser({
+		id : 'text',
+		is : function() {
+			return true;
+		},
+		format : function( str, table ) {
+			var c = table.config;
+			if ( str ) {
+				str = $.trim( c.ignoreCase ? str.toLocaleLowerCase() : str );
+				str = c.sortLocaleCompare ? ts.replaceAccents( str ) : str;
+			}
+			return str;
+		},
+		type : 'text'
+	});
+
+	ts.regex.nondigit = /[^\w,. \-()]/g;
+	ts.addParser({
+		id : 'digit',
+		is : function( str ) {
+			return ts.isDigit( str );
+		},
+		format : function( str, table ) {
+			var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
+			return str && typeof num === 'number' ? num :
+				str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
+		},
+		type : 'numeric'
+	});
+
+	ts.regex.currencyReplace = /[+\-,. ]/g;
+	ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;
+	ts.addParser({
+		id : 'currency',
+		is : function( str ) {
+			str = ( str || '' ).replace( ts.regex.currencyReplace, '' );
+			// test for £$€¤¥¢
+			return ts.regex.currencyTest.test( str );
+		},
+		format : function( str, table ) {
+			var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
+			return str && typeof num === 'number' ? num :
+				str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
+		},
+		type : 'numeric'
+	});
+
+	// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
+	// now, this regex can be updated before initialization
+	ts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;
+	ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\/(www\.)?/;
+	ts.addParser({
+		id : 'url',
+		is : function( str ) {
+			return ts.regex.urlProtocolTest.test( str );
+		},
+		format : function( str ) {
+			return str ? $.trim( str.replace( ts.regex.urlProtocolReplace, '' ) ) : str;
+		},
+		type : 'text'
+	});
+
+	ts.regex.dash = /-/g;
+	ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;
+	ts.addParser({
+		id : 'isoDate',
+		is : function( str ) {
+			return ts.regex.isoDate.test( str );
+		},
+		format : function( str, table ) {
+			var date = str ? new Date( str.replace( ts.regex.dash, '/' ) ) : str;
+			return date instanceof Date && isFinite( date ) ? date.getTime() : str;
+		},
+		type : 'numeric'
+	});
+
+	ts.regex.percent = /%/g;
+	ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;
+	ts.addParser({
+		id : 'percent',
+		is : function( str ) {
+			return ts.regex.percentTest.test( str ) && str.length < 15;
+		},
+		format : function( str, table ) {
+			return str ? ts.formatFloat( str.replace( ts.regex.percent, '' ), table ) : str;
+		},
+		type : 'numeric'
+	});
+
+	// added image parser to core v2.17.9
+	ts.addParser({
+		id : 'image',
+		is : function( str, table, node, $node ) {
+			return $node.find( 'img' ).length > 0;
+		},
+		format : function( str, table, cell ) {
+			return $( cell ).find( 'img' ).attr( table.config.imgAttr || 'alt' ) || str;
+		},
+		parsed : true, // filter widget flag
+		type : 'text'
+	});
+
+	ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parser
+	ts.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;
+	ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;
+	ts.addParser({
+		id : 'usLongDate',
+		is : function( str ) {
+			// two digit years are not allowed cross-browser
+			// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
+			return ts.regex.usLongDateTest1.test( str ) || ts.regex.usLongDateTest2.test( str );
+		},
+		format : function( str, table ) {
+			var date = str ? new Date( str.replace( ts.regex.dateReplace, '$1 $2' ) ) : str;
+			return date instanceof Date && isFinite( date ) ? date.getTime() : str;
+		},
+		type : 'numeric'
+	});
+
+	// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
+	ts.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
+	ts.regex.shortDateReplace = /[\-.,]/g;
+	// XXY covers MDY & DMY formats
+	ts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;
+	ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;
+	ts.convertFormat = function( dateString, format ) {
+		dateString = ( dateString || '' )
+			.replace( ts.regex.spaces, ' ' )
+			.replace( ts.regex.shortDateReplace, '/' );
+		if ( format === 'mmddyyyy' ) {
+			dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$1/$2' );
+		} else if ( format === 'ddmmyyyy' ) {
+			dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$2/$1' );
+		} else if ( format === 'yyyymmdd' ) {
+			dateString = dateString.replace( ts.regex.shortDateYMD, '$1/$2/$3' );
+		}
+		var date = new Date( dateString );
+		return date instanceof Date && isFinite( date ) ? date.getTime() : '';
+	};
+
+	ts.addParser({
+		id : 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
+		is : function( str ) {
+			str = ( str || '' ).replace( ts.regex.spaces, ' ' ).replace( ts.regex.shortDateReplace, '/' );
+			return ts.regex.shortDateTest.test( str );
+		},
+		format : function( str, table, cell, cellIndex ) {
+			if ( str ) {
+				var c = table.config,
+					$header = c.$headerIndexed[ cellIndex ],
+					format = $header.length && $header.data( 'dateFormat' ) ||
+						ts.getData( $header, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat' ) ||
+						c.dateFormat;
+				// save format because getData can be slow...
+				if ( $header.length ) {
+					$header.data( 'dateFormat', format );
+				}
+				return ts.convertFormat( str, format ) || str;
+			}
+			return str;
+		},
+		type : 'numeric'
+	});
+
+	// match 24 hour time & 12 hours time + am/pm - see http://regexr.com/3c3tk
+	ts.regex.timeTest = /^(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)$|^((?:[01]\d|[2][0-4]):[0-5]\d)$/i;
+	ts.regex.timeMatch = /(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i;
+	ts.addParser({
+		id : 'time',
+		is : function( str ) {
+			return ts.regex.timeTest.test( str );
+		},
+		format : function( str, table ) {
+			// isolate time... ignore month, day and year
+			var temp,
+				timePart = ( str || '' ).match( ts.regex.timeMatch ),
+				orig = new Date( str ),
+				// no time component? default to 00:00 by leaving it out, but only if str is defined
+				time = str && ( timePart !== null ? timePart[ 0 ] : '00:00 AM' ),
+				date = time ? new Date( '2000/01/01 ' + time.replace( ts.regex.dateReplace, '$1 $2' ) ) : time;
+			if ( date instanceof Date && isFinite( date ) ) {
+				temp = orig instanceof Date && isFinite( orig ) ? orig.getTime() : 0;
+				// if original string was a valid date, add it to the decimal so the column sorts in some kind of order
+				// luckily new Date() ignores the decimals
+				return temp ? parseFloat( date.getTime() + '.' + orig.getTime() ) : date.getTime();
+			}
+			return str;
+		},
+		type : 'numeric'
+	});
+
+	ts.addParser({
+		id : 'metadata',
+		is : function() {
+			return false;
+		},
+		format : function( str, table, cell ) {
+			var c = table.config,
+			p = ( !c.parserMetadataName ) ? 'sortValue' : c.parserMetadataName;
+			return $( cell ).metadata()[ p ];
+		},
+		type : 'numeric'
+	});
+
+	/*
+		██████ ██████ █████▄ █████▄ ▄████▄
+		  ▄█▀  ██▄▄   ██▄▄██ ██▄▄██ ██▄▄██
+		▄█▀    ██▀▀   ██▀▀██ ██▀▀█  ██▀▀██
+		██████ ██████ █████▀ ██  ██ ██  ██
+		*/
+	// add default widgets
+	ts.addWidget({
+		id : 'zebra',
+		priority : 90,
+		format : function( table, c, wo ) {
+			var $visibleRows, $row, count, isEven, tbodyIndex, rowIndex, len,
+				child = new RegExp( c.cssChildRow, 'i' ),
+				$tbodies = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) );
+			for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				// loop through the visible rows
+				count = 0;
+				$visibleRows = $tbodies.eq( tbodyIndex ).children( 'tr:visible' ).not( c.selectorRemove );
+				len = $visibleRows.length;
+				for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
+					$row = $visibleRows.eq( rowIndex );
+					// style child rows the same way the parent row was styled
+					if ( !child.test( $row[ 0 ].className ) ) { count++; }
+					isEven = ( count % 2 === 0 );
+					$row
+						.removeClass( wo.zebra[ isEven ? 1 : 0 ] )
+						.addClass( wo.zebra[ isEven ? 0 : 1 ] );
+				}
+			}
+		},
+		remove : function( table, c, wo, refreshing ) {
+			if ( refreshing ) { return; }
+			var tbodyIndex, $tbody,
+				$tbodies = c.$tbodies,
+				toRemove = ( wo.zebra || [ 'even', 'odd' ] ).join( ' ' );
+			for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ){
+				$tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
+				$tbody.children().removeClass( toRemove );
+				ts.processTbody( table, $tbody, false ); // restore tbody
+			}
+		}
+	});
+
+})( jQuery );
+
+/*! Widget: storage - updated 11/26/2016 (v2.28.0) */
+/*global JSON:false */
+;(function ($, window, document) {
+	'use strict';
+
+	var ts = $.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
+	*/
+	ts.storage = function(table, key, value, options) {
+		table = $(table)[0];
+		var cookieIndex, cookies, date,
+			hasStorage = false,
+			values = {},
+			c = table.config,
+			wo = c && c.widgetOptions,
+			storageType = ( options && options.useSessionStorage ) || ( wo && wo.storage_useSessionStorage ) ?
+				'sessionStorage' : 'localStorage',
+			$table = $(table),
+			// id from (1) options ID, (2) table 'data-table-group' attribute, (3) widgetOptions.storage_tableId,
+			// (4) table ID, then (5) table index
+			id = options && options.id ||
+				$table.attr( options && options.group || wo && wo.storage_group || 'data-table-group') ||
+				wo && wo.storage_tableId || table.id || $('.tablesorter').index( $table ),
+			// 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
+			url = options && options.url ||
+				$table.attr(options && options.page || wo && wo.storage_page || 'data-table-page') ||
+				wo && wo.storage_fixedUrl || c && c.fixedUrl || window.location.pathname;
+		// update defaults for validator; these values must be falsy!
+		$.extend(true, ts.defaults, {
+			fixedUrl: '',
+			widgetOptions: {
+				storage_fixedUrl: '',
+				storage_group: '',
+				storage_page: '',
+				storage_tableId: '',
+				storage_useSessionStorage: ''
+			}
+		});
+		// https://gist.github.com/paulirish/5558557
+		if (storageType in window) {
+			try {
+				window[storageType].setItem('_tmptest', 'temp');
+				hasStorage = true;
+				window[storageType].removeItem('_tmptest');
+			} catch (error) {
+				if (c && c.debug) {
+					console.warn( storageType + ' is not supported in this browser' );
+				}
+			}
+		}
+		// *** get value ***
+		if ($.parseJSON) {
+			if (hasStorage) {
+				values = $.parseJSON( window[storageType][key] || 'null' ) || {};
+			} else {
+				// old browser, using cookies
+				cookies = document.cookie.split(/[;\s|=]/);
+				// add one to get from the key to the value
+				cookieIndex = $.inArray(key, cookies) + 1;
+				values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {};
+			}
+		}
+		// allow value to be an empty string too
+		if (typeof value !== 'undefined' && window.JSON && JSON.hasOwnProperty('stringify')) {
+			// add unique identifiers = url pathname > table ID/index on page > data
+			if (!values[url]) {
+				values[url] = {};
+			}
+			values[url][id] = value;
+			// *** set value ***
+			if (hasStorage) {
+				window[storageType][key] = JSON.stringify(values);
+			} else {
+				date = new Date();
+				date.setTime(date.getTime() + (31536e+6)); // 365 days
+				document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g, '\"') + '; expires=' + date.toGMTString() + '; path=/';
+			}
+		} else {
+			return values && values[url] ? values[url][id] : '';
+		}
+	};
+
+})(jQuery, window, document);
+
+/*! Widget: uitheme - updated 12/8/2016 (v2.28.1) */
+;(function ($) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	ts.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          : ''  // odd row zebra striping
+		},
+		'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 ui-icon-caret-2-n-s', // class name added to icon when column is not sorted
+			iconSortAsc  : 'ui-icon-carat-1-n ui-icon-caret-1-n', // class name added to icon when column has ascending sort
+			iconSortDesc : 'ui-icon-carat-1-s ui-icon-caret-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'   // odd row zebra striping
+		}
+	};
+
+	$.extend(ts.css, {
+		wrapper : 'tablesorter-wrapper' // ui theme & resizable
+	});
+
+	ts.addWidget({
+		id: 'uitheme',
+		priority: 10,
+		format: function(table, c, wo) {
+			var i, tmp, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme,
+				themesAll = ts.themes,
+				$table = c.$table.add( $( c.namespace + '_extra_table' ) ),
+				$headers = c.$headers.add( $( c.namespace + '_extra_headers' ) ),
+				theme = c.theme || 'jui',
+				themes = themesAll[theme] || {},
+				remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ),
+				iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) );
+			if (c.debug) { time = new Date(); }
+			// initialization code - run once
+			if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) {
+				wo.uitheme_applied = true;
+				oldtheme = themesAll[c.appliedTheme] || {};
+				hasOldTheme = !$.isEmptyObject(oldtheme);
+				oldremove =  hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : '';
+				oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : '';
+				if (hasOldTheme) {
+					wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') );
+					wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') );
+					c.$tbodies.children().removeClass( [ oldtheme.even, oldtheme.odd ].join(' ') );
+				}
+				// update zebra stripes
+				if (themes.even) { wo.zebra[0] += ' ' + themes.even; }
+				if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; }
+				// add caption style
+				$table.children('caption')
+					.removeClass(oldtheme.caption || '')
+					.addClass(themes.caption);
+				// add table/footer class names
+				$tfoot = $table
+					// remove other selected themes
+					.removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') )
+					.addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name
+					.children('tfoot');
+				c.appliedTheme = c.theme;
+
+				if ($tfoot.length) {
+					$tfoot
+						// if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed
+						.children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow)
+						.children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells);
+				}
+				// update header classes
+				$headers
+					.removeClass( (hasOldTheme ? [ oldtheme.header, oldtheme.hover, oldremove ].join(' ') : '') || '' )
+					.addClass(themes.header)
+					.not('.sorter-false')
+					.unbind('mouseenter.tsuitheme mouseleave.tsuitheme')
+					.bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) {
+						// toggleClass with switch added in jQuery 1.3
+						$(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || '');
+					});
+
+				$headers.each(function(){
+					var $this = $(this);
+					if (!$this.find('.' + ts.css.wrapper).length) {
+						// Firefox needs this inner div to position the icon & resizer correctly
+						$this.wrapInner('<div class="' + ts.css.wrapper + '" style="position:relative;height:100%;width:100%"></div>');
+					}
+				});
+				if (c.cssIcon) {
+					// if c.cssIcon is '', then no <i> is added to the header
+					$headers
+						.find('.' + ts.css.icon)
+						.removeClass(hasOldTheme ? [ oldtheme.icons, oldIconRmv ].join(' ') : '')
+						.addClass(themes.icons || '');
+				}
+				// filter widget initializes after uitheme
+				if (ts.hasWidget( c.table, 'filter' )) {
+					tmp = function() {
+						$table.children('thead').children('.' + ts.css.filterRow)
+							.removeClass(hasOldTheme ? oldtheme.filterRow || '' : '')
+							.addClass(themes.filterRow || '');
+					};
+					if (wo.filter_initialized) {
+						tmp();
+					} else {
+						$table.one('filterInit', function() {
+							tmp();
+						});
+					}
+				}
+			}
+			for (i = 0; i < c.columns; i++) {
+				$header = c.$headers
+					.add($(c.namespace + '_extra_headers'))
+					.not('.sorter-false')
+					.filter('[data-column="' + i + '"]');
+				$icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $();
+				$h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last');
+				if ($h.length) {
+					$header.removeClass(remove);
+					$icon.removeClass(iconRmv);
+					if ($h[0].sortDisabled) {
+						// no sort arrows for disabled columns!
+						$icon.removeClass(themes.icons || '');
+					} else {
+						hdr = themes.sortNone;
+						icon = themes.iconSortNone;
+						if ($h.hasClass(ts.css.sortAsc)) {
+							hdr = [ themes.sortAsc, themes.active ].join(' ');
+							icon = themes.iconSortAsc;
+						} else if ($h.hasClass(ts.css.sortDesc)) {
+							hdr = [ themes.sortDesc, themes.active ].join(' ');
+							icon = themes.iconSortDesc;
+						}
+						$header.addClass(hdr);
+						$icon.addClass(icon || '');
+					}
+				}
+			}
+			if (c.debug) {
+				console.log('Applying ' + theme + ' theme' + ts.benchmark(time));
+			}
+		},
+		remove: function(table, c, wo, refreshing) {
+			if (!wo.uitheme_applied) { return; }
+			var $table = c.$table,
+				theme = c.appliedTheme || 'jui',
+				themes = ts.themes[ theme ] || ts.themes.jui,
+				$headers = $table.children('thead').children(),
+				remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc,
+				iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc;
+			$table.removeClass('tablesorter-' + theme + ' ' + themes.table);
+			wo.uitheme_applied = false;
+			if (refreshing) { return; }
+			$table.find(ts.css.header).removeClass(themes.header);
+			$headers
+				.unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover
+				.removeClass(themes.hover + ' ' + remove + ' ' + themes.active)
+				.filter('.' + ts.css.filterRow)
+				.removeClass(themes.filterRow);
+			$headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv);
+		}
+	});
+
+})(jQuery);
+
+/*! Widget: columns */
+;(function ($) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	ts.addWidget({
+		id: 'columns',
+		priority: 30,
+		options : {
+			columns : [ 'primary', 'secondary', 'tertiary' ]
+		},
+		format: function(table, c, wo) {
+			var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx,
+			$table = c.$table,
+			$tbodies = c.$tbodies,
+			sortList = c.sortList,
+			len = sortList.length,
+			// removed c.widgetColumns support
+			css = wo && wo.columns || [ 'primary', 'secondary', 'tertiary' ],
+			last = css.length - 1;
+			remove = css.join(' ');
+			// check if there is a sort (on initialization there may not be one)
+			for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody
+				$rows = $tbody.children('tr');
+				// loop through the visible rows
+				$rows.each(function() {
+					$row = $(this);
+					if (this.style.display !== 'none') {
+						// remove all columns class names
+						$cells = $row.children().removeClass(remove);
+						// add appropriate column class names
+						if (sortList && sortList[0]) {
+							// primary sort column class
+							$cells.eq(sortList[0][0]).addClass(css[0]);
+							if (len > 1) {
+								for (indx = 1; indx < len; indx++) {
+									// secondary, tertiary, etc sort column classes
+									$cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] );
+								}
+							}
+						}
+					}
+				});
+				ts.processTbody(table, $tbody, false);
+			}
+			// add classes to thead and tfoot
+			rows = wo.columns_thead !== false ? [ 'thead tr' ] : [];
+			if (wo.columns_tfoot !== false) {
+				rows.push('tfoot tr');
+			}
+			if (rows.length) {
+				$rows = $table.find( rows.join(',') ).children().removeClass(remove);
+				if (len) {
+					for (indx = 0; indx < len; indx++) {
+						// add primary. secondary, tertiary, etc sort column classes
+						$rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]);
+					}
+				}
+			}
+		},
+		remove: function(table, c, wo) {
+			var tbodyIndex, $tbody,
+				$tbodies = c.$tbodies,
+				remove = (wo.columns || [ 'primary', 'secondary', 'tertiary' ]).join(' ');
+			c.$headers.removeClass(remove);
+			c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove);
+			for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody
+				$tbody.children('tr').each(function() {
+					$(this).children().removeClass(remove);
+				});
+				ts.processTbody(table, $tbody, false); // restore tbody
+			}
+		}
+	});
+
+})(jQuery);
+
+/*! Widget: filter - updated 12/8/2016 (v2.28.1) *//*
+ * Requires tablesorter v2.8+ and jQuery 1.7+
+ * by Rob Garrison
+ */
+;( function ( $ ) {
+	'use strict';
+	var tsf, tsfRegex,
+		ts = $.tablesorter || {},
+		tscss = ts.css,
+		tskeyCodes = ts.keyCodes;
+
+	$.extend( tscss, {
+		filterRow      : 'tablesorter-filter-row',
+		filter         : 'tablesorter-filter',
+		filterDisabled : 'disabled',
+		filterRowHide  : 'hideme'
+	});
+
+	$.extend( tskeyCodes, {
+		backSpace : 8,
+		escape : 27,
+		space : 32,
+		left : 37,
+		down : 40
+	});
+
+	ts.addWidget({
+		id: 'filter',
+		priority: 50,
+		options : {
+			filter_cellFilter    : '',    // css class name added to the filter cell ( string or array )
+			filter_childRows     : false, // if true, filter includes child row content in the search
+			filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
+			filter_childWithSibs : true,  // if true, include matching child row siblings
+			filter_columnAnyMatch: true,  // if true, allows using '#:{query}' in AnyMatch searches ( column:query )
+			filter_columnFilters : true,  // if true, a filter will be added to the top of each table column
+			filter_cssFilter     : '',    // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
+			filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value
+			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; define in css with "display:none" to hide the filtered-out rows
+			filter_formatter     : null,  // add custom filter elements to the filter row
+			filter_functions     : null,  // add custom filter functions using this option
+			filter_hideEmpty     : true,  // hide filter row when table is empty
+			filter_hideFilters   : false, // collapse filter row when mouse leaves the area
+			filter_ignoreCase    : true,  // if true, make all searches case-insensitive
+			filter_liveSearch    : true,  // if true, search column content while the user types ( with a delay )
+			filter_matchType     : { 'input': 'exact', 'select': 'exact' }, // global query settings ('exact' or 'match'); overridden by "filter-match" or "filter-exact" class
+			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_resetOnEsc    : true,  // Reset filter input when the user presses escape - normalized across browsers
+			filter_saveFilters   : false, // Use the $.tablesorter.storage utility to save the most recent filters
+			filter_searchDelay   : 300,   // typing delay in milliseconds before starting a search
+			filter_searchFiltered: true,  // 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_selectSourceSeparator : '|', // filter_selectSource array text left of the separator is added to the option value, right into the option text
+			filter_serversideFiltering : false, // if true, must perform server-side filtering b/c client-side filtering is disabled, but the ui and events will still be used.
+			filter_startsWith    : false, // if true, filter start from the beginning of the cell contents
+			filter_useParsedData : false  // filter all data using parsed content
+		},
+		format: function( table, c, wo ) {
+			if ( !c.$table.hasClass( 'hasFilters' ) ) {
+				tsf.init( table, c, wo );
+			}
+		},
+		remove: function( table, c, wo, refreshing ) {
+			var tbodyIndex, $tbody,
+				$table = c.$table,
+				$tbodies = c.$tbodies,
+				events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
+					.split( ' ' ).join( c.namespace + 'filter ' );
+			$table
+				.removeClass( 'hasFilters' )
+				// add filter namespace to all BUT search
+				.unbind( events.replace( ts.regex.spaces, ' ' ) )
+				// remove the filter row even if refreshing, because the column might have been moved
+				.find( '.' + tscss.filterRow ).remove();
+			wo.filter_initialized = false;
+			if ( refreshing ) { return; }
+			for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
+				$tbody.children().removeClass( wo.filter_filteredRow ).show();
+				ts.processTbody( table, $tbody, false ); // restore tbody
+			}
+			if ( wo.filter_reset ) {
+				$( document ).undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' );
+			}
+		}
+	});
+
+	tsf = ts.filter = {
+
+		// regex used in filter 'check' functions - not for general use and not documented
+		regex: {
+			regex     : /^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/, // 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, data, vars ) {
+				// look for "|", but not if it is inside of a regular expression
+				if ( ( tsfRegex.orTest.test( data.iFilter ) || tsfRegex.orSplit.test( data.filter ) ) &&
+					// this test for regex has potential to slow down the overall search
+					!tsfRegex.regex.test( data.filter ) ) {
+					var indx, filterMatched, query, regex,
+						// duplicate data but split filter
+						data2 = $.extend( {}, data ),
+						filter = data.filter.split( tsfRegex.orSplit ),
+						iFilter = data.iFilter.split( tsfRegex.orSplit ),
+						len = filter.length;
+					for ( indx = 0; indx < len; indx++ ) {
+						data2.nestedFilters = true;
+						data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
+						data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
+						query = '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')';
+						try {
+							// use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
+							// e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
+							regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
+							// filterMatched = data2.filter === '' && indx > 0 ? true
+							// look for an exact match with the 'or' unless the 'filter-match' class is found
+							filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
+							if ( filterMatched ) {
+								return filterMatched;
+							}
+						} catch ( error ) {
+							return null;
+						}
+					}
+					// may be null from processing types
+					return filterMatched || false;
+				}
+				return null;
+			},
+			// Look for an AND or && operator ( logical and )
+			and : function( c, data, vars ) {
+				if ( tsfRegex.andTest.test( data.filter ) ) {
+					var indx, filterMatched, result, query, regex,
+						// duplicate data but split filter
+						data2 = $.extend( {}, data ),
+						filter = data.filter.split( tsfRegex.andSplit ),
+						iFilter = data.iFilter.split( tsfRegex.andSplit ),
+						len = filter.length;
+					for ( indx = 0; indx < len; indx++ ) {
+						data2.nestedFilters = true;
+						data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
+						data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
+						query = ( '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')' )
+							// replace wild cards since /(a*)/i will match anything
+							.replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' );
+						try {
+							// use try/catch just in case RegExp is invalid
+							regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
+							// look for an exact match with the 'and' unless the 'filter-match' class is found
+							result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
+							if ( indx === 0 ) {
+								filterMatched = result;
+							} else {
+								filterMatched = filterMatched && result;
+							}
+						} catch ( error ) {
+							return null;
+						}
+					}
+					// may be null from processing types
+					return filterMatched || false;
+				}
+				return null;
+			},
+			// Look for regex
+			regex: function( c, data ) {
+				if ( tsfRegex.regex.test( data.filter ) ) {
+					var matches,
+						// cache regex per column for optimal speed
+						regex = data.filter_regexCache[ data.index ] || tsfRegex.regex.exec( data.filter ),
+						isRegex = regex instanceof RegExp;
+					try {
+						if ( !isRegex ) {
+							// force case insensitive search if ignoreCase option set?
+							// if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
+							data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
+						}
+						matches = regex.test( data.exact );
+					} catch ( error ) {
+						matches = false;
+					}
+					return matches;
+				}
+				return null;
+			},
+			// Look for operators >, >=, < or <=
+			operators: function( c, data ) {
+				// ignore empty strings... because '' < 10 is true
+				if ( tsfRegex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
+					var cachedValue, result, txt,
+						table = c.table,
+						parsed = data.parsed[ data.index ],
+						query = ts.formatFloat( data.iFilter.replace( tsfRegex.operators, '' ), table ),
+						parser = c.parsers[ data.index ] || {},
+						savedSearch = query;
+					// parse filter value in case we're comparing numbers ( dates )
+					if ( parsed || parser.type === 'numeric' ) {
+						txt = $.trim( '' + data.iFilter.replace( tsfRegex.operators, '' ) );
+						result = tsf.parseFilter( c, txt, data, true );
+						query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
+					}
+					// iExact may be numeric - see issue #149;
+					// check if cached is defined, because sometimes j goes out of range? ( numeric columns )
+					if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) &&
+						typeof data.cache !== 'undefined' ) {
+						cachedValue = data.cache;
+					} else {
+						txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
+						cachedValue = ts.formatFloat( txt, table );
+					}
+					if ( tsfRegex.gtTest.test( data.iFilter ) ) {
+						result = tsfRegex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
+					} else if ( tsfRegex.ltTest.test( data.iFilter ) ) {
+						result = tsfRegex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
+					}
+					// keep showing all rows if nothing follows the operator
+					if ( !result && savedSearch === '' ) {
+						result = true;
+					}
+					return result;
+				}
+				return null;
+			},
+			// Look for a not match
+			notMatch: function( c, data ) {
+				if ( tsfRegex.notTest.test( data.iFilter ) ) {
+					var indx,
+						txt = data.iFilter.replace( '!', '' ),
+						filter = tsf.parseFilter( c, txt, data ) || '';
+					if ( tsfRegex.exact.test( filter ) ) {
+						// look for exact not matches - see #628
+						filter = filter.replace( tsfRegex.exact, '' );
+						return filter === '' ? true : $.trim( filter ) !== data.iExact;
+					} else {
+						indx = data.iExact.search( $.trim( filter ) );
+						return filter === '' ? true :
+							// return true if not found
+							data.anyMatch ? indx < 0 :
+							// return false if found
+							!( c.widgetOptions.filter_startsWith ? indx === 0 : indx >= 0 );
+					}
+				}
+				return null;
+			},
+			// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
+			exact: function( c, data ) {
+				/*jshint eqeqeq:false */
+				if ( tsfRegex.exact.test( data.iFilter ) ) {
+					var txt = data.iFilter.replace( tsfRegex.exact, '' ),
+						filter = tsf.parseFilter( c, txt, data ) || '';
+					return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
+				}
+				return null;
+			},
+			// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
+			range : function( c, data ) {
+				if ( tsfRegex.toTest.test( data.iFilter ) ) {
+					var result, tmp, range1, range2,
+						table = c.table,
+						index = data.index,
+						parsed = data.parsed[index],
+						// make sure the dash is for a range and not indicating a negative number
+						query = data.iFilter.split( tsfRegex.toSplit );
+
+					tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
+					range1 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
+					tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
+					range2 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
+					// parse filter value in case we're comparing numbers ( dates )
+					if ( parsed || c.parsers[ index ].type === 'numeric' ) {
+						result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
+						range1 = ( result !== '' && !isNaN( result ) ) ? result : range1;
+						result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index );
+						range2 = ( result !== '' && !isNaN( result ) ) ? result : range2;
+					}
+					if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
+						result = data.cache;
+					} else {
+						tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
+						result = ts.formatFloat( tmp, table );
+					}
+					if ( range1 > range2 ) {
+						tmp = range1; range1 = range2; range2 = tmp; // swap
+					}
+					return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' );
+				}
+				return null;
+			},
+			// Look for wild card: ? = single, * = multiple, or | = logical OR
+			wild : function( c, data ) {
+				if ( tsfRegex.wildOrTest.test( data.iFilter ) ) {
+					var query = '' + ( tsf.parseFilter( c, data.iFilter, data ) || '' );
+					// look for an exact match with the 'or' unless the 'filter-match' class is found
+					if ( !tsfRegex.wildTest.test( query ) && data.nestedFilters ) {
+						query = data.isMatch ? query : '^(' + query + ')$';
+					}
+					// parsing the filter may not work properly when using wildcards =/
+					try {
+						return new RegExp(
+							query.replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' ),
+							c.widgetOptions.filter_ignoreCase ? 'i' : ''
+						)
+						.test( data.exact );
+					} catch ( error ) {
+						return null;
+					}
+				}
+				return null;
+			},
+			// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
+			fuzzy: function( c, data ) {
+				if ( tsfRegex.fuzzyTest.test( data.iFilter ) ) {
+					var indx,
+						patternIndx = 0,
+						len = data.iExact.length,
+						txt = data.iFilter.slice( 1 ),
+						pattern = tsf.parseFilter( c, txt, data ) || '';
+					for ( indx = 0; indx < len; indx++ ) {
+						if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
+							patternIndx += 1;
+						}
+					}
+					return patternIndx === pattern.length;
+				}
+				return null;
+			}
+		},
+		init: function( table ) {
+			// filter language options
+			ts.language = $.extend( true, {}, {
+				to  : 'to',
+				or  : 'or',
+				and : 'and'
+			}, ts.language );
+
+			var options, string, txt, $header, column, val, fxn, noSelect,
+				c = table.config,
+				wo = c.widgetOptions;
+			c.$table.addClass( 'hasFilters' );
+			c.lastSearch = [];
+
+			// define timers so using clearTimeout won't cause an undefined error
+			wo.filter_searchTimer = null;
+			wo.filter_initTimer = null;
+			wo.filter_formatterCount = 0;
+			wo.filter_formatterInit = [];
+			wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
+			wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
+
+			val = '\\{' + tsfRegex.query + '\\}';
+			$.extend( tsfRegex, {
+				child : new RegExp( c.cssChildRow ),
+				filtered : new RegExp( wo.filter_filteredRow ),
+				alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ),
+				toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ),
+				toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)', 'gi' ),
+				andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
+				andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
+				orTest : new RegExp( '(\\||\\s+' + ts.language.or + '\\s+)', 'i' ),
+				orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
+				iQuery : new RegExp( val, 'i' ),
+				igQuery : new RegExp( val, 'ig' ),
+				operTest : /^[<>]=?/,
+				gtTest  : />/,
+				gteTest : />=/,
+				ltTest  : /</,
+				lteTest : /<=/,
+				notTest : /^\!/,
+				wildOrTest : /[\?\*\|]/,
+				wildTest : /\?\*/,
+				fuzzyTest : /^~/,
+				exactTest : /[=\"\|!]/
+			});
+
+			// don't build filter row if columnFilters is false or all columns are set to 'filter-false'
+			// see issue #156
+			val = c.$headers.filter( '.filter-false, .parser-false' ).length;
+			if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
+				// build filter row
+				tsf.buildRow( table, c, wo );
+			}
+
+			txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset ' +
+				'filterResetSaved filterEnd search '.split( ' ' ).join( c.namespace + 'filter ' );
+			c.$table.bind( txt, function( event, filter ) {
+				val = wo.filter_hideEmpty &&
+					$.isEmptyObject( c.cache ) &&
+					!( c.delayInit && event.type === 'appendCache' );
+				// hide filter row using the 'filtered' class name
+				c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
+				if ( !/(search|filter)/.test( event.type ) ) {
+					event.stopPropagation();
+					tsf.buildDefault( table, true );
+				}
+				if ( event.type === 'filterReset' ) {
+					c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
+					tsf.searching( table, [] );
+				} else if ( event.type === 'filterResetSaved' ) {
+					ts.storage( table, 'tablesorter-filters', '' );
+				} else if ( event.type === 'filterEnd' ) {
+					tsf.buildDefault( table, true );
+				} else {
+					// send false argument to force a new search; otherwise if the filter hasn't changed,
+					// it will return
+					filter = event.type === 'search' ? filter :
+						event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : '';
+					if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) {
+						// force a new search since content has changed
+						c.lastCombinedFilter = null;
+						c.lastSearch = [];
+						// update filterFormatters after update (& small delay) - Fixes #1237
+						setTimeout(function(){
+							c.$table.triggerHandler( 'filterFomatterUpdate' );
+						}, 100);
+					}
+					// pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
+					// input ensures all inputs are updated when a search is triggered on the table
+					// $( 'table' ).trigger( 'search', [...] );
+					tsf.searching( table, filter, true );
+				}
+				return false;
+			});
+
+			// reset button/link
+			if ( wo.filter_reset ) {
+				if ( wo.filter_reset instanceof $ ) {
+					// reset contains a jQuery object, bind to it
+					wo.filter_reset.click( function() {
+						c.$table.triggerHandler( 'filterReset' );
+					});
+				} else if ( $( wo.filter_reset ).length ) {
+					// reset is a jQuery selector, use event delegation
+					$( document )
+						.undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' )
+						.delegate( wo.filter_reset, 'click' + c.namespace + 'filter', function() {
+							// trigger a reset event, so other functions ( filter_formatter ) know when to reset
+							c.$table.triggerHandler( 'filterReset' );
+						});
+				}
+			}
+			if ( wo.filter_functions ) {
+				for ( column = 0; column < c.columns; column++ ) {
+					fxn = ts.getColumnData( table, wo.filter_functions, column );
+					if ( fxn ) {
+						// remove 'filter-select' from header otherwise the options added here are replaced with
+						// all options
+						$header = c.$headerIndexed[ column ].removeClass( 'filter-select' );
+						// don't build select if 'filter-false' or 'parser-false' set
+						noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
+						options = '';
+						if ( fxn === true && noSelect ) {
+							tsf.buildSelect( table, column );
+						} else if ( typeof fxn === 'object' && noSelect ) {
+							// add custom drop down list
+							for ( string in fxn ) {
+								if ( typeof string === 'string' ) {
+									options += options === '' ?
+										'<option value="">' +
+											( $header.data( 'placeholder' ) ||
+												$header.attr( 'data-placeholder' ) ||
+												wo.filter_placeholder.select ||
+												''
+											) +
+										'</option>' : '';
+									val = string;
+									txt = string;
+									if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
+										val = string.split( wo.filter_selectSourceSeparator );
+										txt = val[1];
+										val = val[0];
+									}
+									options += '<option ' +
+										( txt === val ? '' : 'data-function-name="' + string + '" ' ) +
+										'value="' + val + '">' + txt + '</option>';
+								}
+							}
+							c.$table
+								.find( 'thead' )
+								.find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
+								.append( options );
+							txt = wo.filter_selectSource;
+							fxn = typeof txt === 'function' ? true : ts.getColumnData( table, txt, column );
+							if ( fxn ) {
+								// updating so the extra options are appended
+								tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.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.
+			tsf.buildDefault( table, true );
+
+			tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
+			if ( wo.filter_external ) {
+				tsf.bindSearch( table, wo.filter_external );
+			}
+
+			if ( wo.filter_hideFilters ) {
+				tsf.hideFilters( c );
+			}
+
+			// show processing icon
+			if ( c.showProcessing ) {
+				txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
+				c.$table
+					.unbind( txt.replace( ts.regex.spaces, ' ' ) )
+					.bind( txt, function( event, columns ) {
+					// only add processing to certain columns to all columns
+					$header = ( columns ) ?
+						c.$table
+							.find( '.' + tscss.header )
+							.filter( '[data-column]' )
+							.filter( function() {
+								return columns[ $( this ).data( 'column' ) ] !== '';
+							}) : '';
+					ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' );
+				});
+			}
+
+			// set filtered rows count ( intially unfiltered )
+			c.filteredRows = c.totalRows;
+
+			// add default values
+			txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
+			c.$table
+			.unbind( txt.replace( ts.regex.spaces, ' ' ) )
+			.bind( txt, function() {
+				tsf.completeInit( this );
+			});
+			// if filter widget is added after pager has initialized; then set filter init flag
+			if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
+				c.$table.triggerHandler( 'filterFomatterUpdate' );
+				setTimeout( function() {
+					tsf.filterInitComplete( c );
+				}, 100 );
+			} else if ( !wo.filter_initialized ) {
+				tsf.completeInit( table );
+			}
+		},
+		completeInit: function( table ) {
+			// redefine 'c' & 'wo' so they update properly inside this callback
+			var c = table.config,
+				wo = c.widgetOptions,
+				filters = tsf.setDefaults( table, c, wo ) || [];
+			if ( filters.length ) {
+				// prevent delayInit from triggering a cache build if filters are empty
+				if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
+					ts.setFilters( table, filters, true );
+				}
+			}
+			c.$table.triggerHandler( 'filterFomatterUpdate' );
+			// trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
+			setTimeout( function() {
+				if ( !wo.filter_initialized ) {
+					tsf.filterInitComplete( c );
+				}
+			}, 100 );
+		},
+
+		// $cell parameter, but not the config, is passed to the filter_formatters,
+		// so we have to work with it instead
+		formatterUpdated: function( $cell, column ) {
+			// prevent error if $cell is undefined - see #1056
+			var wo = $cell && $cell.closest( 'table' )[0].config.widgetOptions;
+			if ( wo && !wo.filter_initialized ) {
+				// add updates by column since this function
+				// may be called numerous times before initialization
+				wo.filter_formatterInit[ column ] = 1;
+			}
+		},
+		filterInitComplete: function( c ) {
+			var indx, len,
+				wo = c.widgetOptions,
+				count = 0,
+				completed = function() {
+					wo.filter_initialized = true;
+					// update lastSearch - it gets cleared often
+					c.lastSearch = c.$table.data( 'lastSearch' );
+					c.$table.triggerHandler( 'filterInit', c );
+					tsf.findRows( c.table, c.lastSearch || [] );
+				};
+			if ( $.isEmptyObject( wo.filter_formatter ) ) {
+				completed();
+			} else {
+				len = wo.filter_formatterInit.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					if ( wo.filter_formatterInit[ indx ] === 1 ) {
+						count++;
+					}
+				}
+				clearTimeout( wo.filter_initTimer );
+				if ( !wo.filter_initialized && count === wo.filter_formatterCount ) {
+					// filter widget initialized
+					completed();
+				} else if ( !wo.filter_initialized ) {
+					// fall back in case a filter_formatter doesn't call
+					// $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off
+					wo.filter_initTimer = setTimeout( function() {
+						completed();
+					}, 500 );
+				}
+			}
+		},
+		// encode or decode filters for storage; see #1026
+		processFilters: function( filters, encode ) {
+			var indx,
+				// fixes #1237; previously returning an encoded "filters" value
+				result = [],
+				mode = encode ? encodeURIComponent : decodeURIComponent,
+				len = filters.length;
+			for ( indx = 0; indx < len; indx++ ) {
+				if ( filters[ indx ] ) {
+					result[ indx ] = mode( filters[ indx ] );
+				}
+			}
+			return result;
+		},
+		setDefaults: function( table, c, wo ) {
+			var isArray, saved, indx, col, $filters,
+				// get current ( default ) filters
+				filters = ts.getFilters( table ) || [];
+			if ( wo.filter_saveFilters && ts.storage ) {
+				saved = ts.storage( table, 'tablesorter-filters' ) || [];
+				isArray = $.isArray( saved );
+				// make sure we're not just getting an empty array
+				if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) {
+					filters = tsf.processFilters( saved );
+				}
+			}
+			// if no filters saved, then check default settings
+			if ( filters.join( '' ) === '' ) {
+				// allow adding default setting to external filters
+				$filters = c.$headers.add( wo.filter_$externalFilters )
+					.filter( '[' + wo.filter_defaultAttrib + ']' );
+				for ( indx = 0; indx <= c.columns; indx++ ) {
+					// include data-column='all' external filters
+					col = indx === c.columns ? 'all' : indx;
+					filters[ indx ] = $filters
+						.filter( '[data-column="' + col + '"]' )
+						.attr( wo.filter_defaultAttrib ) || filters[indx] || '';
+				}
+			}
+			c.$table.data( 'lastSearch', filters );
+			return filters;
+		},
+		parseFilter: function( c, filter, data, parsed ) {
+			return parsed || data.parsed[ data.index ] ?
+				c.parsers[ data.index ].format( filter, c.table, [], data.index ) :
+				filter;
+		},
+		buildRow: function( table, c, wo ) {
+			var $filter, col, column, $header, makeSelect, disabled, name, ffxn, tmp,
+				// c.columns defined in computeThIndexes()
+				cellFilter = wo.filter_cellFilter,
+				columns = c.columns,
+				arry = $.isArray( cellFilter ),
+				buildFilter = '<tr role="row" class="' + tscss.filterRow + ' ' + c.cssIgnoreRow + '">';
+			for ( column = 0; column < columns; column++ ) {
+				if ( c.$headerIndexed[ column ].length ) {
+					// account for entire column set with colspan. See #1047
+					tmp = c.$headerIndexed[ column ] && c.$headerIndexed[ column ][0].colSpan || 0;
+					if ( tmp > 1 ) {
+						buildFilter += '<td data-column="' + column + '-' + ( column + tmp - 1 ) + '" colspan="' + tmp + '"';
+					} else {
+						buildFilter += '<td data-column="' + column + '"';
+					}
+					if ( arry ) {
+						buildFilter += ( cellFilter[ column ] ? ' class="' + cellFilter[ column ] + '"' : '' );
+					} else {
+						buildFilter += ( cellFilter !== '' ? ' class="' + cellFilter + '"' : '' );
+					}
+					buildFilter += '></td>';
+				}
+			}
+			c.$filters = $( buildFilter += '</tr>' )
+				.appendTo( c.$table.children( 'thead' ).eq( 0 ) )
+				.children( 'td' );
+			// build each filter input
+			for ( column = 0; column < columns; column++ ) {
+				disabled = false;
+				// assuming last cell of a column is the main column
+				$header = c.$headerIndexed[ column ];
+				if ( $header && $header.length ) {
+					// $filter = c.$filters.filter( '[data-column="' + column + '"]' );
+					$filter = tsf.getColumnElm( c, c.$filters, column );
+					ffxn = ts.getColumnData( table, wo.filter_functions, column );
+					makeSelect = ( wo.filter_functions && ffxn && typeof ffxn !== 'function' ) ||
+						$header.hasClass( 'filter-select' );
+					// get data from jQuery data, metadata, headers option or header class name
+					col = ts.getColumnData( table, c.headers, column );
+					disabled = ts.getData( $header[0], col, 'filter' ) === 'false' ||
+						ts.getData( $header[0], col, 'parser' ) === 'false';
+
+					if ( makeSelect ) {
+						buildFilter = $( '<select>' ).appendTo( $filter );
+					} else {
+						ffxn = ts.getColumnData( table, wo.filter_formatter, column );
+						if ( ffxn ) {
+							wo.filter_formatterCount++;
+							buildFilter = ffxn( $filter, column );
+							// no element returned, so lets go find it
+							if ( buildFilter && buildFilter.length === 0 ) {
+								buildFilter = $filter.children( 'input' );
+							}
+							// element not in DOM, so lets attach it
+							if ( buildFilter && ( buildFilter.parent().length === 0 ||
+								( buildFilter.parent().length && buildFilter.parent()[0] !== $filter[0] ) ) ) {
+								$filter.append( buildFilter );
+							}
+						} else {
+							buildFilter = $( '<input type="search">' ).appendTo( $filter );
+						}
+						if ( buildFilter ) {
+							tmp = $header.data( 'placeholder' ) ||
+								$header.attr( 'data-placeholder' ) ||
+								wo.filter_placeholder.search || '';
+							buildFilter.attr( 'placeholder', tmp );
+						}
+					}
+					if ( buildFilter ) {
+						// add filter class name
+						name = ( $.isArray( wo.filter_cssFilter ) ?
+							( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) :
+							wo.filter_cssFilter ) || '';
+						// copy data-column from table cell (it will include colspan)
+						buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', $filter.attr( 'data-column' ) );
+						if ( disabled ) {
+							buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true;
+						}
+					}
+				}
+			}
+		},
+		bindSearch: function( table, $el, internal ) {
+			table = $( table )[0];
+			$el = $( $el ); // allow passing a selector string
+			if ( !$el.length ) { return; }
+			var tmp,
+				c = table.config,
+				wo = c.widgetOptions,
+				namespace = c.namespace + 'filter',
+				$ext = wo.filter_$externalFilters;
+			if ( internal !== true ) {
+				// save anyMatch element
+				tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector;
+				wo.filter_$anyMatch = $el.filter( tmp );
+				if ( $ext && $ext.length ) {
+					wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el );
+				} else {
+					wo.filter_$externalFilters = $el;
+				}
+				// update values ( external filters added after table initialization )
+				ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false );
+			}
+			// unbind events
+			tmp = ( 'keypress keyup keydown search change input '.split( ' ' ).join( namespace + ' ' ) );
+			$el
+			// use data attribute instead of jQuery data since the head is cloned without including
+			// the data/binding
+			.attr( 'data-lastSearchTime', new Date().getTime() )
+			.unbind( tmp.replace( ts.regex.spaces, ' ' ) )
+			.bind( 'keydown' + namespace, function( event ) {
+				if ( event.which === tskeyCodes.escape && !table.config.widgetOptions.filter_resetOnEsc ) {
+					// prevent keypress event
+					return false;
+				}
+			})
+			.bind( 'keyup' + namespace, function( event ) {
+				wo = table.config.widgetOptions; // make sure "wo" isn't cached
+				var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
+					liveSearch = typeof wo.filter_liveSearch === 'boolean' ? wo.filter_liveSearch :
+						ts.getColumnData( table, wo.filter_liveSearch, column );
+				if ( typeof liveSearch === 'undefined' ) {
+					liveSearch = wo.filter_liveSearch.fallback || false;
+				}
+				$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
+				// emulate what webkit does.... escape clears the filter
+				if ( event.which === tskeyCodes.escape ) {
+					// make sure to restore the last value on escape
+					this.value = wo.filter_resetOnEsc ? '' : c.lastSearch[column];
+				// live search
+				} else if ( liveSearch === false ) {
+					return;
+					// don't return if the search value is empty ( all rows need to be revealed )
+				} else if ( this.value !== '' && (
+					// liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace
+					( typeof liveSearch === 'number' && this.value.length < liveSearch ) ||
+					// let return & backspace continue on, but ignore arrows & non-valid characters
+					( event.which !== tskeyCodes.enter && event.which !== tskeyCodes.backSpace &&
+						( event.which < tskeyCodes.space || ( event.which >= tskeyCodes.left && event.which <= tskeyCodes.down ) ) ) ) ) {
+					return;
+				}
+				// change event = no delay; last true flag tells getFilters to skip newest timed input
+				tsf.searching( table, true, true, column );
+			})
+			// include change for select - fixes #473
+			.bind( 'search change keypress input '.split( ' ' ).join( namespace + ' ' ), function( event ) {
+				// don't get cached data, in case data-column changes dynamically
+				var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
+					liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
+						wo.filter_liveSearch :
+						ts.getColumnData( table, wo.filter_liveSearch, column );
+				if ( table.config.widgetOptions.filter_initialized &&
+					// immediate search if user presses enter
+					( event.which === tskeyCodes.enter ||
+						// immediate search if a "search" is triggered on the input
+						event.type === 'search' ||
+						// change & input events must be ignored if liveSearch !== true
+						( event.type === 'change' || event.type === 'input' ) &&
+						// prevent search if liveSearch is a number
+						liveSearch === true &&
+						// don't allow 'change' or 'input' event to process if the input value
+						// is the same - fixes #685
+						this.value !== c.lastSearch[column]
+					)
+				) {
+					event.preventDefault();
+					// init search with no delay
+					$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
+					tsf.searching( table, event.type !== 'keypress', true, column );
+				}
+			});
+		},
+		searching: function( table, filter, skipFirst, column ) {
+			var liveSearch,
+				wo = table.config.widgetOptions;
+			if (typeof column === 'undefined') {
+				// no delay
+				liveSearch = false;
+			} else {
+				liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
+					wo.filter_liveSearch :
+					// get column setting, or set to fallback value, or default to false
+					ts.getColumnData( table, wo.filter_liveSearch, column );
+				if ( typeof liveSearch === 'undefined' ) {
+					liveSearch = wo.filter_liveSearch.fallback || false;
+				}
+			}
+			clearTimeout( wo.filter_searchTimer );
+			if ( typeof filter === 'undefined' || filter === true ) {
+				// delay filtering
+				wo.filter_searchTimer = setTimeout( function() {
+					tsf.checkFilters( table, filter, skipFirst );
+				}, liveSearch ? wo.filter_searchDelay : 10 );
+			} else {
+				// skip delay
+				tsf.checkFilters( table, filter, skipFirst );
+			}
+		},
+		checkFilters: function( table, filter, skipFirst ) {
+			var c = table.config,
+				wo = c.widgetOptions,
+				filterArray = $.isArray( filter ),
+				filters = ( filterArray ) ? filter : ts.getFilters( table, true ),
+				combinedFilters = ( filters || [] ).join( '' ); // combined filter values
+			// prevent errors if delay init is set
+			if ( $.isEmptyObject( c.cache ) ) {
+				// update cache if delayInit set & pager has initialized ( after user initiates a search )
+				if ( c.delayInit && ( !c.pager || c.pager && c.pager.initialized ) ) {
+					ts.updateCache( c, function() {
+						tsf.checkFilters( table, false, skipFirst );
+					});
+				}
+				return;
+			}
+			// add filter array back into inputs
+			if ( filterArray ) {
+				ts.setFilters( table, filters, false, skipFirst !== true );
+				if ( !wo.filter_initialized ) { c.lastCombinedFilter = ''; }
+			}
+			if ( wo.filter_hideFilters ) {
+				// show/hide filter row as needed
+				c.$table
+					.find( '.' + tscss.filterRow )
+					.triggerHandler( tsf.hideFiltersCheck( c ) ? 'mouseleave' : 'mouseenter' );
+			}
+			// return if the last search is the same; but filter === false when updating the search
+			// see example-widget-filter.html filter toggle buttons
+			if ( c.lastCombinedFilter === combinedFilters && filter !== false ) {
+				return;
+			} else if ( filter === false ) {
+				// force filter refresh
+				c.lastCombinedFilter = null;
+				c.lastSearch = [];
+			}
+			// define filter inside it is false
+			filters = filters || [];
+			// convert filters to strings - see #1070
+			filters = Array.prototype.map ?
+				filters.map( String ) :
+				// for IE8 & older browsers - maybe not the best method
+				filters.join( '\ufffd' ).split( '\ufffd' );
+
+			if ( wo.filter_initialized ) {
+				c.$table.triggerHandler( 'filterStart', [ filters ] );
+			}
+			if ( c.showProcessing ) {
+				// give it time for the processing icon to kick in
+				setTimeout( function() {
+					tsf.findRows( table, filters, combinedFilters );
+					return false;
+				}, 30 );
+			} else {
+				tsf.findRows( table, filters, combinedFilters );
+				return false;
+			}
+		},
+		hideFiltersCheck: function( c ) {
+			if (typeof c.widgetOptions.filter_hideFilters === 'function') {
+				var val = c.widgetOptions.filter_hideFilters( c );
+				if (typeof val === 'boolean') {
+					return val;
+				}
+			}
+			return ts.getFilters( c.$table ).join( '' ) === '';
+		},
+		hideFilters: function( c, $table ) {
+			var timer;
+			( $table || c.$table )
+				.find( '.' + tscss.filterRow )
+				.addClass( tscss.filterRowHide )
+				.bind( 'mouseenter mouseleave', function( e ) {
+					// save event object - http://bugs.jquery.com/ticket/12140
+					var event = e,
+						$row = $( this );
+					clearTimeout( timer );
+					timer = setTimeout( function() {
+						if ( /enter|over/.test( event.type ) ) {
+							$row.removeClass( tscss.filterRowHide );
+						} else {
+							// don't hide if input has focus
+							// $( ':focus' ) needs jQuery 1.6+
+							if ( $( document.activeElement ).closest( 'tr' )[0] !== $row[0] ) {
+								// don't hide row if any filter has a value
+								$row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) );
+							}
+						}
+					}, 200 );
+				})
+				.find( 'input, select' ).bind( 'focus blur', function( e ) {
+					var event = e,
+						$row = $( this ).closest( 'tr' );
+					clearTimeout( timer );
+					timer = setTimeout( function() {
+						clearTimeout( timer );
+						// don't hide row if any filter has a value
+						$row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) && event.type !== 'focus' );
+					}, 200 );
+				});
+		},
+		defaultFilter: function( filter, mask ) {
+			if ( filter === '' ) { return filter; }
+			var regex = tsfRegex.iQuery,
+				maskLen = mask.match( tsfRegex.igQuery ).length,
+				query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
+				len = query.length - 1,
+				indx = 0,
+				val = mask;
+			if ( len < 1 && maskLen > 1 ) {
+				// only one 'word' in query but mask has >1 slots
+				query[1] = query[0];
+			}
+			// 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'
+			while ( regex.test( val ) ) {
+				val = val.replace( regex, query[indx++] || '' );
+				if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) {
+					val = mask.replace( regex, val );
+				}
+			}
+			return val;
+		},
+		getLatestSearch: function( $input ) {
+			if ( $input ) {
+				return $input.sort( function( a, b ) {
+					return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' );
+				});
+			}
+			return $input || $();
+		},
+		findRange: function( c, val, ignoreRanges ) {
+			// look for multiple columns '1-3,4-6,8' in data-column
+			var temp, ranges, range, start, end, singles, i, indx, len,
+				columns = [];
+			if ( /^[0-9]+$/.test( val ) ) {
+				// always return an array
+				return [ parseInt( val, 10 ) ];
+			}
+			// process column range
+			if ( !ignoreRanges && /-/.test( val ) ) {
+				ranges = val.match( /(\d+)\s*-\s*(\d+)/g );
+				len = ranges ? ranges.length : 0;
+				for ( indx = 0; indx < len; indx++ ) {
+					range = ranges[indx].split( /\s*-\s*/ );
+					start = parseInt( range[0], 10 ) || 0;
+					end = parseInt( range[1], 10 ) || ( c.columns - 1 );
+					if ( start > end ) {
+						temp = start; start = end; end = temp; // swap
+					}
+					if ( end >= c.columns ) {
+						end = c.columns - 1;
+					}
+					for ( ; start <= end; start++ ) {
+						columns[ columns.length ] = start;
+					}
+					// remove processed range from val
+					val = val.replace( ranges[ indx ], '' );
+				}
+			}
+			// process single columns
+			if ( !ignoreRanges && /,/.test( val ) ) {
+				singles = val.split( /\s*,\s*/ );
+				len = singles.length;
+				for ( i = 0; i < len; i++ ) {
+					if ( singles[ i ] !== '' ) {
+						indx = parseInt( singles[ i ], 10 );
+						if ( indx < c.columns ) {
+							columns[ columns.length ] = indx;
+						}
+					}
+				}
+			}
+			// return all columns
+			if ( !columns.length ) {
+				for ( indx = 0; indx < c.columns; indx++ ) {
+					columns[ columns.length ] = indx;
+				}
+			}
+			return columns;
+		},
+		getColumnElm: function( c, $elements, column ) {
+			// data-column may contain multiple columns '1-3,5-6,8'
+			// replaces: c.$filters.filter( '[data-column="' + column + '"]' );
+			return $elements.filter( function() {
+				var cols = tsf.findRange( c, $( this ).attr( 'data-column' ) );
+				return $.inArray( column, cols ) > -1;
+			});
+		},
+		multipleColumns: function( c, $input ) {
+			// look for multiple columns '1-3,4-6,8' in data-column
+			var wo = c.widgetOptions,
+				// only target 'all' column inputs on initialization
+				// & don't target 'all' column inputs if they don't exist
+				targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
+				val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
+			return tsf.findRange( c, val, !targets );
+		},
+		processTypes: function( c, data, vars ) {
+			var ffxn,
+				filterMatched = null,
+				matches = null;
+			for ( ffxn in tsf.types ) {
+				if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
+					matches = tsf.types[ffxn]( c, data, vars );
+					if ( matches !== null ) {
+						filterMatched = matches;
+					}
+				}
+			}
+			return filterMatched;
+		},
+		matchType: function( c, columnIndex ) {
+			var isMatch,
+				wo = c.widgetOptions,
+				$el = c.$headerIndexed[ columnIndex ];
+			// filter-exact > filter-match > filter_matchType for type
+			if ( $el.hasClass( 'filter-exact' ) ) {
+				isMatch = false;
+			} else if ( $el.hasClass( 'filter-match' ) ) {
+				isMatch = true;
+			} else {
+				// filter-select is not applied when filter_functions are used, so look for a select
+				if ( wo.filter_columnFilters ) {
+					$el = c.$filters
+						.find( '.' + tscss.filter )
+						.add( wo.filter_$externalFilters )
+						.filter( '[data-column="' + columnIndex + '"]' );
+				} else if ( wo.filter_$externalFilters ) {
+					$el = wo.filter_$externalFilters.filter( '[data-column="' + columnIndex + '"]' );
+				}
+				isMatch = $el.length ?
+					c.widgetOptions.filter_matchType[ ( $el[ 0 ].nodeName || '' ).toLowerCase() ] === 'match' :
+					// default to exact, if no inputs found
+					false;
+			}
+			return isMatch;
+		},
+		processRow: function( c, data, vars ) {
+			var result, filterMatched,
+				fxn, ffxn, txt,
+				wo = c.widgetOptions,
+				showRow = true,
+				hasAnyMatchInput = wo.filter_$anyMatch && wo.filter_$anyMatch.length,
+
+				// 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
+				columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
+					// look for multiple columns '1-3,4-6,8'
+					tsf.multipleColumns( c, wo.filter_$anyMatch ) :
+					[];
+			data.$cells = data.$row.children();
+			if ( data.anyMatchFlag && columnIndex.length > 1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
+				data.anyMatch = true;
+				data.isMatch = true;
+				data.rowArray = data.$cells.map( function( i ) {
+					if ( $.inArray( i, columnIndex ) > -1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
+						if ( data.parsed[ i ] ) {
+							txt = data.cacheArray[ i ];
+						} else {
+							txt = data.rawArray[ i ];
+							txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
+							if ( c.sortLocaleCompare ) {
+								txt = ts.replaceAccents( txt );
+							}
+						}
+						return txt;
+					}
+				}).get();
+				data.filter = data.anyMatchFilter;
+				data.iFilter = data.iAnyMatchFilter;
+				data.exact = data.rowArray.join( ' ' );
+				data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
+				data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
+				vars.excludeMatch = vars.noAnyMatch;
+				filterMatched = tsf.processTypes( c, data, vars );
+				if ( filterMatched !== null ) {
+					showRow = filterMatched;
+				} else {
+					if ( wo.filter_startsWith ) {
+						showRow = false;
+						// data.rowArray may not contain all columns
+						columnIndex = Math.min( c.columns, data.rowArray.length );
+						while ( !showRow && columnIndex > 0 ) {
+							columnIndex--;
+							showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;
+						}
+					} else {
+						showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0;
+					}
+				}
+				data.anyMatch = false;
+				// no other filters to process
+				if ( data.filters.join( '' ) === data.filter ) {
+					return showRow;
+				}
+			}
+
+			for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
+				data.filter = data.filters[ columnIndex ];
+				data.index = columnIndex;
+
+				// filter types to exclude, per column
+				vars.excludeMatch = vars.excludeFilter[ columnIndex ];
+
+				// ignore if filter is empty or disabled
+				if ( data.filter ) {
+					data.cache = data.cacheArray[ columnIndex ];
+					result = data.parsed[ columnIndex ] ? data.cache : data.rawArray[ columnIndex ] || '';
+					data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405
+					data.iExact = !tsfRegex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
+						data.exact.toLowerCase() : data.exact;
+					data.isMatch = tsf.matchType( c, columnIndex );
+
+					result = showRow; // if showRow is true, show that row
+
+					// in case select filter option has a different value vs text 'a - z|A through Z'
+					ffxn = wo.filter_columnFilters ?
+						c.$filters.add( wo.filter_$externalFilters )
+							.filter( '[data-column="' + columnIndex + '"]' )
+							.find( 'select option:selected' )
+							.attr( 'data-function-name' ) || '' : '';
+					// replace accents - see #357
+					if ( c.sortLocaleCompare ) {
+						data.filter = ts.replaceAccents( data.filter );
+					}
+
+					// replace column specific default filters - see #1088
+					if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
+						data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
+					}
+
+					// data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ),
+					// data.filter = case sensitive
+					data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
+					fxn = vars.functions[ columnIndex ];
+					filterMatched = null;
+					if ( fxn ) {
+						if ( fxn === true ) {
+							// default selector uses exact match unless 'filter-match' class is found
+							filterMatched = data.isMatch ?
+								// data.iExact may be a number
+								( '' + data.iExact ).search( data.iFilter ) >= 0 :
+								data.filter === data.exact;
+						} else if ( typeof fxn === 'function' ) {
+							// filter callback( exact cell content, parser normalized content,
+							// filter input value, column index, jQuery row object )
+							filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
+						} else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) {
+							// selector option function
+							txt = ffxn || data.filter;
+							filterMatched =
+								fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
+						}
+					}
+					if ( filterMatched === null ) {
+						// cycle through the different filters
+						// filters return a boolean or null if nothing matches
+						filterMatched = tsf.processTypes( c, data, vars );
+						if ( filterMatched !== null ) {
+							result = filterMatched;
+						// Look for match, and add child row data for matching
+						} else {
+							txt = ( data.iExact + data.childRowText ).indexOf( tsf.parseFilter( c, data.iFilter, data ) );
+							result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
+						}
+					} else {
+						result = filterMatched;
+					}
+					showRow = ( result ) ? showRow : false;
+				}
+			}
+			return showRow;
+		},
+		findRows: function( table, filters, combinedFilters ) {
+			if ( table.config.lastCombinedFilter === combinedFilters ||
+				!table.config.widgetOptions.filter_initialized ) {
+				return;
+			}
+			var len, norm_rows, rowData, $rows, $row, rowIndex, tbodyIndex, $tbody, columnIndex,
+				isChild, childRow, lastSearch, showRow, showParent, time, val, indx,
+				notFiltered, searchFiltered, query, injected, res, id, txt,
+				storedFilters = $.extend( [], filters ),
+				c = table.config,
+				wo = c.widgetOptions,
+				// data object passed to filters; anyMatch is a flag for the filters
+				data = {
+					anyMatch: false,
+					filters: filters,
+					// regex filter type cache
+					filter_regexCache : []
+				},
+				vars = {
+					// anyMatch really screws up with these types of filters
+					noAnyMatch: [ 'range',  'operators' ],
+					// cache filter variables that use ts.getColumnData in the main loop
+					functions : [],
+					excludeFilter : [],
+					defaultColFilter : [],
+					defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || ''
+				};
+
+			// parse columns after formatter, in case the class is added at that point
+			data.parsed = [];
+			for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
+				data.parsed[ columnIndex ] = wo.filter_useParsedData ||
+					// parser has a "parsed" parameter
+					( c.parsers && c.parsers[ columnIndex ] && c.parsers[ columnIndex ].parsed ||
+					// getData may not return 'parsed' if other 'filter-' class names exist
+					// ( e.g. <th class="filter-select filter-parsed"> )
+					ts.getData && ts.getData( c.$headerIndexed[ columnIndex ],
+						ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' ||
+					c.$headerIndexed[ columnIndex ].hasClass( 'filter-parsed' ) );
+
+				vars.functions[ columnIndex ] =
+					ts.getColumnData( table, wo.filter_functions, columnIndex ) ||
+					c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
+				vars.defaultColFilter[ columnIndex ] =
+					ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || '';
+				vars.excludeFilter[ columnIndex ] =
+					( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ );
+			}
+
+			if ( c.debug ) {
+				console.log( 'Filter: Starting filter widget search', filters );
+				time = new Date();
+			}
+			// filtered rows count
+			c.filteredRows = 0;
+			c.totalRows = 0;
+			// combindedFilters are undefined on init
+			combinedFilters = ( storedFilters || [] ).join( '' );
+
+			for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true );
+				// skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel!
+				// $rows = $tbody.children( 'tr' ).not( c.selectorRemove );
+				columnIndex = c.columns;
+				// convert stored rows into a jQuery object
+				norm_rows = c.cache[ tbodyIndex ].normalized;
+				$rows = $( $.map( norm_rows, function( el ) {
+					return el[ columnIndex ].$row.get();
+				}) );
+
+				if ( combinedFilters === '' || wo.filter_serversideFiltering ) {
+					$rows
+						.removeClass( wo.filter_filteredRow )
+						.not( '.' + c.cssChildRow )
+						.css( 'display', '' );
+				} else {
+					// filter out child rows
+					$rows = $rows.not( '.' + c.cssChildRow );
+					len = $rows.length;
+
+					if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) ||
+						typeof filters[c.columns] !== 'undefined' ) {
+						data.anyMatchFlag = true;
+						data.anyMatchFilter = '' + (
+							filters[ c.columns ] ||
+							wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
+							''
+						);
+						if ( wo.filter_columnAnyMatch ) {
+							// specific columns search
+							query = data.anyMatchFilter.split( tsfRegex.andSplit );
+							injected = false;
+							for ( indx = 0; indx < query.length; indx++ ) {
+								res = query[ indx ].split( ':' );
+								if ( res.length > 1 ) {
+									// make the column a one-based index ( non-developers start counting from one :P )
+									if ( isNaN( res[0] ) ) {
+										$.each( c.headerContent, function( i, txt ) {
+											// multiple matches are possible
+											if ( txt.toLowerCase().indexOf( res[0] ) > -1 ) {
+												id = i;
+												filters[ id ] = res[1];
+											}
+										});
+									} else {
+										id = parseInt( res[0], 10 ) - 1;
+									}
+									if ( id >= 0 && id < c.columns ) { // if id is an integer
+										filters[ id ] = res[1];
+										query.splice( indx, 1 );
+										indx--;
+										injected = true;
+									}
+								}
+							}
+							if ( injected ) {
+								data.anyMatchFilter = query.join( ' && ' );
+							}
+						}
+					}
+
+					// optimize searching only through already filtered rows - see #313
+					searchFiltered = wo.filter_searchFiltered;
+					lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || [];
+					if ( searchFiltered ) {
+						// cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669
+						for ( indx = 0; indx < columnIndex + 1; indx++ ) {
+							val = filters[indx] || '';
+							// break out of loop if we've already determined not to search filtered rows
+							if ( !searchFiltered ) { indx = columnIndex; }
+							// search already filtered rows if...
+							searchFiltered = searchFiltered && lastSearch.length &&
+								// there are no changes from beginning of filter
+								val.indexOf( lastSearch[indx] || '' ) === 0 &&
+								// if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
+								!tsfRegex.alreadyFiltered.test( val ) &&
+								// if we are not doing exact matches, using '|' ( logical or ) or not '!'
+								!tsfRegex.exactTest.test( val ) &&
+								// don't search only filtered if the value is negative
+								// ( '> -10' => '> -100' will ignore hidden rows )
+								!( tsfRegex.isNeg1.test( val ) || tsfRegex.isNeg2.test( val ) ) &&
+								// if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
+								!( val !== '' && c.$filters && c.$filters.filter( '[data-column="' + indx + '"]' ).find( 'select' ).length &&
+									!tsf.matchType( c, indx ) );
+						}
+					}
+					notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length;
+					// can't search when all rows are hidden - this happens when looking for exact matches
+					if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; }
+					if ( c.debug ) {
+						console.log( 'Filter: Searching through ' +
+							( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' );
+					}
+					if ( data.anyMatchFlag ) {
+						if ( c.sortLocaleCompare ) {
+							// replace accents
+							data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
+						}
+						if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultAnyFilter ) ) {
+							data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
+							// clear search filtered flag because default filters are not saved to the last search
+							searchFiltered = false;
+						}
+						// make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true
+						// when c.ignoreCase is true, the cache contains all lower case data
+						data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ?
+							data.anyMatchFilter :
+							data.anyMatchFilter.toLowerCase();
+					}
+
+					// loop through the rows
+					for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
+
+						txt = $rows[ rowIndex ].className;
+						// the first row can never be a child row
+						isChild = rowIndex && tsfRegex.child.test( txt );
+						// skip child rows & already filtered rows
+						if ( isChild || ( searchFiltered && tsfRegex.filtered.test( txt ) ) ) {
+							continue;
+						}
+
+						data.$row = $rows.eq( rowIndex );
+						data.rowIndex = rowIndex;
+						data.cacheArray = norm_rows[ rowIndex ];
+						rowData = data.cacheArray[ c.columns ];
+						data.rawArray = rowData.raw;
+						data.childRowText = '';
+
+						if ( !wo.filter_childByColumn ) {
+							txt = '';
+							// child row cached text
+							childRow = rowData.child;
+							// 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 ( indx = 0; indx < childRow.length; indx++ ) {
+								txt += ' ' + childRow[indx].join( ' ' ) || '';
+							}
+							data.childRowText = wo.filter_childRows ?
+								( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) :
+								'';
+						}
+
+						showRow = false;
+						showParent = tsf.processRow( c, data, vars );
+						$row = rowData.$row;
+
+						// don't pass reference to val
+						val = showParent ? true : false;
+						childRow = rowData.$row.filter( ':gt(0)' );
+						if ( wo.filter_childRows && childRow.length ) {
+							if ( wo.filter_childByColumn ) {
+								if ( !wo.filter_childWithSibs ) {
+									// hide all child rows
+									childRow.addClass( wo.filter_filteredRow );
+									// if only showing resulting child row, only include parent
+									$row = $row.eq( 0 );
+								}
+								// cycle through each child row
+								for ( indx = 0; indx < childRow.length; indx++ ) {
+									data.$row = childRow.eq( indx );
+									data.cacheArray = rowData.child[ indx ];
+									data.rawArray = data.cacheArray;
+									val = tsf.processRow( c, data, vars );
+									// use OR comparison on child rows
+									showRow = showRow || val;
+									if ( !wo.filter_childWithSibs && val ) {
+										childRow.eq( indx ).removeClass( wo.filter_filteredRow );
+									}
+								}
+							}
+							// keep parent row match even if no child matches... see #1020
+							showRow = showRow || showParent;
+						} else {
+							showRow = val;
+						}
+						$row
+							.toggleClass( wo.filter_filteredRow, !showRow )[0]
+							.display = showRow ? '' : 'none';
+					}
+				}
+				c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length;
+				c.totalRows += $rows.length;
+				ts.processTbody( table, $tbody, false );
+			}
+			c.lastCombinedFilter = combinedFilters; // save last search
+			// don't save 'filters' directly since it may have altered ( AnyMatch column searches )
+			c.lastSearch = storedFilters;
+			c.$table.data( 'lastSearch', storedFilters );
+			if ( wo.filter_saveFilters && ts.storage ) {
+				ts.storage( table, 'tablesorter-filters', tsf.processFilters( storedFilters, true ) );
+			}
+			if ( c.debug ) {
+				console.log( 'Completed filter widget search' + ts.benchmark(time) );
+			}
+			if ( wo.filter_initialized ) {
+				c.$table.triggerHandler( 'filterBeforeEnd', c );
+				c.$table.triggerHandler( 'filterEnd', c );
+			}
+			setTimeout( function() {
+				ts.applyWidget( c.table ); // make sure zebra widget is applied
+			}, 0 );
+		},
+		getOptionSource: function( table, column, onlyAvail ) {
+			table = $( table )[0];
+			var c = table.config,
+				wo = c.widgetOptions,
+				arry = false,
+				source = wo.filter_selectSource,
+				last = c.$table.data( 'lastSearch' ) || [],
+				fxn = typeof source === 'function' ? true : ts.getColumnData( table, source, column );
+
+			if ( onlyAvail && last[column] !== '' ) {
+				onlyAvail = false;
+			}
+
+			// filter select source option
+			if ( fxn === true ) {
+				// OVERALL source
+				arry = source( table, column, onlyAvail );
+			} else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '</option>' ) >= 0 ) ) {
+				// selectSource is a jQuery object or string of options
+				return fxn;
+			} else if ( $.isArray( fxn ) ) {
+				arry = fxn;
+			} else if ( $.type( source ) === 'object' && fxn ) {
+				// custom select source function for a SPECIFIC COLUMN
+				arry = fxn( table, column, onlyAvail );
+			}
+			if ( arry === false ) {
+				// fall back to original method
+				arry = tsf.getOptions( table, column, onlyAvail );
+			}
+
+			return tsf.processOptions( table, column, arry );
+
+		},
+		processOptions: function( table, column, arry ) {
+			if ( !$.isArray( arry ) ) {
+				return false;
+			}
+			table = $( table )[0];
+			var cts, txt, indx, len, parsedTxt, str,
+				c = table.config,
+				validColumn = typeof column !== 'undefined' && column !== null && column >= 0 && column < c.columns,
+				direction = validColumn ? c.$headerIndexed[ column ].hasClass( 'filter-select-sort-desc' ) : false,
+				parsed = [];
+			// get unique elements and sort the list
+			// if $.tablesorter.sortText exists ( not in the original tablesorter ),
+			// then natural sort the list otherwise use a basic sort
+			arry = $.grep( arry, function( value, indx ) {
+				if ( value.text ) {
+					return true;
+				}
+				return $.inArray( value, arry ) === indx;
+			});
+			if ( validColumn && c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) {
+				// unsorted select options
+				return arry;
+			} else {
+				len = arry.length;
+				// parse select option values
+				for ( indx = 0; indx < len; indx++ ) {
+					txt = arry[ indx ];
+					// check for object
+					str = txt.text ? txt.text : txt;
+					// sortNatural breaks if you don't pass it strings
+					parsedTxt = ( validColumn && c.parsers && c.parsers.length &&
+						c.parsers[ column ].format( str, table, [], column ) || str ).toString();
+					parsedTxt = c.widgetOptions.filter_ignoreCase ? parsedTxt.toLowerCase() : parsedTxt;
+					// parse array data using set column parser; this DOES NOT pass the original
+					// table cell to the parser format function
+					if ( txt.text ) {
+						txt.parsed = parsedTxt;
+						parsed[ parsed.length ] = txt;
+					} else {
+						parsed[ parsed.length ] = {
+							text : txt,
+							// check parser length - fixes #934
+							parsed : parsedTxt
+						};
+					}
+				}
+				// sort parsed select options
+				cts = c.textSorter || '';
+				parsed.sort( function( a, b ) {
+					var x = direction ? b.parsed : a.parsed,
+						y = direction ? a.parsed : b.parsed;
+					if ( validColumn && typeof cts === 'function' ) {
+						// custom OVERALL text sorter
+						return cts( x, y, true, column, table );
+					} else if ( validColumn && typeof cts === 'object' && cts.hasOwnProperty( column ) ) {
+						// custom text sorter for a SPECIFIC COLUMN
+						return cts[column]( x, y, true, column, table );
+					} else if ( ts.sortNatural ) {
+						// fall back to natural sort
+						return ts.sortNatural( x, y );
+					}
+					// using an older version! do a basic sort
+					return true;
+				});
+				// rebuild arry from sorted parsed data
+				arry = [];
+				len = parsed.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					arry[ arry.length ] = parsed[indx];
+				}
+				return arry;
+			}
+		},
+		getOptions: function( table, column, onlyAvail ) {
+			table = $( table )[0];
+			var rowIndex, tbodyIndex, len, row, cache, indx, child, childLen,
+				c = table.config,
+				wo = c.widgetOptions,
+				arry = [];
+			for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
+				cache = c.cache[tbodyIndex];
+				len = c.cache[tbodyIndex].normalized.length;
+				// loop through the rows
+				for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
+					// get cached row from cache.row ( old ) or row data object
+					// ( new; last item in normalized array )
+					row = cache.row ?
+						cache.row[ rowIndex ] :
+						cache.normalized[ rowIndex ][ c.columns ].$row[0];
+					// check if has class filtered
+					if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) {
+						continue;
+					}
+					// get non-normalized cell content
+					if ( wo.filter_useParsedData ||
+						c.parsers[column].parsed ||
+						c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) {
+						arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ column ];
+						// child row parsed data
+						if ( wo.filter_childRows && wo.filter_childByColumn ) {
+							childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length - 1;
+							for ( indx = 0; indx < childLen; indx++ ) {
+								arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ c.columns ].child[ indx ][ column ];
+							}
+						}
+					} else {
+						// get raw cached data instead of content directly from the cells
+						arry[ arry.length ] = cache.normalized[ rowIndex ][ c.columns ].raw[ column ];
+						// child row unparsed data
+						if ( wo.filter_childRows && wo.filter_childByColumn ) {
+							childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length;
+							for ( indx = 1; indx < childLen; indx++ ) {
+								child =  cache.normalized[ rowIndex ][ c.columns ].$row.eq( indx ).children().eq( column );
+								arry[ arry.length ] = '' + ts.getElementText( c, child, column );
+							}
+						}
+					}
+				}
+			}
+			return arry;
+		},
+		buildSelect: function( table, column, arry, updating, onlyAvail ) {
+			table = $( table )[0];
+			column = parseInt( column, 10 );
+			if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) {
+				return;
+			}
+
+			var indx, val, txt, t, $filters, $filter, option,
+				c = table.config,
+				wo = c.widgetOptions,
+				node = c.$headerIndexed[ column ],
+				// t.data( 'placeholder' ) won't work in jQuery older than 1.4.3
+				options = '<option value="">' +
+					( node.data( 'placeholder' ) ||
+						node.attr( 'data-placeholder' ) ||
+						wo.filter_placeholder.select || ''
+					) + '</option>',
+				// Get curent filter value
+				currentValue = c.$table
+					.find( 'thead' )
+					.find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
+					.val();
+
+			// nothing included in arry ( external source ), so get the options from
+			// filter_selectSource or column data
+			if ( typeof arry === 'undefined' || arry === '' ) {
+				arry = tsf.getOptionSource( table, column, onlyAvail );
+			}
+
+			if ( $.isArray( arry ) ) {
+				// build option list
+				for ( indx = 0; indx < arry.length; indx++ ) {
+					option = arry[ indx ];
+					if ( option.text ) {
+						// OBJECT!! add data-function-name in case the value is set in filter_functions
+						option['data-function-name'] = typeof option.value === 'undefined' ? option.text : option.value;
+
+						// support jQuery < v1.8, otherwise the below code could be shortened to
+						// options += $( '<option>', option )[ 0 ].outerHTML;
+						options += '<option';
+						for ( val in option ) {
+							if ( option.hasOwnProperty( val ) && val !== 'text' ) {
+								options += ' ' + val + '="' + option[ val ] + '"';
+							}
+						}
+						if ( !option.value ) {
+							options += ' value="' + option.text + '"';
+						}
+						options += '>' + option.text + '</option>';
+						// above code is needed in jQuery < v1.8
+
+						// make sure we don't turn an object into a string (objects without a "text" property)
+					} else if ( '' + option !== '[object Object]' ) {
+						txt = option = ( '' + option ).replace( tsfRegex.quote, '&quot;' );
+						val = txt;
+						// allow including a symbol in the selectSource array
+						// 'a-z|A through Z' so that 'a-z' becomes the option value
+						// and 'A through Z' becomes the option text
+						if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
+							t = txt.split( wo.filter_selectSourceSeparator );
+							val = t[0];
+							txt = t[1];
+						}
+						// replace quotes - fixes #242 & ignore empty strings
+						// see http://stackoverflow.com/q/14990971/145346
+						options += option !== '' ?
+							'<option ' +
+								( val === txt ? '' : 'data-function-name="' + option + '" ' ) +
+								'value="' + val + '">' + txt +
+							'</option>' : '';
+					}
+				}
+				// clear arry so it doesn't get appended twice
+				arry = [];
+			}
+
+			// update all selects in the same column ( clone thead in sticky headers &
+			// any external selects ) - fixes 473
+			$filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) )
+				.find( '.' + tscss.filter );
+			if ( wo.filter_$externalFilters ) {
+				$filters = $filters && $filters.length ?
+					$filters.add( wo.filter_$externalFilters ) :
+					wo.filter_$externalFilters;
+			}
+			$filter = $filters.filter( 'select[data-column="' + column + '"]' );
+
+			// make sure there is a select there!
+			if ( $filter.length ) {
+				$filter[ updating ? 'html' : 'append' ]( options );
+				if ( !$.isArray( arry ) ) {
+					// append options if arry is provided externally as a string or jQuery object
+					// options ( default value ) was already added
+					$filter.append( arry ).val( currentValue );
+				}
+				$filter.val( currentValue );
+			}
+		},
+		buildDefault: function( table, updating ) {
+			var columnIndex, $header, noSelect,
+				c = table.config,
+				wo = c.widgetOptions,
+				columns = c.columns;
+			// build default select dropdown
+			for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) {
+				$header = c.$headerIndexed[columnIndex];
+				noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
+				// look for the filter-select class; build/update it if found
+				if ( ( $header.hasClass( 'filter-select' ) ||
+					ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
+					tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
+				}
+			}
+		}
+	};
+
+	// filter regex variable
+	tsfRegex = tsf.regex;
+
+	ts.getFilters = function( table, getRaw, setFilters, skipFirst ) {
+		var i, $filters, $column, cols,
+			filters = [],
+			c = table ? $( table )[0].config : '',
+			wo = c ? c.widgetOptions : '';
+		if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) ||
+			// setFilters called, but last search is exactly the same as the current
+			// fixes issue #733 & #903 where calling update causes the input values to reset
+			( $.isArray(setFilters) && setFilters.join('') === c.lastCombinedFilter ) ) {
+			return $( table ).data( 'lastSearch' );
+		}
+		if ( c ) {
+			if ( c.$filters ) {
+				$filters = c.$filters.find( '.' + tscss.filter );
+			}
+			if ( wo.filter_$externalFilters ) {
+				$filters = $filters && $filters.length ?
+					$filters.add( wo.filter_$externalFilters ) :
+					wo.filter_$externalFilters;
+			}
+			if ( $filters && $filters.length ) {
+				filters = setFilters || [];
+				for ( i = 0; i < c.columns + 1; i++ ) {
+					cols = ( i === c.columns ?
+						// 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' )
+						wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector :
+						'[data-column="' + i + '"]' );
+					$column = $filters.filter( cols );
+					if ( $column.length ) {
+						// move the latest search to the first slot in the array
+						$column = tsf.getLatestSearch( $column );
+						if ( $.isArray( setFilters ) ) {
+							// skip first ( latest input ) to maintain cursor position while typing
+							if ( skipFirst && $column.length > 1 ) {
+								$column = $column.slice( 1 );
+							}
+							if ( i === c.columns ) {
+								// prevent data-column='all' from filling data-column='0,1' ( etc )
+								cols = $column.filter( wo.filter_anyColumnSelector );
+								$column = cols.length ? cols : $column;
+							}
+							$column
+								.val( setFilters[ i ] )
+								// must include a namespace here; but not c.namespace + 'filter'?
+								.trigger( 'change' + c.namespace );
+						} else {
+							filters[i] = $column.val() || '';
+							// don't change the first... it will move the cursor
+							if ( i === c.columns ) {
+								// don't update range columns from 'all' setting
+								$column
+									.slice( 1 )
+									.filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' )
+									.val( filters[ i ] );
+							} else {
+								$column
+									.slice( 1 )
+									.val( filters[ i ] );
+							}
+						}
+						// save any match input dynamically
+						if ( i === c.columns && $column.length ) {
+							wo.filter_$anyMatch = $column;
+						}
+					}
+				}
+			}
+		}
+		return filters;
+	};
+
+	ts.setFilters = function( table, filter, apply, skipFirst ) {
+		var c = table ? $( table )[0].config : '',
+			valid = ts.getFilters( table, true, filter, skipFirst );
+		// default apply to "true"
+		if ( typeof apply === 'undefined' ) {
+			apply = true;
+		}
+		if ( c && apply ) {
+			// ensure new set filters are applied, even if the search is the same
+			c.lastCombinedFilter = null;
+			c.lastSearch = [];
+			tsf.searching( c.table, filter, skipFirst );
+			c.$table.triggerHandler( 'filterFomatterUpdate' );
+		}
+		return valid.length !== 0;
+	};
+
+})( jQuery );
+
+/*! Widget: stickyHeaders - updated 1/6/2017 (v2.28.4) *//*
+ * Requires tablesorter v2.8+ and jQuery 1.4.3+
+ * by Rob Garrison
+ */
+;(function ($, window) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	$.extend(ts.css, {
+		sticky    : 'tablesorter-stickyHeader', // stickyHeader
+		stickyVis : 'tablesorter-sticky-visible',
+		stickyHide: 'tablesorter-sticky-hidden',
+		stickyWrap: 'tablesorter-sticky-wrapper'
+	});
+
+	// Add a resize event to table headers
+	ts.addHeaderResizeEvent = function(table, disable, settings) {
+		table = $(table)[0]; // make sure we're using a dom element
+		if ( !table.config ) { return; }
+		var defaults = {
+				timer : 250
+			},
+			options = $.extend({}, defaults, settings),
+			c = table.config,
+			wo = c.widgetOptions,
+			checkSizes = function( triggerEvent ) {
+				var index, headers, $header, sizes, width, height,
+					len = c.$headers.length;
+				wo.resize_flag = true;
+				headers = [];
+				for ( index = 0; index < len; index++ ) {
+					$header = c.$headers.eq( index );
+					sizes = $header.data( 'savedSizes' ) || [ 0, 0 ]; // fixes #394
+					width = $header[0].offsetWidth;
+					height = $header[0].offsetHeight;
+					if ( width !== sizes[0] || height !== sizes[1] ) {
+						$header.data( 'savedSizes', [ width, height ] );
+						headers.push( $header[0] );
+					}
+				}
+				if ( headers.length && triggerEvent !== false ) {
+					c.$table.triggerHandler( 'resize', [ headers ] );
+				}
+				wo.resize_flag = false;
+			};
+		clearInterval(wo.resize_timer);
+		if (disable) {
+			wo.resize_flag = false;
+			return false;
+		}
+		checkSizes( false );
+		wo.resize_timer = setInterval(function() {
+			if (wo.resize_flag) { return; }
+			checkSizes();
+		}, options.timer);
+	};
+
+	// Sticky headers based on this awesome article:
+	// http://css-tricks.com/13465-persistent-headers/
+	// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
+	// **************************
+	ts.addWidget({
+		id: 'stickyHeaders',
+		priority: 54, // sticky widget must be initialized after the filter & before pager widget!
+		options: {
+			stickyHeaders : '',       // extra class name added to the sticky header row
+			stickyHeaders_appendTo : null, // jQuery selector or object to phycially attach the sticky headers
+			stickyHeaders_attachTo : null, // jQuery selector or object to attach scroll listener to (overridden by xScroll & yScroll settings)
+			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: true, // scroll table top into view after filtering
+			stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists
+			stickyHeaders_addResizeEvent : true, // trigger 'resize' event on headers
+			stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header
+			stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs
+		},
+		format: function(table, c, wo) {
+			// filter widget doesn't initialize on an empty table. Fixes #449
+			if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) {
+				return;
+			}
+			var index, len, $t,
+				$table = c.$table,
+				// add position: relative to attach element, hopefully it won't cause trouble.
+				$attach = $(wo.stickyHeaders_attachTo),
+				namespace = c.namespace + 'stickyheaders ',
+				// element to watch for the scroll event
+				$yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window),
+				$xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window),
+				$thead = $table.children('thead:first'),
+				$header = $thead.children('tr').not('.sticky-false').children(),
+				$tfoot = $table.children('tfoot'),
+				$stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '',
+				stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0,
+				// is this table nested? If so, find parent sticky header wrapper (div, not table)
+				$nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ?
+					$table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [],
+				nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0,
+				// clone table, then wrap to make sticky header
+				$stickyTable = wo.$sticky = $table.clone()
+					.addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders + ' ' + c.namespace.slice(1) + '_extra_table' )
+					.wrap('<div class="' + ts.css.stickyWrap + '">'),
+				$stickyWrap = $stickyTable.parent()
+					.addClass(ts.css.stickyHide)
+					.css({
+						position   : $attach.length ? 'absolute' : 'fixed',
+						padding    : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ),
+						top        : stickyOffset + nestedStickyTop,
+						left       : 0,
+						visibility : 'hidden',
+						zIndex     : wo.stickyHeaders_zIndex || 2
+					}),
+				$stickyThead = $stickyTable.children('thead:first'),
+				$stickyCells,
+				laststate = '',
+				spacing = 0,
+				setWidth = function($orig, $clone){
+					var index, width, border, $cell, $this,
+						$cells = $orig.filter(':visible'),
+						len = $cells.length;
+					for ( index = 0; index < len; index++ ) {
+						$cell = $clone.filter(':visible').eq(index);
+						$this = $cells.eq(index);
+						// code from https://github.com/jmosbech/StickyTableHeaders
+						if ($this.css('box-sizing') === 'border-box') {
+							width = $this.outerWidth();
+						} else {
+							if ($cell.css('border-collapse') === 'collapse') {
+								if (window.getComputedStyle) {
+									width = parseFloat( window.getComputedStyle($this[0], null).width );
+								} else {
+									// ie8 only
+									border = parseFloat( $this.css('border-width') );
+									width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border;
+								}
+							} else {
+								width = $this.width();
+							}
+						}
+						$cell.css({
+							'width': width,
+							'min-width': width,
+							'max-width': width
+						});
+					}
+				},
+				resizeHeader = function() {
+					stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0;
+					spacing = 0;
+					$stickyWrap.css({
+						left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 :
+								$table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing,
+						width: $table.outerWidth()
+					});
+					setWidth( $table, $stickyTable );
+					setWidth( $header, $stickyCells );
+				},
+				scrollSticky = function( resizing ) {
+					if (!$table.is(':visible')) { return; } // fixes #278
+					// Detect nested tables - fixes #724
+					nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
+					var offset = $table.offset(),
+						yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
+						xWindow = $.isWindow( $xScroll[0] ),
+						attachTop = $attach.length ?
+							( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) :
+							$yScroll.scrollTop(),
+						captionHeight = wo.stickyHeaders_includeCaption ? 0 : $table.children( 'caption' ).height() || 0,
+						scrollTop = attachTop + stickyOffset + nestedStickyTop - captionHeight,
+						tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)) - captionHeight,
+						isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
+						cssSettings = { visibility : isVisible };
+					if ($attach.length) {
+						cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
+					}
+					if (xWindow) {
+						// adjust when scrolling horizontally - fixes issue #143
+						cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
+					}
+					if ($nestedSticky.length) {
+						cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
+					}
+					$stickyWrap
+						.removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
+						.addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide )
+						.css(cssSettings);
+					if (isVisible !== laststate || resizing) {
+						// make sure the column widths match
+						resizeHeader();
+						laststate = isVisible;
+					}
+				};
+			// only add a position relative if a position isn't already defined
+			if ($attach.length && !$attach.css('position')) {
+				$attach.css('position', 'relative');
+			}
+			// fix clone ID, if it exists - fixes #271
+			if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.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
+			$stickyTable.find('thead:gt(0), tr.sticky-false').hide();
+			$stickyTable.find('tbody, tfoot').remove();
+			$stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption);
+			// issue #172 - find td/th in sticky header
+			$stickyCells = $stickyThead.children().children();
+			$stickyTable.css({ height:0, width:0, margin: 0 });
+			// remove resizable block
+			$stickyCells.find('.' + ts.css.resizer).remove();
+			// update sticky header class names to match real header after sorting
+			$table
+				.addClass('hasStickyHeaders')
+				.bind('pagerComplete' + namespace, function() {
+					resizeHeader();
+				});
+
+			ts.bindEvents(table, $stickyThead.children().children('.' + ts.css.header));
+
+			if (wo.stickyHeaders_appendTo) {
+				$(wo.stickyHeaders_appendTo).append( $stickyWrap );
+			} else {
+				// add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned.
+				$table.after( $stickyWrap );
+			}
+
+			// onRenderHeader is defined, we need to do something about it (fixes #641)
+			if (c.onRenderHeader) {
+				$t = $stickyThead.children('tr').children();
+				len = $t.length;
+				for ( index = 0; index < len; index++ ) {
+					// send second parameter
+					c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] );
+				}
+			}
+
+			// make it sticky!
+			$xScroll.add($yScroll)
+				.unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
+				.bind('scroll resize '.split(' ').join( namespace ), function( event ) {
+					scrollSticky( event.type === 'resize' );
+				});
+			c.$table
+				.unbind('stickyHeadersUpdate' + namespace)
+				.bind('stickyHeadersUpdate' + namespace, function(){
+					scrollSticky( true );
+				});
+
+			if (wo.stickyHeaders_addResizeEvent) {
+				ts.addHeaderResizeEvent(table);
+			}
+
+			// look for filter widget
+			if ($table.hasClass('hasFilters') && wo.filter_columnFilters) {
+				// scroll table into view after filtering, if sticky header is active - #482
+				$table.bind('filterEnd' + namespace, function() {
+					// $(':focus') needs jQuery 1.6+
+					var $td = $(document.activeElement).closest('td'),
+						column = $td.parent().children().index($td);
+					// only scroll if sticky header is active
+					if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) {
+						// scroll to original table (not sticky clone)
+						window.scrollTo(0, $table.position().top);
+						// give same input/select focus; check if c.$filters exists; fixes #594
+						if (column >= 0 && c.$filters) {
+							c.$filters.eq(column).find('a, select, input').filter(':visible').focus();
+						}
+					}
+				});
+				ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) );
+				// support hideFilters
+				if (wo.filter_hideFilters) {
+					ts.filter.hideFilters(c, $stickyTable);
+				}
+			}
+
+			// resize table (Firefox)
+			if (wo.stickyHeaders_addResizeEvent) {
+				$table.bind('resize' + c.namespace + 'stickyheaders', function() {
+					resizeHeader();
+				});
+			}
+
+			$table.triggerHandler('stickyHeadersInit');
+
+		},
+		remove: function(table, c, wo) {
+			var namespace = c.namespace + 'stickyheaders ';
+			c.$table
+				.removeClass('hasStickyHeaders')
+				.unbind( ('pagerComplete resize filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
+				.next('.' + ts.css.stickyWrap).remove();
+			if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
+			$(window)
+				.add(wo.stickyHeaders_xScroll)
+				.add(wo.stickyHeaders_yScroll)
+				.add(wo.stickyHeaders_attachTo)
+				.unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') );
+			ts.addHeaderResizeEvent(table, true);
+		}
+	});
+
+})(jQuery, window);
+
+/*! Widget: resizable - updated 12/15/2016 (v2.28.2) */
+/*jshint browser:true, jquery:true, unused:false */
+;(function ($, window) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	$.extend(ts.css, {
+		resizableContainer : 'tablesorter-resizable-container',
+		resizableHandle    : 'tablesorter-resizable-handle',
+		resizableNoSelect  : 'tablesorter-disableSelection',
+		resizableStorage   : 'tablesorter-resizable'
+	});
+
+	// Add extra scroller css
+	$(function(){
+		var s = '<style>' +
+			'body.' + ts.css.resizableNoSelect + ' { -ms-user-select: none; -moz-user-select: -moz-none;' +
+				'-khtml-user-select: none; -webkit-user-select: none; user-select: none; }' +
+			'.' + ts.css.resizableContainer + ' { position: relative; height: 1px; }' +
+			// make handle z-index > than stickyHeader z-index, so the handle stays above sticky header
+			'.' + ts.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>';
+		$('head').append(s);
+	});
+
+	ts.resizable = {
+		init : function( c, wo ) {
+			if ( c.$table.hasClass( 'hasResizable' ) ) { return; }
+			c.$table.addClass( 'hasResizable' );
+
+			var noResize, $header, column, storedSizes, tmp,
+				$table = c.$table,
+				$parent = $table.parent(),
+				marginTop = parseInt( $table.css( 'margin-top' ), 10 ),
+
+			// internal variables
+			vars = wo.resizable_vars = {
+				useStorage : ts.storage && wo.resizable !== false,
+				$wrap : $parent,
+				mouseXPosition : 0,
+				$target : null,
+				$next : null,
+				overflow : $parent.css('overflow') === 'auto' ||
+					$parent.css('overflow') === 'scroll' ||
+					$parent.css('overflow-x') === 'auto' ||
+					$parent.css('overflow-x') === 'scroll',
+				storedSizes : []
+			};
+
+			// set default widths
+			ts.resizableReset( c.table, true );
+
+			// now get measurements!
+			vars.tableWidth = $table.width();
+			// attempt to autodetect
+			vars.fullWidth = Math.abs( $parent.width() - vars.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>');
+			}
+			*/
+
+			if ( vars.useStorage && vars.overflow ) {
+				// save table width
+				ts.storage( c.table, 'tablesorter-table-original-css-width', vars.tableWidth );
+				tmp = ts.storage( c.table, 'tablesorter-table-resized-width' ) || 'auto';
+				ts.resizable.setWidth( $table, tmp, true );
+			}
+			wo.resizable_vars.storedSizes = storedSizes = ( vars.useStorage ?
+				ts.storage( c.table, ts.css.resizableStorage ) :
+				[] ) || [];
+			ts.resizable.setWidths( c, wo, storedSizes );
+			ts.resizable.updateStoredSizes( c, wo );
+
+			wo.$resizable_container = $( '<div class="' + ts.css.resizableContainer + '">' )
+				.css({ top : marginTop })
+				.insertBefore( $table );
+			// add container
+			for ( column = 0; column < c.columns; column++ ) {
+				$header = c.$headerIndexed[ column ];
+				tmp = ts.getColumnData( c.table, c.headers, column );
+				noResize = ts.getData( $header, tmp, 'resizable' ) === 'false';
+				if ( !noResize ) {
+					$( '<div class="' + ts.css.resizableHandle + '">' )
+						.appendTo( wo.$resizable_container )
+						.attr({
+							'data-column' : column,
+							'unselectable' : 'on'
+						})
+						.data( 'header', $header )
+						.bind( 'selectstart', false );
+				}
+			}
+			ts.resizable.bindings( c, wo );
+		},
+
+		updateStoredSizes : function( c, wo ) {
+			var column, $header,
+				len = c.columns,
+				vars = wo.resizable_vars;
+			vars.storedSizes = [];
+			for ( column = 0; column < len; column++ ) {
+				$header = c.$headerIndexed[ column ];
+				vars.storedSizes[ column ] = $header.is(':visible') ? $header.width() : 0;
+			}
+		},
+
+		setWidth : function( $el, width, overflow ) {
+			// overflow tables need min & max width set as well
+			$el.css({
+				'width' : width,
+				'min-width' : overflow ? width : '',
+				'max-width' : overflow ? width : ''
+			});
+		},
+
+		setWidths : function( c, wo, storedSizes ) {
+			var column, $temp,
+				vars = wo.resizable_vars,
+				$extra = $( c.namespace + '_extra_headers' ),
+				$col = c.$table.children( 'colgroup' ).children( 'col' );
+			storedSizes = storedSizes || vars.storedSizes || [];
+			// process only if table ID or url match
+			if ( storedSizes.length ) {
+				for ( column = 0; column < c.columns; column++ ) {
+					// set saved resizable widths
+					ts.resizable.setWidth( c.$headerIndexed[ column ], storedSizes[ column ], vars.overflow );
+					if ( $extra.length ) {
+						// stickyHeaders needs to modify min & max width as well
+						$temp = $extra.eq( column ).add( $col.eq( column ) );
+						ts.resizable.setWidth( $temp, storedSizes[ column ], vars.overflow );
+					}
+				}
+				$temp = $( c.namespace + '_extra_table' );
+				if ( $temp.length && !ts.hasWidget( c.table, 'scroller' ) ) {
+					ts.resizable.setWidth( $temp, c.$table.outerWidth(), vars.overflow );
+				}
+			}
+		},
+
+		setHandlePosition : function( c, wo ) {
+			var startPosition,
+				tableHeight = c.$table.height(),
+				$handles = wo.$resizable_container.children(),
+				handleCenter = Math.floor( $handles.width() / 2 );
+
+			if ( ts.hasWidget( c.table, 'scroller' ) ) {
+				tableHeight = 0;
+				c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function(){
+					var $this = $(this);
+					// center table has a max-height set
+					tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height();
+				});
+			}
+			// subtract out table left position from resizable handles. Fixes #864
+			startPosition = c.$table.position().left;
+			$handles.each( function() {
+				var $this = $(this),
+					column = parseInt( $this.attr( 'data-column' ), 10 ),
+					columns = c.columns - 1,
+					$header = $this.data( 'header' );
+				if ( !$header ) { return; } // see #859
+				if ( !$header.is(':visible') ) {
+					$this.hide();
+				} else if ( column < columns || column === columns && wo.resizable_addLastColumn ) {
+					$this.css({
+						display: 'inline-block',
+						height : tableHeight,
+						left : $header.position().left - startPosition + $header.outerWidth() - handleCenter
+					});
+				}
+			});
+		},
+
+		// prevent text selection while dragging resize bar
+		toggleTextSelection : function( c, wo, toggle ) {
+			var namespace = c.namespace + 'tsresize';
+			wo.resizable_vars.disabled = toggle;
+			$( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle );
+			if ( toggle ) {
+				$( 'body' )
+					.attr( 'unselectable', 'on' )
+					.bind( 'selectstart' + namespace, false );
+			} else {
+				$( 'body' )
+					.removeAttr( 'unselectable' )
+					.unbind( 'selectstart' + namespace );
+			}
+		},
+
+		bindings : function( c, wo ) {
+			var namespace = c.namespace + 'tsresize';
+			wo.$resizable_container.children().bind( 'mousedown', function( event ) {
+				// save header cell and mouse position
+				var column,
+					vars = wo.resizable_vars,
+					$extras = $( c.namespace + '_extra_headers' ),
+					$header = $( event.target ).data( 'header' );
+
+				column = parseInt( $header.attr( 'data-column' ), 10 );
+				vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') );
+				vars.target = column;
+
+				// if table is not as wide as it's parent, then resize the table
+				vars.$next = event.shiftKey || wo.resizable_targetLast ?
+					$header.parent().children().not( '.resizable-false' ).filter( ':last' ) :
+					$header.nextAll( ':not(.resizable-false)' ).eq( 0 );
+
+				column = parseInt( vars.$next.attr( 'data-column' ), 10 );
+				vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') );
+				vars.next = column;
+
+				vars.mouseXPosition = event.pageX;
+				ts.resizable.updateStoredSizes( c, wo );
+				ts.resizable.toggleTextSelection(c, wo, true );
+			});
+
+			$( document )
+				.bind( 'mousemove' + namespace, function( event ) {
+					var vars = wo.resizable_vars;
+					// ignore mousemove if no mousedown
+					if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; }
+					if ( wo.resizable_throttle ) {
+						clearTimeout( vars.timer );
+						vars.timer = setTimeout( function() {
+							ts.resizable.mouseMove( c, wo, event );
+						}, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle );
+					} else {
+						ts.resizable.mouseMove( c, wo, event );
+					}
+				})
+				.bind( 'mouseup' + namespace, function() {
+					if (!wo.resizable_vars.disabled) { return; }
+					ts.resizable.toggleTextSelection( c, wo, false );
+					ts.resizable.stopResize( c, wo );
+					ts.resizable.setHandlePosition( c, wo );
+				});
+
+			// resizeEnd event triggered by scroller widget
+			$( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() {
+				ts.resizable.setHandlePosition( c, wo );
+			});
+
+			// right click to reset columns to default widths
+			c.$table
+				.bind( 'columnUpdate' + namespace + ' pagerComplete' + namespace, function() {
+					ts.resizable.setHandlePosition( c, wo );
+				})
+				.find( 'thead:first' )
+				.add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) )
+				.bind( 'contextmenu' + namespace, function() {
+					// $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
+					var allowClick = wo.resizable_vars.storedSizes.length === 0;
+					ts.resizableReset( c.table );
+					ts.resizable.setHandlePosition( c, wo );
+					wo.resizable_vars.storedSizes = [];
+					return allowClick;
+				});
+
+		},
+
+		mouseMove : function( c, wo, event ) {
+			if ( wo.resizable_vars.mouseXPosition === 0 || !wo.resizable_vars.$target ) { return; }
+			// resize columns
+			var column,
+				total = 0,
+				vars = wo.resizable_vars,
+				$next = vars.$next,
+				tar = vars.storedSizes[ vars.target ],
+				leftEdge = event.pageX - vars.mouseXPosition;
+			if ( vars.overflow ) {
+				if ( tar + leftEdge > 0 ) {
+					vars.storedSizes[ vars.target ] += leftEdge;
+					ts.resizable.setWidth( vars.$target, vars.storedSizes[ vars.target ], true );
+					// update the entire table width
+					for ( column = 0; column < c.columns; column++ ) {
+						total += vars.storedSizes[ column ];
+					}
+					ts.resizable.setWidth( c.$table.add( $( c.namespace + '_extra_table' ) ), total );
+				}
+				if ( !$next.length ) {
+					// if expanding right-most column, scroll the wrapper
+					vars.$wrap[0].scrollLeft = c.$table.width();
+				}
+			} else if ( vars.fullWidth ) {
+				vars.storedSizes[ vars.target ] += leftEdge;
+				vars.storedSizes[ vars.next ] -= leftEdge;
+				ts.resizable.setWidths( c, wo );
+			} else {
+				vars.storedSizes[ vars.target ] += leftEdge;
+				ts.resizable.setWidths( c, wo );
+			}
+			vars.mouseXPosition = event.pageX;
+			// dynamically update sticky header widths
+			c.$table.triggerHandler('stickyHeadersUpdate');
+		},
+
+		stopResize : function( c, wo ) {
+			var vars = wo.resizable_vars;
+			ts.resizable.updateStoredSizes( c, wo );
+			if ( vars.useStorage ) {
+				// save all column widths
+				ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
+				ts.storage( c.table, 'tablesorter-table-resized-width', c.$table.width() );
+			}
+			vars.mouseXPosition = 0;
+			vars.$target = vars.$next = null;
+			// will update stickyHeaders, just in case, see #912
+			c.$table.triggerHandler('stickyHeadersUpdate');
+		}
+	};
+
+	// this widget saves the column widths if
+	// $.tablesorter.storage function is included
+	// **************************
+	ts.addWidget({
+		id: 'resizable',
+		priority: 40,
+		options: {
+			resizable : true, // save column widths to storage
+			resizable_addLastColumn : false,
+			resizable_widths : [],
+			resizable_throttle : false, // set to true (5ms) or any number 0-10 range
+			resizable_targetLast : false,
+			resizable_fullWidth : null
+		},
+		init: function(table, thisWidget, c, wo) {
+			ts.resizable.init( c, wo );
+		},
+		format: function( table, c, wo ) {
+			ts.resizable.setHandlePosition( c, wo );
+		},
+		remove: function( table, c, wo, refreshing ) {
+			if (wo.$resizable_container) {
+				var namespace = c.namespace + 'tsresize';
+				c.$table.add( $( c.namespace + '_extra_table' ) )
+					.removeClass('hasResizable')
+					.children( 'thead' )
+					.unbind( 'contextmenu' + namespace );
+
+				wo.$resizable_container.remove();
+				ts.resizable.toggleTextSelection( c, wo, false );
+				ts.resizableReset( table, refreshing );
+				$( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace );
+			}
+		}
+	});
+
+	ts.resizableReset = function( table, refreshing ) {
+		$( table ).each(function(){
+			var index, $t,
+				c = this.config,
+				wo = c && c.widgetOptions,
+				vars = wo.resizable_vars;
+			if ( table && c && c.$headerIndexed.length ) {
+				// restore the initial table width
+				if ( vars.overflow && vars.tableWidth ) {
+					ts.resizable.setWidth( c.$table, vars.tableWidth, true );
+					if ( vars.useStorage ) {
+						ts.storage( table, 'tablesorter-table-resized-width', 'auto' );
+					}
+				}
+				for ( index = 0; index < c.columns; index++ ) {
+					$t = c.$headerIndexed[ index ];
+					if ( wo.resizable_widths && wo.resizable_widths[ index ] ) {
+						ts.resizable.setWidth( $t, wo.resizable_widths[ index ], vars.overflow );
+					} else if ( !$t.hasClass( 'resizable-false' ) ) {
+						// don't clear the width of any column that is not resizable
+						ts.resizable.setWidth( $t, '', vars.overflow );
+					}
+				}
+
+				// reset stickyHeader widths
+				c.$table.triggerHandler( 'stickyHeadersUpdate' );
+				if ( ts.storage && !refreshing ) {
+					ts.storage( this, ts.css.resizableStorage, {} );
+				}
+			}
+		});
+	};
+
+})( jQuery, window );
+
+/*! Widget: saveSort - updated 10/31/2015 (v2.24.0) *//*
+* Requires tablesorter v2.16+
+* by Rob Garrison
+*/
+;(function ($) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	// this widget saves the last sort only if the
+	// saveSort widget option is true AND the
+	// $.tablesorter.storage function is included
+	// **************************
+	ts.addWidget({
+		id: 'saveSort',
+		priority: 20,
+		options: {
+			saveSort : true
+		},
+		init: function(table, thisWidget, c, wo) {
+			// run widget format before all other widgets are applied to the table
+			thisWidget.format(table, c, wo, true);
+		},
+		format: function(table, c, wo, init) {
+			var stored, time,
+				$table = c.$table,
+				saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true
+				sortList = { 'sortList' : c.sortList };
+			if (c.debug) {
+				time = new Date();
+			}
+			if ($table.hasClass('hasSaveSort')) {
+				if (saveSort && table.hasInitialized && ts.storage) {
+					ts.storage( table, 'tablesorter-savesort', sortList );
+					if (c.debug) {
+						console.log('saveSort widget: Saving last sort: ' + c.sortList + ts.benchmark(time));
+					}
+				}
+			} else {
+				// set table sort on initial run of the widget
+				$table.addClass('hasSaveSort');
+				sortList = '';
+				// get data
+				if (ts.storage) {
+					stored = ts.storage( table, 'tablesorter-savesort' );
+					sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : '';
+					if (c.debug) {
+						console.log('saveSort: Last sort loaded: "' + sortList + '"' + ts.benchmark(time));
+					}
+					$table.bind('saveSortReset', function(event) {
+						event.stopPropagation();
+						ts.storage( table, 'tablesorter-savesort', '' );
+					});
+				}
+				// init is true when widget init is run, this will run this widget before all other widgets have initialized
+				// this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice.
+				if (init && sortList && sortList.length > 0) {
+					c.sortList = sortList;
+				} else if (table.hasInitialized && sortList && sortList.length > 0) {
+					// update sort change
+					ts.sortOn( c, sortList );
+				}
+			}
+		},
+		remove: function(table, c) {
+			c.$table.removeClass('hasSaveSort');
+			// clear storage
+			if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); }
+		}
+	});
+
+})(jQuery);
+
+return jQuery.tablesorter;
+}));
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.combined.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.combined.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..c5600854cc987ae5195923b07c32d6319d7a816f
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.combined.min.js
@@ -0,0 +1,4 @@
+/*! tablesorter (FORK) - updated 01-06-2017 (v2.28.4)*/
+!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(b){"use strict";var c=b.tablesorter={version:"2.28.4",parsers:[],widgets:[],defaults:{theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null,onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,resort:!0,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1,sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",duplicateSpan:!0,textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,initWidgets:!0,widgetClass:"widget-{name}",widgets:[],widgetOptions:{zebra:["even","odd"]},initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssInfoBlock:"tablesorter-infoOnly",cssNoSort:"tablesorter-noSort",cssIgnoreRow:"tablesorter-ignoreRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[],globalize:0,imgAttr:0},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"},language:{sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",sortDisabled:"sorting is disabled",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,chunk:/(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i,comma:/,/g,digitNonUS:/[\s|\.]/g,digitNegativeTest:/^\s*\([.\d]+\)/,digitNegativeReplace:/^\s*\(([.\d]+)\)/,digitTest:/^[\-+(]?\d+[)]?$/,digitReplace:/[,.'"\s]/g},string:{max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,null:0,top:!0,bottom:!1},keyCodes:{enter:13},dates:{},instanceMethods:{},setup:function(a,d){if(!a||!a.tHead||0===a.tBodies.length||a.hasInitialized===!0)return void(d.debug&&(a.hasInitialized?console.warn("Stopping initialization. Tablesorter has already been initialized"):console.error("Stopping initialization! No table, thead or tbody",a)));var e="",f=b(a),g=b.metadata;a.hasInitialized=!1,a.isProcessing=!0,a.config=d,b.data(a,"tablesorter",d),d.debug&&(console[console.group?"group":"log"]("Initializing tablesorter v"+c.version),b.data(a,"startoveralltimer",new Date)),d.supportsDataObject=function(a){return a[0]=parseInt(a[0],10),a[0]>1||1===a[0]&&parseInt(a[1],10)>=4}(b.fn.jquery.split(".")),d.emptyTo=d.emptyTo.toLowerCase(),d.stringTo=d.stringTo.toLowerCase(),d.last={sortList:[],clickedIndex:-1},/tablesorter\-/.test(f.attr("class"))||(e=""!==d.theme?" tablesorter-"+d.theme:""),d.table=a,d.$table=f.addClass(c.css.table+" "+d.tableClass+e).attr("role","grid"),d.$headers=f.find(d.selectorHeaders),d.namespace?d.namespace="."+d.namespace.replace(c.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={},d.textExtraction=d.$table.attr("data-text-extraction")||d.textExtraction||"basic",c.buildHeaders(d),c.fixColumnWidth(a),c.addWidgetFromClass(a),c.applyWidgetOptions(a),c.setupParsers(d),d.totalRows=0,c.validateOptions(d),d.delayInit||c.buildCache(d),c.bindEvents(a,d.$headers,!0),c.bindMethods(d),d.supportsDataObject&&"undefined"!=typeof f.data().sortlist?d.sortList=f.data().sortlist:g&&f.metadata()&&f.metadata().sortlist&&(d.sortList=f.metadata().sortlist),c.applyWidget(a,!0),d.sortList.length>0?c.sortOn(d,d.sortList,{},!d.initWidgets):(c.setHeadersCss(d),d.initWidgets&&c.applyWidget(a,!1)),d.showProcessing&&f.unbind("sortBegin"+d.namespace+" sortEnd"+d.namespace).bind("sortBegin"+d.namespace+" sortEnd"+d.namespace,function(b){clearTimeout(d.timerProcessing),c.isProcessing(a),"sortBegin"===b.type&&(d.timerProcessing=setTimeout(function(){c.isProcessing(a,!0)},500))}),a.hasInitialized=!0,a.isProcessing=!1,d.debug&&(console.log("Overall initialization time:"+c.benchmark(b.data(a,"startoveralltimer"))),d.debug&&console.groupEnd&&console.groupEnd()),f.triggerHandler("tablesorter-initialized",a),"function"==typeof d.initialized&&d.initialized(a)},bindMethods:function(a){var d=a.$table,e=a.namespace,f="sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(e+" ");d.unbind(f.replace(c.regex.spaces," ")).bind("sortReset"+e,function(a,b){a.stopPropagation(),c.sortReset(this.config,b)}).bind("updateAll"+e,function(a,b,d){a.stopPropagation(),c.updateAll(this.config,b,d)}).bind("update"+e+" updateRows"+e,function(a,b,d){a.stopPropagation(),c.update(this.config,b,d)}).bind("updateHeaders"+e,function(a,b){a.stopPropagation(),c.updateHeaders(this.config,b)}).bind("updateCell"+e,function(a,b,d,e){a.stopPropagation(),c.updateCell(this.config,b,d,e)}).bind("addRows"+e,function(a,b,d,e){a.stopPropagation(),c.addRows(this.config,b,d,e)}).bind("updateComplete"+e,function(){this.isUpdating=!1}).bind("sorton"+e,function(a,b,d,e){a.stopPropagation(),c.sortOn(this.config,b,d,e)}).bind("appendCache"+e,function(a,d,e){a.stopPropagation(),c.appendCache(this.config,e),b.isFunction(d)&&d(this)}).bind("updateCache"+e,function(a,b,d){a.stopPropagation(),c.updateCache(this.config,b,d)}).bind("applyWidgetId"+e,function(a,b){a.stopPropagation(),c.applyWidgetId(this,b)}).bind("applyWidgets"+e,function(a,b){a.stopPropagation(),c.applyWidget(this,b)}).bind("refreshWidgets"+e,function(a,b,d){a.stopPropagation(),c.refreshWidgets(this,b,d)}).bind("removeWidget"+e,function(a,b,d){a.stopPropagation(),c.removeWidget(this,b,d)}).bind("destroy"+e,function(a,b,d){a.stopPropagation(),c.destroy(this,b,d)}).bind("resetToLoadState"+e,function(d){d.stopPropagation(),c.removeWidget(this,!0,!1);var e=b.extend(!0,{},a.originalSettings);a=b.extend(!0,c.defaults,e),a.originalSettings=e,this.hasInitialized=!1,c.setup(this,a)})},bindEvents:function(a,d,e){a=b(a)[0];var f,g=a.config,h=g.namespace,i=null;e!==!0&&(d.addClass(h.slice(1)+"_extra_headers"),f=b.fn.closest?d.closest("table")[0]:d.parents("table")[0],f&&"TABLE"===f.nodeName&&f!==a&&b(f).addClass(h.slice(1)+"_extra_table")),f=(g.pointerDown+" "+g.pointerUp+" "+g.pointerClick+" sort keyup ").replace(c.regex.spaces," ").split(" ").join(h+" "),d.find(g.selectorSort).add(d.filter(g.selectorSort)).unbind(f).bind(f,function(a,e){var f,h,j,k=b(a.target),l=" "+a.type+" ";if(!(1!==(a.which||a.button)&&!l.match(" "+g.pointerClick+" | sort | keyup ")||" keyup "===l&&a.which!==c.keyCodes.enter||l.match(" "+g.pointerClick+" ")&&"undefined"!=typeof a.which||l.match(" "+g.pointerUp+" ")&&i!==a.target&&e!==!0)){if(l.match(" "+g.pointerDown+" "))return i=a.target,j=k.jquery.split("."),void("1"===j[0]&&j[1]<4&&a.preventDefault());if(i=null,c.regex.formElements.test(a.target.nodeName)||k.hasClass(g.cssNoSort)||k.parents("."+g.cssNoSort).length>0||k.parents("button").length>0)return!g.cancelSelection;g.delayInit&&c.isEmptyObject(g.cache)&&c.buildCache(g),f=b.fn.closest?b(this).closest("th, td"):/TH|TD/.test(this.nodeName)?b(this):b(this).parents("th, td"),j=d.index(f),g.last.clickedIndex=j<0?f.attr("data-column"):j,h=g.$headers[g.last.clickedIndex],h&&!h.sortDisabled&&c.initSort(g,h,a)}}),g.cancelSelection&&d.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})},buildHeaders:function(a){var d,e,f,g;for(a.headerList=[],a.headerContent=[],a.sortVars=[],a.debug&&(f=new Date),a.columns=c.computeColumnIndex(a.$table.children("thead, tfoot").children("tr")),e=a.cssIcon?'<i class="'+(a.cssIcon===c.css.icon?c.css.icon:a.cssIcon+" "+c.css.icon)+'"></i>':"",a.$headers=b(b.map(a.$table.find(a.selectorHeaders),function(d,f){var g,h,i,j,k,l=b(d);if(!l.parent().hasClass(a.cssIgnoreRow))return g=c.getColumnData(a.table,a.headers,f,!0),a.headerContent[f]=l.html(),""===a.headerTemplate||l.find("."+c.css.headerIn).length||(j=a.headerTemplate.replace(c.regex.templateContent,l.html()).replace(c.regex.templateIcon,l.find("."+c.css.icon).length?"":e),a.onRenderTemplate&&(h=a.onRenderTemplate.apply(l,[f,j]),h&&"string"==typeof h&&(j=h)),l.html('<div class="'+c.css.headerIn+'">'+j+"</div>")),a.onRenderHeader&&a.onRenderHeader.apply(l,[f,a,a.$table]),i=parseInt(l.attr("data-column"),10),d.column=i,k=c.getOrder(c.getData(l,g,"sortInitialOrder")||a.sortInitialOrder),a.sortVars[i]={count:-1,order:k?a.sortReset?[1,0,2]:[1,0]:a.sortReset?[0,1,2]:[0,1],lockedOrder:!1},k=c.getData(l,g,"lockedOrder")||!1,"undefined"!=typeof k&&k!==!1&&(a.sortVars[i].lockedOrder=!0,a.sortVars[i].order=c.getOrder(k)?[1,1]:[0,0]),a.headerList[f]=d,l.addClass(c.css.header+" "+a.cssHeader).parent().addClass(c.css.headerRow+" "+a.cssHeaderRow).attr("role","row"),a.tabIndex&&l.attr("tabindex",0),d})),a.$headerIndexed=[],g=0;g<a.columns;g++)c.isEmptyObject(a.sortVars[g])&&(a.sortVars[g]={}),d=a.$headers.filter('[data-column="'+g+'"]'),a.$headerIndexed[g]=d.length?d.not(".sorter-false").length?d.not(".sorter-false").filter(":last"):d.filter(":last"):b();a.$table.find(a.selectorHeaders).attr({scope:"col",role:"columnheader"}),c.updateHeader(a),a.debug&&(console.log("Built headers:"+c.benchmark(f)),console.log(a.$headers))},addInstanceMethods:function(a){b.extend(c.instanceMethods,a)},setupParsers:function(a,b){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=a.table,s=0,t={};if(a.$tbodies=a.$table.children("tbody:not(."+a.cssInfoBlock+")"),p="undefined"==typeof b?a.$tbodies:b,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:[]};s<q;){if(d=p[s].rows,d.length)for(h=0,g=a.columns,i=0;i<g;i++){if(j=a.$headerIndexed[h],j&&j.length&&(k=c.getColumnData(r,a.headers,h),n=c.getParserById(c.getData(j,k,"extractor")),m=c.getParserById(c.getData(j,k,"sorter")),l="false"===c.getData(j,k,"parser"),a.empties[h]=(c.getData(j,k,"empty")||a.emptyTo||(a.emptyToBottom?"bottom":"top")).toLowerCase(),a.strings[h]=(c.getData(j,k,"string")||a.stringTo||"max").toLowerCase(),l&&(m=c.getParserById("no-parser")),n||(n=!1),m||(m=c.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))for(h+=f,g+=f;f+1>0;)e.parsers[h-f]=m,e.extractors[h-f]=n,f--;h++}s+=e.parsers.length?q:1}a.debug&&(c.isEmptyObject(t)?console.warn("  No parsers detected!"):console[console.table?"table":"log"](t),console.log("Completed detecting parsers"+c.benchmark(o)),console.groupEnd&&console.groupEnd()),a.parsers=e.parsers,a.extractors=e.extractors},addParser:function(a){var b,d=c.parsers.length,e=!0;for(b=0;b<d;b++)c.parsers[b].id.toLowerCase()===a.id.toLowerCase()&&(e=!1);e&&(c.parsers[c.parsers.length]=a)},getParserById:function(a){if("false"==a)return!1;var b,d=c.parsers.length;for(b=0;b<d;b++)if(c.parsers[b].id.toLowerCase()===a.toString().toLowerCase())return c.parsers[b];return!1},detectParserForColumn:function(a,d,e,f){for(var g,h,i,j=c.parsers.length,k=!1,l="",m=!0;""===l&&m;)e++,i=d[e],i&&e<50?i.className.indexOf(c.cssIgnoreRow)<0&&(k=d[e].cells[f],l=c.getElementText(a,k,f),h=b(k),a.debug&&console.log("Checking if value was empty on row "+e+", column: "+f+': "'+l+'"')):m=!1;for(;--j>=0;)if(g=c.parsers[j],g&&"text"!==g.id&&g.is&&g.is(l,a.table,k,h))return g;return c.getParserById("text")},getElementText:function(a,d,e){if(!d)return"";var f,g=a.textExtraction||"",h=d.jquery?d:b(d);return"string"==typeof g?"basic"===g&&"undefined"!=typeof(f=h.attr(a.textAttribute))?b.trim(f):b.trim(d.textContent||h.text()):"function"==typeof g?b.trim(g(h[0],a.table,e)):"function"==typeof(f=c.getColumnData(a.table,g,e))?b.trim(f(h[0],a.table,e)):b.trim(h[0].textContent||h.text())},getParsedText:function(a,b,d,e){"undefined"==typeof e&&(e=c.getElementText(a,b,d));var f=""+e,g=a.parsers[d],h=a.extractors[d];return g&&(h&&"function"==typeof h.format&&(e=h.format(e,a.table,b,d)),f="no-parser"===g.id?"":g.format(""+e,a.table,b,d),a.ignoreCase&&"string"==typeof f&&(f=f.toLowerCase())),f},buildCache:function(a,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B=a.table,C=a.parsers;if(a.$tbodies=a.$table.children("tbody:not(."+a.cssInfoBlock+")"),l="undefined"==typeof e?a.$tbodies:e,a.cache={},a.totalRows=0,!C)return a.debug?console.warn("Warning: *Empty table!* Not building a cache"):"";for(a.debug&&(q=new Date),a.showProcessing&&c.isProcessing(B,!0),k=0;k<l.length;k++){for(u=[],f=a.cache[k]={normalized:[]},r=l[k]&&l[k].rows.length||0,i=0;i<r;++i)if(s={child:[],raw:[]},m=b(l[k].rows[i]),n=[],!m.hasClass(a.selectorRemove.slice(1)))if(m.hasClass(a.cssChildRow)&&0!==i)for(z=f.normalized.length-1,t=f.normalized[z][a.columns],t.$row=t.$row.add(m),m.prev().hasClass(a.cssChildRow)||m.prev().addClass(c.css.cssHasChild),o=m.children("th, td"),z=t.child.length,t.child[z]=[],w=0,y=a.columns,j=0;j<y;j++)p=o[j],p&&(t.child[z][j]=c.getParsedText(a,p,j),v=o[j].colSpan-1,v>0&&(w+=v,y+=v)),w++;else{for(s.$row=m,s.order=i,w=0,y=a.columns,j=0;j<y;++j){if(p=m[0].cells[j],p&&w<a.columns&&(x="undefined"!=typeof C[w],!x&&a.debug&&console.warn("No parser found for row: "+i+", column: "+j+'; cell containing: "'+b(p).text()+'"; does it have a header?'),g=c.getElementText(a,p,w),s.raw[w]=g,h=c.getParsedText(a,p,w,g),n[w]=h,x&&"numeric"===(C[w].type||"").toLowerCase()&&(u[w]=Math.max(Math.abs(h)||0,u[w]||0)),v=p.colSpan-1,v>0)){for(A=0;A<=v;)h=a.duplicateSpan||0===A?g:"string"!=typeof a.textExtraction?c.getElementText(a,p,w+A)||"":"",s.raw[w+A]=h,n[w+A]=h,A++;w+=v,y+=v}w++}n[a.columns]=s,f.normalized[f.normalized.length]=n}f.colMax=u,a.totalRows+=f.normalized.length}if(a.showProcessing&&c.isProcessing(B),a.debug){for(z=Math.min(5,a.cache[0].normalized.length),console[console.group?"group":"log"]("Building cache for "+a.totalRows+" rows (showing "+z+" rows in log) and "+a.columns+" columns"+c.benchmark(q)),g={},j=0;j<a.columns;j++)for(w=0;w<z;w++)g["row: "+w]||(g["row: "+w]={}),g["row: "+w][a.$headerIndexed[j].text()]=a.cache[0].normalized[w][j];console[console.table?"table":"log"](g),console.groupEnd&&console.groupEnd()}b.isFunction(d)&&d(B)},getColumnText:function(a,d,e,f){a=b(a)[0];var g,h,i,j,k,l,m,n,o,p,q="function"==typeof e,r="all"===d,s={raw:[],parsed:[],$cell:[]},t=a.config;if(!c.isEmptyObject(t)){for(k=t.$tbodies.length,g=0;g<k;g++)for(i=t.cache[g].normalized,l=i.length,h=0;h<l;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[s.parsed.length]=n,s.raw[s.raw.length]=m,s.$cell[s.$cell.length]=o));return s}t.debug&&console.warn("No cache found - aborting getColumnText function!")},setHeadersCss:function(a){var d,e,f,g=a.sortList,h=g.length,i=c.css.sortNone+" "+a.cssNone,j=[c.css.sortAsc+" "+a.cssAsc,c.css.sortDesc+" "+a.cssDesc],k=[a.cssIconAsc,a.cssIconDesc,a.cssIconNone],l=["ascending","descending"],m=a.$table.find("tfoot tr").children("td, th").add(b(a.namespace+"_extra_headers")).removeClass(j.join(" "));for(a.$headers.add(b("thead "+a.namespace+"_extra_headers")).removeClass(j.join(" ")).addClass(i).attr("aria-sort","none").find("."+c.css.icon).removeClass(k.join(" ")).addClass(k[2]),e=0;e<h;e++)if(2!==g[e][1]&&(d=a.$headers.filter(function(b){for(var d=!0,e=a.$headers.eq(b),f=parseInt(e.attr("data-column"),10),g=f+a.$headers[b].colSpan;f<g;f++)d=!!d&&(d||c.isValueInArray(f,a.sortList)>-1);return d}),d=d.not(".sorter-false").filter('[data-column="'+g[e][0]+'"]'+(1===h?":last":"")),d.length)){for(f=0;f<d.length;f++)d[f].sortDisabled||d.eq(f).removeClass(i).addClass(j[g[e][1]]).attr("aria-sort",l[g[e][1]]).find("."+c.css.icon).removeClass(k[2]).addClass(k[g[e][1]]);m.length&&m.filter('[data-column="'+g[e][0]+'"]').removeClass(i).addClass(j[g[e][1]])}for(h=a.$headers.length,e=0;e<h;e++)c.setColumnAriaLabel(a,a.$headers.eq(e))},setColumnAriaLabel:function(a,d,e){if(d.length){var f=parseInt(d.attr("data-column"),10),g=a.sortVars[f],h=d.hasClass(c.css.sortAsc)?"sortAsc":d.hasClass(c.css.sortDesc)?"sortDesc":"sortNone",i=b.trim(d.text())+": "+c.language[h];d.hasClass("sorter-false")||e===!1?i+=c.language.sortDisabled:(h=(g.count+1)%g.order.length,e=g.order[h],i+=c.language[0===e?"nextAsc":1===e?"nextDesc":"nextNone"]),d.attr("aria-label",i)}},updateHeader:function(a){var b,d,e,f,g=a.table,h=a.$headers.length;for(b=0;b<h;b++)e=a.$headers.eq(b),f=c.getColumnData(g,a.headers,b,!0),d="false"===c.getData(e,f,"sorter")||"false"===c.getData(e,f,"parser"),c.setColumnSort(a,e,d)},setColumnSort:function(a,b,c){var d=a.table.id;b[0].sortDisabled=c,b[c?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+c),a.tabIndex&&(c?b.removeAttr("tabindex"):b.attr("tabindex","0")),d&&(c?b.removeAttr("aria-controls"):b.attr("aria-controls",d))},updateHeaderSortCount:function(a,d){var e,f,g,h,i,j,k,l,m=d||a.sortList,n=m.length;for(a.sortList=[],h=0;h<n;h++)if(k=m[h],e=parseInt(k[0],10),e<a.columns){switch(a.sortVars[e].order||(l=c.getOrder(a.sortInitialOrder)?a.sortReset?[1,0,2]:[1,0]:a.sortReset?[0,1,2]:[0,1],a.sortVars[e].order=l,a.sortVars[e].count=0),l=a.sortVars[e].order,f=(""+k[1]).match(/^(1|d|s|o|n)/),f=f?f[0]:""){case"1":case"d":f=1;break;case"s":f=i||0;break;case"o":j=l[(i||0)%l.length],f=0===j?1:1===j?0:2;break;case"n":f=l[++a.sortVars[e].count%l.length];break;default:f=0}i=0===h?f:i,g=[e,parseInt(f,10)||0],a.sortList[a.sortList.length]=g,f=b.inArray(g[1],l),a.sortVars[e].count=f>=0?f:g[1]%l.length}},updateAll:function(a,b,d){var e=a.table;e.isUpdating=!0,c.refreshWidgets(e,!0,!0),c.buildHeaders(a),c.bindEvents(e,a.$headers,!0),c.bindMethods(a),c.commonUpdate(a,b,d)},update:function(a,b,d){var e=a.table;e.isUpdating=!0,c.updateHeader(a),c.commonUpdate(a,b,d)},updateHeaders:function(a,b){a.table.isUpdating=!0,c.buildHeaders(a),c.bindEvents(a.table,a.$headers,!0),c.resortComplete(a,b)},updateCell:function(a,d,e,f){if(c.isEmptyObject(a.cache))return c.updateHeader(a),void c.commonUpdate(a,e,f);a.table.isUpdating=!0,a.$table.find(a.selectorRemove).remove();var g,h,i,j,k,l,m=a.$tbodies,n=b(d),o=m.index(b.fn.closest?n.closest("tbody"):n.parents("tbody").filter(":first")),p=a.cache[o],q=b.fn.closest?n.closest("tr"):n.parents("tr").filter(":first");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!==a.columns)for(j=0,g=!1,h=0;h<l;h++)g||q[0].cells[h]===d?g=!0:j+=q[0].cells[h].colSpan;else j=n.index();g=c.getElementText(a,d,j),k[a.columns].raw[j]=g,g=c.getParsedText(a,d,j,g),k[j]=g,k[a.columns].$row=q,"numeric"===(a.parsers[j].type||"").toLowerCase()&&(p.colMax[j]=Math.max(Math.abs(g)||0,p.colMax[j]||0)),g="undefined"!==e?e:a.resort,g!==!1?c.checkResort(a,g,f):c.resortComplete(a,f)}else a.debug&&console.error("updateCell aborted, tbody missing or not within the indicated table"),a.table.isUpdating=!1},addRows:function(d,e,f,g){var h,i,j,k,l,m,n,o,p,q,r,s,t,u="string"==typeof e&&1===d.$tbodies.length&&/<tr/.test(e||""),v=d.table;if(u)e=b(e),d.$tbodies.append(e);else if(!(e&&e instanceof a&&(b.fn.closest?e.closest("table")[0]:e.parents("table")[0])===d.table))return d.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(v.isUpdating=!0,c.isEmptyObject(d.cache))c.updateHeader(d),c.commonUpdate(d,f,g);else{for(l=e.filter("tr").attr("role","row").length,j=d.$tbodies.index(e.parents("tbody").filter(":first")),d.parsers&&d.parsers.length||c.setupParsers(d),k=0;k<l;k++){for(p=0,n=e[k].cells.length,o=d.cache[j].normalized.length,r=[],q={child:[],raw:[],$row:e.eq(k),order:o},m=0;m<n;m++)s=e[k].cells[m],h=c.getElementText(d,s,p),q.raw[p]=h,i=c.getParsedText(d,s,p,h),r[p]=i,"numeric"===(d.parsers[p].type||"").toLowerCase()&&(d.cache[j].colMax[p]=Math.max(Math.abs(i)||0,d.cache[j].colMax[p]||0)),t=s.colSpan-1,t>0&&(p+=t),p++;r[d.columns]=q,d.cache[j].normalized[o]=r}c.checkResort(d,f,g)}},updateCache:function(a,b,d){a.parsers&&a.parsers.length||c.setupParsers(a,d),c.buildCache(a,b,d)},appendCache:function(a,b){var d,e,f,g,h,i,j,k=a.table,l=a.widgetOptions,m=a.$tbodies,n=[],o=a.cache;if(c.isEmptyObject(o))return a.appender?a.appender(k,n):k.isUpdating?a.$table.triggerHandler("updateComplete",k):"";for(a.debug&&(j=new Date),i=0;i<m.length;i++)if(f=m.eq(i),f.length){for(g=c.processTbody(k,f,!0),d=o[i].normalized,e=d.length,h=0;h<e;h++)n[n.length]=d[h][a.columns].$row,a.appender&&(!a.pager||a.pager.removeRows&&l.pager_removeRows||a.pager.ajax)||g.append(d[h][a.columns].$row);c.processTbody(k,g,!1)}a.appender&&a.appender(k,n),a.debug&&console.log("Rebuilt table"+c.benchmark(j)),b||a.appender||c.applyWidget(k),k.isUpdating&&a.$table.triggerHandler("updateComplete",k)},commonUpdate:function(a,b,d){a.$table.find(a.selectorRemove).remove(),c.setupParsers(a),c.buildCache(a),c.checkResort(a,b,d)},initSort:function(a,d,e){if(a.table.isUpdating)return setTimeout(function(){c.initSort(a,d,e)},50);var f,g,h,i,j,k,l,m=!e[a.sortMultiSortKey],n=a.table,o=a.$headers.length,p=parseInt(b(d).attr("data-column"),10),q=a.sortVars[p].order;if(a.$table.triggerHandler("sortStart",n),k=(a.sortVars[p].count+1)%q.length,a.sortVars[p].count=e[a.sortResetKey]?2:k,a.sortRestart)for(h=0;h<o;h++)l=a.$headers.eq(h),k=parseInt(l.attr("data-column"),10),p!==k&&(m||l.hasClass(c.css.sortNone))&&(a.sortVars[k].count=-1);if(m){if(a.sortList=[],a.last.sortList=[],null!==a.sortForce)for(f=a.sortForce,g=0;g<f.length;g++)f[g][0]!==p&&(a.sortList[a.sortList.length]=f[g]);if(i=q[a.sortVars[p].count],i<2&&(a.sortList[a.sortList.length]=[p,i],d.colSpan>1))for(g=1;g<d.colSpan;g++)a.sortList[a.sortList.length]=[p+g,i],a.sortVars[p+g].count=b.inArray(i,q)}else if(a.sortList=b.extend([],a.last.sortList),c.isValueInArray(p,a.sortList)>=0)for(g=0;g<a.sortList.length;g++)k=a.sortList[g],k[0]===p&&(k[1]=q[a.sortVars[p].count],2===k[1]&&(a.sortList.splice(g,1),a.sortVars[p].count=-1));else if(i=q[a.sortVars[p].count],i<2&&(a.sortList[a.sortList.length]=[p,i],d.colSpan>1))for(g=1;g<d.colSpan;g++)a.sortList[a.sortList.length]=[p+g,i],a.sortVars[p+g].count=b.inArray(i,q);if(a.last.sortList=b.extend([],a.sortList),a.sortList.length&&a.sortAppend&&(f=b.isArray(a.sortAppend)?a.sortAppend:a.sortAppend[a.sortList[0][0]],!c.isEmptyObject(f)))for(g=0;g<f.length;g++)if(f[g][0]!==p&&c.isValueInArray(f[g][0],a.sortList)<0){if(i=f[g][1],j=(""+i).match(/^(a|d|s|o|n)/))switch(k=a.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)%q.length;break;default:i=0}a.sortList[a.sortList.length]=[f[g][0],i]}a.$table.triggerHandler("sortBegin",n),setTimeout(function(){c.setHeadersCss(a),c.multisort(a),c.appendCache(a),a.$table.triggerHandler("sortBeforeEnd",n),a.$table.triggerHandler("sortEnd",n)},1)},multisort:function(a){var b,d,e,f,g,h=a.table,i=[],j=0,k=a.textSorter||"",l=a.sortList,m=l.length,n=a.$tbodies.length;if(!a.serverSideSorting&&!c.isEmptyObject(a.cache)){if(a.debug&&(d=new Date),"object"==typeof k)for(e=a.columns;e--;)g=c.getColumnData(h,k,e),"function"==typeof g&&(i[e]=g);for(b=0;b<n;b++)e=a.cache[b].colMax,f=a.cache[b].normalized,f.sort(function(b,d){var f,g,n,o,p,q,r;for(f=0;f<m;f++){if(n=l[f][0],o=l[f][1],j=0===o,a.sortStable&&b[n]===d[n]&&1===m)return b[a.columns].order-d[a.columns].order;if(g=/n/i.test(c.getSortType(a.parsers,n)),g&&a.strings[n]?(g="boolean"==typeof c.string[a.strings[n]]?(j?1:-1)*(c.string[a.strings[n]]?-1:1):a.strings[n]?c.string[a.strings[n]]||0:0,p=a.numberSorter?a.numberSorter(b[n],d[n],j,e[n],h):c["sortNumeric"+(j?"Asc":"Desc")](b[n],d[n],g,e[n],n,a)):(q=j?b:d,r=j?d:b,p="function"==typeof k?k(q[n],r[n],j,n,h):"function"==typeof i[n]?i[n](q[n],r[n],j,n,h):c["sortNatural"+(j?"Asc":"Desc")](b[n],d[n],n,a)),p)return p}return b[a.columns].order-d[a.columns].order});a.debug&&console.log("Applying sort "+l.toString()+c.benchmark(d))}},resortComplete:function(a,c){a.table.isUpdating&&a.$table.triggerHandler("updateComplete",a.table),b.isFunction(c)&&c(a.table)},checkResort:function(a,d,e){var f=b.isArray(d)?d:a.sortList,g="undefined"==typeof d?a.resort:d;g===!1||a.serverSideSorting||a.table.isProcessing?(c.resortComplete(a,e),c.applyWidget(a.table,!1)):f.length?c.sortOn(a,f,function(){c.resortComplete(a,e)},!0):c.sortReset(a,function(){c.resortComplete(a,e),c.applyWidget(a.table,!1)})},sortOn:function(a,d,e,f){var g=a.table;a.$table.triggerHandler("sortStart",g),c.updateHeaderSortCount(a,d),c.setHeadersCss(a),a.delayInit&&c.isEmptyObject(a.cache)&&c.buildCache(a),a.$table.triggerHandler("sortBegin",g),c.multisort(a),c.appendCache(a,f),a.$table.triggerHandler("sortBeforeEnd",g),a.$table.triggerHandler("sortEnd",g),c.applyWidget(g),b.isFunction(e)&&e(g)},sortReset:function(a,d){a.sortList=[],c.setHeadersCss(a),c.multisort(a),c.appendCache(a),b.isFunction(d)&&d(a.table)},getSortType:function(a,b){return a&&a[b]?a[b].type||"":""},getOrder:function(a){return/^d/i.test(a)||1===a},sortNatural:function(a,b){if(a===b)return 0;var d,e,f,g,h,i,j=c.regex;if(j.hex.test(b)){if(d=parseInt((a||"").match(j.hex),16),e=parseInt((b||"").match(j.hex),16),d<e)return-1;if(d>e)return 1}for(d=(a||"").replace(j.chunk,"\\0$1\\0").replace(j.chunks,"").split("\\0"),e=(b||"").replace(j.chunk,"\\0$1\\0").replace(j.chunks,"").split("\\0"),i=Math.max(d.length,e.length),h=0;h<i;h++){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(typeof f!=typeof g&&(f+="",g+=""),f<g)return-1;if(f>g)return 1}return 0},sortNaturalAsc:function(a,b,d,e){if(a===b)return 0;var f=c.string[e.empties[d]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:-f||-1:""===b&&0!==f?"boolean"==typeof f?f?1:-1:f||1:c.sortNatural(a,b)},sortNaturalDesc:function(a,b,d,e){if(a===b)return 0;var f=c.string[e.empties[d]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:f||1:""===b&&0!==f?"boolean"==typeof f?f?1:-1:-f||-1:c.sortNatural(b,a)},sortText:function(a,b){return a>b?1:a<b?-1:0},getTextValue:function(a,b,c){if(c){var d,e=a?a.length:0,f=c+b;for(d=0;d<e;d++)f+=a.charCodeAt(d);return b*f}return 0},sortNumericAsc:function(a,b,d,e,f,g){if(a===b)return 0;var h=c.string[g.empties[f]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:-h||-1:""===b&&0!==h?"boolean"==typeof h?h?1:-1:h||1:(isNaN(a)&&(a=c.getTextValue(a,d,e)),isNaN(b)&&(b=c.getTextValue(b,d,e)),a-b)},sortNumericDesc:function(a,b,d,e,f,g){if(a===b)return 0;var h=c.string[g.empties[f]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:h||1:""===b&&0!==h?"boolean"==typeof h?h?1:-1:-h||-1:(isNaN(a)&&(a=c.getTextValue(a,d,e)),isNaN(b)&&(b=c.getTextValue(b,d,e)),b-a)},sortNumeric:function(a,b){return a-b},addWidget:function(a){a.id&&!c.isEmptyObject(c.getWidgetById(a.id))&&console.warn('"'+a.id+'" widget was loaded more than once!'),c.widgets[c.widgets.length]=a},hasWidget:function(a,c){return a=b(a),a.length&&a[0].config&&a[0].config.widgetInit[c]||!1},getWidgetById:function(a){var b,d,e=c.widgets.length;for(b=0;b<e;b++)if(d=c.widgets[b],d&&d.id&&d.id.toLowerCase()===a.toLowerCase())return d},applyWidgetOptions:function(a){var d,e,f=a.config,g=f.widgets.length;if(g)for(d=0;d<g;d++)e=c.getWidgetById(f.widgets[d]),e&&e.options&&(f.widgetOptions=b.extend(!0,{},e.options,f.widgetOptions),b.extend(!0,c.defaults.widgetOptions,e.options))},addWidgetFromClass:function(a){var b,d,e=a.config,f="^"+e.widgetClass.replace(c.regex.templateName,"(\\S+)+")+"$",g=new RegExp(f,"g"),h=(a.className||"").split(c.regex.spaces);if(h.length)for(b=h.length,d=0;d<b;d++)h[d].match(g)&&(e.widgets[e.widgets.length]=h[d].replace(g,"$1"))},applyWidgetId:function(a,d,e){a=b(a)[0];var f,g,h,i=a.config,j=i.widgetOptions,k=c.getWidgetById(d);k&&(h=k.id,f=!1,b.inArray(h,i.widgets)<0&&(i.widgets[i.widgets.length]=h),i.debug&&(g=new Date),!e&&i.widgetInit[h]||(i.widgetInit[h]=!0,a.hasInitialized&&c.applyWidgetOptions(a),"function"==typeof k.init&&(f=!0,i.debug&&console[console.group?"group":"log"]("Initializing "+h+" widget"),k.init(a,k,i,j))),e||"function"!=typeof k.format||(f=!0,i.debug&&console[console.group?"group":"log"]("Updating "+h+" widget"),k.format(a,i,j,!1)),i.debug&&f&&(console.log("Completed "+(e?"initializing ":"applying ")+h+" widget"+c.benchmark(g)),console.groupEnd&&console.groupEnd()))},applyWidget:function(a,d,e){a=b(a)[0];var f,g,h,i,j,k=a.config,l=[];if(d===!1||!a.hasInitialized||!a.isApplyingWidgets&&!a.isUpdating){if(k.debug&&(j=new Date),c.addWidgetFromClass(a),clearTimeout(k.timerReady),k.widgets.length){for(a.isApplyingWidgets=!0,k.widgets=b.grep(k.widgets,function(a,c){return b.inArray(a,k.widgets)===c}),h=k.widgets||[],g=h.length,f=0;f<g;f++)i=c.getWidgetById(h[f]),i&&i.id?(i.priority||(i.priority=10),l[f]=i):k.debug&&console.warn('"'+h[f]+'" widget code does not exist!');for(l.sort(function(a,b){return a.priority<b.priority?-1:a.priority===b.priority?0:1}),g=l.length,k.debug&&console[console.group?"group":"log"]("Start "+(d?"initializing":"applying")+" widgets"),f=0;f<g;f++)i=l[f],i&&i.id&&c.applyWidgetId(a,i.id,d);k.debug&&console.groupEnd&&console.groupEnd(),d||"function"!=typeof e||e(a)}k.timerReady=setTimeout(function(){a.isApplyingWidgets=!1,b.data(a,"lastWidgetApplication",new Date),k.$table.triggerHandler("tablesorter-ready")},10),k.debug&&(i=k.widgets.length,console.log("Completed "+(d===!0?"initializing ":"applying ")+i+" widget"+(1!==i?"s":"")+c.benchmark(j)))}},removeWidget:function(a,d,e){a=b(a)[0];var f,g,h,i,j=a.config;if(d===!0)for(d=[],i=c.widgets.length,h=0;h<i;h++)g=c.widgets[h],g&&g.id&&(d[d.length]=g.id);else d=(b.isArray(d)?d.join(","):d||"").toLowerCase().split(/[\s,]+/);for(i=d.length,f=0;f<i;f++)g=c.getWidgetById(d[f]),h=b.inArray(d[f],j.widgets),h>=0&&e!==!0&&j.widgets.splice(h,1),g&&g.remove&&(j.debug&&console.log((e?"Refreshing":"Removing")+' "'+d[f]+'" widget'),g.remove(a,j,j.widgetOptions,e),j.widgetInit[d[f]]=!1)},refreshWidgets:function(a,d,e){a=b(a)[0];var f,g,h=a.config,i=h.widgets,j=c.widgets,k=j.length,l=[],m=function(a){b(a).triggerHandler("refreshComplete")};for(f=0;f<k;f++)g=j[f],g&&g.id&&(d||b.inArray(g.id,i)<0)&&(l[l.length]=g.id);c.removeWidget(a,l.join(","),!0),e!==!0?(c.applyWidget(a,d||!1,m),d&&c.applyWidget(a,!1,m)):m(a)},benchmark:function(a){return" ("+((new Date).getTime()-a.getTime())+" ms)"},log:function(){console.log(arguments)},isEmptyObject:function(a){for(var b in a)return!1;return!0},isValueInArray:function(a,b){var c,d=b&&b.length||0;for(c=0;c<d;c++)if(b[c][0]===a)return c;return-1},formatFloat:function(a,d){if("string"!=typeof a||""===a)return a;var e,f=d&&d.config?d.config.usNumberFormat!==!1:"undefined"==typeof d||d;
+return a=f?a.replace(c.regex.comma,""):a.replace(c.regex.digitNonUS,"").replace(c.regex.comma,"."),c.regex.digitNegativeTest.test(a)&&(a=a.replace(c.regex.digitNegativeReplace,"-$1")),e=parseFloat(a),isNaN(e)?b.trim(a):e},isDigit:function(a){return isNaN(a)?c.regex.digitTest.test(a.toString().replace(c.regex.digitReplace,"")):""!==a},computeColumnIndex:function(a,c){var d,e,f,g,h,i,j,k,l,m,n=c&&c.columns||0,o=[],p=new Array(n);for(d=0;d<a.length;d++)for(i=a[d].cells,e=0;e<i.length;e++){for(h=i[e],j=h.parentNode.rowIndex,k=h.rowSpan||1,l=h.colSpan||1,"undefined"==typeof o[j]&&(o[j]=[]),f=0;f<o[j].length+1;f++)if("undefined"==typeof o[j][f]){m=f;break}for(n&&h.cellIndex===m||(h.setAttribute?h.setAttribute("data-column",m):b(h).attr("data-column",m)),f=j;f<j+k;f++)for("undefined"==typeof o[f]&&(o[f]=[]),p=o[f],g=m;g<m+l;g++)p[g]="x"}return p.length},fixColumnWidth:function(a){a=b(a)[0];var d,e,f,g,h,i=a.config,j=i.$table.children("colgroup");if(j.length&&j.hasClass(c.css.colgroup)&&j.remove(),i.widthFixed&&0===i.$table.children("colgroup").length){for(j=b('<colgroup class="'+c.css.colgroup+'">'),d=i.$table.width(),f=i.$tbodies.find("tr:first").children(":visible"),g=f.length,h=0;h<g;h++)e=parseInt(f.eq(h).width()/d*1e3,10)/10+"%",j.append(b("<col>").css("width",e));i.$table.prepend(j)}},getData:function(a,c,d){var e,f,g="",h=b(a);return h.length?(e=!!b.metadata&&h.metadata(),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]||""),b.trim(g)):""},getColumnData:function(a,c,d,e,f){if("object"!=typeof c||null===c)return c;a=b(a)[0];var g,h,i=a.config,j=f||i.$headers,k=i.$headerIndexed&&i.$headerIndexed[d]||j.filter('[data-column="'+d+'"]:last');if("undefined"!=typeof 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]},isProcessing:function(a,d,e){a=b(a);var f=a[0].config,g=e||a.find("."+c.css.header);d?("undefined"!=typeof e&&f.sortList.length>0&&(g=g.filter(function(){return!this.sortDisabled&&c.isValueInArray(parseFloat(b(this).attr("data-column")),f.sortList)>=0})),a.add(g).addClass(c.css.processing+" "+f.cssProcessing)):a.add(g).removeClass(c.css.processing+" "+f.cssProcessing)},processTbody:function(a,c,d){if(a=b(a)[0],d)return a.isProcessing=!0,c.before('<colgroup class="tablesorter-savemyplace"/>'),b.fn.detach?c.detach():c.remove();var e=b(a).find("colgroup.tablesorter-savemyplace");c.insertAfter(e),e.remove(),a.isProcessing=!1},clearTableBody:function(a){b(a)[0].config.$tbodies.children().detach()},characterEquivalents:{a:"áàâãäąå",A:"ÁÀÂÃÄĄÅ",c:"çćč",C:"ÇĆČ",e:"éèêëěę",E:"ÉÈÊËĚĘ",i:"íìİîïı",I:"ÍÌİÎÏ",o:"óòôõöō",O:"ÓÒÔÕÖŌ",ss:"ß",SS:"ẞ",u:"úùûüů",U:"ÚÙÛÜŮ"},replaceAccents:function(a){var b,d="[",e=c.characterEquivalents;if(!c.characterRegex){c.characterRegexArray={};for(b in e)"string"==typeof b&&(d+=e[b],c.characterRegexArray[b]=new RegExp("["+e[b]+"]","g"));c.characterRegex=new RegExp(d+"]")}if(c.characterRegex.test(a))for(b in e)"string"==typeof b&&(a=a.replace(c.characterRegexArray[b],b));return a},validateOptions:function(a){var d,e,f,g,h="headers sortForce sortList sortAppend widgets".split(" "),i=a.originalSettings;if(i){a.debug&&(g=new Date);for(d in i)if(f=typeof c.defaults[d],"undefined"===f)console.warn('Tablesorter Warning! "table.config.'+d+'" option not recognized');else if("object"===f)for(e in i[d])f=c.defaults[d]&&typeof c.defaults[d][e],b.inArray(d,h)<0&&"undefined"===f&&console.warn('Tablesorter Warning! "table.config.'+d+"."+e+'" option not recognized');a.debug&&console.log("validate options time:"+c.benchmark(g))}},restoreHeaders:function(a){var d,e,f=b(a)[0].config,g=f.$table.find(f.selectorHeaders),h=g.length;for(d=0;d<h;d++)e=g.eq(d),e.find("."+c.css.headerIn).length&&e.html(f.headerContent[d])},destroy:function(a,d,e){if(a=b(a)[0],a.hasInitialized){c.removeWidget(a,!0,!1);var f,g=b(a),h=a.config,i=h.debug,j=g.find("thead:first"),k=j.find("tr."+c.css.headerRow).removeClass(c.css.headerRow+" "+h.cssHeaderRow),l=g.find("tfoot:first > tr").children("th, td");d===!1&&b.inArray("uitheme",h.widgets)>=0&&(g.triggerHandler("applyWidgetId",["uitheme"]),g.triggerHandler("applyWidgetId",["zebra"])),j.find("tr").not(k).remove(),f="sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave "+"keypress sortBegin sortEnd resetToLoadState ".split(" ").join(h.namespace+" "),g.removeData("tablesorter").unbind(f.replace(c.regex.spaces," ")),h.$headers.add(l).removeClass([c.css.header,h.cssHeader,h.cssAsc,h.cssDesc,c.css.sortAsc,c.css.sortDesc,c.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(c.regex.spaces," ")),c.restoreHeaders(a),g.toggleClass(c.css.table+" "+h.tableClass+" tablesorter-"+h.theme,d===!1),a.hasInitialized=!1,delete a.config.cache,"function"==typeof e&&e(a),i&&console.log("tablesorter has been removed")}}};b.fn.tablesorter=function(a){return this.each(function(){var d=this,e=b.extend(!0,{},c.defaults,a,c.instanceMethods);e.originalSettings=a,!d.hasInitialized&&c.buildTable&&"TABLE"!==this.nodeName?c.buildTable(d,e):c.setup(d,e)})},window.console&&window.console.log||(c.logs=[],console={},console.log=console.warn=console.error=console.table=function(){var a=arguments.length>1?arguments:arguments[0];c.logs[c.logs.length]={date:Date.now(),log:a}}),c.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"}),c.addParser({id:"text",is:function(){return!0},format:function(a,d){var e=d.config;return a&&(a=b.trim(e.ignoreCase?a.toLocaleLowerCase():a),a=e.sortLocaleCompare?c.replaceAccents(a):a),a},type:"text"}),c.regex.nondigit=/[^\w,. \-()]/g,c.addParser({id:"digit",is:function(a){return c.isDigit(a)},format:function(a,d){var e=c.formatFloat((a||"").replace(c.regex.nondigit,""),d);return a&&"number"==typeof e?e:a?b.trim(a&&d.config.ignoreCase?a.toLocaleLowerCase():a):a},type:"numeric"}),c.regex.currencyReplace=/[+\-,. ]/g,c.regex.currencyTest=/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/,c.addParser({id:"currency",is:function(a){return a=(a||"").replace(c.regex.currencyReplace,""),c.regex.currencyTest.test(a)},format:function(a,d){var e=c.formatFloat((a||"").replace(c.regex.nondigit,""),d);return a&&"number"==typeof e?e:a?b.trim(a&&d.config.ignoreCase?a.toLocaleLowerCase():a):a},type:"numeric"}),c.regex.urlProtocolTest=/^(https?|ftp|file):\/\//,c.regex.urlProtocolReplace=/(https?|ftp|file):\/\/(www\.)?/,c.addParser({id:"url",is:function(a){return c.regex.urlProtocolTest.test(a)},format:function(a){return a?b.trim(a.replace(c.regex.urlProtocolReplace,"")):a},type:"text"}),c.regex.dash=/-/g,c.regex.isoDate=/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/,c.addParser({id:"isoDate",is:function(a){return c.regex.isoDate.test(a)},format:function(a,b){var d=a?new Date(a.replace(c.regex.dash,"/")):a;return d instanceof Date&&isFinite(d)?d.getTime():a},type:"numeric"}),c.regex.percent=/%/g,c.regex.percentTest=/(\d\s*?%|%\s*?\d)/,c.addParser({id:"percent",is:function(a){return c.regex.percentTest.test(a)&&a.length<15},format:function(a,b){return a?c.formatFloat(a.replace(c.regex.percent,""),b):a},type:"numeric"}),c.addParser({id:"image",is:function(a,b,c,d){return d.find("img").length>0},format:function(a,c,d){return b(d).find("img").attr(c.config.imgAttr||"alt")||a},parsed:!0,type:"text"}),c.regex.dateReplace=/(\S)([AP]M)$/i,c.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,c.regex.usLongDateTest2=/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i,c.addParser({id:"usLongDate",is:function(a){return c.regex.usLongDateTest1.test(a)||c.regex.usLongDateTest2.test(a)},format:function(a,b){var d=a?new Date(a.replace(c.regex.dateReplace,"$1 $2")):a;return d instanceof Date&&isFinite(d)?d.getTime():a},type:"numeric"}),c.regex.shortDateTest=/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/,c.regex.shortDateReplace=/[\-.,]/g,c.regex.shortDateXXY=/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,c.regex.shortDateYMD=/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,c.convertFormat=function(a,b){a=(a||"").replace(c.regex.spaces," ").replace(c.regex.shortDateReplace,"/"),"mmddyyyy"===b?a=a.replace(c.regex.shortDateXXY,"$3/$1/$2"):"ddmmyyyy"===b?a=a.replace(c.regex.shortDateXXY,"$3/$2/$1"):"yyyymmdd"===b&&(a=a.replace(c.regex.shortDateYMD,"$1/$2/$3"));var d=new Date(a);return d instanceof Date&&isFinite(d)?d.getTime():""},c.addParser({id:"shortDate",is:function(a){return a=(a||"").replace(c.regex.spaces," ").replace(c.regex.shortDateReplace,"/"),c.regex.shortDateTest.test(a)},format:function(a,b,d,e){if(a){var f=b.config,g=f.$headerIndexed[e],h=g.length&&g.data("dateFormat")||c.getData(g,c.getColumnData(b,f.headers,e),"dateFormat")||f.dateFormat;return g.length&&g.data("dateFormat",h),c.convertFormat(a,h)||a}return a},type:"numeric"}),c.regex.timeTest=/^(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)$|^((?:[01]\d|[2][0-4]):[0-5]\d)$/i,c.regex.timeMatch=/(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i,c.addParser({id:"time",is:function(a){return c.regex.timeTest.test(a)},format:function(a,b){var d,e=(a||"").match(c.regex.timeMatch),f=new Date(a),g=a&&(null!==e?e[0]:"00:00 AM"),h=g?new Date("2000/01/01 "+g.replace(c.regex.dateReplace,"$1 $2")):g;return h instanceof Date&&isFinite(h)?(d=f instanceof Date&&isFinite(f)?f.getTime():0,d?parseFloat(h.getTime()+"."+f.getTime()):h.getTime()):a},type:"numeric"}),c.addParser({id:"metadata",is:function(){return!1},format:function(a,c,d){var e=c.config,f=e.parserMetadataName?e.parserMetadataName:"sortValue";return b(d).metadata()[f]},type:"numeric"}),c.addWidget({id:"zebra",priority:90,format:function(a,c,d){var e,f,g,h,i,j,k,l=new RegExp(c.cssChildRow,"i"),m=c.$tbodies.add(b(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;j<k;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,b,d,e){if(!e){var f,g,h=b.$tbodies,i=(d.zebra||["even","odd"]).join(" ");for(f=0;f<h.length;f++)g=c.processTbody(a,h.eq(f),!0),g.children().removeClass(i),c.processTbody(a,g,!1)}}})}(a),function(a,b,c){"use strict";var d=a.tablesorter||{};d.storage=function(e,f,g,h){e=a(e)[0];var i,j,k,l=!1,m={},n=e.config,o=n&&n.widgetOptions,p=h&&h.useSessionStorage||o&&o.storage_useSessionStorage?"sessionStorage":"localStorage",q=a(e),r=h&&h.id||q.attr(h&&h.group||o&&o.storage_group||"data-table-group")||o&&o.storage_tableId||e.id||a(".tablesorter").index(q),s=h&&h.url||q.attr(h&&h.page||o&&o.storage_page||"data-table-page")||o&&o.storage_fixedUrl||n&&n.fixedUrl||b.location.pathname;if(a.extend(!0,d.defaults,{fixedUrl:"",widgetOptions:{storage_fixedUrl:"",storage_group:"",storage_page:"",storage_tableId:"",storage_useSessionStorage:""}}),p in b)try{b[p].setItem("_tmptest","temp"),l=!0,b[p].removeItem("_tmptest")}catch(a){n&&n.debug&&console.warn(p+" is not supported in this browser")}return a.parseJSON&&(l?m=a.parseJSON(b[p][f]||"null")||{}:(j=c.cookie.split(/[;\s|=]/),i=a.inArray(f,j)+1,m=0!==i?a.parseJSON(j[i]||"null")||{}:{})),"undefined"!=typeof g&&b.JSON&&JSON.hasOwnProperty("stringify")?(m[s]||(m[s]={}),m[s][r]=g,l?b[p][f]=JSON.stringify(m):(k=new Date,k.setTime(k.getTime()+31536e6),c.cookie=f+"="+JSON.stringify(m).replace(/\"/g,'"')+"; expires="+k.toGMTString()+"; path=/"),void 0):m&&m[s]?m[s][r]:""}}(a,window,document),function(a){"use strict";var b=a.tablesorter||{};b.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",sortNone:"",sortAsc:"",sortDesc:"",active:"",hover:"",icons:"",iconSortNone:"bootstrap-icon-unsorted",iconSortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",iconSortDesc:"icon-chevron-down glyphicon glyphicon-chevron-down",filterRow:"",footerRow:"",footerCells:"",even:"",odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",caption:"ui-widget-content",header:"ui-widget-header ui-corner-all ui-state-default",sortNone:"",sortAsc:"",sortDesc:"",active:"ui-state-active",hover:"ui-state-hover",icons:"ui-icon",iconSortNone:"ui-icon-carat-2-n-s ui-icon-caret-2-n-s",iconSortAsc:"ui-icon-carat-1-n ui-icon-caret-1-n",iconSortDesc:"ui-icon-carat-1-s ui-icon-caret-1-s",filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",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,s=b.themes,t=d.$table.add(a(d.namespace+"_extra_table")),u=d.$headers.add(a(d.namespace+"_extra_headers")),v=d.theme||"jui",w=s[v]||{},x=a.trim([w.sortNone,w.sortDesc,w.sortAsc,w.active].join(" ")),y=a.trim([w.iconSortNone,w.iconSortDesc,w.iconSortAsc].join(" "));for(d.debug&&(j=new Date),t.hasClass("tablesorter-"+v)&&d.theme===d.appliedTheme&&e.uitheme_applied||(e.uitheme_applied=!0,o=s[d.appliedTheme]||{},r=!a.isEmptyObject(o),p=r?[o.sortNone,o.sortDesc,o.sortAsc,o.active].join(" "):"",q=r?[o.iconSortNone,o.iconSortDesc,o.iconSortAsc].join(" "):"",r&&(e.zebra[0]=a.trim(" "+e.zebra[0].replace(" "+o.even,"")),e.zebra[1]=a.trim(" "+e.zebra[1].replace(" "+o.odd,"")),d.$tbodies.children().removeClass([o.even,o.odd].join(" "))),w.even&&(e.zebra[0]+=" "+w.even),w.odd&&(e.zebra[1]+=" "+w.odd),t.children("caption").removeClass(o.caption||"").addClass(w.caption),m=t.removeClass((d.appliedTheme?"tablesorter-"+(d.appliedTheme||""):"")+" "+(o.table||"")).addClass("tablesorter-"+v+" "+(w.table||"")).children("tfoot"),d.appliedTheme=d.theme,m.length&&m.children("tr").removeClass(o.footerRow||"").addClass(w.footerRow).children("th, td").removeClass(o.footerCells||"").addClass(w.footerCells),u.removeClass((r?[o.header,o.hover,p].join(" "):"")||"").addClass(w.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(b){a(this)["mouseenter"===b.type?"addClass":"removeClass"](w.hover||"")}),u.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&&u.find("."+b.css.icon).removeClass(r?[o.icons,q].join(" "):"").addClass(w.icons||""),b.hasWidget(d.table,"filter")&&(g=function(){t.children("thead").children("."+b.css.filterRow).removeClass(r?o.filterRow||"":"").addClass(w.filterRow||"")},e.filter_initialized?g():t.one("filterInit",function(){g()}))),f=0;f<d.columns;f++)k=d.$headers.add(a(d.namespace+"_extra_headers")).not(".sorter-false").filter('[data-column="'+f+'"]'),l=b.css.icon?k.find("."+b.css.icon):a(),n=u.not(".sorter-false").filter('[data-column="'+f+'"]:last'),n.length&&(k.removeClass(x),l.removeClass(y),n[0].sortDisabled?l.removeClass(w.icons||""):(h=w.sortNone,i=w.iconSortNone,n.hasClass(b.css.sortAsc)?(h=[w.sortAsc,w.active].join(" "),i=w.iconSortAsc):n.hasClass(b.css.sortDesc)&&(h=[w.sortDesc,w.active].join(" "),i=w.iconSortDesc),k.addClass(h),l.addClass(i||"")));d.debug&&console.log("Applying "+v+" theme"+b.benchmark(j))},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))}}})}(a),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,r=e&&e.columns||["primary","secondary","tertiary"],s=r.length-1;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;m<q;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;m<q;m++)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)}})}(a),function(a){"use strict";var b,c,d=a.tablesorter||{},e=d.css,f=d.keyCodes;a.extend(e,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",filterDisabled:"disabled",filterRowHide:"hideme"}),a.extend(f,{backSpace:8,escape:27,space:32,left:37,down:40}),d.addWidget({id:"filter",priority:50,options:{filter_cellFilter:"",filter_childRows:!1,filter_childByColumn:!1,filter_childWithSibs:!0,filter_columnAnyMatch:!0,filter_columnFilters:!0,filter_cssFilter:"",filter_defaultAttrib:"data-value",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_formatter:null,filter_functions:null,filter_hideEmpty:!0,filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_matchType:{input:"exact",select:"exact"},filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_resetOnEsc:!0,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_selectSourceSeparator:"|",filter_serversideFiltering:!1,filter_startsWith:!1,filter_useParsedData:!1},format:function(a,c,d){c.$table.hasClass("hasFilters")||b.init(a,c,d)},remove:function(b,c,f,g){var h,i,j=c.$table,k=c.$tbodies,l="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(c.namespace+"filter ");if(j.removeClass("hasFilters").unbind(l.replace(d.regex.spaces," ")).find("."+e.filterRow).remove(),f.filter_initialized=!1,!g){for(h=0;h<k.length;h++)i=d.processTbody(b,k.eq(h),!0),i.children().removeClass(f.filter_filteredRow).show(),d.processTbody(b,i,!1);f.filter_reset&&a(document).undelegate(f.filter_reset,"click"+c.namespace+"filter")}}}),b=d.filter={regex:{regex:/^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/,child:/tablesorter-childRow/,filtered:/filtered/,type:/undefined|number/,exact:/(^[\"\'=]+)|([\"\'=]+$)/g,operators:/[<>=]/g,query:"(q|query)",wild01:/\?/g,wild0More:/\*/g,quote:/\"/g,isNeg1:/(>=?\s*-\d)/,isNeg2:/(<=?\s*\d)/},types:{or:function(d,e,f){if((c.orTest.test(e.iFilter)||c.orSplit.test(e.filter))&&!c.regex.test(e.filter)){var g,h,i,j,k=a.extend({},e),l=e.filter.split(c.orSplit),m=e.iFilter.split(c.orSplit),n=l.length;for(g=0;g<n;g++){k.nestedFilters=!0,k.filter=""+(b.parseFilter(d,l[g],e)||""),k.iFilter=""+(b.parseFilter(d,m[g],e)||""),i="("+(b.parseFilter(d,k.filter,e)||"")+")";try{if(j=new RegExp(e.isMatch?i:"^"+i+"$",d.widgetOptions.filter_ignoreCase?"i":""),h=j.test(k.exact)||b.processTypes(d,k,f))return h}catch(a){return null}}return h||!1}return null},and:function(d,e,f){if(c.andTest.test(e.filter)){var g,h,i,j,k,l=a.extend({},e),m=e.filter.split(c.andSplit),n=e.iFilter.split(c.andSplit),o=m.length;for(g=0;g<o;g++){l.nestedFilters=!0,l.filter=""+(b.parseFilter(d,m[g],e)||""),l.iFilter=""+(b.parseFilter(d,n[g],e)||""),j=("("+(b.parseFilter(d,l.filter,e)||"")+")").replace(c.wild01,"\\S{1}").replace(c.wild0More,"\\S*");try{k=new RegExp(e.isMatch?j:"^"+j+"$",d.widgetOptions.filter_ignoreCase?"i":""),i=k.test(l.exact)||b.processTypes(d,l,f),h=0===g?i:h&&i}catch(a){return null}}return h||!1}return null},regex:function(a,b){if(c.regex.test(b.filter)){var d,e=b.filter_regexCache[b.index]||c.regex.exec(b.filter),f=e instanceof RegExp;try{f||(b.filter_regexCache[b.index]=e=new RegExp(e[1],e[2])),d=e.test(b.exact)}catch(a){d=!1}return d}return null},operators:function(e,f){if(c.operTest.test(f.iFilter)&&""!==f.iExact){var g,h,i,j=e.table,k=f.parsed[f.index],l=d.formatFloat(f.iFilter.replace(c.operators,""),j),m=e.parsers[f.index]||{},n=l;return(k||"numeric"===m.type)&&(i=a.trim(""+f.iFilter.replace(c.operators,"")),h=b.parseFilter(e,i,f,!0),l="number"!=typeof h||""===h||isNaN(h)?l:h),!k&&"numeric"!==m.type||isNaN(l)||"undefined"==typeof f.cache?(i=isNaN(f.iExact)?f.iExact.replace(d.regex.nondigit,""):f.iExact,g=d.formatFloat(i,j)):g=f.cache,c.gtTest.test(f.iFilter)?h=c.gteTest.test(f.iFilter)?g>=l:g>l:c.ltTest.test(f.iFilter)&&(h=c.lteTest.test(f.iFilter)?g<=l:g<l),h||""!==n||(h=!0),h}return null},notMatch:function(d,e){if(c.notTest.test(e.iFilter)){var f,g=e.iFilter.replace("!",""),h=b.parseFilter(d,g,e)||"";return c.exact.test(h)?(h=h.replace(c.exact,""),""===h||a.trim(h)!==e.iExact):(f=e.iExact.search(a.trim(h)),""===h||(e.anyMatch?f<0:!(d.widgetOptions.filter_startsWith?0===f:f>=0)))}return null},exact:function(d,e){if(c.exact.test(e.iFilter)){var f=e.iFilter.replace(c.exact,""),g=b.parseFilter(d,f,e)||"";return e.anyMatch?a.inArray(g,e.rowArray)>=0:g==e.iExact}return null},range:function(a,e){if(c.toTest.test(e.iFilter)){var f,g,h,i,j=a.table,k=e.index,l=e.parsed[k],m=e.iFilter.split(c.toSplit);return g=m[0].replace(d.regex.nondigit,"")||"",h=d.formatFloat(b.parseFilter(a,g,e),j),g=m[1].replace(d.regex.nondigit,"")||"",i=d.formatFloat(b.parseFilter(a,g,e),j),(l||"numeric"===a.parsers[k].type)&&(f=a.parsers[k].format(""+m[0],j,a.$headers.eq(k),k),h=""===f||isNaN(f)?h:f,f=a.parsers[k].format(""+m[1],j,a.$headers.eq(k),k),i=""===f||isNaN(f)?i:f),!l&&"numeric"!==a.parsers[k].type||isNaN(h)||isNaN(i)?(g=isNaN(e.iExact)?e.iExact.replace(d.regex.nondigit,""):e.iExact,f=d.formatFloat(g,j)):f=e.cache,h>i&&(g=h,h=i,i=g),f>=h&&f<=i||""===h||""===i}return null},wild:function(a,d){if(c.wildOrTest.test(d.iFilter)){var e=""+(b.parseFilter(a,d.iFilter,d)||"");!c.wildTest.test(e)&&d.nestedFilters&&(e=d.isMatch?e:"^("+e+")$");try{return new RegExp(e.replace(c.wild01,"\\S{1}").replace(c.wild0More,"\\S*"),a.widgetOptions.filter_ignoreCase?"i":"").test(d.exact)}catch(a){return null}}return null},fuzzy:function(a,d){if(c.fuzzyTest.test(d.iFilter)){var e,f=0,g=d.iExact.length,h=d.iFilter.slice(1),i=b.parseFilter(a,h,d)||"";for(e=0;e<g;e++)d.iExact[e]===i[f]&&(f+=1);return f===i.length}return null}},init:function(f){d.language=a.extend(!0,{},{to:"to",or:"or",and:"and"},d.language);var g,h,i,j,k,l,m,n,o=f.config,p=o.widgetOptions;if(o.$table.addClass("hasFilters"),o.lastSearch=[],p.filter_searchTimer=null,p.filter_initTimer=null,p.filter_formatterCount=0,p.filter_formatterInit=[],p.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',p.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',l="\\{"+c.query+"\\}",a.extend(c,{child:new RegExp(o.cssChildRow),filtered:new RegExp(p.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+d.language.or+"|-|"+d.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+d.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+d.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+d.language.and+"|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+d.language.and+"|&&)\\s+)","gi"),orTest:new RegExp("(\\||\\s+"+d.language.or+"\\s+)","i"),orSplit:new RegExp("(?:\\s+(?:"+d.language.or+")\\s+|\\|)","gi"),iQuery:new RegExp(l,"i"),igQuery:new RegExp(l,"ig"),operTest:/^[<>]=?/,gtTest:/>/,gteTest:/>=/,ltTest:/</,lteTest:/<=/,notTest:/^\!/,wildOrTest:/[\?\*\|]/,wildTest:/\?\*/,fuzzyTest:/^~/,exactTest:/[=\"\|!]/}),l=o.$headers.filter(".filter-false, .parser-false").length,p.filter_columnFilters!==!1&&l!==o.$headers.length&&b.buildRow(f,o,p),i="addRows updateCell update updateRows updateComplete appendCache filterReset "+"filterResetSaved filterEnd search ".split(" ").join(o.namespace+"filter "),o.$table.bind(i,function(c,g){return l=p.filter_hideEmpty&&a.isEmptyObject(o.cache)&&!(o.delayInit&&"appendCache"===c.type),o.$table.find("."+e.filterRow).toggleClass(p.filter_filteredRow,l),/(search|filter)/.test(c.type)||(c.stopPropagation(),b.buildDefault(f,!0)),"filterReset"===c.type?(o.$table.find("."+e.filter).add(p.filter_$externalFilters).val(""),b.searching(f,[])):"filterResetSaved"===c.type?d.storage(f,"tablesorter-filters",""):"filterEnd"===c.type?b.buildDefault(f,!0):(g="search"===c.type?g:"updateComplete"===c.type?o.$table.data("lastSearch"):"",/(update|add)/.test(c.type)&&"updateComplete"!==c.type&&(o.lastCombinedFilter=null,o.lastSearch=[],setTimeout(function(){o.$table.triggerHandler("filterFomatterUpdate")},100)),b.searching(f,g,!0)),!1}),p.filter_reset&&(p.filter_reset instanceof a?p.filter_reset.click(function(){o.$table.triggerHandler("filterReset")}):a(p.filter_reset).length&&a(document).undelegate(p.filter_reset,"click"+o.namespace+"filter").delegate(p.filter_reset,"click"+o.namespace+"filter",function(){o.$table.triggerHandler("filterReset")})),p.filter_functions)for(k=0;k<o.columns;k++)if(m=d.getColumnData(f,p.filter_functions,k))if(j=o.$headerIndexed[k].removeClass("filter-select"),n=!(j.hasClass("filter-false")||j.hasClass("parser-false")),g="",m===!0&&n)b.buildSelect(f,k);else if("object"==typeof m&&n){for(h in m)"string"==typeof h&&(g+=""===g?'<option value="">'+(j.data("placeholder")||j.attr("data-placeholder")||p.filter_placeholder.select||"")+"</option>":"",l=h,i=h,h.indexOf(p.filter_selectSourceSeparator)>=0&&(l=h.split(p.filter_selectSourceSeparator),i=l[1],l=l[0]),g+="<option "+(i===l?"":'data-function-name="'+h+'" ')+'value="'+l+'">'+i+"</option>");o.$table.find("thead").find("select."+e.filter+'[data-column="'+k+'"]').append(g),i=p.filter_selectSource,m="function"==typeof i||d.getColumnData(f,i,k),m&&b.buildSelect(o.table,k,"",!0,j.hasClass(p.filter_onlyAvail))}b.buildDefault(f,!0),b.bindSearch(f,o.$table.find("."+e.filter),!0),p.filter_external&&b.bindSearch(f,p.filter_external),p.filter_hideFilters&&b.hideFilters(o),o.showProcessing&&(i="filterStart filterEnd ".split(" ").join(o.namespace+"filter "),o.$table.unbind(i.replace(d.regex.spaces," ")).bind(i,function(b,c){j=c?o.$table.find("."+e.header).filter("[data-column]").filter(function(){return""!==c[a(this).data("column")]}):"",d.isProcessing(f,"filterStart"===b.type,c?j:"")})),o.filteredRows=o.totalRows,i="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(o.namespace+"filter "),o.$table.unbind(i.replace(d.regex.spaces," ")).bind(i,function(){b.completeInit(this)}),o.pager&&o.pager.initialized&&!p.filter_initialized?(o.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){b.filterInitComplete(o)},100)):p.filter_initialized||b.completeInit(f)},completeInit:function(a){var c=a.config,e=c.widgetOptions,f=b.setDefaults(a,c,e)||[];f.length&&(c.delayInit&&""===f.join("")||d.setFilters(a,f,!0)),c.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){e.filter_initialized||b.filterInitComplete(c)},100)},formatterUpdated:function(a,b){var c=a&&a.closest("table")[0].config.widgetOptions;c&&!c.filter_initialized&&(c.filter_formatterInit[b]=1)},filterInitComplete:function(c){var d,e,f=c.widgetOptions,g=0,h=function(){f.filter_initialized=!0,c.lastSearch=c.$table.data("lastSearch"),c.$table.triggerHandler("filterInit",c),b.findRows(c.table,c.lastSearch||[])};if(a.isEmptyObject(f.filter_formatter))h();else{for(e=f.filter_formatterInit.length,d=0;d<e;d++)1===f.filter_formatterInit[d]&&g++;clearTimeout(f.filter_initTimer),f.filter_initialized||g!==f.filter_formatterCount?f.filter_initialized||(f.filter_initTimer=setTimeout(function(){h()},500)):h()}},processFilters:function(a,b){var c,d=[],e=b?encodeURIComponent:decodeURIComponent,f=a.length;for(c=0;c<f;c++)a[c]&&(d[c]=e(a[c]));return d},setDefaults:function(c,e,f){var g,h,i,j,k,l=d.getFilters(c)||[];if(f.filter_saveFilters&&d.storage&&(h=d.storage(c,"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||c.parsed[c.index]?a.parsers[c.index].format(b,a.table,[],c.index):b},buildRow:function(c,f,g){var h,i,j,k,l,m,n,o,p,q=g.filter_cellFilter,r=f.columns,s=a.isArray(q),t='<tr role="row" class="'+e.filterRow+" "+f.cssIgnoreRow+'">';for(j=0;j<r;j++)f.$headerIndexed[j].length&&(p=f.$headerIndexed[j]&&f.$headerIndexed[j][0].colSpan||0,t+=p>1?'<td data-column="'+j+"-"+(j+p-1)+'" colspan="'+p+'"':'<td data-column="'+j+'"',t+=s?q[j]?' class="'+q[j]+'"':"":""!==q?' class="'+q+'"':"",t+="></td>");for(f.$filters=a(t+="</tr>").appendTo(f.$table.children("thead").eq(0)).children("td"),j=0;j<r;j++)m=!1,k=f.$headerIndexed[j],k&&k.length&&(h=b.getColumnElm(f,f.$filters,j),o=d.getColumnData(c,g.filter_functions,j),l=g.filter_functions&&o&&"function"!=typeof o||k.hasClass("filter-select"),i=d.getColumnData(c,f.headers,j),m="false"===d.getData(k[0],i,"filter")||"false"===d.getData(k[0],i,"parser"),l?t=a("<select>").appendTo(h):(o=d.getColumnData(c,g.filter_formatter,j),o?(g.filter_formatterCount++,t=o(h,j),t&&0===t.length&&(t=h.children("input")),t&&(0===t.parent().length||t.parent().length&&t.parent()[0]!==h[0])&&h.append(t)):t=a('<input type="search">').appendTo(h),t&&(p=k.data("placeholder")||k.attr("data-placeholder")||g.filter_placeholder.search||"",t.attr("placeholder",p))),t&&(n=(a.isArray(g.filter_cssFilter)?"undefined"!=typeof g.filter_cssFilter[j]?g.filter_cssFilter[j]||"":"":g.filter_cssFilter)||"",t.addClass(e.filter+" "+n).attr("data-column",h.attr("data-column")),m&&(t.attr("placeholder","").addClass(e.filterDisabled)[0].disabled=!0)))},bindSearch:function(c,e,g){if(c=a(c)[0],e=a(e),e.length){var h,i=c.config,j=i.widgetOptions,k=i.namespace+"filter",l=j.filter_$externalFilters;g!==!0&&(h=j.filter_anyColumnSelector+","+j.filter_multipleColumnSelector,j.filter_$anyMatch=e.filter(h),l&&l.length?j.filter_$externalFilters=j.filter_$externalFilters.add(e):j.filter_$externalFilters=e,d.setFilters(c,i.$table.data("lastSearch")||[],g===!1)),h="keypress keyup keydown search change input ".split(" ").join(k+" "),e.attr("data-lastSearchTime",(new Date).getTime()).unbind(h.replace(d.regex.spaces," ")).bind("keydown"+k,function(a){if(a.which===f.escape&&!c.config.widgetOptions.filter_resetOnEsc)return!1}).bind("keyup"+k,function(e){j=c.config.widgetOptions;var g=parseInt(a(this).attr("data-column"),10),h="boolean"==typeof j.filter_liveSearch?j.filter_liveSearch:d.getColumnData(c,j.filter_liveSearch,g);if("undefined"==typeof h&&(h=j.filter_liveSearch.fallback||!1),a(this).attr("data-lastSearchTime",(new Date).getTime()),e.which===f.escape)this.value=j.filter_resetOnEsc?"":i.lastSearch[g];else{if(h===!1)return;if(""!==this.value&&("number"==typeof h&&this.value.length<h||e.which!==f.enter&&e.which!==f.backSpace&&(e.which<f.space||e.which>=f.left&&e.which<=f.down)))return}b.searching(c,!0,!0,g)}).bind("search change keypress input ".split(" ").join(k+" "),function(e){var g=parseInt(a(this).attr("data-column"),10),h="boolean"==typeof j.filter_liveSearch?j.filter_liveSearch:d.getColumnData(c,j.filter_liveSearch,g);!c.config.widgetOptions.filter_initialized||e.which!==f.enter&&"search"!==e.type&&("change"!==e.type&&"input"!==e.type||h!==!0||this.value===i.lastSearch[g])||(e.preventDefault(),
+a(this).attr("data-lastSearchTime",(new Date).getTime()),b.searching(c,"keypress"!==e.type,!0,g))})}},searching:function(a,c,e,f){var g,h=a.config.widgetOptions;"undefined"==typeof f?g=!1:(g="boolean"==typeof h.filter_liveSearch?h.filter_liveSearch:d.getColumnData(a,h.filter_liveSearch,f),"undefined"==typeof g&&(g=h.filter_liveSearch.fallback||!1)),clearTimeout(h.filter_searchTimer),"undefined"==typeof c||c===!0?h.filter_searchTimer=setTimeout(function(){b.checkFilters(a,c,e)},g?h.filter_searchDelay:10):b.checkFilters(a,c,e)},checkFilters:function(c,f,g){var h=c.config,i=h.widgetOptions,j=a.isArray(f),k=j?f:d.getFilters(c,!0),l=(k||[]).join("");return a.isEmptyObject(h.cache)?void(h.delayInit&&(!h.pager||h.pager&&h.pager.initialized)&&d.updateCache(h,function(){b.checkFilters(c,!1,g)})):(j&&(d.setFilters(c,k,!1,g!==!0),i.filter_initialized||(h.lastCombinedFilter="")),i.filter_hideFilters&&h.$table.find("."+e.filterRow).triggerHandler(b.hideFiltersCheck(h)?"mouseleave":"mouseenter"),h.lastCombinedFilter!==l||f===!1?(f===!1&&(h.lastCombinedFilter=null,h.lastSearch=[]),k=k||[],k=Array.prototype.map?k.map(String):k.join("�").split("�"),i.filter_initialized&&h.$table.triggerHandler("filterStart",[k]),h.showProcessing?void setTimeout(function(){return b.findRows(c,k,l),!1},30):(b.findRows(c,k,l),!1)):void 0)},hideFiltersCheck:function(a){if("function"==typeof a.widgetOptions.filter_hideFilters){var b=a.widgetOptions.filter_hideFilters(a);if("boolean"==typeof b)return b}return""===d.getFilters(a.$table).join("")},hideFilters:function(c,d){var f;(d||c.$table).find("."+e.filterRow).addClass(e.filterRowHide).bind("mouseenter mouseleave",function(d){var g=d,h=a(this);clearTimeout(f),f=setTimeout(function(){/enter|over/.test(g.type)?h.removeClass(e.filterRowHide):a(document.activeElement).closest("tr")[0]!==h[0]&&h.toggleClass(e.filterRowHide,b.hideFiltersCheck(c))},200)}).find("input, select").bind("focus blur",function(d){var g=d,h=a(this).closest("tr");clearTimeout(f),f=setTimeout(function(){clearTimeout(f),h.toggleClass(e.filterRowHide,b.hideFiltersCheck(c)&&"focus"!==g.type)},200)})},defaultFilter:function(b,d){if(""===b)return b;var e=c.iQuery,f=d.match(c.igQuery).length,g=f>1?a.trim(b).split(/\s/):[a.trim(b)],h=g.length-1,i=0,j=d;for(h<1&&f>1&&(g[1]=g[0]);e.test(j);)j=j.replace(e,g[i++]||""),e.test(j)&&i<h&&""!==(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()},findRange:function(a,b,c){var d,e,f,g,h,i,j,k,l,m=[];if(/^[0-9]+$/.test(b))return[parseInt(b,10)];if(!c&&/-/.test(b))for(e=b.match(/(\d+)\s*-\s*(\d+)/g),l=e?e.length:0,k=0;k<l;k++){for(f=e[k].split(/\s*-\s*/),g=parseInt(f[0],10)||0,h=parseInt(f[1],10)||a.columns-1,g>h&&(d=g,g=h,h=d),h>=a.columns&&(h=a.columns-1);g<=h;g++)m[m.length]=g;b=b.replace(e[k],"")}if(!c&&/,/.test(b))for(i=b.split(/\s*,\s*/),l=i.length,j=0;j<l;j++)""!==i[j]&&(k=parseInt(i[j],10),k<a.columns&&(m[m.length]=k));if(!m.length)for(k=0;k<a.columns;k++)m[m.length]=k;return m},getColumnElm:function(c,d,e){return d.filter(function(){var d=b.findRange(c,a(this).attr("data-column"));return a.inArray(e,d)>-1})},multipleColumns:function(c,d){var e=c.widgetOptions,f=e.filter_initialized||!d.filter(e.filter_anyColumnSelector).length,g=a.trim(b.getLatestSearch(d).attr("data-column")||"");return b.findRange(c,g,!f)},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},matchType:function(a,b){var c,d=a.widgetOptions,f=a.$headerIndexed[b];return f.hasClass("filter-exact")?c=!1:f.hasClass("filter-match")?c=!0:(d.filter_columnFilters?f=a.$filters.find("."+e.filter).add(d.filter_$externalFilters).filter('[data-column="'+b+'"]'):d.filter_$externalFilters&&(f=d.filter_$externalFilters.filter('[data-column="'+b+'"]')),c=!!f.length&&"match"===a.widgetOptions.filter_matchType[(f[0].nodeName||"").toLowerCase()]),c},processRow:function(e,f,g){var h,i,j,k,l,m=e.widgetOptions,n=!0,o=m.filter_$anyMatch&&m.filter_$anyMatch.length,p=m.filter_$anyMatch&&m.filter_$anyMatch.length?b.multipleColumns(e,m.filter_$anyMatch):[];if(f.$cells=f.$row.children(),f.anyMatchFlag&&p.length>1||f.anyMatchFilter&&!o){if(f.anyMatch=!0,f.isMatch=!0,f.rowArray=f.$cells.map(function(b){if(a.inArray(b,p)>-1||f.anyMatchFilter&&!o)return f.parsed[b]?l=f.cacheArray[b]:(l=f.rawArray[b],l=a.trim(m.filter_ignoreCase?l.toLowerCase():l),e.sortLocaleCompare&&(l=d.replaceAccents(l))),l}).get(),f.filter=f.anyMatchFilter,f.iFilter=f.iAnyMatchFilter,f.exact=f.rowArray.join(" "),f.iExact=m.filter_ignoreCase?f.exact.toLowerCase():f.exact,f.cache=f.cacheArray.slice(0,-1).join(" "),g.excludeMatch=g.noAnyMatch,i=b.processTypes(e,f,g),null!==i)n=i;else if(m.filter_startsWith)for(n=!1,p=Math.min(e.columns,f.rowArray.length);!n&&p>0;)p--,n=n||0===f.rowArray[p].indexOf(f.iFilter);else n=(f.iExact+f.childRowText).indexOf(f.iFilter)>=0;if(f.anyMatch=!1,f.filters.join("")===f.filter)return n}for(p=0;p<e.columns;p++)f.filter=f.filters[p],f.index=p,g.excludeMatch=g.excludeFilter[p],f.filter&&(f.cache=f.cacheArray[p],h=f.parsed[p]?f.cache:f.rawArray[p]||"",f.exact=e.sortLocaleCompare?d.replaceAccents(h):h,f.iExact=!c.type.test(typeof f.exact)&&m.filter_ignoreCase?f.exact.toLowerCase():f.exact,f.isMatch=b.matchType(e,p),h=n,k=m.filter_columnFilters?e.$filters.add(m.filter_$externalFilters).filter('[data-column="'+p+'"]').find("select option:selected").attr("data-function-name")||"":"",e.sortLocaleCompare&&(f.filter=d.replaceAccents(f.filter)),m.filter_defaultFilter&&c.iQuery.test(g.defaultColFilter[p])&&(f.filter=b.defaultFilter(f.filter,g.defaultColFilter[p])),f.iFilter=m.filter_ignoreCase?(f.filter||"").toLowerCase():f.filter,j=g.functions[p],i=null,j&&(j===!0?i=f.isMatch?(""+f.iExact).search(f.iFilter)>=0:f.filter===f.exact:"function"==typeof j?i=j(f.exact,f.cache,f.filter,p,f.$row,e,f):"function"==typeof j[k||f.filter]&&(l=k||f.filter,i=j[l](f.exact,f.cache,f.filter,p,f.$row,e,f))),null===i?(i=b.processTypes(e,f,g),null!==i?h=i:(l=(f.iExact+f.childRowText).indexOf(b.parseFilter(e,f.iFilter,f)),h=!m.filter_startsWith&&l>=0||m.filter_startsWith&&0===l)):h=i,n=!!h&&n);return n},findRows:function(e,f,g){if(e.config.lastCombinedFilter!==g&&e.config.widgetOptions.filter_initialized){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F=a.extend([],f),G=e.config,H=G.widgetOptions,I={anyMatch:!1,filters:f,filter_regexCache:[]},J={noAnyMatch:["range","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:d.getColumnData(e,H.filter_defaultFilter,G.columns,!0)||""};for(I.parsed=[],p=0;p<G.columns;p++)I.parsed[p]=H.filter_useParsedData||G.parsers&&G.parsers[p]&&G.parsers[p].parsed||d.getData&&"parsed"===d.getData(G.$headerIndexed[p],d.getColumnData(e,G.headers,p),"filter")||G.$headerIndexed[p].hasClass("filter-parsed"),J.functions[p]=d.getColumnData(e,H.filter_functions,p)||G.$headerIndexed[p].hasClass("filter-select"),J.defaultColFilter[p]=d.getColumnData(e,H.filter_defaultFilter,p)||"",J.excludeFilter[p]=(d.getColumnData(e,H.filter_excludeFilter,p,!0)||"").split(/\s+/);for(G.debug&&(console.log("Filter: Starting filter widget search",f),v=new Date),G.filteredRows=0,G.totalRows=0,g=(F||[]).join(""),n=0;n<G.$tbodies.length;n++){if(o=d.processTbody(e,G.$tbodies.eq(n),!0),p=G.columns,i=G.cache[n].normalized,k=a(a.map(i,function(a){return a[p].$row.get()})),""===g||H.filter_serversideFiltering)k.removeClass(H.filter_filteredRow).not("."+G.cssChildRow).css("display","");else{if(k=k.not("."+G.cssChildRow),h=k.length,(H.filter_$anyMatch&&H.filter_$anyMatch.length||"undefined"!=typeof f[G.columns])&&(I.anyMatchFlag=!0,I.anyMatchFilter=""+(f[G.columns]||H.filter_$anyMatch&&b.getLatestSearch(H.filter_$anyMatch).val()||""),H.filter_columnAnyMatch)){for(A=I.anyMatchFilter.split(c.andSplit),B=!1,x=0;x<A.length;x++)C=A[x].split(":"),C.length>1&&(isNaN(C[0])?a.each(G.headerContent,function(a,b){b.toLowerCase().indexOf(C[0])>-1&&(D=a,f[D]=C[1])}):D=parseInt(C[0],10)-1,D>=0&&D<G.columns&&(f[D]=C[1],A.splice(x,1),x--,B=!0));B&&(I.anyMatchFilter=A.join(" && "))}if(z=H.filter_searchFiltered,s=G.lastSearch||G.$table.data("lastSearch")||[],z)for(x=0;x<p+1;x++)w=f[x]||"",z||(x=p),z=z&&s.length&&0===w.indexOf(s[x]||"")&&!c.alreadyFiltered.test(w)&&!c.exactTest.test(w)&&!(c.isNeg1.test(w)||c.isNeg2.test(w))&&!(""!==w&&G.$filters&&G.$filters.filter('[data-column="'+x+'"]').find("select").length&&!b.matchType(G,x));for(y=k.not("."+H.filter_filteredRow).length,z&&0===y&&(z=!1),G.debug&&console.log("Filter: Searching through "+(z&&y<h?y:"all")+" rows"),I.anyMatchFlag&&(G.sortLocaleCompare&&(I.anyMatchFilter=d.replaceAccents(I.anyMatchFilter)),H.filter_defaultFilter&&c.iQuery.test(J.defaultAnyFilter)&&(I.anyMatchFilter=b.defaultFilter(I.anyMatchFilter,J.defaultAnyFilter),z=!1),I.iAnyMatchFilter=H.filter_ignoreCase&&G.ignoreCase?I.anyMatchFilter.toLowerCase():I.anyMatchFilter),m=0;m<h;m++)if(E=k[m].className,q=m&&c.child.test(E),!(q||z&&c.filtered.test(E))){if(I.$row=k.eq(m),I.rowIndex=m,I.cacheArray=i[m],j=I.cacheArray[G.columns],I.rawArray=j.raw,I.childRowText="",!H.filter_childByColumn){for(E="",r=j.child,x=0;x<r.length;x++)E+=" "+r[x].join(" ")||"";I.childRowText=H.filter_childRows?H.filter_ignoreCase?E.toLowerCase():E:""}if(t=!1,u=b.processRow(G,I,J),l=j.$row,w=!!u,r=j.$row.filter(":gt(0)"),H.filter_childRows&&r.length){if(H.filter_childByColumn)for(H.filter_childWithSibs||(r.addClass(H.filter_filteredRow),l=l.eq(0)),x=0;x<r.length;x++)I.$row=r.eq(x),I.cacheArray=j.child[x],I.rawArray=I.cacheArray,w=b.processRow(G,I,J),t=t||w,!H.filter_childWithSibs&&w&&r.eq(x).removeClass(H.filter_filteredRow);t=t||u}else t=w;l.toggleClass(H.filter_filteredRow,!t)[0].display=t?"":"none"}}G.filteredRows+=k.not("."+H.filter_filteredRow).length,G.totalRows+=k.length,d.processTbody(e,o,!1)}G.lastCombinedFilter=g,G.lastSearch=F,G.$table.data("lastSearch",F),H.filter_saveFilters&&d.storage&&d.storage(e,"tablesorter-filters",b.processFilters(F,!0)),G.debug&&console.log("Completed filter widget search"+d.benchmark(v)),H.filter_initialized&&(G.$table.triggerHandler("filterBeforeEnd",G),G.$table.triggerHandler("filterEnd",G)),setTimeout(function(){d.applyWidget(G.table)},0)}},getOptionSource:function(c,e,f){c=a(c)[0];var g=c.config,h=g.widgetOptions,i=!1,j=h.filter_selectSource,k=g.$table.data("lastSearch")||[],l="function"==typeof j||d.getColumnData(c,j,e);if(f&&""!==k[e]&&(f=!1),l===!0)i=j(c,e,f);else{if(l instanceof a||"string"===a.type(l)&&l.indexOf("</option>")>=0)return l;a.isArray(l)?i=l:"object"===a.type(j)&&l&&(i=l(c,e,f))}return i===!1&&(i=b.getOptions(c,e,f)),b.processOptions(c,e,i)},processOptions:function(b,c,e){if(!a.isArray(e))return!1;b=a(b)[0];var f,g,h,i,j,k,l=b.config,m="undefined"!=typeof c&&null!==c&&c>=0&&c<l.columns,n=!!m&&l.$headerIndexed[c].hasClass("filter-select-sort-desc"),o=[];if(e=a.grep(e,function(b,c){return!!b.text||a.inArray(b,e)===c}),m&&l.$headerIndexed[c].hasClass("filter-select-nosort"))return e;for(i=e.length,h=0;h<i;h++)g=e[h],k=g.text?g.text:g,j=(m&&l.parsers&&l.parsers.length&&l.parsers[c].format(k,b,[],c)||k).toString(),j=l.widgetOptions.filter_ignoreCase?j.toLowerCase():j,g.text?(g.parsed=j,o[o.length]=g):o[o.length]={text:g,parsed:j};for(f=l.textSorter||"",o.sort(function(a,e){var g=n?e.parsed:a.parsed,h=n?a.parsed:e.parsed;return m&&"function"==typeof f?f(g,h,!0,c,b):m&&"object"==typeof f&&f.hasOwnProperty(c)?f[c](g,h,!0,c,b):!d.sortNatural||d.sortNatural(g,h)}),e=[],i=o.length,h=0;h<i;h++)e[e.length]=o[h];return e},getOptions:function(b,c,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++)for(j=n.cache[g],h=n.cache[g].normalized.length,f=0;f<h;f++)if(i=j.row?j.row[f]:j.normalized[f][n.columns].$row[0],!e||!i.className.match(o.filter_filteredRow))if(o.filter_useParsedData||n.parsers[c].parsed||n.$headerIndexed[c].hasClass("filter-parsed")){if(p[p.length]=""+j.normalized[f][c],o.filter_childRows&&o.filter_childByColumn)for(m=j.normalized[f][n.columns].$row.length-1,k=0;k<m;k++)p[p.length]=""+j.normalized[f][n.columns].child[k][c]}else if(p[p.length]=j.normalized[f][n.columns].raw[c],o.filter_childRows&&o.filter_childByColumn)for(m=j.normalized[f][n.columns].$row.length,k=1;k<m;k++)l=j.normalized[f][n.columns].$row.eq(k).children().eq(c),p[p.length]=""+d.getElementText(n,l,c);return p},buildSelect:function(d,f,g,h,i){if(d=a(d)[0],f=parseInt(f,10),d.config.cache&&!a.isEmptyObject(d.config.cache)){var j,k,l,m,n,o,p,q=d.config,r=q.widgetOptions,s=q.$headerIndexed[f],t='<option value="">'+(s.data("placeholder")||s.attr("data-placeholder")||r.filter_placeholder.select||"")+"</option>",u=q.$table.find("thead").find("select."+e.filter+'[data-column="'+f+'"]').val();if("undefined"!=typeof g&&""!==g||(g=b.getOptionSource(d,f,i)),a.isArray(g)){for(j=0;j<g.length;j++)if(p=g[j],p.text){p["data-function-name"]="undefined"==typeof p.value?p.text:p.value,t+="<option";for(k in p)p.hasOwnProperty(k)&&"text"!==k&&(t+=" "+k+'="'+p[k]+'"');p.value||(t+=' value="'+p.text+'"'),t+=">"+p.text+"</option>"}else""+p!="[object Object]"&&(l=p=(""+p).replace(c.quote,"&quot;"),k=l,l.indexOf(r.filter_selectSourceSeparator)>=0&&(m=l.split(r.filter_selectSourceSeparator),k=m[0],l=m[1]),t+=""!==p?"<option "+(k===l?"":'data-function-name="'+p+'" ')+'value="'+k+'">'+l+"</option>":"");g=[]}n=(q.$filters?q.$filters:q.$table.children("thead")).find("."+e.filter),r.filter_$externalFilters&&(n=n&&n.length?n.add(r.filter_$externalFilters):r.filter_$externalFilters),o=n.filter('select[data-column="'+f+'"]'),o.length&&(o[h?"html":"append"](t),a.isArray(g)||o.append(g).val(u),o.val(u))}},buildDefault:function(a,c){var e,f,g,h=a.config,i=h.widgetOptions,j=h.columns;for(e=0;e<j;e++)f=h.$headerIndexed[e],g=!(f.hasClass("filter-false")||f.hasClass("parser-false")),(f.hasClass("filter-select")||d.getColumnData(a,i.filter_functions,e)===!0)&&g&&b.buildSelect(a,e,"",c,f.hasClass(i.filter_onlyAvail))}},c=b.regex,d.getFilters=function(c,d,f,g){var h,i,j,k,l=[],m=c?a(c)[0].config:"",n=m?m.widgetOptions:"";if(d!==!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("."+e.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 l},d.setFilters=function(c,e,f,g){var h=c?a(c)[0].config:"",i=d.getFilters(c,!0,e,g);return"undefined"==typeof f&&(f=!0),h&&f&&(h.lastCombinedFilter=null,h.lastSearch=[],b.searching(h.table,e,g),h.$table.triggerHandler("filterFomatterUpdate")),0!==i.length}}(a),function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),c.addHeaderResizeEvent=function(b,c,d){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;b<j;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.triggerHandler("resize",[c]),h.resize_flag=!1};if(clearInterval(h.resize_timer),c)return h.resize_flag=!1,!1;i(!1),h.resize_timer=setInterval(function(){h.resize_flag||i()},f.timer)}},c.addWidget({id:"stickyHeaders",priority:54,options:{stickyHeaders:"",stickyHeaders_appendTo:null,stickyHeaders_attachTo:null,stickyHeaders_xScroll:null,stickyHeaders_yScroll:null,stickyHeaders_offset:0,stickyHeaders_filteredToTop:!0,stickyHeaders_cloneId:"-sticky",stickyHeaders_addResizeEvent:!0,stickyHeaders_includeCaption:!0,stickyHeaders_zIndex:2},format:function(d,e,f){if(!(e.$table.hasClass("hasStickyHeaders")||a.inArray("filter",e.widgets)>=0&&!e.$table.hasClass("hasFilters"))){var g,h,i,j,k=e.$table,l=a(f.stickyHeaders_attachTo),m=e.namespace+"stickyheaders ",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,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,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;d<j;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")){v=u.length?u.offset().top-n.scrollTop()+u.height():0;var d=k.offset(),e=a.isWindow(n[0]),g=a.isWindow(o[0]),h=l.length?e?n.scrollTop():n.offset().top:n.scrollTop(),i=f.stickyHeaders_includeCaption?0:k.children("caption").height()||0,j=h+t+v-i,m=k.height()-(x.height()+(r.height()||0))-i,p=j>d.top&&j<d.top+m?"visible":"hidden",q={visibility:p};l.length&&(q.top=e?j-l.offset().top:l.scrollTop()),g&&(q.left=k.offset().left-parseInt(k.css("margin-left"),10)-o.scrollLeft()-A),u.length&&(q.top=(q.top||0)+t+v),x.removeClass(c.css.stickyVis+" "+c.css.stickyHide).addClass("visible"===p?c.css.stickyVis:c.css.stickyHide).css(q),(p!==z||b)&&(C(),z=p)}};if(l.length&&!l.css("position")&&l.css("position","relative"),w.attr("id")&&(w[0].id+=f.stickyHeaders_cloneId),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)),f.stickyHeaders_appendTo?a(f.stickyHeaders_appendTo).append(x):k.after(x),e.onRenderHeader)for(i=y.children("tr").children(),h=i.length,g=0;g<h;g++)e.onRenderHeader.apply(i.eq(g),[g,e,w]);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),k.hasClass("hasFilters")&&f.filter_columnFilters&&(k.bind("filterEnd"+m,function(){var d=a(document.activeElement).closest("td"),g=d.parent().children().index(d);x.hasClass(c.css.stickyVis)&&f.stickyHeaders_filteredToTop&&(b.scrollTo(0,k.position().top),g>=0&&e.$filters&&e.$filters.eq(g).find("a, select, input").filter(":visible").focus())}),c.filter.bindSearch(k,j.find("."+c.css.filter)),f.filter_hideFilters&&c.filter.hideFilters(e,w)),f.stickyHeaders_addResizeEvent&&k.bind("resize"+e.namespace+"stickyheaders",function(){C()}),k.triggerHandler("stickyHeadersInit")}},remove:function(d,e,f){var g=e.namespace+"stickyheaders ";e.$table.removeClass("hasStickyHeaders").unbind("pagerComplete resize filterEnd stickyHeadersUpdate ".split(" ").join(g).replace(/\s+/g," ")).next("."+c.css.stickyWrap).remove(),f.$sticky&&f.$sticky.length&&f.$sticky.remove(),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,!0)}})}(a,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"}),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("head").append(b)}),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),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:[]};for(c.resizableReset(b.table,!0),m.tableWidth=j.width(),m.fullWidth=Math.abs(k.width()-m.tableWidth)<20,m.useStorage&&m.overflow&&(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);c.resizable.bindings(b,d)}},updateStoredSizes:function(a,b){var c,d,e=a.columns,f=b.resizable_vars;for(f.storedSizes=[],c=0;c<e;c++)d=a.$headerIndexed[c],f.storedSizes[c]=d.is(":visible")?d.width():0},setWidth:function(a,b,c){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");if(e=e||h.storedSizes||[],e.length){for(f=0;f<b.columns;f++)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=b.$table.height(),g=d.$resizable_container.children(),h=Math.floor(g.width()/2);c.hasWidget(b.table,"scroller")&&(f=0,b.$table.closest("."+c.css.scrollerWrap).children().each(function(){var b=a(this);f+=b.filter('[style*="height"]').length?b.height():b.children("table").height()})),e=b.$table.position().left,g.each(function(){var c=a(this),g=parseInt(c.attr("data-column"),10),i=b.columns-1,j=c.data("header");j&&(j.is(":visible")?(g<i||g===i&&d.resizable_addLastColumn)&&c.css({display:"inline-block",height:f,left:j.position().left-e+j.outerWidth()-h}):c.hide())})},toggleTextSelection:function(b,d,e){var f=b.namespace+"tsresize";d.resizable_vars.disabled=e,a("body").toggleClass(c.css.resizableNoSelect,e),e?a("body").attr("unselectable","on").bind("selectstart"+f,!1):a("body").removeAttr("unselectable").unbind("selectstart"+f)},bindings:function(d,e){var f=d.namespace+"tsresize";e.$resizable_container.children().bind("mousedown",function(b){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,e,!0)}),a(document).bind("mousemove"+f,function(a){var b=e.resizable_vars;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,e,!1),c.resizable.stopResize(d,e),c.resizable.setHandlePosition(d,e))}),a(b).bind("resize"+f+" resizeEnd"+f,function(){c.resizable.setHandlePosition(d,e)}),d.$table.bind("columnUpdate"+f+" pagerComplete"+f,function(){c.resizable.setHandlePosition(d,e)}).find("thead:first").add(a(d.namespace+"_extra_table").find("thead:first")).bind("contextmenu"+f,function(){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){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){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||(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,b.$table.triggerHandler("stickyHeadersUpdate")}},stopResize:function(a,b){var d=b.resizable_vars;c.resizable.updateStoredSizes(a,b),d.useStorage&&(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,a.$table.triggerHandler("stickyHeadersUpdate")}},c.addWidget({id:"resizable",priority:40,options:{resizable:!0,resizable_addLastColumn:!1,resizable_widths:[],resizable_throttle:!1,resizable_targetLast:!1,resizable_fullWidth:null},init:function(a,b,d,e){c.resizable.init(d,e)},format:function(a,b,d){c.resizable.setHandlePosition(b,d)},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,e,!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(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);f.$table.triggerHandler("stickyHeadersUpdate"),c.storage&&!d&&c.storage(this,c.css.resizableStorage,{})}})}}(a,window),function(a){"use strict";var b=a.tablesorter||{};b.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(a,b,c,d){b.format(a,c,d,!0)},format:function(c,d,e,f){var g,h,i=d.$table,j=e.saveSort!==!1,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))):(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"),b.storage&&b.storage(a,"tablesorter-savesort","")}})}(a),a.tablesorter});
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.js
new file mode 100644
index 0000000000000000000000000000000000000000..01483135ad666dd9d46fecaeaf251c3592a06ca3
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.js
@@ -0,0 +1,2807 @@
+(function(factory) {
+	if (typeof define === 'function' && define.amd) {
+		define(['jquery'], factory);
+	} else if (typeof module === 'object' && typeof module.exports === 'object') {
+		module.exports = factory(require('jquery'));
+	} else {
+		factory(jQuery);
+	}
+}(function(jQuery) {
+
+/*! TableSorter (FORK) v2.28.4 *//*
+* Client-side table sorting with ease!
+* @requires jQuery v1.2.6+
+*
+* Copyright (c) 2007 Christian Bach
+* fork maintained by Rob Garrison
+*
+* Examples and original docs at: http://tablesorter.com
+* Dual licensed under the MIT and GPL licenses:
+* http://www.opensource.org/licenses/mit-license.php
+* http://www.gnu.org/licenses/gpl.html
+*
+* @type jQuery
+* @name tablesorter (FORK)
+* @cat Plugins/Tablesorter
+* @author Christian Bach - christian.bach@polyester.se
+* @contributor Rob Garrison - https://github.com/Mottie/tablesorter
+* @docs (fork) - https://mottie.github.io/tablesorter/docs/
+*/
+/*jshint browser:true, jquery:true, unused:false, expr: true */
+;( function( $ ) {
+	'use strict';
+	var ts = $.tablesorter = {
+
+		version : '2.28.4',
+
+		parsers : [],
+		widgets : [],
+		defaults : {
+
+			// *** appearance
+			theme            : 'default',  // adds tablesorter-{theme} to the table for styling
+			widthFixed       : false,      // adds colgroup to fix widths of columns
+			showProcessing   : false,      // 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  : true,       // prevent text selection in the header
+			tabIndex         : true,       // 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   : true,       // false for German '1.234.567,89' or French '1 234 567,89'
+			delayInit        : false,      // if false, the parsed table contents will not update until the first sort
+			serverSideSorting: false,      // 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           : true,       // 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       : true,       // 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       : false,      // when sorting two rows with exactly the same content, the original sort order is maintained
+
+			sortInitialOrder : 'asc',      // sort direction on first click
+			sortLocaleCompare: false,      // replace equivalent character (accented characters)
+			sortReset        : false,      // third click on the header will reset column to default - unsorted
+			sortRestart      : false,      // 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
+			duplicateSpan    : true,       // colspan cells in the tbody will have duplicated content in the cache for each spanned column
+			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
+			initWidgets      : true,       // apply widgets on tablesorter initialization
+			widgetClass      : 'widget-{name}', // table class name template to match to include a widget
+			widgets          : [],         // method to add widgets, e.g. widgets: ['zebra']
+			widgetOptions    : {
+				zebra : [ 'even', 'odd' ]  // zebra widget alternating row class names
+			},
+
+			// *** 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 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            : false,
+
+			// *** Internal variables
+			headerList: [],
+			empties: {},
+			strings: {},
+			parsers: [],
+
+			// *** parser options for validator; values must be falsy!
+			globalize: 0,
+			imgAttr: 0
+
+			// removed: widgetZebra: { css: ['even', 'odd'] }
+
+		},
+
+		// 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, ',
+			sortDisabled : 'sorting is disabled',
+			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
+		string : {
+			max      : 1,
+			min      : -1,
+			emptymin : 1,
+			emptymax : -1,
+			zero     : 0,
+			none     : 0,
+			'null'   : 0,
+			top      : true,
+			bottom   : false
+		},
+
+		keyCodes : {
+			enter : 13
+		},
+
+		// placeholder date parser data (globalize)
+		dates : {},
+
+		// These methods can be applied on table.config instance
+		instanceMethods : {},
+
+		/*
+		▄█████ ██████ ██████ ██  ██ █████▄
+		▀█▄    ██▄▄     ██   ██  ██ ██▄▄██
+		   ▀█▄ ██▀▀     ██   ██  ██ ██▀▀▀
+		█████▀ ██████   ██   ▀████▀ ██
+		*/
+
+		setup : function( table, c ) {
+			// if no thead or tbody, or tablesorter is already present, quit
+			if ( !table || !table.tHead || table.tBodies.length === 0 || table.hasInitialized === true ) {
+				if ( c.debug ) {
+					if ( table.hasInitialized ) {
+						console.warn( 'Stopping initialization. Tablesorter has already been initialized' );
+					} else {
+						console.error( 'Stopping initialization! No table, thead or tbody', table );
+					}
+				}
+				return;
+			}
+
+			var tmp = '',
+				$table = $( table ),
+				meta = $.metadata;
+			// initialization flag
+			table.hasInitialized = false;
+			// table is being processed flag
+			table.isProcessing = true;
+			// make sure to store the config object
+			table.config = c;
+			// save the settings where they read
+			$.data( table, 'tablesorter', c );
+			if ( c.debug ) {
+				console[ console.group ? 'group' : 'log' ]( 'Initializing tablesorter v' + ts.version );
+				$.data( table, 'startoveralltimer', new Date() );
+			}
+
+			// removing this in version 3 (only supports jQuery 1.7+)
+			c.supportsDataObject = ( function( version ) {
+				version[ 0 ] = parseInt( version[ 0 ], 10 );
+				return ( version[ 0 ] > 1 ) || ( version[ 0 ] === 1 && parseInt( version[ 1 ], 10 ) >= 4 );
+			})( $.fn.jquery.split( '.' ) );
+			// ensure case insensitivity
+			c.emptyTo = c.emptyTo.toLowerCase();
+			c.stringTo = c.stringTo.toLowerCase();
+			c.last = { sortList : [], clickedIndex : -1 };
+			// add table theme class only if there isn't already one there
+			if ( !/tablesorter\-/.test( $table.attr( 'class' ) ) ) {
+				tmp = ( c.theme !== '' ? ' tablesorter-' + c.theme : '' );
+			}
+			c.table = table;
+			c.$table = $table
+				.addClass( ts.css.table + ' ' + c.tableClass + tmp )
+				.attr( 'role', 'grid' );
+			c.$headers = $table.find( c.selectorHeaders );
+
+			// give the table a unique id, which will be used in namespace binding
+			if ( !c.namespace ) {
+				c.namespace = '.tablesorter' + Math.random().toString( 16 ).slice( 2 );
+			} else {
+				// make sure namespace starts with a period & doesn't have weird characters
+				c.namespace = '.' + c.namespace.replace( ts.regex.nonWord, '' );
+			}
+
+			c.$table.children().children( 'tr' ).attr( 'role', 'row' );
+			c.$tbodies = $table.children( 'tbody:not(.' + c.cssInfoBlock + ')' ).attr({
+				'aria-live' : 'polite',
+				'aria-relevant' : 'all'
+			});
+			if ( c.$table.children( 'caption' ).length ) {
+				tmp = c.$table.children( 'caption' )[ 0 ];
+				if ( !tmp.id ) { tmp.id = c.namespace.slice( 1 ) + 'caption'; }
+				c.$table.attr( 'aria-labelledby', tmp.id );
+			}
+			c.widgetInit = {}; // keep a list of initialized widgets
+			// change textExtraction via data-attribute
+			c.textExtraction = c.$table.attr( 'data-text-extraction' ) || c.textExtraction || 'basic';
+			// build headers
+			ts.buildHeaders( c );
+			// fixate columns if the users supplies the fixedWidth option
+			// do this after theme has been applied
+			ts.fixColumnWidth( table );
+			// add widgets from class name
+			ts.addWidgetFromClass( table );
+			// add widget options before parsing (e.g. grouping widget has parser settings)
+			ts.applyWidgetOptions( table );
+			// try to auto detect column type, and store in tables config
+			ts.setupParsers( c );
+			// start total row count at zero
+			c.totalRows = 0;
+			ts.validateOptions( c );
+			// build the cache for the tbody cells
+			// delayInit will delay building the cache until the user starts a sort
+			if ( !c.delayInit ) { ts.buildCache( c ); }
+			// bind all header events and methods
+			ts.bindEvents( table, c.$headers, true );
+			ts.bindMethods( c );
+			// get sort list from jQuery data or metadata
+			// in jQuery < 1.4, an error occurs when calling $table.data()
+			if ( c.supportsDataObject && typeof $table.data().sortlist !== 'undefined' ) {
+				c.sortList = $table.data().sortlist;
+			} else if ( meta && ( $table.metadata() && $table.metadata().sortlist ) ) {
+				c.sortList = $table.metadata().sortlist;
+			}
+			// apply widget init code
+			ts.applyWidget( table, true );
+			// if user has supplied a sort list to constructor
+			if ( c.sortList.length > 0 ) {
+				ts.sortOn( c, c.sortList, {}, !c.initWidgets );
+			} else {
+				ts.setHeadersCss( c );
+				if ( c.initWidgets ) {
+					// apply widget format
+					ts.applyWidget( table, false );
+				}
+			}
+
+			// show processesing icon
+			if ( c.showProcessing ) {
+				$table
+				.unbind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace )
+				.bind( 'sortBegin' + c.namespace + ' sortEnd' + c.namespace, function( e ) {
+					clearTimeout( c.timerProcessing );
+					ts.isProcessing( table );
+					if ( e.type === 'sortBegin' ) {
+						c.timerProcessing = setTimeout( function() {
+							ts.isProcessing( table, true );
+						}, 500 );
+					}
+				});
+			}
+
+			// initialized
+			table.hasInitialized = true;
+			table.isProcessing = false;
+			if ( c.debug ) {
+				console.log( 'Overall initialization time:' + ts.benchmark( $.data( table, 'startoveralltimer' ) ) );
+				if ( c.debug && console.groupEnd ) { console.groupEnd(); }
+			}
+			$table.triggerHandler( 'tablesorter-initialized', table );
+			if ( typeof c.initialized === 'function' ) {
+				c.initialized( table );
+			}
+		},
+
+		bindMethods : function( c ) {
+			var $table = c.$table,
+				namespace = c.namespace,
+				events = ( 'sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete ' +
+					'sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup ' +
+					'mouseleave ' ).split( ' ' )
+					.join( namespace + ' ' );
+			// apply easy methods that trigger bound events
+			$table
+			.unbind( events.replace( ts.regex.spaces, ' ' ) )
+			.bind( 'sortReset' + namespace, function( e, callback ) {
+				e.stopPropagation();
+				// using this.config to ensure functions are getting a non-cached version of the config
+				ts.sortReset( this.config, callback );
+			})
+			.bind( 'updateAll' + namespace, function( e, resort, callback ) {
+				e.stopPropagation();
+				ts.updateAll( this.config, resort, callback );
+			})
+			.bind( 'update' + namespace + ' updateRows' + namespace, function( e, resort, callback ) {
+				e.stopPropagation();
+				ts.update( this.config, resort, callback );
+			})
+			.bind( 'updateHeaders' + namespace, function( e, callback ) {
+				e.stopPropagation();
+				ts.updateHeaders( this.config, callback );
+			})
+			.bind( 'updateCell' + namespace, function( e, cell, resort, callback ) {
+				e.stopPropagation();
+				ts.updateCell( this.config, cell, resort, callback );
+			})
+			.bind( 'addRows' + namespace, function( e, $row, resort, callback ) {
+				e.stopPropagation();
+				ts.addRows( this.config, $row, resort, callback );
+			})
+			.bind( 'updateComplete' + namespace, function() {
+				this.isUpdating = false;
+			})
+			.bind( 'sorton' + namespace, function( e, list, callback, init ) {
+				e.stopPropagation();
+				ts.sortOn( this.config, list, callback, init );
+			})
+			.bind( 'appendCache' + namespace, function( e, callback, init ) {
+				e.stopPropagation();
+				ts.appendCache( this.config, init );
+				if ( $.isFunction( callback ) ) {
+					callback( this );
+				}
+			})
+			// $tbodies variable is used by the tbody sorting widget
+			.bind( 'updateCache' + namespace, function( e, callback, $tbodies ) {
+				e.stopPropagation();
+				ts.updateCache( this.config, callback, $tbodies );
+			})
+			.bind( 'applyWidgetId' + namespace, function( e, id ) {
+				e.stopPropagation();
+				ts.applyWidgetId( this, id );
+			})
+			.bind( 'applyWidgets' + namespace, function( e, init ) {
+				e.stopPropagation();
+				// apply widgets
+				ts.applyWidget( this, init );
+			})
+			.bind( 'refreshWidgets' + namespace, function( e, all, dontapply ) {
+				e.stopPropagation();
+				ts.refreshWidgets( this, all, dontapply );
+			})
+			.bind( 'removeWidget' + namespace, function( e, name, refreshing ) {
+				e.stopPropagation();
+				ts.removeWidget( this, name, refreshing );
+			})
+			.bind( 'destroy' + namespace, function( e, removeClasses, callback ) {
+				e.stopPropagation();
+				ts.destroy( this, removeClasses, callback );
+			})
+			.bind( 'resetToLoadState' + namespace, function( e ) {
+				e.stopPropagation();
+				// remove all widgets
+				ts.removeWidget( this, true, false );
+				var tmp = $.extend( true, {}, c.originalSettings );
+				// restore original settings; this clears out current settings, but does not clear
+				// values saved to storage.
+				c = $.extend( true, ts.defaults, tmp );
+				c.originalSettings = tmp;
+				this.hasInitialized = false;
+				// setup the entire table again
+				ts.setup( this, c );
+			});
+		},
+
+		bindEvents : function( table, $headers, core ) {
+			table = $( table )[ 0 ];
+			var tmp,
+				c = table.config,
+				namespace = c.namespace,
+				downTarget = null;
+			if ( core !== true ) {
+				$headers.addClass( namespace.slice( 1 ) + '_extra_headers' );
+				tmp = $.fn.closest ? $headers.closest( 'table' )[ 0 ] : $headers.parents( 'table' )[ 0 ];
+				if ( tmp && tmp.nodeName === 'TABLE' && tmp !== table ) {
+					$( tmp ).addClass( namespace.slice( 1 ) + '_extra_table' );
+				}
+			}
+			tmp = ( c.pointerDown + ' ' + c.pointerUp + ' ' + c.pointerClick + ' sort keyup ' )
+				.replace( ts.regex.spaces, ' ' )
+				.split( ' ' )
+				.join( namespace + ' ' );
+			// apply event handling to headers and/or additional headers (stickyheaders, scroller, etc)
+			$headers
+			// http://stackoverflow.com/questions/5312849/jquery-find-self;
+			.find( c.selectorSort )
+			.add( $headers.filter( c.selectorSort ) )
+			.unbind( tmp )
+			.bind( tmp, function( e, external ) {
+				var $cell, cell, temp,
+					$target = $( e.target ),
+					// wrap event type in spaces, so the match doesn't trigger on inner words
+					type = ' ' + e.type + ' ';
+				// only recognize left clicks
+				if ( ( ( e.which || e.button ) !== 1 && !type.match( ' ' + c.pointerClick + ' | sort | keyup ' ) ) ||
+					// allow pressing enter
+					( type === ' keyup ' && e.which !== ts.keyCodes.enter ) ||
+					// allow triggering a click event (e.which is undefined) & ignore physical clicks
+					( type.match( ' ' + c.pointerClick + ' ' ) && typeof e.which !== 'undefined' ) ) {
+					return;
+				}
+				// ignore mouseup if mousedown wasn't on the same target
+				if ( type.match( ' ' + c.pointerUp + ' ' ) && downTarget !== e.target && external !== true ) {
+					return;
+				}
+				// set target on mousedown
+				if ( type.match( ' ' + c.pointerDown + ' ' ) ) {
+					downTarget = e.target;
+					// preventDefault needed or jQuery v1.3.2 and older throws an
+					// "Uncaught TypeError: handler.apply is not a function" error
+					temp = $target.jquery.split( '.' );
+					if ( temp[ 0 ] === '1' && temp[ 1 ] < 4 ) { e.preventDefault(); }
+					return;
+				}
+				downTarget = null;
+				// prevent sort being triggered on form elements
+				if ( ts.regex.formElements.test( e.target.nodeName ) ||
+					// nosort class name, or elements within a nosort container
+					$target.hasClass( c.cssNoSort ) || $target.parents( '.' + c.cssNoSort ).length > 0 ||
+					// elements within a button
+					$target.parents( 'button' ).length > 0 ) {
+					return !c.cancelSelection;
+				}
+				if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
+					ts.buildCache( c );
+				}
+				// jQuery v1.2.6 doesn't have closest()
+				$cell = $.fn.closest ? $( this ).closest( 'th, td' ) :
+					/TH|TD/.test( this.nodeName ) ? $( this ) : $( this ).parents( 'th, td' );
+				// reference original table headers and find the same cell
+				// don't use $headers or IE8 throws an error - see #987
+				temp = $headers.index( $cell );
+				c.last.clickedIndex = ( temp < 0 ) ? $cell.attr( 'data-column' ) : temp;
+				// use column index if $headers is undefined
+				cell = c.$headers[ c.last.clickedIndex ];
+				if ( cell && !cell.sortDisabled ) {
+					ts.initSort( c, cell, e );
+				}
+			});
+			if ( c.cancelSelection ) {
+				// cancel selection
+				$headers
+					.attr( 'unselectable', 'on' )
+					.bind( 'selectstart', false )
+					.css({
+						'user-select' : 'none',
+						'MozUserSelect' : 'none' // not needed for jQuery 1.8+
+					});
+			}
+		},
+
+		buildHeaders : function( c ) {
+			var $temp, icon, timer, indx;
+			c.headerList = [];
+			c.headerContent = [];
+			c.sortVars = [];
+			if ( c.debug ) {
+				timer = new Date();
+			}
+			// children tr in tfoot - see issue #196 & #547
+			// don't pass table.config to computeColumnIndex here - widgets (math) pass it to "quickly" index tbody cells
+			c.columns = ts.computeColumnIndex( c.$table.children( 'thead, tfoot' ).children( 'tr' ) );
+			// add icon if cssIcon option exists
+			icon = c.cssIcon ?
+				'<i class="' + ( c.cssIcon === ts.css.icon ? ts.css.icon : c.cssIcon + ' ' + ts.css.icon ) + '"></i>' :
+				'';
+			// redefine c.$headers here in case of an updateAll that replaces or adds an entire header cell - see #683
+			c.$headers = $( $.map( c.$table.find( c.selectorHeaders ), function( elem, index ) {
+				var configHeaders, header, column, template, tmp,
+					$elem = $( elem );
+				// ignore cell (don't add it to c.$headers) if row has ignoreRow class
+				if ( $elem.parent().hasClass( c.cssIgnoreRow ) ) { return; }
+				// make sure to get header cell & not column indexed cell
+				configHeaders = ts.getColumnData( c.table, c.headers, index, true );
+				// save original header content
+				c.headerContent[ index ] = $elem.html();
+				// if headerTemplate is empty, don't reformat the header cell
+				if ( c.headerTemplate !== '' && !$elem.find( '.' + ts.css.headerIn ).length ) {
+					// set up header template
+					template = c.headerTemplate
+						.replace( ts.regex.templateContent, $elem.html() )
+						.replace( ts.regex.templateIcon, $elem.find( '.' + ts.css.icon ).length ? '' : icon );
+					if ( c.onRenderTemplate ) {
+						header = c.onRenderTemplate.apply( $elem, [ index, template ] );
+						// only change t if something is returned
+						if ( header && typeof header === 'string' ) {
+							template = header;
+						}
+					}
+					$elem.html( '<div class="' + ts.css.headerIn + '">' + template + '</div>' ); // faster than wrapInner
+				}
+				if ( c.onRenderHeader ) {
+					c.onRenderHeader.apply( $elem, [ index, c, c.$table ] );
+				}
+				column = parseInt( $elem.attr( 'data-column' ), 10 );
+				elem.column = column;
+				tmp = ts.getOrder( ts.getData( $elem, configHeaders, 'sortInitialOrder' ) || c.sortInitialOrder );
+				// this may get updated numerous times if there are multiple rows
+				c.sortVars[ column ] = {
+					count : -1, // set to -1 because clicking on the header automatically adds one
+					order:  tmp ?
+						( c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ] ) : // desc, asc, unsorted
+						( c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ] ),  // asc, desc, unsorted
+					lockedOrder : false
+				};
+				tmp = ts.getData( $elem, configHeaders, 'lockedOrder' ) || false;
+				if ( typeof tmp !== 'undefined' && tmp !== false ) {
+					c.sortVars[ column ].lockedOrder = true;
+					c.sortVars[ column ].order = ts.getOrder( tmp ) ? [ 1, 1 ] : [ 0, 0 ];
+				}
+				// add cell to headerList
+				c.headerList[ index ] = elem;
+				// add to parent in case there are multiple rows
+				$elem
+					.addClass( ts.css.header + ' ' + c.cssHeader )
+					.parent()
+					.addClass( ts.css.headerRow + ' ' + c.cssHeaderRow )
+					.attr( 'role', 'row' );
+				// allow keyboard cursor to focus on element
+				if ( c.tabIndex ) {
+					$elem.attr( 'tabindex', 0 );
+				}
+				return elem;
+			}) );
+			// cache headers per column
+			c.$headerIndexed = [];
+			for ( indx = 0; indx < c.columns; indx++ ) {
+				// colspan in header making a column undefined
+				if ( ts.isEmptyObject( c.sortVars[ indx ] ) ) {
+					c.sortVars[ indx ] = {};
+				}
+				$temp = c.$headers.filter( '[data-column="' + indx + '"]' );
+				// target sortable column cells, unless there are none, then use non-sortable cells
+				// .last() added in jQuery 1.4; use .filter(':last') to maintain compatibility with jQuery v1.2.6
+				c.$headerIndexed[ indx ] = $temp.length ?
+					$temp.not( '.sorter-false' ).length ?
+						$temp.not( '.sorter-false' ).filter( ':last' ) :
+						$temp.filter( ':last' ) :
+					$();
+			}
+			c.$table.find( c.selectorHeaders ).attr({
+				scope: 'col',
+				role : 'columnheader'
+			});
+			// enable/disable sorting
+			ts.updateHeader( c );
+			if ( c.debug ) {
+				console.log( 'Built headers:' + ts.benchmark( timer ) );
+				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( methods ) {
+			$.extend( ts.instanceMethods, methods );
+		},
+
+		/*
+		█████▄ ▄████▄ █████▄ ▄█████ ██████ █████▄ ▄█████
+		██▄▄██ ██▄▄██ ██▄▄██ ▀█▄    ██▄▄   ██▄▄██ ▀█▄
+		██▀▀▀  ██▀▀██ ██▀██     ▀█▄ ██▀▀   ██▀██     ▀█▄
+		██     ██  ██ ██  ██ █████▀ ██████ ██  ██ █████▀
+		*/
+		setupParsers : function( c, $tbodies ) {
+			var rows, list, span, max, colIndex, indx, header, configHeaders,
+				noParser, parser, extractor, time, tbody, len,
+				table = c.table,
+				tbodyIndex = 0,
+				debug = {};
+			// update table bodies in case we start with an empty table
+			c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
+			tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies;
+			len = tbody.length;
+			if ( len === 0 ) {
+				return c.debug ? console.warn( 'Warning: *Empty table!* Not building a parser cache' ) : '';
+			} else if ( c.debug ) {
+				time = new Date();
+				console[ console.group ? 'group' : 'log' ]( 'Detecting parsers for each column' );
+			}
+			list = {
+				extractors: [],
+				parsers: []
+			};
+			while ( tbodyIndex < len ) {
+				rows = tbody[ tbodyIndex ].rows;
+				if ( rows.length ) {
+					colIndex = 0;
+					max = c.columns;
+					for ( indx = 0; indx < max; indx++ ) {
+						header = c.$headerIndexed[ colIndex ];
+						if ( header && header.length ) {
+							// get column indexed table cell
+							configHeaders = ts.getColumnData( table, c.headers, colIndex );
+							// get column parser/extractor
+							extractor = ts.getParserById( ts.getData( header, configHeaders, 'extractor' ) );
+							parser = ts.getParserById( ts.getData( header, configHeaders, 'sorter' ) );
+							noParser = ts.getData( header, configHeaders, 'parser' ) === 'false';
+							// empty cells behaviour - keeping emptyToBottom for backwards compatibility
+							c.empties[colIndex] = (
+								ts.getData( header, configHeaders, 'empty' ) ||
+								c.emptyTo || ( c.emptyToBottom ? 'bottom' : 'top' ) ).toLowerCase();
+							// text strings behaviour in numerical sorts
+							c.strings[colIndex] = (
+								ts.getData( header, configHeaders, 'string' ) ||
+								c.stringTo ||
+								'max' ).toLowerCase();
+							if ( noParser ) {
+								parser = ts.getParserById( 'no-parser' );
+							}
+							if ( !extractor ) {
+								// For now, maybe detect someday
+								extractor = false;
+							}
+							if ( !parser ) {
+								parser = ts.detectParserForColumn( c, rows, -1, colIndex );
+							}
+							if ( c.debug ) {
+								debug[ '(' + colIndex + ') ' + header.text() ] = {
+									parser : parser.id,
+									extractor : extractor ? extractor.id : 'none',
+									string : c.strings[ colIndex ],
+									empty  : c.empties[ colIndex ]
+								};
+							}
+							list.parsers[ colIndex ] = parser;
+							list.extractors[ colIndex ] = extractor;
+							span = header[ 0 ].colSpan - 1;
+							if ( span > 0 ) {
+								colIndex += span;
+								max += span;
+								while ( span + 1 > 0 ) {
+									// set colspan columns to use the same parsers & extractors
+									list.parsers[ colIndex - span ] = parser;
+									list.extractors[ colIndex - span ] = extractor;
+									span--;
+								}
+							}
+						}
+						colIndex++;
+					}
+				}
+				tbodyIndex += ( list.parsers.length ) ? len : 1;
+			}
+			if ( c.debug ) {
+				if ( !ts.isEmptyObject( debug ) ) {
+					console[ console.table ? 'table' : 'log' ]( debug );
+				} else {
+					console.warn( '  No parsers detected!' );
+				}
+				console.log( 'Completed detecting parsers' + ts.benchmark( time ) );
+				if ( console.groupEnd ) { console.groupEnd(); }
+			}
+			c.parsers = list.parsers;
+			c.extractors = list.extractors;
+		},
+
+		addParser : function( parser ) {
+			var indx,
+				len = ts.parsers.length,
+				add = true;
+			for ( indx = 0; indx < len; indx++ ) {
+				if ( ts.parsers[ indx ].id.toLowerCase() === parser.id.toLowerCase() ) {
+					add = false;
+				}
+			}
+			if ( add ) {
+				ts.parsers[ ts.parsers.length ] = parser;
+			}
+		},
+
+		getParserById : function( name ) {
+			/*jshint eqeqeq:false */
+			if ( name == 'false' ) { return false; }
+			var indx,
+				len = ts.parsers.length;
+			for ( indx = 0; indx < len; indx++ ) {
+				if ( ts.parsers[ indx ].id.toLowerCase() === ( name.toString() ).toLowerCase() ) {
+					return ts.parsers[ indx ];
+				}
+			}
+			return false;
+		},
+
+		detectParserForColumn : function( c, rows, rowIndex, cellIndex ) {
+			var cur, $node, row,
+				indx = ts.parsers.length,
+				node = false,
+				nodeValue = '',
+				keepLooking = true;
+			while ( nodeValue === '' && keepLooking ) {
+				rowIndex++;
+				row = rows[ rowIndex ];
+				// stop looking after 50 empty rows
+				if ( row && rowIndex < 50 ) {
+					if ( row.className.indexOf( ts.cssIgnoreRow ) < 0 ) {
+						node = rows[ rowIndex ].cells[ cellIndex ];
+						nodeValue = ts.getElementText( c, node, cellIndex );
+						$node = $( node );
+						if ( c.debug ) {
+							console.log( 'Checking if value was empty on row ' + rowIndex + ', column: ' +
+								cellIndex + ': "' + nodeValue + '"' );
+						}
+					}
+				} else {
+					keepLooking = false;
+				}
+			}
+			while ( --indx >= 0 ) {
+				cur = ts.parsers[ indx ];
+				// ignore the default text parser because it will always be true
+				if ( cur && cur.id !== 'text' && cur.is && cur.is( nodeValue, c.table, node, $node ) ) {
+					return cur;
+				}
+			}
+			// nothing found, return the generic parser (text)
+			return ts.getParserById( 'text' );
+		},
+
+		getElementText : function( c, node, cellIndex ) {
+			if ( !node ) { return ''; }
+			var tmp,
+				extract = c.textExtraction || '',
+				// node could be a jquery object
+				// http://jsperf.com/jquery-vs-instanceof-jquery/2
+				$node = node.jquery ? node : $( node );
+			if ( typeof extract === 'string' ) {
+				// 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/
+				if ( extract === 'basic' && typeof ( tmp = $node.attr( c.textAttribute ) ) !== 'undefined' ) {
+					return $.trim( tmp );
+				}
+				return $.trim( node.textContent || $node.text() );
+			} else {
+				if ( typeof extract === 'function' ) {
+					return $.trim( extract( $node[ 0 ], c.table, cellIndex ) );
+				} else if ( typeof ( tmp = ts.getColumnData( c.table, extract, cellIndex ) ) === 'function' ) {
+					return $.trim( tmp( $node[ 0 ], c.table, cellIndex ) );
+				}
+			}
+			// fallback
+			return $.trim( $node[ 0 ].textContent || $node.text() );
+		},
+
+		// centralized function to extract/parse cell contents
+		getParsedText : function( c, cell, colIndex, txt ) {
+			if ( typeof txt === 'undefined' ) {
+				txt = ts.getElementText( c, cell, colIndex );
+			}
+			// if no parser, make sure to return the txt
+			var val = '' + txt,
+				parser = c.parsers[ colIndex ],
+				extractor = c.extractors[ colIndex ];
+			if ( parser ) {
+				// do extract before parsing, if there is one
+				if ( extractor && typeof extractor.format === 'function' ) {
+					txt = extractor.format( txt, c.table, cell, colIndex );
+				}
+				// 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
+				val = parser.id === 'no-parser' ? '' :
+					// make sure txt is a string (extractor may have converted it)
+					parser.format( '' + txt, c.table, cell, colIndex );
+				if ( c.ignoreCase && typeof val === 'string' ) {
+					val = val.toLowerCase();
+				}
+			}
+			return val;
+		},
+
+		/*
+		▄████▄ ▄████▄ ▄████▄ ██  ██ ██████
+		██  ▀▀ ██▄▄██ ██  ▀▀ ██▄▄██ ██▄▄
+		██  ▄▄ ██▀▀██ ██  ▄▄ ██▀▀██ ██▀▀
+		▀████▀ ██  ██ ▀████▀ ██  ██ ██████
+		*/
+		buildCache : function( c, callback, $tbodies ) {
+			var cache, val, txt, rowIndex, colIndex, tbodyIndex, $tbody, $row,
+				cols, $cells, cell, cacheTime, totalRows, rowData, prevRowData,
+				colMax, span, cacheIndex, hasParser, max, len, index,
+				table = c.table,
+				parsers = c.parsers;
+			// update tbody variable
+			c.$tbodies = c.$table.children( 'tbody:not(.' + c.cssInfoBlock + ')' );
+			$tbody = typeof $tbodies === 'undefined' ? c.$tbodies : $tbodies,
+			c.cache = {};
+			c.totalRows = 0;
+			// if no parsers found, return - it's an empty table.
+			if ( !parsers ) {
+				return c.debug ? console.warn( 'Warning: *Empty table!* Not building a cache' ) : '';
+			}
+			if ( c.debug ) {
+				cacheTime = new Date();
+			}
+			// processing icon
+			if ( c.showProcessing ) {
+				ts.isProcessing( table, true );
+			}
+			for ( tbodyIndex = 0; tbodyIndex < $tbody.length; tbodyIndex++ ) {
+				colMax = []; // column max value per tbody
+				cache = c.cache[ tbodyIndex ] = {
+					normalized: [] // array of normalized row data; last entry contains 'rowData' above
+					// colMax: #   // added at the end
+				};
+
+				totalRows = ( $tbody[ tbodyIndex ] && $tbody[ tbodyIndex ].rows.length ) || 0;
+				for ( rowIndex = 0; rowIndex < totalRows; ++rowIndex ) {
+					rowData = {
+						// order: original row order #
+						// $row : jQuery Object[]
+						child: [], // child row text (filter widget)
+						raw: []    // original row text
+					};
+					/** Add the table data to main data array */
+					$row = $( $tbody[ tbodyIndex ].rows[ rowIndex ] );
+					cols = [];
+					// ignore "remove-me" rows
+					if ( $row.hasClass( c.selectorRemove.slice(1) ) ) {
+						continue;
+					}
+					// 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 ( $row.hasClass( c.cssChildRow ) && rowIndex !== 0 ) {
+						len = cache.normalized.length - 1;
+						prevRowData = cache.normalized[ len ][ c.columns ];
+						prevRowData.$row = prevRowData.$row.add( $row );
+						// add 'hasChild' class name to parent row
+						if ( !$row.prev().hasClass( c.cssChildRow ) ) {
+							$row.prev().addClass( ts.css.cssHasChild );
+						}
+						// save child row content (un-parsed!)
+						$cells = $row.children( 'th, td' );
+						len = prevRowData.child.length;
+						prevRowData.child[ len ] = [];
+						// child row content does not account for colspans/rowspans; so indexing may be off
+						cacheIndex = 0;
+						max = c.columns;
+						for ( colIndex = 0; colIndex < max; colIndex++ ) {
+							cell = $cells[ colIndex ];
+							if ( cell ) {
+								prevRowData.child[ len ][ colIndex ] = ts.getParsedText( c, cell, colIndex );
+								span = $cells[ colIndex ].colSpan - 1;
+								if ( span > 0 ) {
+									cacheIndex += span;
+									max += span;
+								}
+							}
+							cacheIndex++;
+						}
+						// go to the next for loop
+						continue;
+					}
+					rowData.$row = $row;
+					rowData.order = rowIndex; // add original row position to rowCache
+					cacheIndex = 0;
+					max = c.columns;
+					for ( colIndex = 0; colIndex < max; ++colIndex ) {
+						cell = $row[ 0 ].cells[ colIndex ];
+						if ( cell && cacheIndex < c.columns ) {
+							hasParser = typeof parsers[ cacheIndex ] !== 'undefined';
+							if ( !hasParser && c.debug ) {
+								console.warn( 'No parser found for row: ' + rowIndex + ', column: ' + colIndex +
+									'; cell containing: "' + $(cell).text() + '"; does it have a header?' );
+							}
+							val = ts.getElementText( c, cell, cacheIndex );
+							rowData.raw[ cacheIndex ] = val; // save original row text
+							// save raw column text even if there is no parser set
+							txt = ts.getParsedText( c, cell, cacheIndex, val );
+							cols[ cacheIndex ] = txt;
+							if ( hasParser && ( parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
+								// determine column max value (ignore sign)
+								colMax[ cacheIndex ] = Math.max( Math.abs( txt ) || 0, colMax[ cacheIndex ] || 0 );
+							}
+							// allow colSpan in tbody
+							span = cell.colSpan - 1;
+							if ( span > 0 ) {
+								index = 0;
+								while ( index <= span ) {
+									// duplicate text (or not) to spanned columns
+									// instead of setting duplicate span to empty string, use textExtraction to try to get a value
+									// see http://stackoverflow.com/q/36449711/145346
+									txt = c.duplicateSpan || index === 0 ?
+										val :
+										typeof c.textExtraction !== 'string' ?
+											ts.getElementText( c, cell, cacheIndex + index ) || '' :
+											'';
+									rowData.raw[ cacheIndex + index ] = txt;
+									cols[ cacheIndex + index ] = txt;
+									index++;
+								}
+								cacheIndex += span;
+								max += span;
+							}
+						}
+						cacheIndex++;
+					}
+					// ensure rowData is always in the same location (after the last column)
+					cols[ c.columns ] = rowData;
+					cache.normalized[ cache.normalized.length ] = cols;
+				}
+				cache.colMax = colMax;
+				// total up rows, not including child rows
+				c.totalRows += cache.normalized.length;
+
+			}
+			if ( c.showProcessing ) {
+				ts.isProcessing( table ); // remove processing icon
+			}
+			if ( c.debug ) {
+				len = Math.min( 5, c.cache[ 0 ].normalized.length );
+				console[ console.group ? 'group' : 'log' ]( 'Building cache for ' + c.totalRows +
+					' rows (showing ' + len + ' rows in log) and ' + c.columns + ' columns' +
+					ts.benchmark( cacheTime ) );
+				val = {};
+				for ( colIndex = 0; colIndex < c.columns; colIndex++ ) {
+					for ( cacheIndex = 0; cacheIndex < len; cacheIndex++ ) {
+						if ( !val[ 'row: ' + cacheIndex ] ) {
+							val[ 'row: ' + cacheIndex ] = {};
+						}
+						val[ 'row: ' + cacheIndex ][ c.$headerIndexed[ colIndex ].text() ] =
+							c.cache[ 0 ].normalized[ cacheIndex ][ colIndex ];
+					}
+				}
+				console[ console.table ? 'table' : 'log' ]( val );
+				if ( console.groupEnd ) { console.groupEnd(); }
+			}
+			if ( $.isFunction( callback ) ) {
+				callback( table );
+			}
+		},
+
+		getColumnText : function( table, column, callback, rowFilter ) {
+			table = $( table )[0];
+			var tbodyIndex, rowIndex, cache, row, tbodyLen, rowLen, raw, parsed, $cell, result,
+				hasCallback = typeof callback === 'function',
+				allColumns = column === 'all',
+				data = { raw : [], parsed: [], $cell: [] },
+				c = table.config;
+			if ( ts.isEmptyObject( c ) ) {
+				if ( c.debug ) {
+					console.warn( 'No cache found - aborting getColumnText function!' );
+				}
+			} else {
+				tbodyLen = c.$tbodies.length;
+				for ( tbodyIndex = 0; tbodyIndex < tbodyLen; tbodyIndex++ ) {
+					cache = c.cache[ tbodyIndex ].normalized;
+					rowLen = cache.length;
+					for ( rowIndex = 0; rowIndex < rowLen; rowIndex++ ) {
+						row = cache[ rowIndex ];
+						if ( rowFilter && !row[ c.columns ].$row.is( rowFilter ) ) {
+							continue;
+						}
+						result = true;
+						parsed = ( allColumns ) ? row.slice( 0, c.columns ) : row[ column ];
+						row = row[ c.columns ];
+						raw = ( allColumns ) ? row.raw : row.raw[ column ];
+						$cell = ( allColumns ) ? row.$row.children() : row.$row.children().eq( column );
+						if ( hasCallback ) {
+							result = callback({
+								tbodyIndex : tbodyIndex,
+								rowIndex : rowIndex,
+								parsed : parsed,
+								raw : raw,
+								$row : row.$row,
+								$cell : $cell
+							});
+						}
+						if ( result !== false ) {
+							data.parsed[ data.parsed.length ] = parsed;
+							data.raw[ data.raw.length ] = raw;
+							data.$cell[ data.$cell.length ] = $cell;
+						}
+					}
+				}
+				// return everything
+				return data;
+			}
+		},
+
+		/*
+		██  ██ █████▄ █████▄ ▄████▄ ██████ ██████
+		██  ██ ██▄▄██ ██  ██ ██▄▄██   ██   ██▄▄
+		██  ██ ██▀▀▀  ██  ██ ██▀▀██   ██   ██▀▀
+		▀████▀ ██     █████▀ ██  ██   ██   ██████
+		*/
+		setHeadersCss : function( c ) {
+			var $sorted, indx, column,
+				list = c.sortList,
+				len = list.length,
+				none = ts.css.sortNone + ' ' + c.cssNone,
+				css = [ ts.css.sortAsc + ' ' + c.cssAsc, ts.css.sortDesc + ' ' + c.cssDesc ],
+				cssIcon = [ c.cssIconAsc, c.cssIconDesc, c.cssIconNone ],
+				aria = [ 'ascending', 'descending' ],
+				// find the footer
+				$headers = c.$table
+					.find( 'tfoot tr' )
+					.children( 'td, th' )
+					.add( $( c.namespace + '_extra_headers' ) )
+					.removeClass( css.join( ' ' ) );
+			// remove all header information
+			c.$headers
+				.add( $( 'thead ' + c.namespace + '_extra_headers' ) )
+				.removeClass( css.join( ' ' ) )
+				.addClass( none )
+				.attr( 'aria-sort', 'none' )
+				.find( '.' + ts.css.icon )
+				.removeClass( cssIcon.join( ' ' ) )
+				.addClass( cssIcon[ 2 ] );
+			for ( indx = 0; indx < len; indx++ ) {
+				// direction = 2 means reset!
+				if ( list[ indx ][ 1 ] !== 2 ) {
+					// multicolumn sorting updating - see #1005
+					// .not(function(){}) needs jQuery 1.4
+					// filter(function(i, el){}) <- el is undefined in jQuery v1.2.6
+					$sorted = c.$headers.filter( function( i ) {
+						// only include headers that are in the sortList (this includes colspans)
+						var include = true,
+							$el = c.$headers.eq( i ),
+							col = parseInt( $el.attr( 'data-column' ), 10 ),
+							end = col + c.$headers[ i ].colSpan;
+						for ( ; col < end; col++ ) {
+							include = include ? include || ts.isValueInArray( col, c.sortList ) > -1 : false;
+						}
+						return include;
+					});
+
+					// choose the :last in case there are nested columns
+					$sorted = $sorted
+						.not( '.sorter-false' )
+						.filter( '[data-column="' + list[ indx ][ 0 ] + '"]' + ( len === 1 ? ':last' : '' ) );
+					if ( $sorted.length ) {
+						for ( column = 0; column < $sorted.length; column++ ) {
+							if ( !$sorted[ column ].sortDisabled ) {
+								$sorted
+									.eq( column )
+									.removeClass( none )
+									.addClass( css[ list[ indx ][ 1 ] ] )
+									.attr( 'aria-sort', aria[ list[ indx ][ 1 ] ] )
+									.find( '.' + ts.css.icon )
+									.removeClass( cssIcon[ 2 ] )
+									.addClass( cssIcon[ list[ indx ][ 1 ] ] );
+							}
+						}
+						// add sorted class to footer & extra headers, if they exist
+						if ( $headers.length ) {
+							$headers
+								.filter( '[data-column="' + list[ indx ][ 0 ] + '"]' )
+								.removeClass( none )
+								.addClass( css[ list[ indx ][ 1 ] ] );
+						}
+					}
+				}
+			}
+			// add verbose aria labels
+			len = c.$headers.length;
+			for ( indx = 0; indx < len; indx++ ) {
+				ts.setColumnAriaLabel( c, c.$headers.eq( indx ) );
+			}
+		},
+
+		// nextSort (optional), lets you disable next sort text
+		setColumnAriaLabel : function( c, $header, nextSort ) {
+			if ( $header.length ) {
+				var column = parseInt( $header.attr( 'data-column' ), 10 ),
+					vars = c.sortVars[ column ],
+					tmp = $header.hasClass( ts.css.sortAsc ) ?
+						'sortAsc' :
+						$header.hasClass( ts.css.sortDesc ) ? 'sortDesc' : 'sortNone',
+					txt = $.trim( $header.text() ) + ': ' + ts.language[ tmp ];
+				if ( $header.hasClass( 'sorter-false' ) || nextSort === false ) {
+					txt += ts.language.sortDisabled;
+				} else {
+					tmp = ( vars.count + 1 ) % vars.order.length;
+					nextSort = vars.order[ tmp ];
+					// if nextSort
+					txt += ts.language[ nextSort === 0 ? 'nextAsc' : nextSort === 1 ? 'nextDesc' : 'nextNone' ];
+				}
+				$header.attr( 'aria-label', txt );
+			}
+		},
+
+		updateHeader : function( c ) {
+			var index, isDisabled, $header, col,
+				table = c.table,
+				len = c.$headers.length;
+			for ( index = 0; index < len; index++ ) {
+				$header = c.$headers.eq( index );
+				col = ts.getColumnData( table, c.headers, index, true );
+				// add 'sorter-false' class if 'parser-false' is set
+				isDisabled = ts.getData( $header, col, 'sorter' ) === 'false' || ts.getData( $header, col, 'parser' ) === 'false';
+				ts.setColumnSort( c, $header, isDisabled );
+			}
+		},
+
+		setColumnSort : function( c, $header, isDisabled ) {
+			var id = c.table.id;
+			$header[ 0 ].sortDisabled = isDisabled;
+			$header[ isDisabled ? 'addClass' : 'removeClass' ]( 'sorter-false' )
+				.attr( 'aria-disabled', '' + isDisabled );
+			// disable tab index on disabled cells
+			if ( c.tabIndex ) {
+				if ( isDisabled ) {
+					$header.removeAttr( 'tabindex' );
+				} else {
+					$header.attr( 'tabindex', '0' );
+				}
+			}
+			// aria-controls - requires table ID
+			if ( id ) {
+				if ( isDisabled ) {
+					$header.removeAttr( 'aria-controls' );
+				} else {
+					$header.attr( 'aria-controls', id );
+				}
+			}
+		},
+
+		updateHeaderSortCount : function( c, list ) {
+			var col, dir, group, indx, primary, temp, val, order,
+				sortList = list || c.sortList,
+				len = sortList.length;
+			c.sortList = [];
+			for ( indx = 0; indx < len; indx++ ) {
+				val = sortList[ indx ];
+				// ensure all sortList values are numeric - fixes #127
+				col = parseInt( val[ 0 ], 10 );
+				// prevents error if sorton array is wrong
+				if ( col < c.columns ) {
+
+					// set order if not already defined - due to colspan header without associated header cell
+					// adding this check prevents a javascript error
+					if ( !c.sortVars[ col ].order ) {
+						if ( ts.getOrder( c.sortInitialOrder ) ) {
+							order = c.sortReset ? [ 1, 0, 2 ] : [ 1, 0 ];
+						} else {
+							order = c.sortReset ? [ 0, 1, 2 ] : [ 0, 1 ];
+						}
+						c.sortVars[ col ].order = order;
+						c.sortVars[ col ].count = 0;
+					}
+
+					order = c.sortVars[ col ].order;
+					dir = ( '' + val[ 1 ] ).match( /^(1|d|s|o|n)/ );
+					dir = dir ? dir[ 0 ] : '';
+					// 0/(a)sc (default), 1/(d)esc, (s)ame, (o)pposite, (n)ext
+					switch ( dir ) {
+						case '1' : case 'd' : // descending
+							dir = 1;
+							break;
+						case 's' : // same direction (as primary column)
+							// if primary sort is set to 's', make it ascending
+							dir = primary || 0;
+							break;
+						case 'o' :
+							temp = order[ ( primary || 0 ) % order.length ];
+							// opposite of primary column; but resets if primary resets
+							dir = temp === 0 ? 1 : temp === 1 ? 0 : 2;
+							break;
+						case 'n' :
+							dir = order[ ( ++c.sortVars[ col ].count ) % order.length ];
+							break;
+						default : // ascending
+							dir = 0;
+							break;
+					}
+					primary = indx === 0 ? dir : primary;
+					group = [ col, parseInt( dir, 10 ) || 0 ];
+					c.sortList[ c.sortList.length ] = group;
+					dir = $.inArray( group[ 1 ], order ); // fixes issue #167
+					c.sortVars[ col ].count = dir >= 0 ? dir : group[ 1 ] % order.length;
+				}
+			}
+		},
+
+		updateAll : function( c, resort, callback ) {
+			var table = c.table;
+			table.isUpdating = true;
+			ts.refreshWidgets( table, true, true );
+			ts.buildHeaders( c );
+			ts.bindEvents( table, c.$headers, true );
+			ts.bindMethods( c );
+			ts.commonUpdate( c, resort, callback );
+		},
+
+		update : function( c, resort, callback ) {
+			var table = c.table;
+			table.isUpdating = true;
+			// update sorting (if enabled/disabled)
+			ts.updateHeader( c );
+			ts.commonUpdate( c, resort, callback );
+		},
+
+		// simple header update - see #989
+		updateHeaders : function( c, callback ) {
+			c.table.isUpdating = true;
+			ts.buildHeaders( c );
+			ts.bindEvents( c.table, c.$headers, true );
+			ts.resortComplete( c, callback );
+		},
+
+		updateCell : function( c, cell, resort, callback ) {
+			if ( ts.isEmptyObject( c.cache ) ) {
+				// empty table, do an update instead - fixes #1099
+				ts.updateHeader( c );
+				ts.commonUpdate( c, resort, callback );
+				return;
+			}
+			c.table.isUpdating = true;
+			c.$table.find( c.selectorRemove ).remove();
+			// get position from the dom
+			var tmp, indx, row, icell, cache, len,
+				$tbodies = c.$tbodies,
+				$cell = $( cell ),
+				// update cache - format: function( s, table, cell, cellIndex )
+				// no closest in jQuery v1.2.6
+				tbodyIndex = $tbodies
+					.index( $.fn.closest ? $cell.closest( 'tbody' ) : $cell.parents( 'tbody' ).filter( ':first' ) ),
+				tbcache = c.cache[ tbodyIndex ],
+				$row = $.fn.closest ? $cell.closest( 'tr' ) : $cell.parents( 'tr' ).filter( ':first' );
+			cell = $cell[ 0 ]; // in case cell is a jQuery object
+			// tbody may not exist if update is initialized while tbody is removed for processing
+			if ( $tbodies.length && tbodyIndex >= 0 ) {
+				row = $tbodies.eq( tbodyIndex ).find( 'tr' ).index( $row );
+				cache = tbcache.normalized[ row ];
+				len = $row[ 0 ].cells.length;
+				if ( len !== c.columns ) {
+					// colspan in here somewhere!
+					icell = 0;
+					tmp = false;
+					for ( indx = 0; indx < len; indx++ ) {
+						if ( !tmp && $row[ 0 ].cells[ indx ] !== cell ) {
+							icell += $row[ 0 ].cells[ indx ].colSpan;
+						} else {
+							tmp = true;
+						}
+					}
+				} else {
+					icell = $cell.index();
+				}
+				tmp = ts.getElementText( c, cell, icell ); // raw
+				cache[ c.columns ].raw[ icell ] = tmp;
+				tmp = ts.getParsedText( c, cell, icell, tmp );
+				cache[ icell ] = tmp; // parsed
+				cache[ c.columns ].$row = $row;
+				if ( ( c.parsers[ icell ].type || '' ).toLowerCase() === 'numeric' ) {
+					// update column max value (ignore sign)
+					tbcache.colMax[ icell ] = Math.max( Math.abs( tmp ) || 0, tbcache.colMax[ icell ] || 0 );
+				}
+				tmp = resort !== 'undefined' ? resort : c.resort;
+				if ( tmp !== false ) {
+					// widgets will be reapplied
+					ts.checkResort( c, tmp, callback );
+				} else {
+					// don't reapply widgets is resort is false, just in case it causes
+					// problems with element focus
+					ts.resortComplete( c, callback );
+				}
+			} else {
+				if ( c.debug ) {
+					console.error( 'updateCell aborted, tbody missing or not within the indicated table' );
+				}
+				c.table.isUpdating = false;
+			}
+		},
+
+		addRows : function( c, $row, resort, callback ) {
+			var txt, val, tbodyIndex, rowIndex, rows, cellIndex, len, order,
+				cacheIndex, rowData, cells, cell, span,
+				// allow passing a row string if only one non-info tbody exists in the table
+				valid = typeof $row === 'string' && c.$tbodies.length === 1 && /<tr/.test( $row || '' ),
+				table = c.table;
+			if ( valid ) {
+				$row = $( $row );
+				c.$tbodies.append( $row );
+			} else if ( !$row ||
+				// row is a jQuery object?
+				!( $row instanceof jQuery ) ||
+				// row contained in the table?
+				( $.fn.closest ? $row.closest( 'table' )[ 0 ] : $row.parents( 'table' )[ 0 ] ) !== c.table ) {
+				if ( 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' );
+				}
+				return false;
+			}
+			table.isUpdating = true;
+			if ( ts.isEmptyObject( c.cache ) ) {
+				// empty table, do an update instead - fixes #450
+				ts.updateHeader( c );
+				ts.commonUpdate( c, resort, callback );
+			} else {
+				rows = $row.filter( 'tr' ).attr( 'role', 'row' ).length;
+				tbodyIndex = c.$tbodies.index( $row.parents( 'tbody' ).filter( ':first' ) );
+				// fixes adding rows to an empty table - see issue #179
+				if ( !( c.parsers && c.parsers.length ) ) {
+					ts.setupParsers( c );
+				}
+				// add each row
+				for ( rowIndex = 0; rowIndex < rows; rowIndex++ ) {
+					cacheIndex = 0;
+					len = $row[ rowIndex ].cells.length;
+					order = c.cache[ tbodyIndex ].normalized.length;
+					cells = [];
+					rowData = {
+						child : [],
+						raw : [],
+						$row : $row.eq( rowIndex ),
+						order : order
+					};
+					// add each cell
+					for ( cellIndex = 0; cellIndex < len; cellIndex++ ) {
+						cell = $row[ rowIndex ].cells[ cellIndex ];
+						txt = ts.getElementText( c, cell, cacheIndex );
+						rowData.raw[ cacheIndex ] = txt;
+						val = ts.getParsedText( c, cell, cacheIndex, txt );
+						cells[ cacheIndex ] = val;
+						if ( ( c.parsers[ cacheIndex ].type || '' ).toLowerCase() === 'numeric' ) {
+							// update column max value (ignore sign)
+							c.cache[ tbodyIndex ].colMax[ cacheIndex ] =
+								Math.max( Math.abs( val ) || 0, c.cache[ tbodyIndex ].colMax[ cacheIndex ] || 0 );
+						}
+						span = cell.colSpan - 1;
+						if ( span > 0 ) {
+							cacheIndex += span;
+						}
+						cacheIndex++;
+					}
+					// add the row data to the end
+					cells[ c.columns ] = rowData;
+					// update cache
+					c.cache[ tbodyIndex ].normalized[ order ] = cells;
+				}
+				// resort using current settings
+				ts.checkResort( c, resort, callback );
+			}
+		},
+
+		updateCache : function( c, callback, $tbodies ) {
+			// rebuild parsers
+			if ( !( c.parsers && c.parsers.length ) ) {
+				ts.setupParsers( c, $tbodies );
+			}
+			// rebuild the cache map
+			ts.buildCache( c, callback, $tbodies );
+		},
+
+		// init flag (true) used by pager plugin to prevent widget application
+		// renamed from appendToTable
+		appendCache : function( c, init ) {
+			var parsed, totalRows, $tbody, $curTbody, rowIndex, tbodyIndex, appendTime,
+				table = c.table,
+				wo = c.widgetOptions,
+				$tbodies = c.$tbodies,
+				rows = [],
+				cache = c.cache;
+			// empty table - fixes #206/#346
+			if ( ts.isEmptyObject( cache ) ) {
+				// run pager appender in case the table was just emptied
+				return c.appender ? c.appender( table, rows ) :
+					table.isUpdating ? c.$table.triggerHandler( 'updateComplete', table ) : ''; // Fixes #532
+			}
+			if ( c.debug ) {
+				appendTime = new Date();
+			}
+			for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = $tbodies.eq( tbodyIndex );
+				if ( $tbody.length ) {
+					// detach tbody for manipulation
+					$curTbody = ts.processTbody( table, $tbody, true );
+					parsed = cache[ tbodyIndex ].normalized;
+					totalRows = parsed.length;
+					for ( rowIndex = 0; rowIndex < totalRows; rowIndex++ ) {
+						rows[rows.length] = parsed[ rowIndex ][ c.columns ].$row;
+						// removeRows used by the pager plugin; don't render if using ajax - fixes #411
+						if ( !c.appender || ( c.pager && ( !c.pager.removeRows || !wo.pager_removeRows ) && !c.pager.ajax ) ) {
+							$curTbody.append( parsed[ rowIndex ][ c.columns ].$row );
+						}
+					}
+					// restore tbody
+					ts.processTbody( table, $curTbody, false );
+				}
+			}
+			if ( c.appender ) {
+				c.appender( table, rows );
+			}
+			if ( c.debug ) {
+				console.log( 'Rebuilt table' + ts.benchmark( appendTime ) );
+			}
+			// apply table widgets; but not before ajax completes
+			if ( !init && !c.appender ) {
+				ts.applyWidget( table );
+			}
+			if ( table.isUpdating ) {
+				c.$table.triggerHandler( 'updateComplete', table );
+			}
+		},
+
+		commonUpdate : function( c, resort, callback ) {
+			// remove rows/elements before update
+			c.$table.find( c.selectorRemove ).remove();
+			// rebuild parsers
+			ts.setupParsers( c );
+			// rebuild the cache map
+			ts.buildCache( c );
+			ts.checkResort( c, resort, callback );
+		},
+
+		/*
+		▄█████ ▄████▄ █████▄ ██████ ██ █████▄ ▄████▄
+		▀█▄    ██  ██ ██▄▄██   ██   ██ ██  ██ ██ ▄▄▄
+		   ▀█▄ ██  ██ ██▀██    ██   ██ ██  ██ ██ ▀██
+		█████▀ ▀████▀ ██  ██   ██   ██ ██  ██ ▀████▀
+		*/
+		initSort : function( c, cell, event ) {
+			if ( c.table.isUpdating ) {
+				// let any updates complete before initializing a sort
+				return setTimeout( function(){
+					ts.initSort( c, cell, event );
+				}, 50 );
+			}
+
+			var arry, indx, headerIndx, dir, temp, tmp, $header,
+				notMultiSort = !event[ c.sortMultiSortKey ],
+				table = c.table,
+				len = c.$headers.length,
+				// get current column index
+				col = parseInt( $( cell ).attr( 'data-column' ), 10 ),
+				order = c.sortVars[ col ].order;
+
+			// Only call sortStart if sorting is enabled
+			c.$table.triggerHandler( 'sortStart', table );
+			// get current column sort order
+			tmp = ( c.sortVars[ col ].count + 1 ) % order.length;
+			c.sortVars[ col ].count = event[ c.sortResetKey ] ? 2 : tmp;
+			// reset all sorts on non-current column - issue #30
+			if ( c.sortRestart ) {
+				for ( headerIndx = 0; headerIndx < len; headerIndx++ ) {
+					$header = c.$headers.eq( headerIndx );
+					tmp = parseInt( $header.attr( 'data-column' ), 10 );
+					// only reset counts on columns that weren't just clicked on and if not included in a multisort
+					if ( col !== tmp && ( notMultiSort || $header.hasClass( ts.css.sortNone ) ) ) {
+						c.sortVars[ tmp ].count = -1;
+					}
+				}
+			}
+			// user only wants to sort on one column
+			if ( notMultiSort ) {
+				// flush the sort list
+				c.sortList = [];
+				c.last.sortList = [];
+				if ( c.sortForce !== null ) {
+					arry = c.sortForce;
+					for ( indx = 0; indx < arry.length; indx++ ) {
+						if ( arry[ indx ][ 0 ] !== col ) {
+							c.sortList[ c.sortList.length ] = arry[ indx ];
+						}
+					}
+				}
+				// add column to sort list
+				dir = order[ c.sortVars[ col ].count ];
+				if ( dir < 2 ) {
+					c.sortList[ c.sortList.length ] = [ col, dir ];
+					// add other columns if header spans across multiple
+					if ( cell.colSpan > 1 ) {
+						for ( indx = 1; indx < cell.colSpan; indx++ ) {
+							c.sortList[ c.sortList.length ] = [ col + indx, dir ];
+							// update count on columns in colSpan
+							c.sortVars[ col + indx ].count = $.inArray( dir, order );
+						}
+					}
+				}
+				// multi column sorting
+			} else {
+				// get rid of the sortAppend before adding more - fixes issue #115 & #523
+				c.sortList = $.extend( [], c.last.sortList );
+
+				// the user has clicked on an already sorted column
+				if ( ts.isValueInArray( col, c.sortList ) >= 0 ) {
+					// reverse the sorting direction
+					for ( indx = 0; indx < c.sortList.length; indx++ ) {
+						tmp = c.sortList[ indx ];
+						if ( tmp[ 0 ] === col ) {
+							// order.count seems to be incorrect when compared to cell.count
+							tmp[ 1 ] = order[ c.sortVars[ col ].count ];
+							if ( tmp[1] === 2 ) {
+								c.sortList.splice( indx, 1 );
+								c.sortVars[ col ].count = -1;
+							}
+						}
+					}
+				} else {
+					// add column to sort list array
+					dir = order[ c.sortVars[ col ].count ];
+					if ( dir < 2 ) {
+						c.sortList[ c.sortList.length ] = [ col, dir ];
+						// add other columns if header spans across multiple
+						if ( cell.colSpan > 1 ) {
+							for ( indx = 1; indx < cell.colSpan; indx++ ) {
+								c.sortList[ c.sortList.length ] = [ col + indx, dir ];
+								// update count on columns in colSpan
+								c.sortVars[ col + indx ].count = $.inArray( dir, order );
+							}
+						}
+					}
+				}
+			}
+			// save sort before applying sortAppend
+			c.last.sortList = $.extend( [], c.sortList );
+			if ( c.sortList.length && c.sortAppend ) {
+				arry = $.isArray( c.sortAppend ) ? c.sortAppend : c.sortAppend[ c.sortList[ 0 ][ 0 ] ];
+				if ( !ts.isEmptyObject( arry ) ) {
+					for ( indx = 0; indx < arry.length; indx++ ) {
+						if ( arry[ indx ][ 0 ] !== col && ts.isValueInArray( arry[ indx ][ 0 ], c.sortList ) < 0 ) {
+							dir = arry[ indx ][ 1 ];
+							temp = ( '' + dir ).match( /^(a|d|s|o|n)/ );
+							if ( temp ) {
+								tmp = c.sortList[ 0 ][ 1 ];
+								switch ( temp[ 0 ] ) {
+									case 'd' :
+										dir = 1;
+										break;
+									case 's' :
+										dir = tmp;
+										break;
+									case 'o' :
+										dir = tmp === 0 ? 1 : 0;
+										break;
+									case 'n' :
+										dir = ( tmp + 1 ) % order.length;
+										break;
+									default:
+										dir = 0;
+										break;
+								}
+							}
+							c.sortList[ c.sortList.length ] = [ arry[ indx ][ 0 ], dir ];
+						}
+					}
+				}
+			}
+			// sortBegin event triggered immediately before the sort
+			c.$table.triggerHandler( 'sortBegin', table );
+			// setTimeout needed so the processing icon shows up
+			setTimeout( function() {
+				// set css for headers
+				ts.setHeadersCss( c );
+				ts.multisort( c );
+				ts.appendCache( c );
+				c.$table.triggerHandler( 'sortBeforeEnd', table );
+				c.$table.triggerHandler( 'sortEnd', table );
+			}, 1 );
+		},
+
+		// sort multiple columns
+		multisort : function( c ) { /*jshint loopfunc:true */
+			var tbodyIndex, sortTime, colMax, rows, tmp,
+				table = c.table,
+				sorter = [],
+				dir = 0,
+				textSorter = c.textSorter || '',
+				sortList = c.sortList,
+				sortLen = sortList.length,
+				len = c.$tbodies.length;
+			if ( c.serverSideSorting || ts.isEmptyObject( c.cache ) ) {
+				// empty table - fixes #206/#346
+				return;
+			}
+			if ( c.debug ) { sortTime = new Date(); }
+			// cache textSorter to optimize speed
+			if ( typeof textSorter === 'object' ) {
+				colMax = c.columns;
+				while ( colMax-- ) {
+					tmp = ts.getColumnData( table, textSorter, colMax );
+					if ( typeof tmp === 'function' ) {
+						sorter[ colMax ] = tmp;
+					}
+				}
+			}
+			for ( tbodyIndex = 0; tbodyIndex < len; tbodyIndex++ ) {
+				colMax = c.cache[ tbodyIndex ].colMax;
+				rows = c.cache[ tbodyIndex ].normalized;
+
+				rows.sort( function( a, b ) {
+					var sortIndex, num, col, order, sort, x, y;
+					// rows is undefined here in IE, so don't use it!
+					for ( sortIndex = 0; sortIndex < sortLen; sortIndex++ ) {
+						col = sortList[ sortIndex ][ 0 ];
+						order = sortList[ sortIndex ][ 1 ];
+						// sort direction, true = asc, false = desc
+						dir = order === 0;
+
+						if ( c.sortStable && a[ col ] === b[ col ] && sortLen === 1 ) {
+							return a[ c.columns ].order - b[ c.columns ].order;
+						}
+
+						// fallback to natural sort since it is more robust
+						num = /n/i.test( ts.getSortType( c.parsers, col ) );
+						if ( num && c.strings[ col ] ) {
+							// sort strings in numerical columns
+							if ( typeof ( ts.string[ c.strings[ col ] ] ) === 'boolean' ) {
+								num = ( dir ? 1 : -1 ) * ( ts.string[ c.strings[ col ] ] ? -1 : 1 );
+							} else {
+								num = ( c.strings[ col ] ) ? ts.string[ c.strings[ col ] ] || 0 : 0;
+							}
+							// fall back to built-in numeric sort
+							// var sort = $.tablesorter['sort' + s]( a[col], b[col], dir, colMax[col], table );
+							sort = c.numberSorter ? c.numberSorter( a[ col ], b[ col ], dir, colMax[ col ], table ) :
+								ts[ 'sortNumeric' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ], b[ col ], num, colMax[ col ], col, c );
+						} else {
+							// set a & b depending on sort direction
+							x = dir ? a : b;
+							y = dir ? b : a;
+							// text sort function
+							if ( typeof textSorter === 'function' ) {
+								// custom OVERALL text sorter
+								sort = textSorter( x[ col ], y[ col ], dir, col, table );
+							} else if ( typeof sorter[ col ] === 'function' ) {
+								// custom text sorter for a SPECIFIC COLUMN
+								sort = sorter[ col ]( x[ col ], y[ col ], dir, col, table );
+							} else {
+								// fall back to natural sort
+								sort = ts[ 'sortNatural' + ( dir ? 'Asc' : 'Desc' ) ]( a[ col ], b[ col ], col, c );
+							}
+						}
+						if ( sort ) { return sort; }
+					}
+					return a[ c.columns ].order - b[ c.columns ].order;
+				});
+			}
+			if ( c.debug ) {
+				console.log( 'Applying sort ' + sortList.toString() + ts.benchmark( sortTime ) );
+			}
+		},
+
+		resortComplete : function( c, callback ) {
+			if ( c.table.isUpdating ) {
+				c.$table.triggerHandler( 'updateComplete', c.table );
+			}
+			if ( $.isFunction( callback ) ) {
+				callback( c.table );
+			}
+		},
+
+		checkResort : function( c, resort, callback ) {
+			var sortList = $.isArray( resort ) ? resort : c.sortList,
+				// if no resort parameter is passed, fallback to config.resort (true by default)
+				resrt = typeof resort === 'undefined' ? c.resort : resort;
+			// don't try to resort if the table is still processing
+			// this will catch spamming of the updateCell method
+			if ( resrt !== false && !c.serverSideSorting && !c.table.isProcessing ) {
+				if ( sortList.length ) {
+					ts.sortOn( c, sortList, function() {
+						ts.resortComplete( c, callback );
+					}, true );
+				} else {
+					ts.sortReset( c, function() {
+						ts.resortComplete( c, callback );
+						ts.applyWidget( c.table, false );
+					} );
+				}
+			} else {
+				ts.resortComplete( c, callback );
+				ts.applyWidget( c.table, false );
+			}
+		},
+
+		sortOn : function( c, list, callback, init ) {
+			var table = c.table;
+			c.$table.triggerHandler( 'sortStart', table );
+			// update header count index
+			ts.updateHeaderSortCount( c, list );
+			// set css for headers
+			ts.setHeadersCss( c );
+			// fixes #346
+			if ( c.delayInit && ts.isEmptyObject( c.cache ) ) {
+				ts.buildCache( c );
+			}
+			c.$table.triggerHandler( 'sortBegin', table );
+			// sort the table and append it to the dom
+			ts.multisort( c );
+			ts.appendCache( c, init );
+			c.$table.triggerHandler( 'sortBeforeEnd', table );
+			c.$table.triggerHandler( 'sortEnd', table );
+			ts.applyWidget( table );
+			if ( $.isFunction( callback ) ) {
+				callback( table );
+			}
+		},
+
+		sortReset : function( c, callback ) {
+			c.sortList = [];
+			ts.setHeadersCss( c );
+			ts.multisort( c );
+			ts.appendCache( c );
+			if ( $.isFunction( callback ) ) {
+				callback( c.table );
+			}
+		},
+
+		getSortType : function( parsers, column ) {
+			return ( parsers && parsers[ column ] ) ? parsers[ column ].type || '' : '';
+		},
+
+		getOrder : function( val ) {
+			// look for 'd' in 'desc' order; return true
+			return ( /^d/i.test( val ) || val === 1 );
+		},
+
+		// 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, b ) {
+			if ( a === b ) { return 0; }
+			var aNum, bNum, aFloat, bFloat, indx, max,
+				regex = ts.regex;
+			// first try and sort Hex codes
+			if ( regex.hex.test( b ) ) {
+				aNum = parseInt( ( a || '' ).match( regex.hex ), 16 );
+				bNum = parseInt( ( b || '' ).match( regex.hex ), 16 );
+				if ( aNum < bNum ) { return -1; }
+				if ( aNum > bNum ) { return 1; }
+			}
+			// chunk/tokenize
+			aNum = ( a || '' ).replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
+			bNum = ( b || '' ).replace( regex.chunk, '\\0$1\\0' ).replace( regex.chunks, '' ).split( '\\0' );
+			max = Math.max( aNum.length, bNum.length );
+			// natural sorting through split numeric strings and default strings
+			for ( indx = 0; indx < max; indx++ ) {
+				// find floats not starting with '0', string or 0 if not defined
+				aFloat = isNaN( aNum[ indx ] ) ? aNum[ indx ] || 0 : parseFloat( aNum[ indx ] ) || 0;
+				bFloat = isNaN( bNum[ indx ] ) ? bNum[ indx ] || 0 : parseFloat( bNum[ indx ] ) || 0;
+				// handle numeric vs string comparison - number < string - (Kyle Adams)
+				if ( isNaN( aFloat ) !== isNaN( bFloat ) ) { return isNaN( aFloat ) ? 1 : -1; }
+				// rely on string comparison if different types - i.e. '02' < 2 != '02' < '2'
+				if ( typeof aFloat !== typeof bFloat ) {
+					aFloat += '';
+					bFloat += '';
+				}
+				if ( aFloat < bFloat ) { return -1; }
+				if ( aFloat > bFloat ) { return 1; }
+			}
+			return 0;
+		},
+
+		sortNaturalAsc : function( a, b, col, c ) {
+			if ( a === b ) { return 0; }
+			var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
+			if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
+			if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
+			return ts.sortNatural( a, b );
+		},
+
+		sortNaturalDesc : function( a, b, col, c ) {
+			if ( a === b ) { return 0; }
+			var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
+			if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
+			if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
+			return ts.sortNatural( b, a );
+		},
+
+		// basic alphabetical sort
+		sortText : function( a, b ) {
+			return a > b ? 1 : ( a < b ? -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( val, num, max ) {
+			if ( max ) {
+				// make sure the text value is greater than the max numerical value (max)
+				var indx,
+					len = val ? val.length : 0,
+					n = max + num;
+				for ( indx = 0; indx < len; indx++ ) {
+					n += val.charCodeAt( indx );
+				}
+				return num * n;
+			}
+			return 0;
+		},
+
+		sortNumericAsc : function( a, b, num, max, col, c ) {
+			if ( a === b ) { return 0; }
+			var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
+			if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : -empty || -1; }
+			if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : empty || 1; }
+			if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
+			if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
+			return a - b;
+		},
+
+		sortNumericDesc : function( a, b, num, max, col, c ) {
+			if ( a === b ) { return 0; }
+			var empty = ts.string[ ( c.empties[ col ] || c.emptyTo ) ];
+			if ( a === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? -1 : 1 ) : empty || 1; }
+			if ( b === '' && empty !== 0 ) { return typeof empty === 'boolean' ? ( empty ? 1 : -1 ) : -empty || -1; }
+			if ( isNaN( a ) ) { a = ts.getTextValue( a, num, max ); }
+			if ( isNaN( b ) ) { b = ts.getTextValue( b, num, max ); }
+			return b - a;
+		},
+
+		sortNumeric : function( a, b ) {
+			return a - b;
+		},
+
+		/*
+		██ ██ ██ ██ █████▄ ▄████▄ ██████ ██████ ▄█████
+		██ ██ ██ ██ ██  ██ ██ ▄▄▄ ██▄▄     ██   ▀█▄
+		██ ██ ██ ██ ██  ██ ██ ▀██ ██▀▀     ██      ▀█▄
+		███████▀ ██ █████▀ ▀████▀ ██████   ██   █████▀
+		*/
+		addWidget : function( widget ) {
+			if ( widget.id && !ts.isEmptyObject( ts.getWidgetById( widget.id ) ) ) {
+				console.warn( '"' + widget.id + '" widget was loaded more than once!' );
+			}
+			ts.widgets[ ts.widgets.length ] = widget;
+		},
+
+		hasWidget : function( $table, name ) {
+			$table = $( $table );
+			return $table.length && $table[ 0 ].config && $table[ 0 ].config.widgetInit[ name ] || false;
+		},
+
+		getWidgetById : function( name ) {
+			var indx, widget,
+				len = ts.widgets.length;
+			for ( indx = 0; indx < len; indx++ ) {
+				widget = ts.widgets[ indx ];
+				if ( widget && widget.id && widget.id.toLowerCase() === name.toLowerCase() ) {
+					return widget;
+				}
+			}
+		},
+
+		applyWidgetOptions : function( table ) {
+			var indx, widget,
+				c = table.config,
+				len = c.widgets.length;
+			if ( len ) {
+				for ( indx = 0; indx < len; indx++ ) {
+					widget = ts.getWidgetById( c.widgets[ indx ] );
+					if ( widget && widget.options ) {
+						c.widgetOptions = $.extend( true, {}, widget.options, c.widgetOptions );
+						// add widgetOptions to defaults for option validator
+						$.extend( true, ts.defaults.widgetOptions, widget.options );
+					}
+				}
+			}
+		},
+
+		addWidgetFromClass : function( table ) {
+			var len, indx,
+				c = table.config,
+				// look for widgets to apply from table class
+				// don't match from 'ui-widget-content'; use \S instead of \w to include widgets
+				// with dashes in the name, e.g. "widget-test-2" extracts out "test-2"
+				regex = '^' + c.widgetClass.replace( ts.regex.templateName, '(\\S+)+' ) + '$',
+				widgetClass = new RegExp( regex, 'g' ),
+				// split up table class (widget id's can include dashes) - stop using match
+				// otherwise only one widget gets extracted, see #1109
+				widgets = ( table.className || '' ).split( ts.regex.spaces );
+			if ( widgets.length ) {
+				len = widgets.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					if ( widgets[ indx ].match( widgetClass ) ) {
+						c.widgets[ c.widgets.length ] = widgets[ indx ].replace( widgetClass, '$1' );
+					}
+				}
+			}
+		},
+
+		applyWidgetId : function( table, id, init ) {
+			table = $(table)[0];
+			var applied, time, name,
+				c = table.config,
+				wo = c.widgetOptions,
+				widget = ts.getWidgetById( id );
+			if ( widget ) {
+				name = widget.id;
+				applied = false;
+				// add widget name to option list so it gets reapplied after sorting, filtering, etc
+				if ( $.inArray( name, c.widgets ) < 0 ) {
+					c.widgets[ c.widgets.length ] = name;
+				}
+				if ( c.debug ) { time = new Date(); }
+
+				if ( init || !( c.widgetInit[ name ] ) ) {
+					// set init flag first to prevent calling init more than once (e.g. pager)
+					c.widgetInit[ name ] = true;
+					if ( table.hasInitialized ) {
+						// don't reapply widget options on tablesorter init
+						ts.applyWidgetOptions( table );
+					}
+					if ( typeof widget.init === 'function' ) {
+						applied = true;
+						if ( c.debug ) {
+							console[ console.group ? 'group' : 'log' ]( 'Initializing ' + name + ' widget' );
+						}
+						widget.init( table, widget, c, wo );
+					}
+				}
+				if ( !init && typeof widget.format === 'function' ) {
+					applied = true;
+					if ( c.debug ) {
+						console[ console.group ? 'group' : 'log' ]( 'Updating ' + name + ' widget' );
+					}
+					widget.format( table, c, wo, false );
+				}
+				if ( c.debug ) {
+					if ( applied ) {
+						console.log( 'Completed ' + ( init ? 'initializing ' : 'applying ' ) + name + ' widget' + ts.benchmark( time ) );
+						if ( console.groupEnd ) { console.groupEnd(); }
+					}
+				}
+			}
+		},
+
+		applyWidget : function( table, init, callback ) {
+			table = $( table )[ 0 ]; // in case this is called externally
+			var indx, len, names, widget, time,
+				c = table.config,
+				widgets = [];
+			// prevent numerous consecutive widget applications
+			if ( init !== false && table.hasInitialized && ( table.isApplyingWidgets || table.isUpdating ) ) {
+				return;
+			}
+			if ( c.debug ) { time = new Date(); }
+			ts.addWidgetFromClass( table );
+			// prevent "tablesorter-ready" from firing multiple times in a row
+			clearTimeout( c.timerReady );
+			if ( c.widgets.length ) {
+				table.isApplyingWidgets = true;
+				// ensure unique widget ids
+				c.widgets = $.grep( c.widgets, function( val, index ) {
+					return $.inArray( val, c.widgets ) === index;
+				});
+				names = c.widgets || [];
+				len = names.length;
+				// build widget array & add priority as needed
+				for ( indx = 0; indx < len; indx++ ) {
+					widget = ts.getWidgetById( names[ indx ] );
+					if ( widget && widget.id ) {
+						// set priority to 10 if not defined
+						if ( !widget.priority ) { widget.priority = 10; }
+						widgets[ indx ] = widget;
+					} else if ( c.debug ) {
+						console.warn( '"' + names[ indx ] + '" widget code does not exist!' );
+					}
+				}
+				// sort widgets by priority
+				widgets.sort( function( a, b ) {
+					return a.priority < b.priority ? -1 : a.priority === b.priority ? 0 : 1;
+				});
+				// add/update selected widgets
+				len = widgets.length;
+				if ( c.debug ) {
+					console[ console.group ? 'group' : 'log' ]( 'Start ' + ( init ? 'initializing' : 'applying' ) + ' widgets' );
+				}
+				for ( indx = 0; indx < len; indx++ ) {
+					widget = widgets[ indx ];
+					if ( widget && widget.id ) {
+						ts.applyWidgetId( table, widget.id, init );
+					}
+				}
+				if ( c.debug && console.groupEnd ) { console.groupEnd(); }
+				// callback executed on init only
+				if ( !init && typeof callback === 'function' ) {
+					callback( table );
+				}
+			}
+			c.timerReady = setTimeout( function() {
+				table.isApplyingWidgets = false;
+				$.data( table, 'lastWidgetApplication', new Date() );
+				c.$table.triggerHandler( 'tablesorter-ready' );
+			}, 10 );
+			if ( c.debug ) {
+				widget = c.widgets.length;
+				console.log( 'Completed ' +
+					( init === true ? 'initializing ' : 'applying ' ) + widget +
+					' widget' + ( widget !== 1 ? 's' : '' ) + ts.benchmark( time ) );
+			}
+		},
+
+		removeWidget : function( table, name, refreshing ) {
+			table = $( table )[ 0 ];
+			var index, widget, indx, len,
+				c = table.config;
+			// if name === true, add all widgets from $.tablesorter.widgets
+			if ( name === true ) {
+				name = [];
+				len = ts.widgets.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					widget = ts.widgets[ indx ];
+					if ( widget && widget.id ) {
+						name[ name.length ] = widget.id;
+					}
+				}
+			} else {
+				// name can be either an array of widgets names,
+				// or a space/comma separated list of widget names
+				name = ( $.isArray( name ) ? name.join( ',' ) : name || '' ).toLowerCase().split( /[\s,]+/ );
+			}
+			len = name.length;
+			for ( index = 0; index < len; index++ ) {
+				widget = ts.getWidgetById( name[ index ] );
+				indx = $.inArray( name[ index ], c.widgets );
+				// don't remove the widget from config.widget if refreshing
+				if ( indx >= 0 && refreshing !== true ) {
+					c.widgets.splice( indx, 1 );
+				}
+				if ( widget && widget.remove ) {
+					if ( c.debug ) {
+						console.log( ( refreshing ? 'Refreshing' : 'Removing' ) + ' "' + name[ index ] + '" widget' );
+					}
+					widget.remove( table, c, c.widgetOptions, refreshing );
+					c.widgetInit[ name[ index ] ] = false;
+				}
+			}
+		},
+
+		refreshWidgets : function( table, doAll, dontapply ) {
+			table = $( table )[ 0 ]; // see issue #243
+			var indx, widget,
+				c = table.config,
+				curWidgets = c.widgets,
+				widgets = ts.widgets,
+				len = widgets.length,
+				list = [],
+				callback = function( table ) {
+					$( table ).triggerHandler( 'refreshComplete' );
+				};
+			// remove widgets not defined in config.widgets, unless doAll is true
+			for ( indx = 0; indx < len; indx++ ) {
+				widget = widgets[ indx ];
+				if ( widget && widget.id && ( doAll || $.inArray( widget.id, curWidgets ) < 0 ) ) {
+					list[ list.length ] = widget.id;
+				}
+			}
+			ts.removeWidget( table, list.join( ',' ), true );
+			if ( dontapply !== true ) {
+				// call widget init if
+				ts.applyWidget( table, doAll || false, callback );
+				if ( doAll ) {
+					// apply widget format
+					ts.applyWidget( table, false, callback );
+				}
+			} else {
+				callback( table );
+			}
+		},
+
+		/*
+		██  ██ ██████ ██ ██     ██ ██████ ██ ██████ ▄█████
+		██  ██   ██   ██ ██     ██   ██   ██ ██▄▄   ▀█▄
+		██  ██   ██   ██ ██     ██   ██   ██ ██▀▀      ▀█▄
+		▀████▀   ██   ██ ██████ ██   ██   ██ ██████ █████▀
+		*/
+		benchmark : function( diff ) {
+			return ( ' (' + ( new Date().getTime() - diff.getTime() ) + ' ms)' );
+		},
+		// deprecated ts.log
+		log : function() {
+			console.log( arguments );
+		},
+
+		// $.isEmptyObject from jQuery v1.4
+		isEmptyObject : function( obj ) {
+			/*jshint forin: false */
+			for ( var name in obj ) {
+				return false;
+			}
+			return true;
+		},
+
+		isValueInArray : function( column, arry ) {
+			var indx,
+				len = arry && arry.length || 0;
+			for ( indx = 0; indx < len; indx++ ) {
+				if ( arry[ indx ][ 0 ] === column ) {
+					return indx;
+				}
+			}
+			return -1;
+		},
+
+		formatFloat : function( str, table ) {
+			if ( typeof str !== 'string' || str === '' ) { return str; }
+			// allow using formatFloat without a table; defaults to US number format
+			var num,
+				usFormat = table && table.config ? table.config.usNumberFormat !== false :
+					typeof table !== 'undefined' ? table : true;
+			if ( usFormat ) {
+				// US Format - 1,234,567.89 -> 1234567.89
+				str = str.replace( ts.regex.comma, '' );
+			} else {
+				// German Format = 1.234.567,89 -> 1234567.89
+				// French Format = 1 234 567,89 -> 1234567.89
+				str = str.replace( ts.regex.digitNonUS, '' ).replace( ts.regex.comma, '.' );
+			}
+			if ( ts.regex.digitNegativeTest.test( str ) ) {
+				// make (#) into a negative number -> (10) = -10
+				str = str.replace( ts.regex.digitNegativeReplace, '-$1' );
+			}
+			num = parseFloat( str );
+			// return the text instead of zero
+			return isNaN( num ) ? $.trim( str ) : num;
+		},
+
+		isDigit : function( str ) {
+			// replace all unwanted chars and match
+			return isNaN( str ) ?
+				ts.regex.digitTest.test( str.toString().replace( ts.regex.digitReplace, '' ) ) :
+				str !== '';
+		},
+
+		// computeTableHeaderCellIndexes from:
+		// http://www.javascripttoolbox.com/lib/table/examples.php
+		// http://www.javascripttoolbox.com/temp/table_cellindex.html
+		computeColumnIndex : function( $rows, c ) {
+			var i, j, k, l, cell, cells, rowIndex, rowSpan, colSpan, firstAvailCol,
+				// total columns has been calculated, use it to set the matrixrow
+				columns = c && c.columns || 0,
+				matrix = [],
+				matrixrow = new Array( columns );
+			for ( i = 0; i < $rows.length; i++ ) {
+				cells = $rows[ i ].cells;
+				for ( j = 0; j < cells.length; j++ ) {
+					cell = cells[ j ];
+					rowIndex = cell.parentNode.rowIndex;
+					rowSpan = cell.rowSpan || 1;
+					colSpan = cell.colSpan || 1;
+					if ( typeof matrix[ rowIndex ] === 'undefined' ) {
+						matrix[ rowIndex ] = [];
+					}
+					// Find first available column in the first row
+					for ( k = 0; k < matrix[ rowIndex ].length + 1; k++ ) {
+						if ( typeof matrix[ rowIndex ][ k ] === 'undefined' ) {
+							firstAvailCol = k;
+							break;
+						}
+					}
+					// jscs:disable disallowEmptyBlocks
+					if ( columns && cell.cellIndex === firstAvailCol ) {
+						// don't to anything
+					} else if ( cell.setAttribute ) {
+						// jscs:enable disallowEmptyBlocks
+						// add data-column (setAttribute = IE8+)
+						cell.setAttribute( 'data-column', firstAvailCol );
+					} else {
+						// remove once we drop support for IE7 - 1/12/2016
+						$( cell ).attr( 'data-column', firstAvailCol );
+					}
+					for ( k = rowIndex; k < rowIndex + rowSpan; k++ ) {
+						if ( typeof matrix[ k ] === 'undefined' ) {
+							matrix[ k ] = [];
+						}
+						matrixrow = matrix[ k ];
+						for ( l = firstAvailCol; l < firstAvailCol + colSpan; l++ ) {
+							matrixrow[ l ] = 'x';
+						}
+					}
+				}
+			}
+			return matrixrow.length;
+		},
+
+		// automatically add a colgroup with col elements set to a percentage width
+		fixColumnWidth : function( table ) {
+			table = $( table )[ 0 ];
+			var overallWidth, percent, $tbodies, len, index,
+				c = table.config,
+				$colgroup = c.$table.children( 'colgroup' );
+			// remove plugin-added colgroup, in case we need to refresh the widths
+			if ( $colgroup.length && $colgroup.hasClass( ts.css.colgroup ) ) {
+				$colgroup.remove();
+			}
+			if ( c.widthFixed && c.$table.children( 'colgroup' ).length === 0 ) {
+				$colgroup = $( '<colgroup class="' + ts.css.colgroup + '">' );
+				overallWidth = c.$table.width();
+				// only add col for visible columns - fixes #371
+				$tbodies = c.$tbodies.find( 'tr:first' ).children( ':visible' );
+				len = $tbodies.length;
+				for ( index = 0; index < len; index++ ) {
+					percent = parseInt( ( $tbodies.eq( index ).width() / overallWidth ) * 1000, 10 ) / 10 + '%';
+					$colgroup.append( $( '<col>' ).css( 'width', percent ) );
+				}
+				c.$table.prepend( $colgroup );
+			}
+		},
+
+		// 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( header, configHeader, key ) {
+			var meta, cl4ss,
+				val = '',
+				$header = $( header );
+			if ( !$header.length ) { return ''; }
+			meta = $.metadata ? $header.metadata() : false;
+			cl4ss = ' ' + ( $header.attr( 'class' ) || '' );
+			if ( typeof $header.data( key ) !== 'undefined' ||
+				typeof $header.data( key.toLowerCase() ) !== 'undefined' ) {
+				// 'data-lockedOrder' is assigned to 'lockedorder'; but 'data-locked-order' is assigned to 'lockedOrder'
+				// 'data-sort-initial-order' is assigned to 'sortInitialOrder'
+				val += $header.data( key ) || $header.data( key.toLowerCase() );
+			} else if ( meta && typeof meta[ key ] !== 'undefined' ) {
+				val += meta[ key ];
+			} else if ( configHeader && typeof configHeader[ key ] !== 'undefined' ) {
+				val += configHeader[ key ];
+			} else if ( cl4ss !== ' ' && cl4ss.match( ' ' + key + '-' ) ) {
+				// include sorter class name 'sorter-text', etc; now works with 'sorter-my-custom-parser'
+				val = cl4ss.match( new RegExp( '\\s' + key + '-([\\w-]+)' ) )[ 1 ] || '';
+			}
+			return $.trim( val );
+		},
+
+		getColumnData : function( table, obj, indx, getCell, $headers ) {
+			if ( typeof obj !== 'object' || obj === null ) {
+				return obj;
+			}
+			table = $( table )[ 0 ];
+			var $header, key,
+				c = table.config,
+				$cells = ( $headers || c.$headers ),
+				// c.$headerIndexed is not defined initially
+				$cell = c.$headerIndexed && c.$headerIndexed[ indx ] ||
+					$cells.filter( '[data-column="' + indx + '"]:last' );
+			if ( typeof obj[ indx ] !== 'undefined' ) {
+				return getCell ? obj[ indx ] : obj[ $cells.index( $cell ) ];
+			}
+			for ( key in obj ) {
+				if ( typeof key === 'string' ) {
+					$header = $cell
+						// header cell with class/id
+						.filter( key )
+						// find elements within the header cell with cell/id
+						.add( $cell.find( key ) );
+					if ( $header.length ) {
+						return obj[ key ];
+					}
+				}
+			}
+			return;
+		},
+
+		// *** Process table ***
+		// add processing indicator
+		isProcessing : function( $table, toggle, $headers ) {
+			$table = $( $table );
+			var c = $table[ 0 ].config,
+				// default to all headers
+				$header = $headers || $table.find( '.' + ts.css.header );
+			if ( toggle ) {
+				// don't use sortList if custom $headers used
+				if ( typeof $headers !== 'undefined' && c.sortList.length > 0 ) {
+					// get headers from the sortList
+					$header = $header.filter( function() {
+						// get data-column from attr to keep compatibility with jQuery 1.2.6
+						return this.sortDisabled ?
+							false :
+							ts.isValueInArray( parseFloat( $( this ).attr( 'data-column' ) ), c.sortList ) >= 0;
+					});
+				}
+				$table.add( $header ).addClass( ts.css.processing + ' ' + c.cssProcessing );
+			} else {
+				$table.add( $header ).removeClass( ts.css.processing + ' ' + c.cssProcessing );
+			}
+		},
+
+		// detach tbody but save the position
+		// don't use tbody because there are portions that look for a tbody index (updateCell)
+		processTbody : function( table, $tb, getIt ) {
+			table = $( table )[ 0 ];
+			if ( getIt ) {
+				table.isProcessing = true;
+				$tb.before( '<colgroup class="tablesorter-savemyplace"/>' );
+				return $.fn.detach ? $tb.detach() : $tb.remove();
+			}
+			var holdr = $( table ).find( 'colgroup.tablesorter-savemyplace' );
+			$tb.insertAfter( holdr );
+			holdr.remove();
+			table.isProcessing = false;
+		},
+
+		clearTableBody : function( table ) {
+			$( table )[ 0 ].config.$tbodies.children().detach();
+		},
+
+		// used when replacing accented characters during sorting
+		characterEquivalents : {
+			'a' : '\u00e1\u00e0\u00e2\u00e3\u00e4\u0105\u00e5', // áàâãäąå
+			'A' : '\u00c1\u00c0\u00c2\u00c3\u00c4\u0104\u00c5', // ÁÀÂÃÄĄÅ
+			'c' : '\u00e7\u0107\u010d', // çćč
+			'C' : '\u00c7\u0106\u010c', // ÇĆČ
+			'e' : '\u00e9\u00e8\u00ea\u00eb\u011b\u0119', // éèêëěę
+			'E' : '\u00c9\u00c8\u00ca\u00cb\u011a\u0118', // ÉÈÊËĚĘ
+			'i' : '\u00ed\u00ec\u0130\u00ee\u00ef\u0131', // íìİîïı
+			'I' : '\u00cd\u00cc\u0130\u00ce\u00cf', // ÍÌİÎÏ
+			'o' : '\u00f3\u00f2\u00f4\u00f5\u00f6\u014d', // óòôõöō
+			'O' : '\u00d3\u00d2\u00d4\u00d5\u00d6\u014c', // ÓÒÔÕÖŌ
+			'ss': '\u00df', // ß (s sharp)
+			'SS': '\u1e9e', // ẞ (Capital sharp s)
+			'u' : '\u00fa\u00f9\u00fb\u00fc\u016f', // úùûüů
+			'U' : '\u00da\u00d9\u00db\u00dc\u016e' // ÚÙÛÜŮ
+		},
+
+		replaceAccents : function( str ) {
+			var chr,
+				acc = '[',
+				eq = ts.characterEquivalents;
+			if ( !ts.characterRegex ) {
+				ts.characterRegexArray = {};
+				for ( chr in eq ) {
+					if ( typeof chr === 'string' ) {
+						acc += eq[ chr ];
+						ts.characterRegexArray[ chr ] = new RegExp( '[' + eq[ chr ] + ']', 'g' );
+					}
+				}
+				ts.characterRegex = new RegExp( acc + ']' );
+			}
+			if ( ts.characterRegex.test( str ) ) {
+				for ( chr in eq ) {
+					if ( typeof chr === 'string' ) {
+						str = str.replace( ts.characterRegexArray[ chr ], chr );
+					}
+				}
+			}
+			return str;
+		},
+
+		validateOptions : function( c ) {
+			var setting, setting2, typ, timer,
+				// ignore options containing an array
+				ignore = 'headers sortForce sortList sortAppend widgets'.split( ' ' ),
+				orig = c.originalSettings;
+			if ( orig ) {
+				if ( c.debug ) {
+					timer = new Date();
+				}
+				for ( setting in orig ) {
+					typ = typeof ts.defaults[setting];
+					if ( typ === 'undefined' ) {
+						console.warn( 'Tablesorter Warning! "table.config.' + setting + '" option not recognized' );
+					} else if ( typ === 'object' ) {
+						for ( setting2 in orig[setting] ) {
+							typ = ts.defaults[setting] && typeof ts.defaults[setting][setting2];
+							if ( $.inArray( setting, ignore ) < 0 && typ === 'undefined' ) {
+								console.warn( 'Tablesorter Warning! "table.config.' + setting + '.' + setting2 + '" option not recognized' );
+							}
+						}
+					}
+				}
+				if ( c.debug ) {
+					console.log( 'validate options time:' + ts.benchmark( timer ) );
+				}
+			}
+		},
+
+		// restore headers
+		restoreHeaders : function( table ) {
+			var index, $cell,
+				c = $( table )[ 0 ].config,
+				$headers = c.$table.find( c.selectorHeaders ),
+				len = $headers.length;
+			// don't use c.$headers here in case header cells were swapped
+			for ( index = 0; index < len; index++ ) {
+				$cell = $headers.eq( index );
+				// only restore header cells if it is wrapped
+				// because this is also used by the updateAll method
+				if ( $cell.find( '.' + ts.css.headerIn ).length ) {
+					$cell.html( c.headerContent[ index ] );
+				}
+			}
+		},
+
+		destroy : function( table, removeClasses, callback ) {
+			table = $( table )[ 0 ];
+			if ( !table.hasInitialized ) { return; }
+			// remove all widgets
+			ts.removeWidget( table, true, false );
+			var events,
+				$t = $( table ),
+				c = table.config,
+				debug = c.debug,
+				$h = $t.find( 'thead:first' ),
+				$r = $h.find( 'tr.' + ts.css.headerRow ).removeClass( ts.css.headerRow + ' ' + c.cssHeaderRow ),
+				$f = $t.find( 'tfoot:first > tr' ).children( 'th, td' );
+			if ( removeClasses === false && $.inArray( 'uitheme', c.widgets ) >= 0 ) {
+				// reapply uitheme classes, in case we want to maintain appearance
+				$t.triggerHandler( 'applyWidgetId', [ 'uitheme' ] );
+				$t.triggerHandler( 'applyWidgetId', [ 'zebra' ] );
+			}
+			// remove widget added rows, just in case
+			$h.find( 'tr' ).not( $r ).remove();
+			// disable tablesorter - not using .unbind( namespace ) because namespacing was
+			// added in jQuery v1.4.3 - see http://api.jquery.com/event.namespace/
+			events = 'sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton ' +
+				'appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave ' +
+				'keypress sortBegin sortEnd resetToLoadState '.split( ' ' )
+				.join( c.namespace + ' ' );
+			$t
+				.removeData( 'tablesorter' )
+				.unbind( events.replace( ts.regex.spaces, ' ' ) );
+			c.$headers
+				.add( $f )
+				.removeClass( [ ts.css.header, c.cssHeader, c.cssAsc, c.cssDesc, ts.css.sortAsc, ts.css.sortDesc, ts.css.sortNone ].join( ' ' ) )
+				.removeAttr( 'data-column' )
+				.removeAttr( 'aria-label' )
+				.attr( 'aria-disabled', 'true' );
+			$r
+				.find( c.selectorSort )
+				.unbind( ( 'mousedown mouseup keypress '.split( ' ' ).join( c.namespace + ' ' ) ).replace( ts.regex.spaces, ' ' ) );
+			ts.restoreHeaders( table );
+			$t.toggleClass( ts.css.table + ' ' + c.tableClass + ' tablesorter-' + c.theme, removeClasses === false );
+			// clear flag in case the plugin is initialized again
+			table.hasInitialized = false;
+			delete table.config.cache;
+			if ( typeof callback === 'function' ) {
+				callback( table );
+			}
+			if ( debug ) {
+				console.log( 'tablesorter has been removed' );
+			}
+		}
+
+	};
+
+	$.fn.tablesorter = function( settings ) {
+		return this.each( function() {
+			var table = this,
+			// merge & extend config options
+			c = $.extend( true, {}, ts.defaults, settings, ts.instanceMethods );
+			// save initial settings
+			c.originalSettings = settings;
+			// create a table from data (build table widget)
+			if ( !table.hasInitialized && ts.buildTable && this.nodeName !== 'TABLE' ) {
+				// return the table (in case the original target is the table's container)
+				ts.buildTable( table, c );
+			} else {
+				ts.setup( table, c );
+			}
+		});
+	};
+
+	// set up debug logs
+	if ( !( window.console && window.console.log ) ) {
+		// access $.tablesorter.logs for browsers that don't have a console...
+		ts.logs = [];
+		/*jshint -W020 */
+		console = {};
+		console.log = console.warn = console.error = console.table = function() {
+			var arg = arguments.length > 1 ? arguments : arguments[0];
+			ts.logs[ ts.logs.length ] = { date: Date.now(), log: arg };
+		};
+	}
+
+	// add default parsers
+	ts.addParser({
+		id : 'no-parser',
+		is : function() {
+			return false;
+		},
+		format : function() {
+			return '';
+		},
+		type : 'text'
+	});
+
+	ts.addParser({
+		id : 'text',
+		is : function() {
+			return true;
+		},
+		format : function( str, table ) {
+			var c = table.config;
+			if ( str ) {
+				str = $.trim( c.ignoreCase ? str.toLocaleLowerCase() : str );
+				str = c.sortLocaleCompare ? ts.replaceAccents( str ) : str;
+			}
+			return str;
+		},
+		type : 'text'
+	});
+
+	ts.regex.nondigit = /[^\w,. \-()]/g;
+	ts.addParser({
+		id : 'digit',
+		is : function( str ) {
+			return ts.isDigit( str );
+		},
+		format : function( str, table ) {
+			var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
+			return str && typeof num === 'number' ? num :
+				str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
+		},
+		type : 'numeric'
+	});
+
+	ts.regex.currencyReplace = /[+\-,. ]/g;
+	ts.regex.currencyTest = /^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/;
+	ts.addParser({
+		id : 'currency',
+		is : function( str ) {
+			str = ( str || '' ).replace( ts.regex.currencyReplace, '' );
+			// test for £$€¤¥¢
+			return ts.regex.currencyTest.test( str );
+		},
+		format : function( str, table ) {
+			var num = ts.formatFloat( ( str || '' ).replace( ts.regex.nondigit, '' ), table );
+			return str && typeof num === 'number' ? num :
+				str ? $.trim( str && table.config.ignoreCase ? str.toLocaleLowerCase() : str ) : str;
+		},
+		type : 'numeric'
+	});
+
+	// too many protocols to add them all https://en.wikipedia.org/wiki/URI_scheme
+	// now, this regex can be updated before initialization
+	ts.regex.urlProtocolTest = /^(https?|ftp|file):\/\//;
+	ts.regex.urlProtocolReplace = /(https?|ftp|file):\/\/(www\.)?/;
+	ts.addParser({
+		id : 'url',
+		is : function( str ) {
+			return ts.regex.urlProtocolTest.test( str );
+		},
+		format : function( str ) {
+			return str ? $.trim( str.replace( ts.regex.urlProtocolReplace, '' ) ) : str;
+		},
+		type : 'text'
+	});
+
+	ts.regex.dash = /-/g;
+	ts.regex.isoDate = /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/;
+	ts.addParser({
+		id : 'isoDate',
+		is : function( str ) {
+			return ts.regex.isoDate.test( str );
+		},
+		format : function( str, table ) {
+			var date = str ? new Date( str.replace( ts.regex.dash, '/' ) ) : str;
+			return date instanceof Date && isFinite( date ) ? date.getTime() : str;
+		},
+		type : 'numeric'
+	});
+
+	ts.regex.percent = /%/g;
+	ts.regex.percentTest = /(\d\s*?%|%\s*?\d)/;
+	ts.addParser({
+		id : 'percent',
+		is : function( str ) {
+			return ts.regex.percentTest.test( str ) && str.length < 15;
+		},
+		format : function( str, table ) {
+			return str ? ts.formatFloat( str.replace( ts.regex.percent, '' ), table ) : str;
+		},
+		type : 'numeric'
+	});
+
+	// added image parser to core v2.17.9
+	ts.addParser({
+		id : 'image',
+		is : function( str, table, node, $node ) {
+			return $node.find( 'img' ).length > 0;
+		},
+		format : function( str, table, cell ) {
+			return $( cell ).find( 'img' ).attr( table.config.imgAttr || 'alt' ) || str;
+		},
+		parsed : true, // filter widget flag
+		type : 'text'
+	});
+
+	ts.regex.dateReplace = /(\S)([AP]M)$/i; // used by usLongDate & time parser
+	ts.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;
+	ts.regex.usLongDateTest2 = /^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i;
+	ts.addParser({
+		id : 'usLongDate',
+		is : function( str ) {
+			// two digit years are not allowed cross-browser
+			// Jan 01, 2013 12:34:56 PM or 01 Jan 2013
+			return ts.regex.usLongDateTest1.test( str ) || ts.regex.usLongDateTest2.test( str );
+		},
+		format : function( str, table ) {
+			var date = str ? new Date( str.replace( ts.regex.dateReplace, '$1 $2' ) ) : str;
+			return date instanceof Date && isFinite( date ) ? date.getTime() : str;
+		},
+		type : 'numeric'
+	});
+
+	// testing for ##-##-#### or ####-##-##, so it's not perfect; time can be included
+	ts.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
+	ts.regex.shortDateReplace = /[\-.,]/g;
+	// XXY covers MDY & DMY formats
+	ts.regex.shortDateXXY = /(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/;
+	ts.regex.shortDateYMD = /(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/;
+	ts.convertFormat = function( dateString, format ) {
+		dateString = ( dateString || '' )
+			.replace( ts.regex.spaces, ' ' )
+			.replace( ts.regex.shortDateReplace, '/' );
+		if ( format === 'mmddyyyy' ) {
+			dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$1/$2' );
+		} else if ( format === 'ddmmyyyy' ) {
+			dateString = dateString.replace( ts.regex.shortDateXXY, '$3/$2/$1' );
+		} else if ( format === 'yyyymmdd' ) {
+			dateString = dateString.replace( ts.regex.shortDateYMD, '$1/$2/$3' );
+		}
+		var date = new Date( dateString );
+		return date instanceof Date && isFinite( date ) ? date.getTime() : '';
+	};
+
+	ts.addParser({
+		id : 'shortDate', // 'mmddyyyy', 'ddmmyyyy' or 'yyyymmdd'
+		is : function( str ) {
+			str = ( str || '' ).replace( ts.regex.spaces, ' ' ).replace( ts.regex.shortDateReplace, '/' );
+			return ts.regex.shortDateTest.test( str );
+		},
+		format : function( str, table, cell, cellIndex ) {
+			if ( str ) {
+				var c = table.config,
+					$header = c.$headerIndexed[ cellIndex ],
+					format = $header.length && $header.data( 'dateFormat' ) ||
+						ts.getData( $header, ts.getColumnData( table, c.headers, cellIndex ), 'dateFormat' ) ||
+						c.dateFormat;
+				// save format because getData can be slow...
+				if ( $header.length ) {
+					$header.data( 'dateFormat', format );
+				}
+				return ts.convertFormat( str, format ) || str;
+			}
+			return str;
+		},
+		type : 'numeric'
+	});
+
+	// match 24 hour time & 12 hours time + am/pm - see http://regexr.com/3c3tk
+	ts.regex.timeTest = /^(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)$|^((?:[01]\d|[2][0-4]):[0-5]\d)$/i;
+	ts.regex.timeMatch = /(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i;
+	ts.addParser({
+		id : 'time',
+		is : function( str ) {
+			return ts.regex.timeTest.test( str );
+		},
+		format : function( str, table ) {
+			// isolate time... ignore month, day and year
+			var temp,
+				timePart = ( str || '' ).match( ts.regex.timeMatch ),
+				orig = new Date( str ),
+				// no time component? default to 00:00 by leaving it out, but only if str is defined
+				time = str && ( timePart !== null ? timePart[ 0 ] : '00:00 AM' ),
+				date = time ? new Date( '2000/01/01 ' + time.replace( ts.regex.dateReplace, '$1 $2' ) ) : time;
+			if ( date instanceof Date && isFinite( date ) ) {
+				temp = orig instanceof Date && isFinite( orig ) ? orig.getTime() : 0;
+				// if original string was a valid date, add it to the decimal so the column sorts in some kind of order
+				// luckily new Date() ignores the decimals
+				return temp ? parseFloat( date.getTime() + '.' + orig.getTime() ) : date.getTime();
+			}
+			return str;
+		},
+		type : 'numeric'
+	});
+
+	ts.addParser({
+		id : 'metadata',
+		is : function() {
+			return false;
+		},
+		format : function( str, table, cell ) {
+			var c = table.config,
+			p = ( !c.parserMetadataName ) ? 'sortValue' : c.parserMetadataName;
+			return $( cell ).metadata()[ p ];
+		},
+		type : 'numeric'
+	});
+
+	/*
+		██████ ██████ █████▄ █████▄ ▄████▄
+		  ▄█▀  ██▄▄   ██▄▄██ ██▄▄██ ██▄▄██
+		▄█▀    ██▀▀   ██▀▀██ ██▀▀█  ██▀▀██
+		██████ ██████ █████▀ ██  ██ ██  ██
+		*/
+	// add default widgets
+	ts.addWidget({
+		id : 'zebra',
+		priority : 90,
+		format : function( table, c, wo ) {
+			var $visibleRows, $row, count, isEven, tbodyIndex, rowIndex, len,
+				child = new RegExp( c.cssChildRow, 'i' ),
+				$tbodies = c.$tbodies.add( $( c.namespace + '_extra_table' ).children( 'tbody:not(.' + c.cssInfoBlock + ')' ) );
+			for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				// loop through the visible rows
+				count = 0;
+				$visibleRows = $tbodies.eq( tbodyIndex ).children( 'tr:visible' ).not( c.selectorRemove );
+				len = $visibleRows.length;
+				for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
+					$row = $visibleRows.eq( rowIndex );
+					// style child rows the same way the parent row was styled
+					if ( !child.test( $row[ 0 ].className ) ) { count++; }
+					isEven = ( count % 2 === 0 );
+					$row
+						.removeClass( wo.zebra[ isEven ? 1 : 0 ] )
+						.addClass( wo.zebra[ isEven ? 0 : 1 ] );
+				}
+			}
+		},
+		remove : function( table, c, wo, refreshing ) {
+			if ( refreshing ) { return; }
+			var tbodyIndex, $tbody,
+				$tbodies = c.$tbodies,
+				toRemove = ( wo.zebra || [ 'even', 'odd' ] ).join( ' ' );
+			for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ){
+				$tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
+				$tbody.children().removeClass( toRemove );
+				ts.processTbody( table, $tbody, false ); // restore tbody
+			}
+		}
+	});
+
+})( jQuery );
+
+return jQuery.tablesorter;
+}));
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..8cf7cbc4652a0d21a9dfe919d2660e0ba806cf90
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.min.js
@@ -0,0 +1,2 @@
+!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(b){"use strict";var c=b.tablesorter={version:"2.28.4",parsers:[],widgets:[],defaults:{theme:"default",widthFixed:!1,showProcessing:!1,headerTemplate:"{content}",onRenderTemplate:null,onRenderHeader:null,cancelSelection:!0,tabIndex:!0,dateFormat:"mmddyyyy",sortMultiSortKey:"shiftKey",sortResetKey:"ctrlKey",usNumberFormat:!0,delayInit:!1,serverSideSorting:!1,resort:!0,headers:{},ignoreCase:!0,sortForce:null,sortList:[],sortAppend:null,sortStable:!1,sortInitialOrder:"asc",sortLocaleCompare:!1,sortReset:!1,sortRestart:!1,emptyTo:"bottom",stringTo:"max",duplicateSpan:!0,textExtraction:"basic",textAttribute:"data-text",textSorter:null,numberSorter:null,initWidgets:!0,widgetClass:"widget-{name}",widgets:[],widgetOptions:{zebra:["even","odd"]},initialized:null,tableClass:"",cssAsc:"",cssDesc:"",cssNone:"",cssHeader:"",cssHeaderRow:"",cssProcessing:"",cssChildRow:"tablesorter-childRow",cssInfoBlock:"tablesorter-infoOnly",cssNoSort:"tablesorter-noSort",cssIgnoreRow:"tablesorter-ignoreRow",cssIcon:"tablesorter-icon",cssIconNone:"",cssIconAsc:"",cssIconDesc:"",pointerClick:"click",pointerDown:"mousedown",pointerUp:"mouseup",selectorHeaders:"> thead th, > thead td",selectorSort:"th, td",selectorRemove:".remove-me",debug:!1,headerList:[],empties:{},strings:{},parsers:[],globalize:0,imgAttr:0},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"},language:{sortAsc:"Ascending sort applied, ",sortDesc:"Descending sort applied, ",sortNone:"No sort applied, ",sortDisabled:"sorting is disabled",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,chunk:/(^([+\-]?(?:\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?)?$|^0x[0-9a-f]+$|\d+)/gi,chunks:/(^\\0|\\0$)/,hex:/^0x[0-9a-f]+$/i,comma:/,/g,digitNonUS:/[\s|\.]/g,digitNegativeTest:/^\s*\([.\d]+\)/,digitNegativeReplace:/^\s*\(([.\d]+)\)/,digitTest:/^[\-+(]?\d+[)]?$/,digitReplace:/[,.'"\s]/g},string:{max:1,min:-1,emptymin:1,emptymax:-1,zero:0,none:0,null:0,top:!0,bottom:!1},keyCodes:{enter:13},dates:{},instanceMethods:{},setup:function(a,d){if(!a||!a.tHead||0===a.tBodies.length||a.hasInitialized===!0)return void(d.debug&&(a.hasInitialized?console.warn("Stopping initialization. Tablesorter has already been initialized"):console.error("Stopping initialization! No table, thead or tbody",a)));var e="",f=b(a),g=b.metadata;a.hasInitialized=!1,a.isProcessing=!0,a.config=d,b.data(a,"tablesorter",d),d.debug&&(console[console.group?"group":"log"]("Initializing tablesorter v"+c.version),b.data(a,"startoveralltimer",new Date)),d.supportsDataObject=function(a){return a[0]=parseInt(a[0],10),a[0]>1||1===a[0]&&parseInt(a[1],10)>=4}(b.fn.jquery.split(".")),d.emptyTo=d.emptyTo.toLowerCase(),d.stringTo=d.stringTo.toLowerCase(),d.last={sortList:[],clickedIndex:-1},/tablesorter\-/.test(f.attr("class"))||(e=""!==d.theme?" tablesorter-"+d.theme:""),d.table=a,d.$table=f.addClass(c.css.table+" "+d.tableClass+e).attr("role","grid"),d.$headers=f.find(d.selectorHeaders),d.namespace?d.namespace="."+d.namespace.replace(c.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={},d.textExtraction=d.$table.attr("data-text-extraction")||d.textExtraction||"basic",c.buildHeaders(d),c.fixColumnWidth(a),c.addWidgetFromClass(a),c.applyWidgetOptions(a),c.setupParsers(d),d.totalRows=0,c.validateOptions(d),d.delayInit||c.buildCache(d),c.bindEvents(a,d.$headers,!0),c.bindMethods(d),d.supportsDataObject&&"undefined"!=typeof f.data().sortlist?d.sortList=f.data().sortlist:g&&f.metadata()&&f.metadata().sortlist&&(d.sortList=f.metadata().sortlist),c.applyWidget(a,!0),d.sortList.length>0?c.sortOn(d,d.sortList,{},!d.initWidgets):(c.setHeadersCss(d),d.initWidgets&&c.applyWidget(a,!1)),d.showProcessing&&f.unbind("sortBegin"+d.namespace+" sortEnd"+d.namespace).bind("sortBegin"+d.namespace+" sortEnd"+d.namespace,function(b){clearTimeout(d.timerProcessing),c.isProcessing(a),"sortBegin"===b.type&&(d.timerProcessing=setTimeout(function(){c.isProcessing(a,!0)},500))}),a.hasInitialized=!0,a.isProcessing=!1,d.debug&&(console.log("Overall initialization time:"+c.benchmark(b.data(a,"startoveralltimer"))),d.debug&&console.groupEnd&&console.groupEnd()),f.triggerHandler("tablesorter-initialized",a),"function"==typeof d.initialized&&d.initialized(a)},bindMethods:function(a){var d=a.$table,e=a.namespace,f="sortReset update updateRows updateAll updateHeaders addRows updateCell updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets destroy mouseup mouseleave ".split(" ").join(e+" ");d.unbind(f.replace(c.regex.spaces," ")).bind("sortReset"+e,function(a,b){a.stopPropagation(),c.sortReset(this.config,b)}).bind("updateAll"+e,function(a,b,d){a.stopPropagation(),c.updateAll(this.config,b,d)}).bind("update"+e+" updateRows"+e,function(a,b,d){a.stopPropagation(),c.update(this.config,b,d)}).bind("updateHeaders"+e,function(a,b){a.stopPropagation(),c.updateHeaders(this.config,b)}).bind("updateCell"+e,function(a,b,d,e){a.stopPropagation(),c.updateCell(this.config,b,d,e)}).bind("addRows"+e,function(a,b,d,e){a.stopPropagation(),c.addRows(this.config,b,d,e)}).bind("updateComplete"+e,function(){this.isUpdating=!1}).bind("sorton"+e,function(a,b,d,e){a.stopPropagation(),c.sortOn(this.config,b,d,e)}).bind("appendCache"+e,function(a,d,e){a.stopPropagation(),c.appendCache(this.config,e),b.isFunction(d)&&d(this)}).bind("updateCache"+e,function(a,b,d){a.stopPropagation(),c.updateCache(this.config,b,d)}).bind("applyWidgetId"+e,function(a,b){a.stopPropagation(),c.applyWidgetId(this,b)}).bind("applyWidgets"+e,function(a,b){a.stopPropagation(),c.applyWidget(this,b)}).bind("refreshWidgets"+e,function(a,b,d){a.stopPropagation(),c.refreshWidgets(this,b,d)}).bind("removeWidget"+e,function(a,b,d){a.stopPropagation(),c.removeWidget(this,b,d)}).bind("destroy"+e,function(a,b,d){a.stopPropagation(),c.destroy(this,b,d)}).bind("resetToLoadState"+e,function(d){d.stopPropagation(),c.removeWidget(this,!0,!1);var e=b.extend(!0,{},a.originalSettings);a=b.extend(!0,c.defaults,e),a.originalSettings=e,this.hasInitialized=!1,c.setup(this,a)})},bindEvents:function(a,d,e){a=b(a)[0];var f,g=a.config,h=g.namespace,i=null;e!==!0&&(d.addClass(h.slice(1)+"_extra_headers"),f=b.fn.closest?d.closest("table")[0]:d.parents("table")[0],f&&"TABLE"===f.nodeName&&f!==a&&b(f).addClass(h.slice(1)+"_extra_table")),f=(g.pointerDown+" "+g.pointerUp+" "+g.pointerClick+" sort keyup ").replace(c.regex.spaces," ").split(" ").join(h+" "),d.find(g.selectorSort).add(d.filter(g.selectorSort)).unbind(f).bind(f,function(a,e){var f,h,j,k=b(a.target),l=" "+a.type+" ";if(!(1!==(a.which||a.button)&&!l.match(" "+g.pointerClick+" | sort | keyup ")||" keyup "===l&&a.which!==c.keyCodes.enter||l.match(" "+g.pointerClick+" ")&&"undefined"!=typeof a.which||l.match(" "+g.pointerUp+" ")&&i!==a.target&&e!==!0)){if(l.match(" "+g.pointerDown+" "))return i=a.target,j=k.jquery.split("."),void("1"===j[0]&&j[1]<4&&a.preventDefault());if(i=null,c.regex.formElements.test(a.target.nodeName)||k.hasClass(g.cssNoSort)||k.parents("."+g.cssNoSort).length>0||k.parents("button").length>0)return!g.cancelSelection;g.delayInit&&c.isEmptyObject(g.cache)&&c.buildCache(g),f=b.fn.closest?b(this).closest("th, td"):/TH|TD/.test(this.nodeName)?b(this):b(this).parents("th, td"),j=d.index(f),g.last.clickedIndex=j<0?f.attr("data-column"):j,h=g.$headers[g.last.clickedIndex],h&&!h.sortDisabled&&c.initSort(g,h,a)}}),g.cancelSelection&&d.attr("unselectable","on").bind("selectstart",!1).css({"user-select":"none",MozUserSelect:"none"})},buildHeaders:function(a){var d,e,f,g;for(a.headerList=[],a.headerContent=[],a.sortVars=[],a.debug&&(f=new Date),a.columns=c.computeColumnIndex(a.$table.children("thead, tfoot").children("tr")),e=a.cssIcon?'<i class="'+(a.cssIcon===c.css.icon?c.css.icon:a.cssIcon+" "+c.css.icon)+'"></i>':"",a.$headers=b(b.map(a.$table.find(a.selectorHeaders),function(d,f){var g,h,i,j,k,l=b(d);if(!l.parent().hasClass(a.cssIgnoreRow))return g=c.getColumnData(a.table,a.headers,f,!0),a.headerContent[f]=l.html(),""===a.headerTemplate||l.find("."+c.css.headerIn).length||(j=a.headerTemplate.replace(c.regex.templateContent,l.html()).replace(c.regex.templateIcon,l.find("."+c.css.icon).length?"":e),a.onRenderTemplate&&(h=a.onRenderTemplate.apply(l,[f,j]),h&&"string"==typeof h&&(j=h)),l.html('<div class="'+c.css.headerIn+'">'+j+"</div>")),a.onRenderHeader&&a.onRenderHeader.apply(l,[f,a,a.$table]),i=parseInt(l.attr("data-column"),10),d.column=i,k=c.getOrder(c.getData(l,g,"sortInitialOrder")||a.sortInitialOrder),a.sortVars[i]={count:-1,order:k?a.sortReset?[1,0,2]:[1,0]:a.sortReset?[0,1,2]:[0,1],lockedOrder:!1},k=c.getData(l,g,"lockedOrder")||!1,"undefined"!=typeof k&&k!==!1&&(a.sortVars[i].lockedOrder=!0,a.sortVars[i].order=c.getOrder(k)?[1,1]:[0,0]),a.headerList[f]=d,l.addClass(c.css.header+" "+a.cssHeader).parent().addClass(c.css.headerRow+" "+a.cssHeaderRow).attr("role","row"),a.tabIndex&&l.attr("tabindex",0),d})),a.$headerIndexed=[],g=0;g<a.columns;g++)c.isEmptyObject(a.sortVars[g])&&(a.sortVars[g]={}),d=a.$headers.filter('[data-column="'+g+'"]'),a.$headerIndexed[g]=d.length?d.not(".sorter-false").length?d.not(".sorter-false").filter(":last"):d.filter(":last"):b();a.$table.find(a.selectorHeaders).attr({scope:"col",role:"columnheader"}),c.updateHeader(a),a.debug&&(console.log("Built headers:"+c.benchmark(f)),console.log(a.$headers))},addInstanceMethods:function(a){b.extend(c.instanceMethods,a)},setupParsers:function(a,b){var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=a.table,s=0,t={};if(a.$tbodies=a.$table.children("tbody:not(."+a.cssInfoBlock+")"),p="undefined"==typeof b?a.$tbodies:b,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:[]};s<q;){if(d=p[s].rows,d.length)for(h=0,g=a.columns,i=0;i<g;i++){if(j=a.$headerIndexed[h],j&&j.length&&(k=c.getColumnData(r,a.headers,h),n=c.getParserById(c.getData(j,k,"extractor")),m=c.getParserById(c.getData(j,k,"sorter")),l="false"===c.getData(j,k,"parser"),a.empties[h]=(c.getData(j,k,"empty")||a.emptyTo||(a.emptyToBottom?"bottom":"top")).toLowerCase(),a.strings[h]=(c.getData(j,k,"string")||a.stringTo||"max").toLowerCase(),l&&(m=c.getParserById("no-parser")),n||(n=!1),m||(m=c.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))for(h+=f,g+=f;f+1>0;)e.parsers[h-f]=m,e.extractors[h-f]=n,f--;h++}s+=e.parsers.length?q:1}a.debug&&(c.isEmptyObject(t)?console.warn("  No parsers detected!"):console[console.table?"table":"log"](t),console.log("Completed detecting parsers"+c.benchmark(o)),console.groupEnd&&console.groupEnd()),a.parsers=e.parsers,a.extractors=e.extractors},addParser:function(a){var b,d=c.parsers.length,e=!0;for(b=0;b<d;b++)c.parsers[b].id.toLowerCase()===a.id.toLowerCase()&&(e=!1);e&&(c.parsers[c.parsers.length]=a)},getParserById:function(a){if("false"==a)return!1;var b,d=c.parsers.length;for(b=0;b<d;b++)if(c.parsers[b].id.toLowerCase()===a.toString().toLowerCase())return c.parsers[b];return!1},detectParserForColumn:function(a,d,e,f){for(var g,h,i,j=c.parsers.length,k=!1,l="",m=!0;""===l&&m;)e++,i=d[e],i&&e<50?i.className.indexOf(c.cssIgnoreRow)<0&&(k=d[e].cells[f],l=c.getElementText(a,k,f),h=b(k),a.debug&&console.log("Checking if value was empty on row "+e+", column: "+f+': "'+l+'"')):m=!1;for(;--j>=0;)if(g=c.parsers[j],g&&"text"!==g.id&&g.is&&g.is(l,a.table,k,h))return g;return c.getParserById("text")},getElementText:function(a,d,e){if(!d)return"";var f,g=a.textExtraction||"",h=d.jquery?d:b(d);return"string"==typeof g?"basic"===g&&"undefined"!=typeof(f=h.attr(a.textAttribute))?b.trim(f):b.trim(d.textContent||h.text()):"function"==typeof g?b.trim(g(h[0],a.table,e)):"function"==typeof(f=c.getColumnData(a.table,g,e))?b.trim(f(h[0],a.table,e)):b.trim(h[0].textContent||h.text())},getParsedText:function(a,b,d,e){"undefined"==typeof e&&(e=c.getElementText(a,b,d));var f=""+e,g=a.parsers[d],h=a.extractors[d];return g&&(h&&"function"==typeof h.format&&(e=h.format(e,a.table,b,d)),f="no-parser"===g.id?"":g.format(""+e,a.table,b,d),a.ignoreCase&&"string"==typeof f&&(f=f.toLowerCase())),f},buildCache:function(a,d,e){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B=a.table,C=a.parsers;if(a.$tbodies=a.$table.children("tbody:not(."+a.cssInfoBlock+")"),l="undefined"==typeof e?a.$tbodies:e,a.cache={},a.totalRows=0,!C)return a.debug?console.warn("Warning: *Empty table!* Not building a cache"):"";for(a.debug&&(q=new Date),a.showProcessing&&c.isProcessing(B,!0),k=0;k<l.length;k++){for(u=[],f=a.cache[k]={normalized:[]},r=l[k]&&l[k].rows.length||0,i=0;i<r;++i)if(s={child:[],raw:[]},m=b(l[k].rows[i]),n=[],!m.hasClass(a.selectorRemove.slice(1)))if(m.hasClass(a.cssChildRow)&&0!==i)for(z=f.normalized.length-1,t=f.normalized[z][a.columns],t.$row=t.$row.add(m),m.prev().hasClass(a.cssChildRow)||m.prev().addClass(c.css.cssHasChild),o=m.children("th, td"),z=t.child.length,t.child[z]=[],w=0,y=a.columns,j=0;j<y;j++)p=o[j],p&&(t.child[z][j]=c.getParsedText(a,p,j),v=o[j].colSpan-1,v>0&&(w+=v,y+=v)),w++;else{for(s.$row=m,s.order=i,w=0,y=a.columns,j=0;j<y;++j){if(p=m[0].cells[j],p&&w<a.columns&&(x="undefined"!=typeof C[w],!x&&a.debug&&console.warn("No parser found for row: "+i+", column: "+j+'; cell containing: "'+b(p).text()+'"; does it have a header?'),g=c.getElementText(a,p,w),s.raw[w]=g,h=c.getParsedText(a,p,w,g),n[w]=h,x&&"numeric"===(C[w].type||"").toLowerCase()&&(u[w]=Math.max(Math.abs(h)||0,u[w]||0)),v=p.colSpan-1,v>0)){for(A=0;A<=v;)h=a.duplicateSpan||0===A?g:"string"!=typeof a.textExtraction?c.getElementText(a,p,w+A)||"":"",s.raw[w+A]=h,n[w+A]=h,A++;w+=v,y+=v}w++}n[a.columns]=s,f.normalized[f.normalized.length]=n}f.colMax=u,a.totalRows+=f.normalized.length}if(a.showProcessing&&c.isProcessing(B),a.debug){for(z=Math.min(5,a.cache[0].normalized.length),console[console.group?"group":"log"]("Building cache for "+a.totalRows+" rows (showing "+z+" rows in log) and "+a.columns+" columns"+c.benchmark(q)),g={},j=0;j<a.columns;j++)for(w=0;w<z;w++)g["row: "+w]||(g["row: "+w]={}),g["row: "+w][a.$headerIndexed[j].text()]=a.cache[0].normalized[w][j];console[console.table?"table":"log"](g),console.groupEnd&&console.groupEnd()}b.isFunction(d)&&d(B)},getColumnText:function(a,d,e,f){a=b(a)[0];var g,h,i,j,k,l,m,n,o,p,q="function"==typeof e,r="all"===d,s={raw:[],parsed:[],$cell:[]},t=a.config;if(!c.isEmptyObject(t)){for(k=t.$tbodies.length,g=0;g<k;g++)for(i=t.cache[g].normalized,l=i.length,h=0;h<l;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[s.parsed.length]=n,s.raw[s.raw.length]=m,s.$cell[s.$cell.length]=o));return s}t.debug&&console.warn("No cache found - aborting getColumnText function!")},setHeadersCss:function(a){var d,e,f,g=a.sortList,h=g.length,i=c.css.sortNone+" "+a.cssNone,j=[c.css.sortAsc+" "+a.cssAsc,c.css.sortDesc+" "+a.cssDesc],k=[a.cssIconAsc,a.cssIconDesc,a.cssIconNone],l=["ascending","descending"],m=a.$table.find("tfoot tr").children("td, th").add(b(a.namespace+"_extra_headers")).removeClass(j.join(" "));for(a.$headers.add(b("thead "+a.namespace+"_extra_headers")).removeClass(j.join(" ")).addClass(i).attr("aria-sort","none").find("."+c.css.icon).removeClass(k.join(" ")).addClass(k[2]),e=0;e<h;e++)if(2!==g[e][1]&&(d=a.$headers.filter(function(b){for(var d=!0,e=a.$headers.eq(b),f=parseInt(e.attr("data-column"),10),g=f+a.$headers[b].colSpan;f<g;f++)d=!!d&&(d||c.isValueInArray(f,a.sortList)>-1);return d}),d=d.not(".sorter-false").filter('[data-column="'+g[e][0]+'"]'+(1===h?":last":"")),d.length)){for(f=0;f<d.length;f++)d[f].sortDisabled||d.eq(f).removeClass(i).addClass(j[g[e][1]]).attr("aria-sort",l[g[e][1]]).find("."+c.css.icon).removeClass(k[2]).addClass(k[g[e][1]]);m.length&&m.filter('[data-column="'+g[e][0]+'"]').removeClass(i).addClass(j[g[e][1]])}for(h=a.$headers.length,e=0;e<h;e++)c.setColumnAriaLabel(a,a.$headers.eq(e))},setColumnAriaLabel:function(a,d,e){if(d.length){var f=parseInt(d.attr("data-column"),10),g=a.sortVars[f],h=d.hasClass(c.css.sortAsc)?"sortAsc":d.hasClass(c.css.sortDesc)?"sortDesc":"sortNone",i=b.trim(d.text())+": "+c.language[h];d.hasClass("sorter-false")||e===!1?i+=c.language.sortDisabled:(h=(g.count+1)%g.order.length,e=g.order[h],i+=c.language[0===e?"nextAsc":1===e?"nextDesc":"nextNone"]),d.attr("aria-label",i)}},updateHeader:function(a){var b,d,e,f,g=a.table,h=a.$headers.length;for(b=0;b<h;b++)e=a.$headers.eq(b),f=c.getColumnData(g,a.headers,b,!0),d="false"===c.getData(e,f,"sorter")||"false"===c.getData(e,f,"parser"),c.setColumnSort(a,e,d)},setColumnSort:function(a,b,c){var d=a.table.id;b[0].sortDisabled=c,b[c?"addClass":"removeClass"]("sorter-false").attr("aria-disabled",""+c),a.tabIndex&&(c?b.removeAttr("tabindex"):b.attr("tabindex","0")),d&&(c?b.removeAttr("aria-controls"):b.attr("aria-controls",d))},updateHeaderSortCount:function(a,d){var e,f,g,h,i,j,k,l,m=d||a.sortList,n=m.length;for(a.sortList=[],h=0;h<n;h++)if(k=m[h],e=parseInt(k[0],10),e<a.columns){switch(a.sortVars[e].order||(l=c.getOrder(a.sortInitialOrder)?a.sortReset?[1,0,2]:[1,0]:a.sortReset?[0,1,2]:[0,1],a.sortVars[e].order=l,a.sortVars[e].count=0),l=a.sortVars[e].order,f=(""+k[1]).match(/^(1|d|s|o|n)/),f=f?f[0]:""){case"1":case"d":f=1;break;case"s":f=i||0;break;case"o":j=l[(i||0)%l.length],f=0===j?1:1===j?0:2;break;case"n":f=l[++a.sortVars[e].count%l.length];break;default:f=0}i=0===h?f:i,g=[e,parseInt(f,10)||0],a.sortList[a.sortList.length]=g,f=b.inArray(g[1],l),a.sortVars[e].count=f>=0?f:g[1]%l.length}},updateAll:function(a,b,d){var e=a.table;e.isUpdating=!0,c.refreshWidgets(e,!0,!0),c.buildHeaders(a),c.bindEvents(e,a.$headers,!0),c.bindMethods(a),c.commonUpdate(a,b,d)},update:function(a,b,d){var e=a.table;e.isUpdating=!0,c.updateHeader(a),c.commonUpdate(a,b,d)},updateHeaders:function(a,b){a.table.isUpdating=!0,c.buildHeaders(a),c.bindEvents(a.table,a.$headers,!0),c.resortComplete(a,b)},updateCell:function(a,d,e,f){if(c.isEmptyObject(a.cache))return c.updateHeader(a),void c.commonUpdate(a,e,f);a.table.isUpdating=!0,a.$table.find(a.selectorRemove).remove();var g,h,i,j,k,l,m=a.$tbodies,n=b(d),o=m.index(b.fn.closest?n.closest("tbody"):n.parents("tbody").filter(":first")),p=a.cache[o],q=b.fn.closest?n.closest("tr"):n.parents("tr").filter(":first");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!==a.columns)for(j=0,g=!1,h=0;h<l;h++)g||q[0].cells[h]===d?g=!0:j+=q[0].cells[h].colSpan;else j=n.index();g=c.getElementText(a,d,j),k[a.columns].raw[j]=g,g=c.getParsedText(a,d,j,g),k[j]=g,k[a.columns].$row=q,"numeric"===(a.parsers[j].type||"").toLowerCase()&&(p.colMax[j]=Math.max(Math.abs(g)||0,p.colMax[j]||0)),g="undefined"!==e?e:a.resort,g!==!1?c.checkResort(a,g,f):c.resortComplete(a,f)}else a.debug&&console.error("updateCell aborted, tbody missing or not within the indicated table"),a.table.isUpdating=!1},addRows:function(d,e,f,g){var h,i,j,k,l,m,n,o,p,q,r,s,t,u="string"==typeof e&&1===d.$tbodies.length&&/<tr/.test(e||""),v=d.table;if(u)e=b(e),d.$tbodies.append(e);else if(!(e&&e instanceof a&&(b.fn.closest?e.closest("table")[0]:e.parents("table")[0])===d.table))return d.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(v.isUpdating=!0,c.isEmptyObject(d.cache))c.updateHeader(d),c.commonUpdate(d,f,g);else{for(l=e.filter("tr").attr("role","row").length,j=d.$tbodies.index(e.parents("tbody").filter(":first")),d.parsers&&d.parsers.length||c.setupParsers(d),k=0;k<l;k++){for(p=0,n=e[k].cells.length,o=d.cache[j].normalized.length,r=[],q={child:[],raw:[],$row:e.eq(k),order:o},m=0;m<n;m++)s=e[k].cells[m],h=c.getElementText(d,s,p),q.raw[p]=h,i=c.getParsedText(d,s,p,h),r[p]=i,"numeric"===(d.parsers[p].type||"").toLowerCase()&&(d.cache[j].colMax[p]=Math.max(Math.abs(i)||0,d.cache[j].colMax[p]||0)),t=s.colSpan-1,t>0&&(p+=t),p++;r[d.columns]=q,d.cache[j].normalized[o]=r}c.checkResort(d,f,g)}},updateCache:function(a,b,d){a.parsers&&a.parsers.length||c.setupParsers(a,d),c.buildCache(a,b,d)},appendCache:function(a,b){var d,e,f,g,h,i,j,k=a.table,l=a.widgetOptions,m=a.$tbodies,n=[],o=a.cache;if(c.isEmptyObject(o))return a.appender?a.appender(k,n):k.isUpdating?a.$table.triggerHandler("updateComplete",k):"";for(a.debug&&(j=new Date),i=0;i<m.length;i++)if(f=m.eq(i),f.length){for(g=c.processTbody(k,f,!0),d=o[i].normalized,e=d.length,h=0;h<e;h++)n[n.length]=d[h][a.columns].$row,a.appender&&(!a.pager||a.pager.removeRows&&l.pager_removeRows||a.pager.ajax)||g.append(d[h][a.columns].$row);c.processTbody(k,g,!1)}a.appender&&a.appender(k,n),a.debug&&console.log("Rebuilt table"+c.benchmark(j)),b||a.appender||c.applyWidget(k),k.isUpdating&&a.$table.triggerHandler("updateComplete",k)},commonUpdate:function(a,b,d){a.$table.find(a.selectorRemove).remove(),c.setupParsers(a),c.buildCache(a),c.checkResort(a,b,d)},initSort:function(a,d,e){if(a.table.isUpdating)return setTimeout(function(){c.initSort(a,d,e)},50);var f,g,h,i,j,k,l,m=!e[a.sortMultiSortKey],n=a.table,o=a.$headers.length,p=parseInt(b(d).attr("data-column"),10),q=a.sortVars[p].order;if(a.$table.triggerHandler("sortStart",n),k=(a.sortVars[p].count+1)%q.length,a.sortVars[p].count=e[a.sortResetKey]?2:k,a.sortRestart)for(h=0;h<o;h++)l=a.$headers.eq(h),k=parseInt(l.attr("data-column"),10),p!==k&&(m||l.hasClass(c.css.sortNone))&&(a.sortVars[k].count=-1);if(m){if(a.sortList=[],a.last.sortList=[],null!==a.sortForce)for(f=a.sortForce,g=0;g<f.length;g++)f[g][0]!==p&&(a.sortList[a.sortList.length]=f[g]);if(i=q[a.sortVars[p].count],i<2&&(a.sortList[a.sortList.length]=[p,i],d.colSpan>1))for(g=1;g<d.colSpan;g++)a.sortList[a.sortList.length]=[p+g,i],a.sortVars[p+g].count=b.inArray(i,q)}else if(a.sortList=b.extend([],a.last.sortList),c.isValueInArray(p,a.sortList)>=0)for(g=0;g<a.sortList.length;g++)k=a.sortList[g],k[0]===p&&(k[1]=q[a.sortVars[p].count],2===k[1]&&(a.sortList.splice(g,1),a.sortVars[p].count=-1));else if(i=q[a.sortVars[p].count],i<2&&(a.sortList[a.sortList.length]=[p,i],d.colSpan>1))for(g=1;g<d.colSpan;g++)a.sortList[a.sortList.length]=[p+g,i],a.sortVars[p+g].count=b.inArray(i,q);if(a.last.sortList=b.extend([],a.sortList),a.sortList.length&&a.sortAppend&&(f=b.isArray(a.sortAppend)?a.sortAppend:a.sortAppend[a.sortList[0][0]],!c.isEmptyObject(f)))for(g=0;g<f.length;g++)if(f[g][0]!==p&&c.isValueInArray(f[g][0],a.sortList)<0){if(i=f[g][1],j=(""+i).match(/^(a|d|s|o|n)/))switch(k=a.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)%q.length;break;default:i=0}a.sortList[a.sortList.length]=[f[g][0],i]}a.$table.triggerHandler("sortBegin",n),setTimeout(function(){c.setHeadersCss(a),c.multisort(a),c.appendCache(a),a.$table.triggerHandler("sortBeforeEnd",n),a.$table.triggerHandler("sortEnd",n)},1)},multisort:function(a){var b,d,e,f,g,h=a.table,i=[],j=0,k=a.textSorter||"",l=a.sortList,m=l.length,n=a.$tbodies.length;if(!a.serverSideSorting&&!c.isEmptyObject(a.cache)){if(a.debug&&(d=new Date),"object"==typeof k)for(e=a.columns;e--;)g=c.getColumnData(h,k,e),"function"==typeof g&&(i[e]=g);for(b=0;b<n;b++)e=a.cache[b].colMax,f=a.cache[b].normalized,f.sort(function(b,d){var f,g,n,o,p,q,r;for(f=0;f<m;f++){if(n=l[f][0],o=l[f][1],j=0===o,a.sortStable&&b[n]===d[n]&&1===m)return b[a.columns].order-d[a.columns].order;if(g=/n/i.test(c.getSortType(a.parsers,n)),g&&a.strings[n]?(g="boolean"==typeof c.string[a.strings[n]]?(j?1:-1)*(c.string[a.strings[n]]?-1:1):a.strings[n]?c.string[a.strings[n]]||0:0,p=a.numberSorter?a.numberSorter(b[n],d[n],j,e[n],h):c["sortNumeric"+(j?"Asc":"Desc")](b[n],d[n],g,e[n],n,a)):(q=j?b:d,r=j?d:b,p="function"==typeof k?k(q[n],r[n],j,n,h):"function"==typeof i[n]?i[n](q[n],r[n],j,n,h):c["sortNatural"+(j?"Asc":"Desc")](b[n],d[n],n,a)),p)return p}return b[a.columns].order-d[a.columns].order});a.debug&&console.log("Applying sort "+l.toString()+c.benchmark(d))}},resortComplete:function(a,c){a.table.isUpdating&&a.$table.triggerHandler("updateComplete",a.table),b.isFunction(c)&&c(a.table)},checkResort:function(a,d,e){var f=b.isArray(d)?d:a.sortList,g="undefined"==typeof d?a.resort:d;g===!1||a.serverSideSorting||a.table.isProcessing?(c.resortComplete(a,e),c.applyWidget(a.table,!1)):f.length?c.sortOn(a,f,function(){c.resortComplete(a,e)},!0):c.sortReset(a,function(){c.resortComplete(a,e),c.applyWidget(a.table,!1)})},sortOn:function(a,d,e,f){var g=a.table;a.$table.triggerHandler("sortStart",g),c.updateHeaderSortCount(a,d),c.setHeadersCss(a),a.delayInit&&c.isEmptyObject(a.cache)&&c.buildCache(a),a.$table.triggerHandler("sortBegin",g),c.multisort(a),c.appendCache(a,f),a.$table.triggerHandler("sortBeforeEnd",g),a.$table.triggerHandler("sortEnd",g),c.applyWidget(g),b.isFunction(e)&&e(g)},sortReset:function(a,d){a.sortList=[],c.setHeadersCss(a),c.multisort(a),c.appendCache(a),b.isFunction(d)&&d(a.table)},getSortType:function(a,b){return a&&a[b]?a[b].type||"":""},getOrder:function(a){return/^d/i.test(a)||1===a},sortNatural:function(a,b){if(a===b)return 0;var d,e,f,g,h,i,j=c.regex;if(j.hex.test(b)){if(d=parseInt((a||"").match(j.hex),16),e=parseInt((b||"").match(j.hex),16),d<e)return-1;if(d>e)return 1}for(d=(a||"").replace(j.chunk,"\\0$1\\0").replace(j.chunks,"").split("\\0"),e=(b||"").replace(j.chunk,"\\0$1\\0").replace(j.chunks,"").split("\\0"),i=Math.max(d.length,e.length),h=0;h<i;h++){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(typeof f!=typeof g&&(f+="",g+=""),f<g)return-1;if(f>g)return 1}return 0},sortNaturalAsc:function(a,b,d,e){if(a===b)return 0;var f=c.string[e.empties[d]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:-f||-1:""===b&&0!==f?"boolean"==typeof f?f?1:-1:f||1:c.sortNatural(a,b)},sortNaturalDesc:function(a,b,d,e){if(a===b)return 0;var f=c.string[e.empties[d]||e.emptyTo];return""===a&&0!==f?"boolean"==typeof f?f?-1:1:f||1:""===b&&0!==f?"boolean"==typeof f?f?1:-1:-f||-1:c.sortNatural(b,a)},sortText:function(a,b){return a>b?1:a<b?-1:0},getTextValue:function(a,b,c){if(c){var d,e=a?a.length:0,f=c+b;for(d=0;d<e;d++)f+=a.charCodeAt(d);return b*f}return 0},sortNumericAsc:function(a,b,d,e,f,g){if(a===b)return 0;var h=c.string[g.empties[f]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:-h||-1:""===b&&0!==h?"boolean"==typeof h?h?1:-1:h||1:(isNaN(a)&&(a=c.getTextValue(a,d,e)),isNaN(b)&&(b=c.getTextValue(b,d,e)),a-b)},sortNumericDesc:function(a,b,d,e,f,g){if(a===b)return 0;var h=c.string[g.empties[f]||g.emptyTo];return""===a&&0!==h?"boolean"==typeof h?h?-1:1:h||1:""===b&&0!==h?"boolean"==typeof h?h?1:-1:-h||-1:(isNaN(a)&&(a=c.getTextValue(a,d,e)),isNaN(b)&&(b=c.getTextValue(b,d,e)),b-a)},sortNumeric:function(a,b){return a-b},addWidget:function(a){a.id&&!c.isEmptyObject(c.getWidgetById(a.id))&&console.warn('"'+a.id+'" widget was loaded more than once!'),c.widgets[c.widgets.length]=a},hasWidget:function(a,c){return a=b(a),a.length&&a[0].config&&a[0].config.widgetInit[c]||!1},getWidgetById:function(a){var b,d,e=c.widgets.length;for(b=0;b<e;b++)if(d=c.widgets[b],d&&d.id&&d.id.toLowerCase()===a.toLowerCase())return d},applyWidgetOptions:function(a){var d,e,f=a.config,g=f.widgets.length;if(g)for(d=0;d<g;d++)e=c.getWidgetById(f.widgets[d]),e&&e.options&&(f.widgetOptions=b.extend(!0,{},e.options,f.widgetOptions),b.extend(!0,c.defaults.widgetOptions,e.options))},addWidgetFromClass:function(a){var b,d,e=a.config,f="^"+e.widgetClass.replace(c.regex.templateName,"(\\S+)+")+"$",g=new RegExp(f,"g"),h=(a.className||"").split(c.regex.spaces);if(h.length)for(b=h.length,d=0;d<b;d++)h[d].match(g)&&(e.widgets[e.widgets.length]=h[d].replace(g,"$1"))},applyWidgetId:function(a,d,e){a=b(a)[0];var f,g,h,i=a.config,j=i.widgetOptions,k=c.getWidgetById(d);k&&(h=k.id,f=!1,b.inArray(h,i.widgets)<0&&(i.widgets[i.widgets.length]=h),i.debug&&(g=new Date),!e&&i.widgetInit[h]||(i.widgetInit[h]=!0,a.hasInitialized&&c.applyWidgetOptions(a),"function"==typeof k.init&&(f=!0,i.debug&&console[console.group?"group":"log"]("Initializing "+h+" widget"),k.init(a,k,i,j))),e||"function"!=typeof k.format||(f=!0,i.debug&&console[console.group?"group":"log"]("Updating "+h+" widget"),k.format(a,i,j,!1)),i.debug&&f&&(console.log("Completed "+(e?"initializing ":"applying ")+h+" widget"+c.benchmark(g)),console.groupEnd&&console.groupEnd()))},applyWidget:function(a,d,e){a=b(a)[0];var f,g,h,i,j,k=a.config,l=[];if(d===!1||!a.hasInitialized||!a.isApplyingWidgets&&!a.isUpdating){if(k.debug&&(j=new Date),c.addWidgetFromClass(a),clearTimeout(k.timerReady),k.widgets.length){for(a.isApplyingWidgets=!0,k.widgets=b.grep(k.widgets,function(a,c){return b.inArray(a,k.widgets)===c}),h=k.widgets||[],g=h.length,f=0;f<g;f++)i=c.getWidgetById(h[f]),i&&i.id?(i.priority||(i.priority=10),l[f]=i):k.debug&&console.warn('"'+h[f]+'" widget code does not exist!');for(l.sort(function(a,b){return a.priority<b.priority?-1:a.priority===b.priority?0:1}),g=l.length,k.debug&&console[console.group?"group":"log"]("Start "+(d?"initializing":"applying")+" widgets"),f=0;f<g;f++)i=l[f],i&&i.id&&c.applyWidgetId(a,i.id,d);k.debug&&console.groupEnd&&console.groupEnd(),d||"function"!=typeof e||e(a)}k.timerReady=setTimeout(function(){a.isApplyingWidgets=!1,b.data(a,"lastWidgetApplication",new Date),k.$table.triggerHandler("tablesorter-ready")},10),k.debug&&(i=k.widgets.length,console.log("Completed "+(d===!0?"initializing ":"applying ")+i+" widget"+(1!==i?"s":"")+c.benchmark(j)))}},removeWidget:function(a,d,e){a=b(a)[0];var f,g,h,i,j=a.config;if(d===!0)for(d=[],i=c.widgets.length,h=0;h<i;h++)g=c.widgets[h],g&&g.id&&(d[d.length]=g.id);else d=(b.isArray(d)?d.join(","):d||"").toLowerCase().split(/[\s,]+/);for(i=d.length,f=0;f<i;f++)g=c.getWidgetById(d[f]),h=b.inArray(d[f],j.widgets),h>=0&&e!==!0&&j.widgets.splice(h,1),g&&g.remove&&(j.debug&&console.log((e?"Refreshing":"Removing")+' "'+d[f]+'" widget'),g.remove(a,j,j.widgetOptions,e),j.widgetInit[d[f]]=!1)},refreshWidgets:function(a,d,e){a=b(a)[0];var f,g,h=a.config,i=h.widgets,j=c.widgets,k=j.length,l=[],m=function(a){b(a).triggerHandler("refreshComplete")};for(f=0;f<k;f++)g=j[f],g&&g.id&&(d||b.inArray(g.id,i)<0)&&(l[l.length]=g.id);c.removeWidget(a,l.join(","),!0),e!==!0?(c.applyWidget(a,d||!1,m),d&&c.applyWidget(a,!1,m)):m(a)},benchmark:function(a){return" ("+((new Date).getTime()-a.getTime())+" ms)"},log:function(){console.log(arguments)},isEmptyObject:function(a){for(var b in a)return!1;return!0},isValueInArray:function(a,b){var c,d=b&&b.length||0;for(c=0;c<d;c++)if(b[c][0]===a)return c;return-1},formatFloat:function(a,d){if("string"!=typeof a||""===a)return a;var e,f=d&&d.config?d.config.usNumberFormat!==!1:"undefined"==typeof d||d;
+return a=f?a.replace(c.regex.comma,""):a.replace(c.regex.digitNonUS,"").replace(c.regex.comma,"."),c.regex.digitNegativeTest.test(a)&&(a=a.replace(c.regex.digitNegativeReplace,"-$1")),e=parseFloat(a),isNaN(e)?b.trim(a):e},isDigit:function(a){return isNaN(a)?c.regex.digitTest.test(a.toString().replace(c.regex.digitReplace,"")):""!==a},computeColumnIndex:function(a,c){var d,e,f,g,h,i,j,k,l,m,n=c&&c.columns||0,o=[],p=new Array(n);for(d=0;d<a.length;d++)for(i=a[d].cells,e=0;e<i.length;e++){for(h=i[e],j=h.parentNode.rowIndex,k=h.rowSpan||1,l=h.colSpan||1,"undefined"==typeof o[j]&&(o[j]=[]),f=0;f<o[j].length+1;f++)if("undefined"==typeof o[j][f]){m=f;break}for(n&&h.cellIndex===m||(h.setAttribute?h.setAttribute("data-column",m):b(h).attr("data-column",m)),f=j;f<j+k;f++)for("undefined"==typeof o[f]&&(o[f]=[]),p=o[f],g=m;g<m+l;g++)p[g]="x"}return p.length},fixColumnWidth:function(a){a=b(a)[0];var d,e,f,g,h,i=a.config,j=i.$table.children("colgroup");if(j.length&&j.hasClass(c.css.colgroup)&&j.remove(),i.widthFixed&&0===i.$table.children("colgroup").length){for(j=b('<colgroup class="'+c.css.colgroup+'">'),d=i.$table.width(),f=i.$tbodies.find("tr:first").children(":visible"),g=f.length,h=0;h<g;h++)e=parseInt(f.eq(h).width()/d*1e3,10)/10+"%",j.append(b("<col>").css("width",e));i.$table.prepend(j)}},getData:function(a,c,d){var e,f,g="",h=b(a);return h.length?(e=!!b.metadata&&h.metadata(),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]||""),b.trim(g)):""},getColumnData:function(a,c,d,e,f){if("object"!=typeof c||null===c)return c;a=b(a)[0];var g,h,i=a.config,j=f||i.$headers,k=i.$headerIndexed&&i.$headerIndexed[d]||j.filter('[data-column="'+d+'"]:last');if("undefined"!=typeof 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]},isProcessing:function(a,d,e){a=b(a);var f=a[0].config,g=e||a.find("."+c.css.header);d?("undefined"!=typeof e&&f.sortList.length>0&&(g=g.filter(function(){return!this.sortDisabled&&c.isValueInArray(parseFloat(b(this).attr("data-column")),f.sortList)>=0})),a.add(g).addClass(c.css.processing+" "+f.cssProcessing)):a.add(g).removeClass(c.css.processing+" "+f.cssProcessing)},processTbody:function(a,c,d){if(a=b(a)[0],d)return a.isProcessing=!0,c.before('<colgroup class="tablesorter-savemyplace"/>'),b.fn.detach?c.detach():c.remove();var e=b(a).find("colgroup.tablesorter-savemyplace");c.insertAfter(e),e.remove(),a.isProcessing=!1},clearTableBody:function(a){b(a)[0].config.$tbodies.children().detach()},characterEquivalents:{a:"áàâãäąå",A:"ÁÀÂÃÄĄÅ",c:"çćč",C:"ÇĆČ",e:"éèêëěę",E:"ÉÈÊËĚĘ",i:"íìİîïı",I:"ÍÌİÎÏ",o:"óòôõöō",O:"ÓÒÔÕÖŌ",ss:"ß",SS:"ẞ",u:"úùûüů",U:"ÚÙÛÜŮ"},replaceAccents:function(a){var b,d="[",e=c.characterEquivalents;if(!c.characterRegex){c.characterRegexArray={};for(b in e)"string"==typeof b&&(d+=e[b],c.characterRegexArray[b]=new RegExp("["+e[b]+"]","g"));c.characterRegex=new RegExp(d+"]")}if(c.characterRegex.test(a))for(b in e)"string"==typeof b&&(a=a.replace(c.characterRegexArray[b],b));return a},validateOptions:function(a){var d,e,f,g,h="headers sortForce sortList sortAppend widgets".split(" "),i=a.originalSettings;if(i){a.debug&&(g=new Date);for(d in i)if(f=typeof c.defaults[d],"undefined"===f)console.warn('Tablesorter Warning! "table.config.'+d+'" option not recognized');else if("object"===f)for(e in i[d])f=c.defaults[d]&&typeof c.defaults[d][e],b.inArray(d,h)<0&&"undefined"===f&&console.warn('Tablesorter Warning! "table.config.'+d+"."+e+'" option not recognized');a.debug&&console.log("validate options time:"+c.benchmark(g))}},restoreHeaders:function(a){var d,e,f=b(a)[0].config,g=f.$table.find(f.selectorHeaders),h=g.length;for(d=0;d<h;d++)e=g.eq(d),e.find("."+c.css.headerIn).length&&e.html(f.headerContent[d])},destroy:function(a,d,e){if(a=b(a)[0],a.hasInitialized){c.removeWidget(a,!0,!1);var f,g=b(a),h=a.config,i=h.debug,j=g.find("thead:first"),k=j.find("tr."+c.css.headerRow).removeClass(c.css.headerRow+" "+h.cssHeaderRow),l=g.find("tfoot:first > tr").children("th, td");d===!1&&b.inArray("uitheme",h.widgets)>=0&&(g.triggerHandler("applyWidgetId",["uitheme"]),g.triggerHandler("applyWidgetId",["zebra"])),j.find("tr").not(k).remove(),f="sortReset update updateRows updateAll updateHeaders updateCell addRows updateComplete sorton appendCache updateCache applyWidgetId applyWidgets refreshWidgets removeWidget destroy mouseup mouseleave "+"keypress sortBegin sortEnd resetToLoadState ".split(" ").join(h.namespace+" "),g.removeData("tablesorter").unbind(f.replace(c.regex.spaces," ")),h.$headers.add(l).removeClass([c.css.header,h.cssHeader,h.cssAsc,h.cssDesc,c.css.sortAsc,c.css.sortDesc,c.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(c.regex.spaces," ")),c.restoreHeaders(a),g.toggleClass(c.css.table+" "+h.tableClass+" tablesorter-"+h.theme,d===!1),a.hasInitialized=!1,delete a.config.cache,"function"==typeof e&&e(a),i&&console.log("tablesorter has been removed")}}};b.fn.tablesorter=function(a){return this.each(function(){var d=this,e=b.extend(!0,{},c.defaults,a,c.instanceMethods);e.originalSettings=a,!d.hasInitialized&&c.buildTable&&"TABLE"!==this.nodeName?c.buildTable(d,e):c.setup(d,e)})},window.console&&window.console.log||(c.logs=[],console={},console.log=console.warn=console.error=console.table=function(){var a=arguments.length>1?arguments:arguments[0];c.logs[c.logs.length]={date:Date.now(),log:a}}),c.addParser({id:"no-parser",is:function(){return!1},format:function(){return""},type:"text"}),c.addParser({id:"text",is:function(){return!0},format:function(a,d){var e=d.config;return a&&(a=b.trim(e.ignoreCase?a.toLocaleLowerCase():a),a=e.sortLocaleCompare?c.replaceAccents(a):a),a},type:"text"}),c.regex.nondigit=/[^\w,. \-()]/g,c.addParser({id:"digit",is:function(a){return c.isDigit(a)},format:function(a,d){var e=c.formatFloat((a||"").replace(c.regex.nondigit,""),d);return a&&"number"==typeof e?e:a?b.trim(a&&d.config.ignoreCase?a.toLocaleLowerCase():a):a},type:"numeric"}),c.regex.currencyReplace=/[+\-,. ]/g,c.regex.currencyTest=/^\(?\d+[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]|[\u00a3$\u20ac\u00a4\u00a5\u00a2?.]\d+\)?$/,c.addParser({id:"currency",is:function(a){return a=(a||"").replace(c.regex.currencyReplace,""),c.regex.currencyTest.test(a)},format:function(a,d){var e=c.formatFloat((a||"").replace(c.regex.nondigit,""),d);return a&&"number"==typeof e?e:a?b.trim(a&&d.config.ignoreCase?a.toLocaleLowerCase():a):a},type:"numeric"}),c.regex.urlProtocolTest=/^(https?|ftp|file):\/\//,c.regex.urlProtocolReplace=/(https?|ftp|file):\/\/(www\.)?/,c.addParser({id:"url",is:function(a){return c.regex.urlProtocolTest.test(a)},format:function(a){return a?b.trim(a.replace(c.regex.urlProtocolReplace,"")):a},type:"text"}),c.regex.dash=/-/g,c.regex.isoDate=/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}/,c.addParser({id:"isoDate",is:function(a){return c.regex.isoDate.test(a)},format:function(a,b){var d=a?new Date(a.replace(c.regex.dash,"/")):a;return d instanceof Date&&isFinite(d)?d.getTime():a},type:"numeric"}),c.regex.percent=/%/g,c.regex.percentTest=/(\d\s*?%|%\s*?\d)/,c.addParser({id:"percent",is:function(a){return c.regex.percentTest.test(a)&&a.length<15},format:function(a,b){return a?c.formatFloat(a.replace(c.regex.percent,""),b):a},type:"numeric"}),c.addParser({id:"image",is:function(a,b,c,d){return d.find("img").length>0},format:function(a,c,d){return b(d).find("img").attr(c.config.imgAttr||"alt")||a},parsed:!0,type:"text"}),c.regex.dateReplace=/(\S)([AP]M)$/i,c.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,c.regex.usLongDateTest2=/^\d{1,2}\s+[A-Z]{3,10}\s+\d{4}/i,c.addParser({id:"usLongDate",is:function(a){return c.regex.usLongDateTest1.test(a)||c.regex.usLongDateTest2.test(a)},format:function(a,b){var d=a?new Date(a.replace(c.regex.dateReplace,"$1 $2")):a;return d instanceof Date&&isFinite(d)?d.getTime():a},type:"numeric"}),c.regex.shortDateTest=/(^\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4})|(^\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2})/,c.regex.shortDateReplace=/[\-.,]/g,c.regex.shortDateXXY=/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,c.regex.shortDateYMD=/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/,c.convertFormat=function(a,b){a=(a||"").replace(c.regex.spaces," ").replace(c.regex.shortDateReplace,"/"),"mmddyyyy"===b?a=a.replace(c.regex.shortDateXXY,"$3/$1/$2"):"ddmmyyyy"===b?a=a.replace(c.regex.shortDateXXY,"$3/$2/$1"):"yyyymmdd"===b&&(a=a.replace(c.regex.shortDateYMD,"$1/$2/$3"));var d=new Date(a);return d instanceof Date&&isFinite(d)?d.getTime():""},c.addParser({id:"shortDate",is:function(a){return a=(a||"").replace(c.regex.spaces," ").replace(c.regex.shortDateReplace,"/"),c.regex.shortDateTest.test(a)},format:function(a,b,d,e){if(a){var f=b.config,g=f.$headerIndexed[e],h=g.length&&g.data("dateFormat")||c.getData(g,c.getColumnData(b,f.headers,e),"dateFormat")||f.dateFormat;return g.length&&g.data("dateFormat",h),c.convertFormat(a,h)||a}return a},type:"numeric"}),c.regex.timeTest=/^(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)$|^((?:[01]\d|[2][0-4]):[0-5]\d)$/i,c.regex.timeMatch=/(0?[1-9]|1[0-2]):([0-5]\d)(\s[AP]M)|((?:[01]\d|[2][0-4]):[0-5]\d)/i,c.addParser({id:"time",is:function(a){return c.regex.timeTest.test(a)},format:function(a,b){var d,e=(a||"").match(c.regex.timeMatch),f=new Date(a),g=a&&(null!==e?e[0]:"00:00 AM"),h=g?new Date("2000/01/01 "+g.replace(c.regex.dateReplace,"$1 $2")):g;return h instanceof Date&&isFinite(h)?(d=f instanceof Date&&isFinite(f)?f.getTime():0,d?parseFloat(h.getTime()+"."+f.getTime()):h.getTime()):a},type:"numeric"}),c.addParser({id:"metadata",is:function(){return!1},format:function(a,c,d){var e=c.config,f=e.parserMetadataName?e.parserMetadataName:"sortValue";return b(d).metadata()[f]},type:"numeric"}),c.addWidget({id:"zebra",priority:90,format:function(a,c,d){var e,f,g,h,i,j,k,l=new RegExp(c.cssChildRow,"i"),m=c.$tbodies.add(b(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;j<k;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,b,d,e){if(!e){var f,g,h=b.$tbodies,i=(d.zebra||["even","odd"]).join(" ");for(f=0;f<h.length;f++)g=c.processTbody(a,h.eq(f),!0),g.children().removeClass(i),c.processTbody(a,g,!1)}}})}(a),a.tablesorter});
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.pager.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.pager.js
new file mode 100644
index 0000000000000000000000000000000000000000..ad8599e593737b4e1cd9b360d45a9ab5aa0e8231
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.pager.js
@@ -0,0 +1,1241 @@
+/*!
+* tablesorter (FORK) pager plugin
+* updated 1/6/2017 (v2.28.4)
+*/
+/*jshint browser:true, jquery:true, unused:false */
+;(function($) {
+	'use strict';
+	/*jshint supernew:true */
+	var ts = $.tablesorter;
+
+	$.extend({
+		tablesorterPager: new function() {
+
+			this.defaults = {
+				// target the pager markup
+				container: null,
+
+				// use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}"
+				// where {page} is replaced by the page number, {size} is replaced by the number of records to show,
+				// {sortList:col} adds the sortList to the url into a "col" array, and {filterList:fcol} adds
+				// the filterList to the url into an "fcol" array.
+				// So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url
+				// and a filterList = [[2,Blue],[3,13]] becomes "&fcol[2]=Blue&fcol[3]=13" in the url
+				ajaxUrl: null,
+
+				// modify the url after all processing has been applied
+				customAjaxUrl: function(table, url) { return url; },
+
+				// ajax error callback from $.tablesorter.showError function
+				// ajaxError: function( config, xhr, settings, exception ){ return exception; };
+				// returning false will abort the error message
+				ajaxError: null,
+
+				// modify the $.ajax object to allow complete control over your ajax requests
+				ajaxObject: {
+					dataType: 'json'
+				},
+
+				// set this to false if you want to block ajax loading on init
+				processAjaxOnInit: true,
+
+				// process ajax so that the following information is returned:
+				// [ total_rows (number), rows (array of arrays), headers (array; optional) ]
+				// example:
+				// [
+				//   100,  // total rows
+				//   [
+				//     [ "row1cell1", "row1cell2", ... "row1cellN" ],
+				//     [ "row2cell1", "row2cell2", ... "row2cellN" ],
+				//     ...
+				//     [ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
+				//   ],
+				//   [ "header1", "header2", ... "headerN" ] // optional
+				// ]
+				ajaxProcessing: function(ajax){ return [ 0, [], null ]; },
+
+				// output default: '{page}/{totalPages}'
+				// possible variables: {size}, {page}, {totalPages}, {filteredPages}, {startRow},
+				// {endRow}, {filteredRows} and {totalRows}
+				output: '{startRow} to {endRow} of {totalRows} rows', // '{page}/{totalPages}'
+
+				// apply disabled classname to the pager arrows when the rows at either extreme is visible
+				updateArrows: true,
+
+				// starting page of the pager (zero based index)
+				page: 0,
+
+				// reset pager after filtering; set to desired page #
+				// set to false to not change page at filter start
+				pageReset: 0,
+
+				// Number of visible rows
+				size: 10,
+
+				// Number of options to include in the pager number selector
+				maxOptionSize: 20,
+
+				// Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js)
+				savePages: true,
+
+				// defines custom storage key
+				storageKey: 'tablesorter-pager',
+
+				// if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty
+				// table row set to a height to compensate; default is false
+				fixedHeight: false,
+
+				// count child rows towards the set page size? (set true if it is a visible table row within the pager)
+				// if true, child row(s) may not appear to be attached to its parent row, may be split across pages or
+				// may distort the table if rowspan or cellspans are included.
+				countChildRows: false,
+
+				// remove rows from the table to speed up the sort of large tables.
+				// setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled.
+				removeRows: false, // removing rows in larger tables speeds up the sort
+
+				// css class names of pager arrows
+				cssFirst: '.first', // go to first page arrow
+				cssPrev: '.prev', // previous page arrow
+				cssNext: '.next', // next page arrow
+				cssLast: '.last', // go to last page arrow
+				cssGoto: '.gotoPage', // go to page selector - select dropdown that sets the current page
+				cssPageDisplay: '.pagedisplay', // location of where the "output" is displayed
+				cssPageSize: '.pagesize', // page size selector - select dropdown that sets the "size" option
+				cssErrorRow: 'tablesorter-errorRow', // error information row
+
+				// class added to arrows when at the extremes (i.e. prev/first arrows are "disabled" when on the first page)
+				cssDisabled: 'disabled', // Note there is no period "." in front of this class name
+
+				// stuff not set by the user
+				totalRows: 0,
+				totalPages: 0,
+				filteredRows: 0,
+				filteredPages: 0,
+				ajaxCounter: 0,
+				currentFilters: [],
+				startRow: 0,
+				endRow: 0,
+				$size: null,
+				last: {}
+
+			};
+
+			var pagerEvents = 'filterInit filterStart filterEnd sortEnd disablePager enablePager destroyPager updateComplete ' +
+			'pageSize pageSet pageAndSize pagerUpdate refreshComplete ',
+
+			$this = this,
+
+			// hide arrows at extremes
+			pagerArrows = function( table, p, disable ) {
+				var tmp,
+					a = 'addClass',
+					r = 'removeClass',
+					d = p.cssDisabled,
+					dis = !!disable,
+					first = ( dis || p.page === 0 ),
+					tp = getTotalPages( table, p ),
+					last = ( dis || (p.page === tp - 1) || tp === 0 );
+				if ( p.updateArrows ) {
+					tmp = p.$container.find(p.cssFirst + ',' + p.cssPrev);
+					tmp[ first ? a : r ](d); // toggle disabled class
+					tmp.each(function(){
+						this.ariaDisabled = first;
+					});
+					tmp = p.$container.find(p.cssNext + ',' + p.cssLast);
+					tmp[ last ? a : r ](d);
+					tmp.each(function(){
+						this.ariaDisabled = last;
+					});
+				}
+			},
+
+			calcFilters = function(table, p) {
+				var normalized, indx, len,
+				c = table.config,
+				hasFilters = c.$table.hasClass('hasFilters');
+				if (hasFilters && !p.ajax) {
+					if (ts.isEmptyObject(c.cache)) {
+						// delayInit: true so nothing is in the cache
+						p.filteredRows = p.totalRows = c.$tbodies.eq(0).children('tr').not( p.countChildRows ? '' : '.' + c.cssChildRow ).length;
+					} else {
+						p.filteredRows = 0;
+						normalized = c.cache[0].normalized;
+						len = normalized.length;
+						for (indx = 0; indx < len; indx++) {
+							p.filteredRows += p.regexRows.test(normalized[indx][c.columns].$row[0].className) ? 0 : 1;
+						}
+					}
+				} else if (!hasFilters) {
+					p.filteredRows = p.totalRows;
+				}
+			},
+
+			updatePageDisplay = function(table, p, completed) {
+				if ( p.initializing ) { return; }
+				var s, t, $out, $el, indx, len, options, output,
+				c = table.config,
+				namespace = c.namespace + 'pager',
+				sz = parsePageSize( p, p.size, 'get' ); // don't allow dividing by zero
+				if (sz === 'all') { sz = p.totalRows; }
+				if (p.countChildRows) { t[ t.length ] = c.cssChildRow; }
+				p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method
+				c.totalRows = p.totalRows;
+				parsePageNumber( table, p );
+				calcFilters(table, p);
+				c.filteredRows = p.filteredRows;
+				p.filteredPages = Math.ceil( p.filteredRows / sz ) || 0;
+				if ( getTotalPages( table, p ) >= 0 ) {
+					t = (sz * p.page > p.filteredRows) && completed;
+					p.page = (t) ? p.pageReset || 0 : p.page;
+					p.startRow = (t) ? sz * p.page + 1 : (p.filteredRows === 0 ? 0 : sz * p.page + 1);
+					p.endRow = Math.min( p.filteredRows, p.totalRows, sz * ( p.page + 1 ) );
+					$out = p.$container.find(p.cssPageDisplay);
+
+					// Output param can be callback for custom rendering or string
+					if (typeof p.output === 'function') {
+						s = p.output(table, p);
+					} else {
+						output = $out
+							// get output template from data-pager-output or data-pager-output-filtered
+							.attr('data-pager-output' + (p.filteredRows < p.totalRows ? '-filtered' : '')) ||
+							p.output;
+						// form the output string (can now get a new output string from the server)
+						s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || output : output )
+							// {page} = one-based index; {page+#} = zero based index +/- value
+							.replace(/\{page([\-+]\d+)?\}/gi, function(m, n){
+								return p.totalPages ? p.page + (n ? parseInt(n, 10) : 1) : 0;
+							})
+							// {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object)
+							.replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){
+								var len, indx,
+								str = m.replace(/[{}\s]/g, ''),
+								extra = str.split(':'),
+								data = p.ajaxData,
+								// return zero for default page/row numbers
+								deflt = /(rows?|pages?)$/i.test(str) ? 0 : '';
+								if (/(startRow|page)/.test(extra[0]) && extra[1] === 'input') {
+									len = ('' + (extra[0] === 'page' ? p.totalPages : p.totalRows)).length;
+									indx = extra[0] === 'page' ? p.page + 1 : p.startRow;
+									return '<input type="text" class="ts-' + extra[0] + '" style="max-width:' + len + 'em" value="' + indx + '"/>';
+								}
+								return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt;
+							});
+					}
+					$el = p.$container.find(p.cssGoto);
+					if ( $el.length ) {
+						t = '';
+						options = buildPageSelect( table, p );
+						len = options.length;
+						for (indx = 0; indx < len; indx++) {
+							t += '<option value="' + options[indx] + '">' + options[indx] + '</option>';
+						}
+						// innerHTML doesn't work in IE9 - http://support2.microsoft.com/kb/276228
+						$el.html(t).val( p.page + 1 );
+					}
+					if ($out.length) {
+						$out[ ($out[0].nodeName === 'INPUT') ? 'val' : 'html' ](s);
+						// rebind startRow/page inputs
+						$out.find('.ts-startRow, .ts-page').unbind('change' + namespace).bind('change' + namespace, function(){
+							var v = $(this).val(),
+							pg = $(this).hasClass('ts-startRow') ? Math.floor( v / sz ) + 1 : v;
+							c.$table.triggerHandler('pageSet' + namespace, [ pg ]);
+						});
+					}
+				}
+				pagerArrows( table, p );
+				fixHeight(table, p);
+				if (p.initialized && completed !== false) {
+					if (c.debug) {
+						console.log('Pager: Triggering pagerComplete');
+					}
+					c.$table.triggerHandler('pagerComplete', p);
+					// save pager info to storage
+					if (p.savePages && ts.storage) {
+						ts.storage(table, p.storageKey, {
+							page : p.page,
+							size : sz === p.totalRows ? 'all' : sz
+						});
+					}
+				}
+			},
+
+			buildPageSelect = function( table, p ) {
+				// Filter the options page number link array if it's larger than 'maxOptionSize'
+				// as large page set links will slow the browser on large dom inserts
+				var i, central_focus_size, focus_option_pages, insert_index, option_length, focus_length,
+				pg = getTotalPages( table, p ) || 1,
+				// make skip set size multiples of 5
+				skip_set_size = Math.ceil( ( pg / p.maxOptionSize ) / 5 ) * 5,
+				large_collection = pg > p.maxOptionSize,
+				current_page = p.page + 1,
+				start_page = skip_set_size,
+				end_page = pg - skip_set_size,
+				option_pages = [ 1 ],
+				// construct default options pages array
+				option_pages_start_page = (large_collection) ? skip_set_size : 1;
+
+				for ( i = option_pages_start_page; i <= pg; ) {
+					option_pages[ option_pages.length ] = i;
+					i = i + ( large_collection ? skip_set_size : 1 );
+				}
+				option_pages[ option_pages.length ] = pg;
+				if (large_collection) {
+					focus_option_pages = [];
+					// don't allow central focus size to be > 5 on either side of current page
+					central_focus_size = Math.max( Math.floor( p.maxOptionSize / skip_set_size ) - 1, 5 );
+
+					start_page = current_page - central_focus_size;
+					if (start_page < 1) { start_page = 1; }
+					end_page = current_page + central_focus_size;
+					if (end_page > pg) { end_page = pg; }
+					// construct an array to get a focus set around the current page
+					for (i = start_page; i <= end_page ; i++) {
+						focus_option_pages[ focus_option_pages.length ] = i;
+					}
+
+					// keep unique values
+					option_pages = $.grep(option_pages, function(value, indx) {
+						return $.inArray(value, option_pages) === indx;
+					});
+
+					option_length = option_pages.length;
+					focus_length = focus_option_pages.length;
+
+					// make sure at all option_pages aren't replaced
+					if (option_length - focus_length > skip_set_size / 2 && option_length + focus_length > p.maxOptionSize ) {
+						insert_index = Math.floor(option_length / 2) - Math.floor(focus_length / 2);
+						Array.prototype.splice.apply(option_pages, [ insert_index, focus_length ]);
+					}
+					option_pages = option_pages.concat(focus_option_pages);
+
+				}
+
+				// keep unique values again
+				option_pages = $.grep(option_pages, function(value, indx) {
+					return $.inArray(value, option_pages) === indx;
+				})
+				.sort(function(a, b) { return a - b; });
+
+				return option_pages;
+			},
+
+			fixHeight = function(table, p) {
+				var d, h,
+				c = table.config,
+				$b = c.$tbodies.eq(0);
+				$b.find('tr.pagerSavedHeightSpacer').remove();
+				if (p.fixedHeight && !p.isDisabled) {
+					h = $.data(table, 'pagerSavedHeight');
+					if (h) {
+						d = h - $b.height();
+						if ( d > 5 && $.data(table, 'pagerLastSize') === p.size &&
+						$b.children('tr:visible').length < (p.size === 'all' ? p.totalRows : p.size) ) {
+							$b.append('<tr class="pagerSavedHeightSpacer ' + c.selectorRemove.slice(1) + '" style="height:' + d + 'px;"></tr>');
+						}
+					}
+				}
+			},
+
+			changeHeight = function(table, p) {
+				var h,
+				c = table.config,
+				$b = c.$tbodies.eq(0);
+				$b.find('tr.pagerSavedHeightSpacer').remove();
+				if (!$b.children('tr:visible').length) {
+					$b.append('<tr class="pagerSavedHeightSpacer ' + c.selectorRemove.slice(1) + '"><td>&nbsp</td></tr>');
+				}
+				h = $b.children('tr').eq(0).height() * (p.size === 'all' ? p.totalRows : p.size);
+				$.data(table, 'pagerSavedHeight', h);
+				fixHeight(table, p);
+				$.data(table, 'pagerLastSize', p.size);
+			},
+
+			hideRows = function(table, p){
+				if (!p.ajaxUrl) {
+					var i,
+					lastIndex = 0,
+					c = table.config,
+					rows = c.$tbodies.eq(0).children('tr'),
+					l = rows.length,
+					sz = p.size === 'all' ? p.totalRows : p.size,
+					s = ( p.page * sz ),
+					e =  s + sz,
+					last = 0, // for cache indexing
+					j = 0; // size counter
+					p.cacheIndex = [];
+					for ( i = 0; i < l; i++ ){
+						if ( !p.regexFiltered.test(rows[i].className) ) {
+							if (j === s && rows[i].className.match(c.cssChildRow)) {
+								// hide child rows @ start of pager (if already visible)
+								rows[i].style.display = 'none';
+							} else {
+								rows[i].style.display = ( j >= s && j < e ) ? '' : 'none';
+								if (last !== j && j >= s && j < e) {
+									p.cacheIndex[ p.cacheIndex.length ] = i;
+									last = j;
+								}
+								// don't count child rows
+								j += rows[i].className.match(c.cssChildRow + '|' + c.selectorRemove.slice(1)) && !p.countChildRows ? 0 : 1;
+								if ( j === e && rows[i].style.display !== 'none' && rows[i].className.match(ts.css.cssHasChild) ) {
+									lastIndex = i;
+								}
+							}
+						}
+					}
+					// add any attached child rows to last row of pager. Fixes part of issue #396
+					if ( lastIndex > 0 && rows[lastIndex].className.match(ts.css.cssHasChild) ) {
+						while ( ++lastIndex < l && rows[lastIndex].className.match(c.cssChildRow) ) {
+							rows[lastIndex].style.display = '';
+						}
+					}
+				}
+			},
+
+			hideRowsSetup = function(table, p){
+				var $el = p.$container.find(p.cssPageSize);
+				p.size = parsePageSize( p, $el.val(), 'get' );
+				$el.val( p.size );
+				$.data(table, 'pagerLastSize', p.size);
+				pagerArrows( table, p );
+				if ( !p.removeRows ) {
+					hideRows(table, p);
+					$(table).bind('sortEnd filterEnd '.split(' ').join(table.config.namespace + 'pager '), function(){
+						hideRows(table, p);
+					});
+				}
+			},
+
+			renderAjax = function(data, table, p, xhr, settings, exception){
+				// process data
+				if ( typeof p.ajaxProcessing === 'function' ) {
+
+					// in case nothing is returned by ajax, empty out the table; see #1032
+					// but do it before calling pager_ajaxProcessing because that function may add content
+					// directly to the table
+					table.config.$tbodies.eq(0).empty();
+
+					// ajaxProcessing result: [ total, rows, headers ]
+					var i, j, t, hsh, $f, $sh, $headers, $h, icon, th, d, l, rr_count, len, sz,
+					c = table.config,
+					$table = c.$table,
+					tds = '',
+					result = p.ajaxProcessing(data, table, xhr) || [ 0, [] ],
+					hl = $table.find('thead th').length;
+
+					// Clean up any previous error.
+					ts.showError( table );
+
+					if ( exception ) {
+						if (c.debug) {
+							console.error('Pager: >> Ajax Error', xhr, settings, exception);
+						}
+						ts.showError( table, xhr, settings, exception );
+						c.$tbodies.eq(0).children('tr').detach();
+						p.totalRows = 0;
+					} else {
+						// process ajax object
+						if (!$.isArray(result)) {
+							p.ajaxData = result;
+							c.totalRows = p.totalRows = result.total;
+							c.filteredRows = p.filteredRows = typeof result.filteredRows !== 'undefined' ? result.filteredRows : result.total;
+							th = result.headers;
+							d = result.rows || [];
+						} else {
+							// allow [ total, rows, headers ]  or [ rows, total, headers ]
+							t = isNaN(result[0]) && !isNaN(result[1]);
+							// ensure a zero returned row count doesn't fail the logical ||
+							rr_count = result[t ? 1 : 0];
+							p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count;
+							// can't set filtered rows when returning an array
+							c.totalRows = c.filteredRows = p.filteredRows = p.totalRows;
+							// set row data to empty array if nothing found - see http://stackoverflow.com/q/30875583/145346
+							d = p.totalRows === 0 ? [] : result[t ? 0 : 1] || []; // row data
+							th = result[2]; // headers
+						}
+						l = d && d.length;
+						if (d instanceof jQuery) {
+							if (p.processAjaxOnInit) {
+								// append jQuery object
+								c.$tbodies.eq(0).empty();
+								c.$tbodies.eq(0).append(d);
+							}
+						} else if (l) {
+							// build table from array
+							for ( i = 0; i < l; i++ ) {
+								tds += '<tr>';
+								for ( j = 0; j < d[i].length; j++ ) {
+									// build tbody cells; watch for data containing HTML markup - see #434
+									tds += /^\s*<td/.test(d[i][j]) ? $.trim(d[i][j]) : '<td>' + d[i][j] + '</td>';
+								}
+								tds += '</tr>';
+							}
+							// add rows to first tbody
+							if (p.processAjaxOnInit) {
+								c.$tbodies.eq(0).html( tds );
+							}
+						}
+						p.processAjaxOnInit = true;
+						// update new header text
+						if ( th ) {
+							hsh = $table.hasClass('hasStickyHeaders');
+							$sh = hsh ?
+								c.widgetOptions.$sticky.children('thead:first').children('tr:not(.' + c.cssIgnoreRow + ')').children() :
+								'';
+							$f = $table.find('tfoot tr:first').children();
+							// don't change td headers (may contain pager)
+							$headers = c.$headers.filter( 'th ' );
+							len = $headers.length;
+							for ( j = 0; j < len; j++ ) {
+								$h = $headers.eq( j );
+								// add new test within the first span it finds, or just in the header
+								if ( $h.find('.' + ts.css.icon).length ) {
+									icon = $h.find('.' + ts.css.icon).clone(true);
+									$h.find('.' + ts.css.headerIn).html( th[j] ).append(icon);
+									if ( hsh && $sh.length ) {
+										icon = $sh.eq(j).find('.' + ts.css.icon).clone(true);
+										$sh.eq(j).find('.' + ts.css.headerIn).html( th[j] ).append(icon);
+									}
+								} else {
+									$h.find('.' + ts.css.headerIn).html( th[j] );
+									if (hsh && $sh.length) {
+										// add sticky header to container just in case it contains pager controls
+										p.$container = p.$container.add( c.widgetOptions.$sticky );
+										$sh.eq(j).find('.' + ts.css.headerIn).html( th[j] );
+									}
+								}
+								$f.eq(j).html( th[j] );
+							}
+						}
+					}
+					if (c.showProcessing) {
+						ts.isProcessing(table); // remove loading icon
+					}
+					sz = parsePageSize( p, p.size, 'get' );
+					// make sure last pager settings are saved, prevents multiple server side calls with
+					// the same parameters
+					p.totalPages = sz === 'all' ? 1 : Math.ceil( p.totalRows / sz );
+					p.last.totalRows = p.totalRows;
+					p.last.currentFilters = p.currentFilters;
+					p.last.sortList = (c.sortList || []).join(',');
+					updatePageDisplay(table, p, false);
+					// tablesorter core updateCache (not pager)
+					ts.updateCache( c, function(){
+						if (p.initialized) {
+							// apply widgets after table has rendered & after a delay to prevent
+							// multiple applyWidget blocking code from blocking this trigger
+							setTimeout(function(){
+								if (c.debug) {
+									console.log('Pager: Triggering pagerChange');
+								}
+								$table.triggerHandler( 'pagerChange', p );
+								ts.applyWidget( table );
+								updatePageDisplay(table, p, true);
+							}, 0);
+						}
+					});
+
+				}
+				if (!p.initialized) {
+					pagerInitialized(table, p);
+				}
+			},
+
+			getAjax = function(table, p) {
+				var url = getAjaxUrl(table, p),
+				$doc = $(document),
+				counter,
+				c = table.config,
+				namespace = c.namespace + 'pager';
+				if ( url !== '' ) {
+					if (c.showProcessing) {
+						ts.isProcessing(table, true); // show loading icon
+					}
+					$doc.bind('ajaxError' + namespace, function(e, xhr, settings, exception) {
+						renderAjax(null, table, p, xhr, settings, exception);
+						$doc.unbind('ajaxError' + namespace);
+					});
+
+					counter = ++p.ajaxCounter;
+
+					p.last.ajaxUrl = url; // remember processed url
+					p.ajaxObject.url = url; // from the ajaxUrl option and modified by customAjaxUrl
+					p.ajaxObject.success = function(data, status, jqxhr) {
+						// Refuse to process old ajax commands that were overwritten by new ones - see #443
+						if (counter < p.ajaxCounter){
+							return;
+						}
+						renderAjax(data, table, p, jqxhr);
+						$doc.unbind('ajaxError' + namespace);
+						if (typeof p.oldAjaxSuccess === 'function') {
+							p.oldAjaxSuccess(data);
+						}
+					};
+					if (c.debug) {
+						console.log('Pager: Ajax initialized', p.ajaxObject);
+					}
+					$.ajax(p.ajaxObject);
+				}
+			},
+
+			getAjaxUrl = function(table, p) {
+				var indx, len,
+				c = table.config,
+				url = (p.ajaxUrl) ? p.ajaxUrl
+				// allow using "{page+1}" in the url string to switch to a non-zero based index
+				.replace(/\{page([\-+]\d+)?\}/, function(s, n){ return p.page + (n ? parseInt(n, 10) : 0); })
+				// this will pass "all" to server when size is set to "all"
+				.replace(/\{size\}/g, p.size) : '',
+				sortList = c.sortList,
+				filterList = p.currentFilters || $(table).data('lastSearch') || [],
+				sortCol = url.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/),
+				filterCol = url.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/),
+				arry = [];
+				if (sortCol) {
+					sortCol = sortCol[1];
+					len = sortList.length;
+					for (indx = 0; indx < len; indx++) {
+						arry[ arry.length ] = sortCol + '[' + sortList[indx][0] + ']=' + sortList[indx][1];
+					}
+					// if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col"
+					url = url.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : sortCol );
+					arry = [];
+				}
+				if (filterCol) {
+					filterCol = filterCol[1];
+					len = filterList.length;
+					for (indx = 0; indx < len; indx++) {
+						if (filterList[indx]) {
+							arry[ arry.length ] = filterCol + '[' + indx + ']=' + encodeURIComponent( filterList[indx] );
+						}
+					}
+					// if the arry is empty, just add the fcol parameter... "&{filterList:fcol}" becomes "&fcol"
+					url = url.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : filterCol );
+					p.currentFilters = filterList;
+				}
+				if ( typeof p.customAjaxUrl === 'function' ) {
+					url = p.customAjaxUrl(table, url);
+				}
+				if (c.debug) {
+					console.log('Pager: Ajax url = ' + url);
+				}
+				return url;
+			},
+
+			renderTable = function(table, rows, p) {
+				var $tb, index, count, added,
+				$t = $(table),
+				c = table.config,
+				f = c.$table.hasClass('hasFilters'),
+				l = rows && rows.length || 0, // rows may be undefined
+				e = p.size === 'all' ? p.totalRows : p.size,
+				s = ( p.page * e );
+				if ( l < 1 ) {
+					if (c.debug) {
+						console.warn('Pager: >> No rows for pager to render');
+					}
+					// empty table, abort!
+					return;
+				}
+				if ( p.page >= p.totalPages ) {
+					// lets not render the table more than once
+					moveToLastPage(table, p);
+				}
+				p.cacheIndex = [];
+				p.isDisabled = false; // needed because sorting will change the page and re-enable the pager
+				if (p.initialized) {
+					if (c.debug) {
+						console.log('Pager: Triggering pagerChange');
+					}
+					$t.triggerHandler( 'pagerChange', p );
+				}
+				if ( !p.removeRows ) {
+					hideRows(table, p);
+				} else {
+					ts.clearTableBody(table);
+					$tb = ts.processTbody(table, c.$tbodies.eq(0), true);
+					// not filtered, start from the calculated starting point (s)
+					// if filtered, start from zero
+					index = f ? 0 : s;
+					count = f ? 0 : s;
+					added = 0;
+					while (added < e && index < rows.length) {
+						if (!f || !p.regexFiltered.test(rows[index][0].className)){
+							count++;
+							if (count > s && added <= e) {
+								added++;
+								p.cacheIndex[ p.cacheIndex.length ] = index;
+								$tb.append(rows[index]);
+							}
+						}
+						index++;
+					}
+					ts.processTbody(table, $tb, false);
+				}
+				updatePageDisplay(table, p);
+				if (table.isUpdating) {
+					if (c.debug) {
+						console.log('Pager: Triggering updateComplete');
+					}
+					$t.triggerHandler('updateComplete', [ table, true ]);
+				}
+			},
+
+			showAllRows = function(table, p) {
+				var index, $controls, len;
+				if ( p.ajax ) {
+					pagerArrows( table, p, true );
+				} else {
+					$.data(table, 'pagerLastPage', p.page);
+					$.data(table, 'pagerLastSize', p.size);
+					p.page = 0;
+					p.size = 'all';
+					p.totalPages = 1;
+					$(table)
+					.addClass('pagerDisabled')
+					.removeAttr('aria-describedby')
+					.find('tr.pagerSavedHeightSpacer').remove();
+					renderTable(table, table.config.rowsCopy, p);
+					p.isDisabled = true;
+					ts.applyWidget( table );
+					if (table.config.debug) {
+						console.log('Pager: Disabled');
+					}
+				}
+				// disable size selector
+				$controls = p.$container.find( p.cssGoto + ',' + p.cssPageSize + ', .ts-startRow, .ts-page' );
+				len = $controls.length;
+				for ( index = 0; index < len; index++ ) {
+					$controls.eq( index ).addClass( p.cssDisabled )[0].disabled = true;
+					$controls[ index ].ariaDisabled = true;
+				}
+			},
+
+			// updateCache if delayInit: true
+			updateCache = function(table) {
+				var c = table.config,
+				p = c.pager;
+				// tablesorter core updateCache (not pager)
+				ts.updateCache( c, function(){
+					var i,
+					rows = [],
+					n = table.config.cache[0].normalized;
+					p.totalRows = n.length;
+					for (i = 0; i < p.totalRows; i++) {
+						rows[ rows.length ] = n[i][c.columns].$row;
+					}
+					c.rowsCopy = rows;
+					moveToPage(table, p, true);
+				});
+			},
+
+			moveToPage = function(table, p, pageMoved) {
+				if ( p.isDisabled ) { return; }
+				var tmp,
+				c = table.config,
+				$t = $(table),
+				l = p.last;
+				if ( pageMoved !== false && p.initialized && ts.isEmptyObject(c.cache)) {
+					return updateCache(table);
+				}
+				// abort page move if the table has filters and has not been initialized
+				if (p.ajax && ts.hasWidget(table, 'filter') && !c.widgetOptions.filter_initialized) { return; }
+				parsePageNumber( table, p );
+				calcFilters(table, p);
+				// fixes issue where one currentFilter is [] and the other is ['','',''],
+				// making the next if comparison think the filters are different (joined by commas). Fixes #202.
+				l.currentFilters = (l.currentFilters || []).join('') === '' ? [] : l.currentFilters;
+				p.currentFilters = (p.currentFilters || []).join('') === '' ? [] : p.currentFilters;
+				// don't allow rendering multiple times on the same page/size/totalRows/filters/sorts
+				if ( l.page === p.page && l.size === p.size && l.totalRows === p.totalRows &&
+				(l.currentFilters || []).join(',') === (p.currentFilters || []).join(',') &&
+				// check for ajax url changes see #730
+				(l.ajaxUrl || '') === (p.ajaxObject.url || '') &&
+				// & ajax url option changes (dynamically add/remove/rename sort & filter parameters)
+				(l.optAjaxUrl || '') === (p.ajaxUrl || '') &&
+				l.sortList === (c.sortList || []).join(',') ) { return; }
+				if (c.debug) {
+					console.log('Pager: Changing to page ' + p.page);
+				}
+				p.last = {
+					page : p.page,
+					size : p.size,
+					// fixes #408; modify sortList otherwise it auto-updates
+					sortList : (c.sortList || []).join(','),
+					totalRows : p.totalRows,
+					currentFilters : p.currentFilters || [],
+					ajaxUrl : p.ajaxObject.url || '',
+					optAjaxUrl : p.ajaxUrl || ''
+				};
+				if (p.ajax) {
+					if ( !p.processAjaxOnInit && !ts.isEmptyObject(p.initialRows) ) {
+						p.processAjaxOnInit = true;
+						tmp = p.initialRows;
+						p.totalRows = typeof tmp.total !== 'undefined' ? tmp.total :
+						( c.debug ? console.error('Pager: no initial total page set!') || 0 : 0 );
+						p.filteredRows = typeof tmp.filtered !== 'undefined' ? tmp.filtered :
+						( c.debug ? console.error('Pager: no initial filtered page set!') || 0 : 0 );
+						pagerInitialized( table, p );
+					} else {
+						getAjax(table, p);
+					}
+				} else if (!p.ajax) {
+					renderTable(table, c.rowsCopy, p);
+				}
+				$.data(table, 'pagerLastPage', p.page);
+				if (p.initialized && pageMoved !== false) {
+					if (c.debug) {
+						console.log('Pager: Triggering pageMoved');
+					}
+					$t.triggerHandler('pageMoved', p);
+					ts.applyWidget( table );
+					if (table.isUpdating) {
+						if (c.debug) {
+							console.log('Pager: Triggering updateComplete');
+						}
+						$t.triggerHandler('updateComplete', [ table, true ]);
+					}
+				}
+			},
+
+			getTotalPages = function( table, p ) {
+				return ts.hasWidget( table, 'filter' ) ? Math.min( p.totalPages, p.filteredPages ) : p.totalPages;
+			},
+
+			// set to either set or get value
+			parsePageSize = function( p, size, mode ) {
+				var s = parseInt( size, 10 ) || p.size || p.settings.size || 10;
+				return p.initialized && (/all/i.test( size ) || s === p.totalRows) ?
+				// "get" to get `p.size` or "set" to set `pageSize.val()`
+				'all' : ( mode === 'get' ? s : p.size );
+			},
+
+			parsePageNumber = function( table, p ) {
+				var min = getTotalPages( table, p ) - 1;
+				p.page = parseInt( p.page, 10 );
+				if ( p.page < 0 || isNaN( p.page ) ) { p.page = 0; }
+				if ( p.page > min && min >= 0 ) { p.page = min; }
+				return p.page;
+			},
+
+			setPageSize = function(table, size, p) {
+				p.size = parsePageSize( p, size, 'get' );
+				p.$container.find(p.cssPageSize).val( parsePageSize( p, p.size, 'set' ) );
+				$.data(table, 'pagerLastPage', parsePageNumber( table, p ) );
+				$.data(table, 'pagerLastSize', p.size);
+				p.totalPages = p.size === 'all' ? 1 : Math.ceil( p.totalRows / p.size );
+				p.filteredPages = p.size === 'all' ? 1 : Math.ceil( p.filteredRows / p.size );
+				moveToPage(table, p);
+			},
+
+			moveToFirstPage = function(table, p) {
+				p.page = 0;
+				moveToPage(table, p);
+			},
+
+			moveToLastPage = function(table, p) {
+				p.page = getTotalPages( table, p ) - 1;
+				moveToPage(table, p);
+			},
+
+			moveToNextPage = function(table, p) {
+				p.page++;
+				var last = getTotalPages( table, p ) - 1;
+				if ( p.page >= last ) {
+					p.page = last;
+				}
+				moveToPage(table, p);
+			},
+
+			moveToPrevPage = function(table, p) {
+				p.page--;
+				if ( p.page <= 0 ) {
+					p.page = 0;
+				}
+				moveToPage(table, p);
+			},
+
+			pagerInitialized = function(table, p) {
+				p.initialized = true;
+				p.initializing = false;
+				if (table.config.debug) {
+					console.log('Pager: Triggering pagerInitialized');
+				}
+				$(table).triggerHandler( 'pagerInitialized', p );
+				ts.applyWidget( table );
+				updatePageDisplay(table, p);
+			},
+
+			resetState = function(table, p) {
+				var c = table.config;
+				c.pager = $.extend( true, {}, $.tablesorterPager.defaults, p.settings );
+				init(table, p.settings);
+			},
+
+			destroyPager = function(table, p) {
+				var c = table.config,
+				namespace = c.namespace + 'pager',
+				ctrls = [ p.cssFirst, p.cssPrev, p.cssNext, p.cssLast, p.cssGoto, p.cssPageSize ].join( ',' );
+				showAllRows(table, p);
+				p.$container
+				// hide pager controls
+				.hide()
+				// unbind
+				.find( ctrls )
+				.unbind( namespace );
+				c.appender = null; // remove pager appender function
+				c.$table.unbind( namespace );
+				if (ts.storage) {
+					ts.storage(table, p.storageKey, '');
+				}
+				delete c.pager;
+				delete c.rowsCopy;
+			},
+
+			enablePager = function(table, p, triggered) {
+				var info, size, $el,
+				c = table.config;
+				p.$container.find(p.cssGoto + ',' + p.cssPageSize + ',.ts-startRow, .ts-page')
+				.removeClass(p.cssDisabled)
+				.removeAttr('disabled')
+				.each(function(){
+					this.ariaDisabled = false;
+				});
+				p.isDisabled = false;
+				p.page = $.data(table, 'pagerLastPage') || p.page || 0;
+				$el = p.$container.find(p.cssPageSize);
+				size = $el.find('option[selected]').val();
+				p.size = $.data(table, 'pagerLastSize') || parsePageSize( p, size, 'get' );
+				$el.val( p.size ); // set page size
+				p.totalPages = p.size === 'all' ? 1 : Math.ceil( getTotalPages( table, p ) / p.size );
+				// if table id exists, include page display with aria info
+				if ( table.id && !c.$table.attr( 'aria-describedby' ) ) {
+					$el = p.$container.find( p.cssPageDisplay );
+					info = $el.attr( 'id' );
+					if ( !info ) {
+						// only add pageDisplay id if it doesn't exist - see #1288
+						info = table.id + '_pager_info';
+						$el.attr( 'id', info );
+					}
+					c.$table.attr( 'aria-describedby', info );
+				}
+				changeHeight(table, p);
+				if ( triggered ) {
+					// tablesorter core update table
+					ts.update( c );
+					setPageSize(table, p.size, p);
+					hideRowsSetup(table, p);
+					if (c.debug) {
+						console.log('Pager: Enabled');
+					}
+				}
+			},
+
+			init = function(table, settings) {
+				var t, ctrls, fxn, size, $el,
+				c = table.config,
+				wo = c.widgetOptions,
+				p = c.pager = $.extend( true, {}, $.tablesorterPager.defaults, settings ),
+				$t = c.$table,
+				namespace = c.namespace + 'pager',
+				// added in case the pager is reinitialized after being destroyed.
+				pager = p.$container = $(p.container).addClass('tablesorter-pager').show();
+				// save a copy of the original settings
+				p.settings = $.extend( true, {}, $.tablesorterPager.defaults, settings );
+				if (c.debug) {
+					console.log('Pager: Initializing');
+				}
+				p.oldAjaxSuccess = p.oldAjaxSuccess || p.ajaxObject.success;
+				c.appender = $this.appender;
+				p.initializing = true;
+				if (p.savePages && ts.storage) {
+					t = ts.storage(table, p.storageKey) || {}; // fixes #387
+					p.page = isNaN(t.page) ? p.page : t.page;
+					p.size = t.size === 'all' ? t.size : ( isNaN( t.size ) ? p.size : t.size ) || p.setSize || 10;
+					$.data(table, 'pagerLastSize', p.size);
+					pager.find(p.cssPageSize).val(p.size);
+				}
+				// skipped rows
+				p.regexRows = new RegExp('(' + (wo.filter_filteredRow || 'filtered') + '|' + c.selectorRemove.slice(1) + '|' + c.cssChildRow + ')');
+				p.regexFiltered = new RegExp(wo.filter_filteredRow || 'filtered');
+
+				$t
+				// .unbind( namespace ) adding in jQuery 1.4.3 ( I think )
+				.unbind( pagerEvents.split(' ').join(namespace + ' ').replace(/\s+/g, ' ') )
+				.bind('filterInit filterStart '.split(' ').join(namespace + ' '), function(e, filters) {
+					p.currentFilters = $.isArray(filters) ? filters : c.$table.data('lastSearch');
+					// don't change page if filters are the same (pager updating, etc)
+					if (e.type === 'filterStart' && p.pageReset !== false && (c.lastCombinedFilter || '') !== (p.currentFilters || []).join('')) {
+						p.page = p.pageReset; // fixes #456 & #565
+					}
+				})
+				// update pager after filter widget completes
+				.bind('filterEnd sortEnd '.split(' ').join(namespace + ' '), function() {
+					p.currentFilters = c.$table.data('lastSearch');
+					if (p.initialized || p.initializing) {
+						if (c.delayInit && c.rowsCopy && c.rowsCopy.length === 0) {
+							// make sure we have a copy of all table rows once the cache has been built
+							updateCache(table);
+						}
+						updatePageDisplay(table, p, false);
+						moveToPage(table, p, false);
+						ts.applyWidget( table );
+					}
+				})
+				.bind('disablePager' + namespace, function(e){
+					e.stopPropagation();
+					showAllRows(table, p);
+				})
+				.bind('enablePager' + namespace, function(e){
+					e.stopPropagation();
+					enablePager(table, p, true);
+				})
+				.bind('destroyPager' + namespace, function(e){
+					e.stopPropagation();
+					destroyPager(table, p);
+				})
+				.bind('resetToLoadState' + namespace, function(e){
+					e.stopPropagation();
+					resetState(table, p);
+				})
+				.bind('updateComplete' + namespace, function(e, table, triggered){
+					e.stopPropagation();
+					// table can be unintentionally undefined in tablesorter v2.17.7 and earlier
+					// don't recalculate total rows/pages if using ajax
+					if ( !table || triggered || p.ajax ) { return; }
+					var $rows = c.$tbodies.eq(0).children('tr').not(c.selectorRemove);
+					p.totalRows = $rows.length - ( p.countChildRows ? 0 : $rows.filter('.' + c.cssChildRow).length );
+					p.totalPages = p.size === 'all' ? 1 : Math.ceil( p.totalRows / p.size );
+					if ($rows.length && c.rowsCopy && c.rowsCopy.length === 0) {
+						// make a copy of all table rows once the cache has been built
+						updateCache(table);
+					}
+					if ( p.page >= p.totalPages ) {
+						moveToLastPage(table, p);
+					}
+					hideRows(table, p);
+					changeHeight(table, p);
+					updatePageDisplay(table, p, true);
+				})
+				.bind('pageSize refreshComplete '.split(' ').join(namespace + ' '), function(e, size){
+					e.stopPropagation();
+					setPageSize(table, parsePageSize( p, size, 'get' ), p);
+					hideRows(table, p);
+					updatePageDisplay(table, p, false);
+				})
+				.bind('pageSet pagerUpdate '.split(' ').join(namespace + ' '), function(e, num){
+					e.stopPropagation();
+					// force pager refresh
+					if (e.type === 'pagerUpdate') {
+						num = typeof num === 'undefined' ? p.page + 1 : num;
+						p.last.page = true;
+					}
+					p.page = (parseInt(num, 10) || 1) - 1;
+					moveToPage(table, p, true);
+					updatePageDisplay(table, p, false);
+				})
+				.bind('pageAndSize' + namespace, function(e, page, size){
+					e.stopPropagation();
+					p.page = (parseInt(page, 10) || 1) - 1;
+					setPageSize(table, parsePageSize( p, size, 'get' ), p);
+					moveToPage(table, p, true);
+					hideRows(table, p);
+					updatePageDisplay(table, p, false);
+				});
+
+				// clicked controls
+				ctrls = [ p.cssFirst, p.cssPrev, p.cssNext, p.cssLast ];
+				fxn = [ moveToFirstPage, moveToPrevPage, moveToNextPage, moveToLastPage ];
+				if (c.debug && !pager.length) {
+					console.warn('Pager: >> Container not found');
+				}
+				pager.find(ctrls.join(','))
+				.attr('tabindex', 0)
+				.unbind('click' + namespace)
+				.bind('click' + namespace, function(e){
+					e.stopPropagation();
+					var i, $t = $(this), l = ctrls.length;
+					if ( !$t.hasClass(p.cssDisabled) ) {
+						for (i = 0; i < l; i++) {
+							if ($t.is(ctrls[i])) {
+								fxn[i](table, p);
+								break;
+							}
+						}
+					}
+				});
+
+				// goto selector
+				$el = pager.find(p.cssGoto);
+				if ( $el.length ) {
+					$el
+					.unbind('change' + namespace)
+					.bind('change' + namespace, function(){
+						p.page = $(this).val() - 1;
+						moveToPage(table, p, true);
+						updatePageDisplay(table, p, false);
+					});
+				} else if (c.debug) {
+					console.warn('Pager: >> Goto selector not found');
+				}
+				// page size selector
+				$el = pager.find(p.cssPageSize);
+				if ( $el.length ) {
+					// setting an option as selected appears to cause issues with initial page size
+					$el.find('option').removeAttr('selected');
+					$el.unbind('change' + namespace).bind('change' + namespace, function() {
+						if ( !$(this).hasClass(p.cssDisabled) ) {
+							var size = $(this).val();
+							// in case there are more than one pager
+							p.$container.find(p.cssGoto).val( size );
+							setPageSize(table, size, p);
+							changeHeight(table, p);
+						}
+						return false;
+					});
+				} else if (c.debug) {
+					console.warn('Pager: >> Size selector not found');
+				}
+
+				// clear initialized flag
+				p.initialized = false;
+				// before initialization event
+				$t.triggerHandler('pagerBeforeInitialized', p);
+
+				enablePager(table, p, false);
+				if ( typeof p.ajaxUrl === 'string' ) {
+					// ajax pager; interact with database
+					p.ajax = true;
+					// When filtering with ajax, allow only custom filtering function, disable default
+					// filtering since it will be done server side.
+					c.widgetOptions.filter_serversideFiltering = true;
+					c.serverSideSorting = true;
+					moveToPage(table, p);
+				} else {
+					p.ajax = false;
+					// Regular pager; all rows stored in memory
+					ts.appendCache( c, true ); // true = don't apply widgets
+					hideRowsSetup(table, p);
+				}
+
+				// pager initialized
+				if (!p.ajax && !p.initialized) {
+					p.initializing = false;
+					p.initialized = true;
+					moveToPage(table, p);
+					if (c.debug) {
+						console.log('Pager: Triggering pagerInitialized');
+					}
+					c.$table.triggerHandler( 'pagerInitialized', p );
+					if ( !( c.widgetOptions.filter_initialized && ts.hasWidget(table, 'filter') ) ) {
+						updatePageDisplay(table, p, false);
+					}
+				}
+
+				// make the hasWidget function think that the pager widget is being used
+				c.widgetInit.pager = true;
+			};
+
+			$this.appender = function(table, rows) {
+				var c = table.config,
+				p = c.pager;
+				if ( !p.ajax ) {
+					c.rowsCopy = rows;
+					p.totalRows = p.countChildRows ? c.$tbodies.eq(0).children('tr').length : rows.length;
+					p.size = $.data(table, 'pagerLastSize') || p.size || p.settings.size || 10;
+					p.totalPages = p.size === 'all' ? 1 : Math.ceil( p.totalRows / p.size );
+					renderTable(table, rows, p);
+					// update display here in case all rows are removed
+					updatePageDisplay(table, p, false);
+				}
+			};
+
+			$this.construct = function(settings) {
+				return this.each(function() {
+					// check if tablesorter has initialized
+					if (!(this.config && this.hasInitialized)) { return; }
+					init(this, settings);
+				});
+			};
+
+		}()
+	});
+
+	// see #486
+	ts.showError = function( table, xhr, settings, exception ) {
+		var $row,
+			$table = $( table ),
+			c = $table[0].config,
+			wo = c && c.widgetOptions,
+			errorRow = c.pager && c.pager.cssErrorRow ||
+			wo && wo.pager_css && wo.pager_css.errorRow ||
+			'tablesorter-errorRow',
+			typ = typeof xhr,
+			valid = true,
+			message = '',
+			removeRow = function(){
+				c.$table.find( 'thead' ).find( '.' + errorRow ).remove();
+			};
+
+		if ( !$table.length ) {
+			console.error('tablesorter showError: no table parameter passed');
+			return;
+		}
+
+		// ajaxError callback for plugin or widget - see #992
+		if ( typeof c.pager.ajaxError === 'function' ) {
+			valid = c.pager.ajaxError( c, xhr, settings, exception );
+			if ( valid === false ) {
+				return removeRow();
+			} else {
+				message = valid;
+			}
+		} else if ( typeof wo.pager_ajaxError === 'function' ) {
+			valid = wo.pager_ajaxError( c, xhr, settings, exception );
+			if ( valid === false ) {
+				return removeRow();
+			} else {
+				message = valid;
+			}
+		}
+
+		if ( message === '' ) {
+			if ( typ === 'object' ) {
+				message =
+					xhr.status === 0 ? 'Not connected, verify Network' :
+					xhr.status === 404 ? 'Requested page not found [404]' :
+					xhr.status === 500 ? 'Internal Server Error [500]' :
+					exception === 'parsererror' ? 'Requested JSON parse failed' :
+					exception === 'timeout' ? 'Time out error' :
+					exception === 'abort' ? 'Ajax Request aborted' :
+					'Uncaught error: ' + xhr.statusText + ' [' + xhr.status + ']';
+			} else if ( typ === 'string'  ) {
+				// keep backward compatibility (external usage just passes a message string)
+				message = xhr;
+			} else {
+				// remove all error rows
+				return removeRow();
+			}
+		}
+
+		// allow message to include entire row HTML!
+		$row = ( /tr\>/.test(message) ? $(message) : $('<tr><td colspan="' + c.columns + '">' + message + '</td></tr>') )
+			.click( function() {
+				$( this ).remove();
+			})
+			// add error row to thead instead of tbody, or clicking on the header will result in a parser error
+			.appendTo( c.$table.find( 'thead:first' ) )
+			.addClass( errorRow + ' ' + c.selectorRemove.slice(1) )
+			.attr({
+				role : 'alert',
+				'aria-live' : 'assertive'
+			});
+
+	};
+
+	// extend plugin scope
+	$.fn.extend({
+		tablesorterPager: $.tablesorterPager.construct
+	});
+
+})(jQuery);
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.widgets.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.widgets.js
new file mode 100644
index 0000000000000000000000000000000000000000..92e4b77bf26b8711d25fd5cb0aa21139eba913a0
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.widgets.js
@@ -0,0 +1,3043 @@
+/*! tablesorter (FORK) - updated 01-06-2017 (v2.28.4)*/
+/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
+(function(factory) {
+	if (typeof define === 'function' && define.amd) {
+		define(['jquery'], factory);
+	} else if (typeof module === 'object' && typeof module.exports === 'object') {
+		module.exports = factory(require('jquery'));
+	} else {
+		factory(jQuery);
+	}
+}(function(jQuery) {
+
+/*! Widget: storage - updated 11/26/2016 (v2.28.0) */
+/*global JSON:false */
+;(function ($, window, document) {
+	'use strict';
+
+	var ts = $.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
+	*/
+	ts.storage = function(table, key, value, options) {
+		table = $(table)[0];
+		var cookieIndex, cookies, date,
+			hasStorage = false,
+			values = {},
+			c = table.config,
+			wo = c && c.widgetOptions,
+			storageType = ( options && options.useSessionStorage ) || ( wo && wo.storage_useSessionStorage ) ?
+				'sessionStorage' : 'localStorage',
+			$table = $(table),
+			// id from (1) options ID, (2) table 'data-table-group' attribute, (3) widgetOptions.storage_tableId,
+			// (4) table ID, then (5) table index
+			id = options && options.id ||
+				$table.attr( options && options.group || wo && wo.storage_group || 'data-table-group') ||
+				wo && wo.storage_tableId || table.id || $('.tablesorter').index( $table ),
+			// 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
+			url = options && options.url ||
+				$table.attr(options && options.page || wo && wo.storage_page || 'data-table-page') ||
+				wo && wo.storage_fixedUrl || c && c.fixedUrl || window.location.pathname;
+		// update defaults for validator; these values must be falsy!
+		$.extend(true, ts.defaults, {
+			fixedUrl: '',
+			widgetOptions: {
+				storage_fixedUrl: '',
+				storage_group: '',
+				storage_page: '',
+				storage_tableId: '',
+				storage_useSessionStorage: ''
+			}
+		});
+		// https://gist.github.com/paulirish/5558557
+		if (storageType in window) {
+			try {
+				window[storageType].setItem('_tmptest', 'temp');
+				hasStorage = true;
+				window[storageType].removeItem('_tmptest');
+			} catch (error) {
+				if (c && c.debug) {
+					console.warn( storageType + ' is not supported in this browser' );
+				}
+			}
+		}
+		// *** get value ***
+		if ($.parseJSON) {
+			if (hasStorage) {
+				values = $.parseJSON( window[storageType][key] || 'null' ) || {};
+			} else {
+				// old browser, using cookies
+				cookies = document.cookie.split(/[;\s|=]/);
+				// add one to get from the key to the value
+				cookieIndex = $.inArray(key, cookies) + 1;
+				values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {};
+			}
+		}
+		// allow value to be an empty string too
+		if (typeof value !== 'undefined' && window.JSON && JSON.hasOwnProperty('stringify')) {
+			// add unique identifiers = url pathname > table ID/index on page > data
+			if (!values[url]) {
+				values[url] = {};
+			}
+			values[url][id] = value;
+			// *** set value ***
+			if (hasStorage) {
+				window[storageType][key] = JSON.stringify(values);
+			} else {
+				date = new Date();
+				date.setTime(date.getTime() + (31536e+6)); // 365 days
+				document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g, '\"') + '; expires=' + date.toGMTString() + '; path=/';
+			}
+		} else {
+			return values && values[url] ? values[url][id] : '';
+		}
+	};
+
+})(jQuery, window, document);
+
+/*! Widget: uitheme - updated 12/8/2016 (v2.28.1) */
+;(function ($) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	ts.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          : ''  // odd row zebra striping
+		},
+		'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 ui-icon-caret-2-n-s', // class name added to icon when column is not sorted
+			iconSortAsc  : 'ui-icon-carat-1-n ui-icon-caret-1-n', // class name added to icon when column has ascending sort
+			iconSortDesc : 'ui-icon-carat-1-s ui-icon-caret-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'   // odd row zebra striping
+		}
+	};
+
+	$.extend(ts.css, {
+		wrapper : 'tablesorter-wrapper' // ui theme & resizable
+	});
+
+	ts.addWidget({
+		id: 'uitheme',
+		priority: 10,
+		format: function(table, c, wo) {
+			var i, tmp, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme,
+				themesAll = ts.themes,
+				$table = c.$table.add( $( c.namespace + '_extra_table' ) ),
+				$headers = c.$headers.add( $( c.namespace + '_extra_headers' ) ),
+				theme = c.theme || 'jui',
+				themes = themesAll[theme] || {},
+				remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ),
+				iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) );
+			if (c.debug) { time = new Date(); }
+			// initialization code - run once
+			if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) {
+				wo.uitheme_applied = true;
+				oldtheme = themesAll[c.appliedTheme] || {};
+				hasOldTheme = !$.isEmptyObject(oldtheme);
+				oldremove =  hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : '';
+				oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : '';
+				if (hasOldTheme) {
+					wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') );
+					wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') );
+					c.$tbodies.children().removeClass( [ oldtheme.even, oldtheme.odd ].join(' ') );
+				}
+				// update zebra stripes
+				if (themes.even) { wo.zebra[0] += ' ' + themes.even; }
+				if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; }
+				// add caption style
+				$table.children('caption')
+					.removeClass(oldtheme.caption || '')
+					.addClass(themes.caption);
+				// add table/footer class names
+				$tfoot = $table
+					// remove other selected themes
+					.removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') )
+					.addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name
+					.children('tfoot');
+				c.appliedTheme = c.theme;
+
+				if ($tfoot.length) {
+					$tfoot
+						// if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed
+						.children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow)
+						.children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells);
+				}
+				// update header classes
+				$headers
+					.removeClass( (hasOldTheme ? [ oldtheme.header, oldtheme.hover, oldremove ].join(' ') : '') || '' )
+					.addClass(themes.header)
+					.not('.sorter-false')
+					.unbind('mouseenter.tsuitheme mouseleave.tsuitheme')
+					.bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) {
+						// toggleClass with switch added in jQuery 1.3
+						$(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || '');
+					});
+
+				$headers.each(function(){
+					var $this = $(this);
+					if (!$this.find('.' + ts.css.wrapper).length) {
+						// Firefox needs this inner div to position the icon & resizer correctly
+						$this.wrapInner('<div class="' + ts.css.wrapper + '" style="position:relative;height:100%;width:100%"></div>');
+					}
+				});
+				if (c.cssIcon) {
+					// if c.cssIcon is '', then no <i> is added to the header
+					$headers
+						.find('.' + ts.css.icon)
+						.removeClass(hasOldTheme ? [ oldtheme.icons, oldIconRmv ].join(' ') : '')
+						.addClass(themes.icons || '');
+				}
+				// filter widget initializes after uitheme
+				if (ts.hasWidget( c.table, 'filter' )) {
+					tmp = function() {
+						$table.children('thead').children('.' + ts.css.filterRow)
+							.removeClass(hasOldTheme ? oldtheme.filterRow || '' : '')
+							.addClass(themes.filterRow || '');
+					};
+					if (wo.filter_initialized) {
+						tmp();
+					} else {
+						$table.one('filterInit', function() {
+							tmp();
+						});
+					}
+				}
+			}
+			for (i = 0; i < c.columns; i++) {
+				$header = c.$headers
+					.add($(c.namespace + '_extra_headers'))
+					.not('.sorter-false')
+					.filter('[data-column="' + i + '"]');
+				$icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $();
+				$h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last');
+				if ($h.length) {
+					$header.removeClass(remove);
+					$icon.removeClass(iconRmv);
+					if ($h[0].sortDisabled) {
+						// no sort arrows for disabled columns!
+						$icon.removeClass(themes.icons || '');
+					} else {
+						hdr = themes.sortNone;
+						icon = themes.iconSortNone;
+						if ($h.hasClass(ts.css.sortAsc)) {
+							hdr = [ themes.sortAsc, themes.active ].join(' ');
+							icon = themes.iconSortAsc;
+						} else if ($h.hasClass(ts.css.sortDesc)) {
+							hdr = [ themes.sortDesc, themes.active ].join(' ');
+							icon = themes.iconSortDesc;
+						}
+						$header.addClass(hdr);
+						$icon.addClass(icon || '');
+					}
+				}
+			}
+			if (c.debug) {
+				console.log('Applying ' + theme + ' theme' + ts.benchmark(time));
+			}
+		},
+		remove: function(table, c, wo, refreshing) {
+			if (!wo.uitheme_applied) { return; }
+			var $table = c.$table,
+				theme = c.appliedTheme || 'jui',
+				themes = ts.themes[ theme ] || ts.themes.jui,
+				$headers = $table.children('thead').children(),
+				remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc,
+				iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc;
+			$table.removeClass('tablesorter-' + theme + ' ' + themes.table);
+			wo.uitheme_applied = false;
+			if (refreshing) { return; }
+			$table.find(ts.css.header).removeClass(themes.header);
+			$headers
+				.unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover
+				.removeClass(themes.hover + ' ' + remove + ' ' + themes.active)
+				.filter('.' + ts.css.filterRow)
+				.removeClass(themes.filterRow);
+			$headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv);
+		}
+	});
+
+})(jQuery);
+
+/*! Widget: columns */
+;(function ($) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	ts.addWidget({
+		id: 'columns',
+		priority: 30,
+		options : {
+			columns : [ 'primary', 'secondary', 'tertiary' ]
+		},
+		format: function(table, c, wo) {
+			var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx,
+			$table = c.$table,
+			$tbodies = c.$tbodies,
+			sortList = c.sortList,
+			len = sortList.length,
+			// removed c.widgetColumns support
+			css = wo && wo.columns || [ 'primary', 'secondary', 'tertiary' ],
+			last = css.length - 1;
+			remove = css.join(' ');
+			// check if there is a sort (on initialization there may not be one)
+			for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody
+				$rows = $tbody.children('tr');
+				// loop through the visible rows
+				$rows.each(function() {
+					$row = $(this);
+					if (this.style.display !== 'none') {
+						// remove all columns class names
+						$cells = $row.children().removeClass(remove);
+						// add appropriate column class names
+						if (sortList && sortList[0]) {
+							// primary sort column class
+							$cells.eq(sortList[0][0]).addClass(css[0]);
+							if (len > 1) {
+								for (indx = 1; indx < len; indx++) {
+									// secondary, tertiary, etc sort column classes
+									$cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] );
+								}
+							}
+						}
+					}
+				});
+				ts.processTbody(table, $tbody, false);
+			}
+			// add classes to thead and tfoot
+			rows = wo.columns_thead !== false ? [ 'thead tr' ] : [];
+			if (wo.columns_tfoot !== false) {
+				rows.push('tfoot tr');
+			}
+			if (rows.length) {
+				$rows = $table.find( rows.join(',') ).children().removeClass(remove);
+				if (len) {
+					for (indx = 0; indx < len; indx++) {
+						// add primary. secondary, tertiary, etc sort column classes
+						$rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]);
+					}
+				}
+			}
+		},
+		remove: function(table, c, wo) {
+			var tbodyIndex, $tbody,
+				$tbodies = c.$tbodies,
+				remove = (wo.columns || [ 'primary', 'secondary', 'tertiary' ]).join(' ');
+			c.$headers.removeClass(remove);
+			c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove);
+			for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody
+				$tbody.children('tr').each(function() {
+					$(this).children().removeClass(remove);
+				});
+				ts.processTbody(table, $tbody, false); // restore tbody
+			}
+		}
+	});
+
+})(jQuery);
+
+/*! Widget: filter - updated 12/8/2016 (v2.28.1) *//*
+ * Requires tablesorter v2.8+ and jQuery 1.7+
+ * by Rob Garrison
+ */
+;( function ( $ ) {
+	'use strict';
+	var tsf, tsfRegex,
+		ts = $.tablesorter || {},
+		tscss = ts.css,
+		tskeyCodes = ts.keyCodes;
+
+	$.extend( tscss, {
+		filterRow      : 'tablesorter-filter-row',
+		filter         : 'tablesorter-filter',
+		filterDisabled : 'disabled',
+		filterRowHide  : 'hideme'
+	});
+
+	$.extend( tskeyCodes, {
+		backSpace : 8,
+		escape : 27,
+		space : 32,
+		left : 37,
+		down : 40
+	});
+
+	ts.addWidget({
+		id: 'filter',
+		priority: 50,
+		options : {
+			filter_cellFilter    : '',    // css class name added to the filter cell ( string or array )
+			filter_childRows     : false, // if true, filter includes child row content in the search
+			filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
+			filter_childWithSibs : true,  // if true, include matching child row siblings
+			filter_columnAnyMatch: true,  // if true, allows using '#:{query}' in AnyMatch searches ( column:query )
+			filter_columnFilters : true,  // if true, a filter will be added to the top of each table column
+			filter_cssFilter     : '',    // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
+			filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value
+			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; define in css with "display:none" to hide the filtered-out rows
+			filter_formatter     : null,  // add custom filter elements to the filter row
+			filter_functions     : null,  // add custom filter functions using this option
+			filter_hideEmpty     : true,  // hide filter row when table is empty
+			filter_hideFilters   : false, // collapse filter row when mouse leaves the area
+			filter_ignoreCase    : true,  // if true, make all searches case-insensitive
+			filter_liveSearch    : true,  // if true, search column content while the user types ( with a delay )
+			filter_matchType     : { 'input': 'exact', 'select': 'exact' }, // global query settings ('exact' or 'match'); overridden by "filter-match" or "filter-exact" class
+			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_resetOnEsc    : true,  // Reset filter input when the user presses escape - normalized across browsers
+			filter_saveFilters   : false, // Use the $.tablesorter.storage utility to save the most recent filters
+			filter_searchDelay   : 300,   // typing delay in milliseconds before starting a search
+			filter_searchFiltered: true,  // 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_selectSourceSeparator : '|', // filter_selectSource array text left of the separator is added to the option value, right into the option text
+			filter_serversideFiltering : false, // if true, must perform server-side filtering b/c client-side filtering is disabled, but the ui and events will still be used.
+			filter_startsWith    : false, // if true, filter start from the beginning of the cell contents
+			filter_useParsedData : false  // filter all data using parsed content
+		},
+		format: function( table, c, wo ) {
+			if ( !c.$table.hasClass( 'hasFilters' ) ) {
+				tsf.init( table, c, wo );
+			}
+		},
+		remove: function( table, c, wo, refreshing ) {
+			var tbodyIndex, $tbody,
+				$table = c.$table,
+				$tbodies = c.$tbodies,
+				events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
+					.split( ' ' ).join( c.namespace + 'filter ' );
+			$table
+				.removeClass( 'hasFilters' )
+				// add filter namespace to all BUT search
+				.unbind( events.replace( ts.regex.spaces, ' ' ) )
+				// remove the filter row even if refreshing, because the column might have been moved
+				.find( '.' + tscss.filterRow ).remove();
+			wo.filter_initialized = false;
+			if ( refreshing ) { return; }
+			for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
+				$tbody.children().removeClass( wo.filter_filteredRow ).show();
+				ts.processTbody( table, $tbody, false ); // restore tbody
+			}
+			if ( wo.filter_reset ) {
+				$( document ).undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' );
+			}
+		}
+	});
+
+	tsf = ts.filter = {
+
+		// regex used in filter 'check' functions - not for general use and not documented
+		regex: {
+			regex     : /^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/, // 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, data, vars ) {
+				// look for "|", but not if it is inside of a regular expression
+				if ( ( tsfRegex.orTest.test( data.iFilter ) || tsfRegex.orSplit.test( data.filter ) ) &&
+					// this test for regex has potential to slow down the overall search
+					!tsfRegex.regex.test( data.filter ) ) {
+					var indx, filterMatched, query, regex,
+						// duplicate data but split filter
+						data2 = $.extend( {}, data ),
+						filter = data.filter.split( tsfRegex.orSplit ),
+						iFilter = data.iFilter.split( tsfRegex.orSplit ),
+						len = filter.length;
+					for ( indx = 0; indx < len; indx++ ) {
+						data2.nestedFilters = true;
+						data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
+						data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
+						query = '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')';
+						try {
+							// use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
+							// e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
+							regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
+							// filterMatched = data2.filter === '' && indx > 0 ? true
+							// look for an exact match with the 'or' unless the 'filter-match' class is found
+							filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
+							if ( filterMatched ) {
+								return filterMatched;
+							}
+						} catch ( error ) {
+							return null;
+						}
+					}
+					// may be null from processing types
+					return filterMatched || false;
+				}
+				return null;
+			},
+			// Look for an AND or && operator ( logical and )
+			and : function( c, data, vars ) {
+				if ( tsfRegex.andTest.test( data.filter ) ) {
+					var indx, filterMatched, result, query, regex,
+						// duplicate data but split filter
+						data2 = $.extend( {}, data ),
+						filter = data.filter.split( tsfRegex.andSplit ),
+						iFilter = data.iFilter.split( tsfRegex.andSplit ),
+						len = filter.length;
+					for ( indx = 0; indx < len; indx++ ) {
+						data2.nestedFilters = true;
+						data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
+						data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
+						query = ( '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')' )
+							// replace wild cards since /(a*)/i will match anything
+							.replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' );
+						try {
+							// use try/catch just in case RegExp is invalid
+							regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
+							// look for an exact match with the 'and' unless the 'filter-match' class is found
+							result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
+							if ( indx === 0 ) {
+								filterMatched = result;
+							} else {
+								filterMatched = filterMatched && result;
+							}
+						} catch ( error ) {
+							return null;
+						}
+					}
+					// may be null from processing types
+					return filterMatched || false;
+				}
+				return null;
+			},
+			// Look for regex
+			regex: function( c, data ) {
+				if ( tsfRegex.regex.test( data.filter ) ) {
+					var matches,
+						// cache regex per column for optimal speed
+						regex = data.filter_regexCache[ data.index ] || tsfRegex.regex.exec( data.filter ),
+						isRegex = regex instanceof RegExp;
+					try {
+						if ( !isRegex ) {
+							// force case insensitive search if ignoreCase option set?
+							// if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
+							data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
+						}
+						matches = regex.test( data.exact );
+					} catch ( error ) {
+						matches = false;
+					}
+					return matches;
+				}
+				return null;
+			},
+			// Look for operators >, >=, < or <=
+			operators: function( c, data ) {
+				// ignore empty strings... because '' < 10 is true
+				if ( tsfRegex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
+					var cachedValue, result, txt,
+						table = c.table,
+						parsed = data.parsed[ data.index ],
+						query = ts.formatFloat( data.iFilter.replace( tsfRegex.operators, '' ), table ),
+						parser = c.parsers[ data.index ] || {},
+						savedSearch = query;
+					// parse filter value in case we're comparing numbers ( dates )
+					if ( parsed || parser.type === 'numeric' ) {
+						txt = $.trim( '' + data.iFilter.replace( tsfRegex.operators, '' ) );
+						result = tsf.parseFilter( c, txt, data, true );
+						query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
+					}
+					// iExact may be numeric - see issue #149;
+					// check if cached is defined, because sometimes j goes out of range? ( numeric columns )
+					if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) &&
+						typeof data.cache !== 'undefined' ) {
+						cachedValue = data.cache;
+					} else {
+						txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
+						cachedValue = ts.formatFloat( txt, table );
+					}
+					if ( tsfRegex.gtTest.test( data.iFilter ) ) {
+						result = tsfRegex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
+					} else if ( tsfRegex.ltTest.test( data.iFilter ) ) {
+						result = tsfRegex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
+					}
+					// keep showing all rows if nothing follows the operator
+					if ( !result && savedSearch === '' ) {
+						result = true;
+					}
+					return result;
+				}
+				return null;
+			},
+			// Look for a not match
+			notMatch: function( c, data ) {
+				if ( tsfRegex.notTest.test( data.iFilter ) ) {
+					var indx,
+						txt = data.iFilter.replace( '!', '' ),
+						filter = tsf.parseFilter( c, txt, data ) || '';
+					if ( tsfRegex.exact.test( filter ) ) {
+						// look for exact not matches - see #628
+						filter = filter.replace( tsfRegex.exact, '' );
+						return filter === '' ? true : $.trim( filter ) !== data.iExact;
+					} else {
+						indx = data.iExact.search( $.trim( filter ) );
+						return filter === '' ? true :
+							// return true if not found
+							data.anyMatch ? indx < 0 :
+							// return false if found
+							!( c.widgetOptions.filter_startsWith ? indx === 0 : indx >= 0 );
+					}
+				}
+				return null;
+			},
+			// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
+			exact: function( c, data ) {
+				/*jshint eqeqeq:false */
+				if ( tsfRegex.exact.test( data.iFilter ) ) {
+					var txt = data.iFilter.replace( tsfRegex.exact, '' ),
+						filter = tsf.parseFilter( c, txt, data ) || '';
+					return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
+				}
+				return null;
+			},
+			// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
+			range : function( c, data ) {
+				if ( tsfRegex.toTest.test( data.iFilter ) ) {
+					var result, tmp, range1, range2,
+						table = c.table,
+						index = data.index,
+						parsed = data.parsed[index],
+						// make sure the dash is for a range and not indicating a negative number
+						query = data.iFilter.split( tsfRegex.toSplit );
+
+					tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
+					range1 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
+					tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
+					range2 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
+					// parse filter value in case we're comparing numbers ( dates )
+					if ( parsed || c.parsers[ index ].type === 'numeric' ) {
+						result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
+						range1 = ( result !== '' && !isNaN( result ) ) ? result : range1;
+						result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index );
+						range2 = ( result !== '' && !isNaN( result ) ) ? result : range2;
+					}
+					if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
+						result = data.cache;
+					} else {
+						tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
+						result = ts.formatFloat( tmp, table );
+					}
+					if ( range1 > range2 ) {
+						tmp = range1; range1 = range2; range2 = tmp; // swap
+					}
+					return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' );
+				}
+				return null;
+			},
+			// Look for wild card: ? = single, * = multiple, or | = logical OR
+			wild : function( c, data ) {
+				if ( tsfRegex.wildOrTest.test( data.iFilter ) ) {
+					var query = '' + ( tsf.parseFilter( c, data.iFilter, data ) || '' );
+					// look for an exact match with the 'or' unless the 'filter-match' class is found
+					if ( !tsfRegex.wildTest.test( query ) && data.nestedFilters ) {
+						query = data.isMatch ? query : '^(' + query + ')$';
+					}
+					// parsing the filter may not work properly when using wildcards =/
+					try {
+						return new RegExp(
+							query.replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' ),
+							c.widgetOptions.filter_ignoreCase ? 'i' : ''
+						)
+						.test( data.exact );
+					} catch ( error ) {
+						return null;
+					}
+				}
+				return null;
+			},
+			// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
+			fuzzy: function( c, data ) {
+				if ( tsfRegex.fuzzyTest.test( data.iFilter ) ) {
+					var indx,
+						patternIndx = 0,
+						len = data.iExact.length,
+						txt = data.iFilter.slice( 1 ),
+						pattern = tsf.parseFilter( c, txt, data ) || '';
+					for ( indx = 0; indx < len; indx++ ) {
+						if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
+							patternIndx += 1;
+						}
+					}
+					return patternIndx === pattern.length;
+				}
+				return null;
+			}
+		},
+		init: function( table ) {
+			// filter language options
+			ts.language = $.extend( true, {}, {
+				to  : 'to',
+				or  : 'or',
+				and : 'and'
+			}, ts.language );
+
+			var options, string, txt, $header, column, val, fxn, noSelect,
+				c = table.config,
+				wo = c.widgetOptions;
+			c.$table.addClass( 'hasFilters' );
+			c.lastSearch = [];
+
+			// define timers so using clearTimeout won't cause an undefined error
+			wo.filter_searchTimer = null;
+			wo.filter_initTimer = null;
+			wo.filter_formatterCount = 0;
+			wo.filter_formatterInit = [];
+			wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
+			wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
+
+			val = '\\{' + tsfRegex.query + '\\}';
+			$.extend( tsfRegex, {
+				child : new RegExp( c.cssChildRow ),
+				filtered : new RegExp( wo.filter_filteredRow ),
+				alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ),
+				toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ),
+				toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)', 'gi' ),
+				andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
+				andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
+				orTest : new RegExp( '(\\||\\s+' + ts.language.or + '\\s+)', 'i' ),
+				orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
+				iQuery : new RegExp( val, 'i' ),
+				igQuery : new RegExp( val, 'ig' ),
+				operTest : /^[<>]=?/,
+				gtTest  : />/,
+				gteTest : />=/,
+				ltTest  : /</,
+				lteTest : /<=/,
+				notTest : /^\!/,
+				wildOrTest : /[\?\*\|]/,
+				wildTest : /\?\*/,
+				fuzzyTest : /^~/,
+				exactTest : /[=\"\|!]/
+			});
+
+			// don't build filter row if columnFilters is false or all columns are set to 'filter-false'
+			// see issue #156
+			val = c.$headers.filter( '.filter-false, .parser-false' ).length;
+			if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
+				// build filter row
+				tsf.buildRow( table, c, wo );
+			}
+
+			txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset ' +
+				'filterResetSaved filterEnd search '.split( ' ' ).join( c.namespace + 'filter ' );
+			c.$table.bind( txt, function( event, filter ) {
+				val = wo.filter_hideEmpty &&
+					$.isEmptyObject( c.cache ) &&
+					!( c.delayInit && event.type === 'appendCache' );
+				// hide filter row using the 'filtered' class name
+				c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
+				if ( !/(search|filter)/.test( event.type ) ) {
+					event.stopPropagation();
+					tsf.buildDefault( table, true );
+				}
+				if ( event.type === 'filterReset' ) {
+					c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
+					tsf.searching( table, [] );
+				} else if ( event.type === 'filterResetSaved' ) {
+					ts.storage( table, 'tablesorter-filters', '' );
+				} else if ( event.type === 'filterEnd' ) {
+					tsf.buildDefault( table, true );
+				} else {
+					// send false argument to force a new search; otherwise if the filter hasn't changed,
+					// it will return
+					filter = event.type === 'search' ? filter :
+						event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : '';
+					if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) {
+						// force a new search since content has changed
+						c.lastCombinedFilter = null;
+						c.lastSearch = [];
+						// update filterFormatters after update (& small delay) - Fixes #1237
+						setTimeout(function(){
+							c.$table.triggerHandler( 'filterFomatterUpdate' );
+						}, 100);
+					}
+					// pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
+					// input ensures all inputs are updated when a search is triggered on the table
+					// $( 'table' ).trigger( 'search', [...] );
+					tsf.searching( table, filter, true );
+				}
+				return false;
+			});
+
+			// reset button/link
+			if ( wo.filter_reset ) {
+				if ( wo.filter_reset instanceof $ ) {
+					// reset contains a jQuery object, bind to it
+					wo.filter_reset.click( function() {
+						c.$table.triggerHandler( 'filterReset' );
+					});
+				} else if ( $( wo.filter_reset ).length ) {
+					// reset is a jQuery selector, use event delegation
+					$( document )
+						.undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' )
+						.delegate( wo.filter_reset, 'click' + c.namespace + 'filter', function() {
+							// trigger a reset event, so other functions ( filter_formatter ) know when to reset
+							c.$table.triggerHandler( 'filterReset' );
+						});
+				}
+			}
+			if ( wo.filter_functions ) {
+				for ( column = 0; column < c.columns; column++ ) {
+					fxn = ts.getColumnData( table, wo.filter_functions, column );
+					if ( fxn ) {
+						// remove 'filter-select' from header otherwise the options added here are replaced with
+						// all options
+						$header = c.$headerIndexed[ column ].removeClass( 'filter-select' );
+						// don't build select if 'filter-false' or 'parser-false' set
+						noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
+						options = '';
+						if ( fxn === true && noSelect ) {
+							tsf.buildSelect( table, column );
+						} else if ( typeof fxn === 'object' && noSelect ) {
+							// add custom drop down list
+							for ( string in fxn ) {
+								if ( typeof string === 'string' ) {
+									options += options === '' ?
+										'<option value="">' +
+											( $header.data( 'placeholder' ) ||
+												$header.attr( 'data-placeholder' ) ||
+												wo.filter_placeholder.select ||
+												''
+											) +
+										'</option>' : '';
+									val = string;
+									txt = string;
+									if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
+										val = string.split( wo.filter_selectSourceSeparator );
+										txt = val[1];
+										val = val[0];
+									}
+									options += '<option ' +
+										( txt === val ? '' : 'data-function-name="' + string + '" ' ) +
+										'value="' + val + '">' + txt + '</option>';
+								}
+							}
+							c.$table
+								.find( 'thead' )
+								.find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
+								.append( options );
+							txt = wo.filter_selectSource;
+							fxn = typeof txt === 'function' ? true : ts.getColumnData( table, txt, column );
+							if ( fxn ) {
+								// updating so the extra options are appended
+								tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.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.
+			tsf.buildDefault( table, true );
+
+			tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
+			if ( wo.filter_external ) {
+				tsf.bindSearch( table, wo.filter_external );
+			}
+
+			if ( wo.filter_hideFilters ) {
+				tsf.hideFilters( c );
+			}
+
+			// show processing icon
+			if ( c.showProcessing ) {
+				txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
+				c.$table
+					.unbind( txt.replace( ts.regex.spaces, ' ' ) )
+					.bind( txt, function( event, columns ) {
+					// only add processing to certain columns to all columns
+					$header = ( columns ) ?
+						c.$table
+							.find( '.' + tscss.header )
+							.filter( '[data-column]' )
+							.filter( function() {
+								return columns[ $( this ).data( 'column' ) ] !== '';
+							}) : '';
+					ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' );
+				});
+			}
+
+			// set filtered rows count ( intially unfiltered )
+			c.filteredRows = c.totalRows;
+
+			// add default values
+			txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
+			c.$table
+			.unbind( txt.replace( ts.regex.spaces, ' ' ) )
+			.bind( txt, function() {
+				tsf.completeInit( this );
+			});
+			// if filter widget is added after pager has initialized; then set filter init flag
+			if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
+				c.$table.triggerHandler( 'filterFomatterUpdate' );
+				setTimeout( function() {
+					tsf.filterInitComplete( c );
+				}, 100 );
+			} else if ( !wo.filter_initialized ) {
+				tsf.completeInit( table );
+			}
+		},
+		completeInit: function( table ) {
+			// redefine 'c' & 'wo' so they update properly inside this callback
+			var c = table.config,
+				wo = c.widgetOptions,
+				filters = tsf.setDefaults( table, c, wo ) || [];
+			if ( filters.length ) {
+				// prevent delayInit from triggering a cache build if filters are empty
+				if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
+					ts.setFilters( table, filters, true );
+				}
+			}
+			c.$table.triggerHandler( 'filterFomatterUpdate' );
+			// trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
+			setTimeout( function() {
+				if ( !wo.filter_initialized ) {
+					tsf.filterInitComplete( c );
+				}
+			}, 100 );
+		},
+
+		// $cell parameter, but not the config, is passed to the filter_formatters,
+		// so we have to work with it instead
+		formatterUpdated: function( $cell, column ) {
+			// prevent error if $cell is undefined - see #1056
+			var wo = $cell && $cell.closest( 'table' )[0].config.widgetOptions;
+			if ( wo && !wo.filter_initialized ) {
+				// add updates by column since this function
+				// may be called numerous times before initialization
+				wo.filter_formatterInit[ column ] = 1;
+			}
+		},
+		filterInitComplete: function( c ) {
+			var indx, len,
+				wo = c.widgetOptions,
+				count = 0,
+				completed = function() {
+					wo.filter_initialized = true;
+					// update lastSearch - it gets cleared often
+					c.lastSearch = c.$table.data( 'lastSearch' );
+					c.$table.triggerHandler( 'filterInit', c );
+					tsf.findRows( c.table, c.lastSearch || [] );
+				};
+			if ( $.isEmptyObject( wo.filter_formatter ) ) {
+				completed();
+			} else {
+				len = wo.filter_formatterInit.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					if ( wo.filter_formatterInit[ indx ] === 1 ) {
+						count++;
+					}
+				}
+				clearTimeout( wo.filter_initTimer );
+				if ( !wo.filter_initialized && count === wo.filter_formatterCount ) {
+					// filter widget initialized
+					completed();
+				} else if ( !wo.filter_initialized ) {
+					// fall back in case a filter_formatter doesn't call
+					// $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off
+					wo.filter_initTimer = setTimeout( function() {
+						completed();
+					}, 500 );
+				}
+			}
+		},
+		// encode or decode filters for storage; see #1026
+		processFilters: function( filters, encode ) {
+			var indx,
+				// fixes #1237; previously returning an encoded "filters" value
+				result = [],
+				mode = encode ? encodeURIComponent : decodeURIComponent,
+				len = filters.length;
+			for ( indx = 0; indx < len; indx++ ) {
+				if ( filters[ indx ] ) {
+					result[ indx ] = mode( filters[ indx ] );
+				}
+			}
+			return result;
+		},
+		setDefaults: function( table, c, wo ) {
+			var isArray, saved, indx, col, $filters,
+				// get current ( default ) filters
+				filters = ts.getFilters( table ) || [];
+			if ( wo.filter_saveFilters && ts.storage ) {
+				saved = ts.storage( table, 'tablesorter-filters' ) || [];
+				isArray = $.isArray( saved );
+				// make sure we're not just getting an empty array
+				if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) {
+					filters = tsf.processFilters( saved );
+				}
+			}
+			// if no filters saved, then check default settings
+			if ( filters.join( '' ) === '' ) {
+				// allow adding default setting to external filters
+				$filters = c.$headers.add( wo.filter_$externalFilters )
+					.filter( '[' + wo.filter_defaultAttrib + ']' );
+				for ( indx = 0; indx <= c.columns; indx++ ) {
+					// include data-column='all' external filters
+					col = indx === c.columns ? 'all' : indx;
+					filters[ indx ] = $filters
+						.filter( '[data-column="' + col + '"]' )
+						.attr( wo.filter_defaultAttrib ) || filters[indx] || '';
+				}
+			}
+			c.$table.data( 'lastSearch', filters );
+			return filters;
+		},
+		parseFilter: function( c, filter, data, parsed ) {
+			return parsed || data.parsed[ data.index ] ?
+				c.parsers[ data.index ].format( filter, c.table, [], data.index ) :
+				filter;
+		},
+		buildRow: function( table, c, wo ) {
+			var $filter, col, column, $header, makeSelect, disabled, name, ffxn, tmp,
+				// c.columns defined in computeThIndexes()
+				cellFilter = wo.filter_cellFilter,
+				columns = c.columns,
+				arry = $.isArray( cellFilter ),
+				buildFilter = '<tr role="row" class="' + tscss.filterRow + ' ' + c.cssIgnoreRow + '">';
+			for ( column = 0; column < columns; column++ ) {
+				if ( c.$headerIndexed[ column ].length ) {
+					// account for entire column set with colspan. See #1047
+					tmp = c.$headerIndexed[ column ] && c.$headerIndexed[ column ][0].colSpan || 0;
+					if ( tmp > 1 ) {
+						buildFilter += '<td data-column="' + column + '-' + ( column + tmp - 1 ) + '" colspan="' + tmp + '"';
+					} else {
+						buildFilter += '<td data-column="' + column + '"';
+					}
+					if ( arry ) {
+						buildFilter += ( cellFilter[ column ] ? ' class="' + cellFilter[ column ] + '"' : '' );
+					} else {
+						buildFilter += ( cellFilter !== '' ? ' class="' + cellFilter + '"' : '' );
+					}
+					buildFilter += '></td>';
+				}
+			}
+			c.$filters = $( buildFilter += '</tr>' )
+				.appendTo( c.$table.children( 'thead' ).eq( 0 ) )
+				.children( 'td' );
+			// build each filter input
+			for ( column = 0; column < columns; column++ ) {
+				disabled = false;
+				// assuming last cell of a column is the main column
+				$header = c.$headerIndexed[ column ];
+				if ( $header && $header.length ) {
+					// $filter = c.$filters.filter( '[data-column="' + column + '"]' );
+					$filter = tsf.getColumnElm( c, c.$filters, column );
+					ffxn = ts.getColumnData( table, wo.filter_functions, column );
+					makeSelect = ( wo.filter_functions && ffxn && typeof ffxn !== 'function' ) ||
+						$header.hasClass( 'filter-select' );
+					// get data from jQuery data, metadata, headers option or header class name
+					col = ts.getColumnData( table, c.headers, column );
+					disabled = ts.getData( $header[0], col, 'filter' ) === 'false' ||
+						ts.getData( $header[0], col, 'parser' ) === 'false';
+
+					if ( makeSelect ) {
+						buildFilter = $( '<select>' ).appendTo( $filter );
+					} else {
+						ffxn = ts.getColumnData( table, wo.filter_formatter, column );
+						if ( ffxn ) {
+							wo.filter_formatterCount++;
+							buildFilter = ffxn( $filter, column );
+							// no element returned, so lets go find it
+							if ( buildFilter && buildFilter.length === 0 ) {
+								buildFilter = $filter.children( 'input' );
+							}
+							// element not in DOM, so lets attach it
+							if ( buildFilter && ( buildFilter.parent().length === 0 ||
+								( buildFilter.parent().length && buildFilter.parent()[0] !== $filter[0] ) ) ) {
+								$filter.append( buildFilter );
+							}
+						} else {
+							buildFilter = $( '<input type="search">' ).appendTo( $filter );
+						}
+						if ( buildFilter ) {
+							tmp = $header.data( 'placeholder' ) ||
+								$header.attr( 'data-placeholder' ) ||
+								wo.filter_placeholder.search || '';
+							buildFilter.attr( 'placeholder', tmp );
+						}
+					}
+					if ( buildFilter ) {
+						// add filter class name
+						name = ( $.isArray( wo.filter_cssFilter ) ?
+							( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) :
+							wo.filter_cssFilter ) || '';
+						// copy data-column from table cell (it will include colspan)
+						buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', $filter.attr( 'data-column' ) );
+						if ( disabled ) {
+							buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true;
+						}
+					}
+				}
+			}
+		},
+		bindSearch: function( table, $el, internal ) {
+			table = $( table )[0];
+			$el = $( $el ); // allow passing a selector string
+			if ( !$el.length ) { return; }
+			var tmp,
+				c = table.config,
+				wo = c.widgetOptions,
+				namespace = c.namespace + 'filter',
+				$ext = wo.filter_$externalFilters;
+			if ( internal !== true ) {
+				// save anyMatch element
+				tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector;
+				wo.filter_$anyMatch = $el.filter( tmp );
+				if ( $ext && $ext.length ) {
+					wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el );
+				} else {
+					wo.filter_$externalFilters = $el;
+				}
+				// update values ( external filters added after table initialization )
+				ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false );
+			}
+			// unbind events
+			tmp = ( 'keypress keyup keydown search change input '.split( ' ' ).join( namespace + ' ' ) );
+			$el
+			// use data attribute instead of jQuery data since the head is cloned without including
+			// the data/binding
+			.attr( 'data-lastSearchTime', new Date().getTime() )
+			.unbind( tmp.replace( ts.regex.spaces, ' ' ) )
+			.bind( 'keydown' + namespace, function( event ) {
+				if ( event.which === tskeyCodes.escape && !table.config.widgetOptions.filter_resetOnEsc ) {
+					// prevent keypress event
+					return false;
+				}
+			})
+			.bind( 'keyup' + namespace, function( event ) {
+				wo = table.config.widgetOptions; // make sure "wo" isn't cached
+				var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
+					liveSearch = typeof wo.filter_liveSearch === 'boolean' ? wo.filter_liveSearch :
+						ts.getColumnData( table, wo.filter_liveSearch, column );
+				if ( typeof liveSearch === 'undefined' ) {
+					liveSearch = wo.filter_liveSearch.fallback || false;
+				}
+				$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
+				// emulate what webkit does.... escape clears the filter
+				if ( event.which === tskeyCodes.escape ) {
+					// make sure to restore the last value on escape
+					this.value = wo.filter_resetOnEsc ? '' : c.lastSearch[column];
+				// live search
+				} else if ( liveSearch === false ) {
+					return;
+					// don't return if the search value is empty ( all rows need to be revealed )
+				} else if ( this.value !== '' && (
+					// liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace
+					( typeof liveSearch === 'number' && this.value.length < liveSearch ) ||
+					// let return & backspace continue on, but ignore arrows & non-valid characters
+					( event.which !== tskeyCodes.enter && event.which !== tskeyCodes.backSpace &&
+						( event.which < tskeyCodes.space || ( event.which >= tskeyCodes.left && event.which <= tskeyCodes.down ) ) ) ) ) {
+					return;
+				}
+				// change event = no delay; last true flag tells getFilters to skip newest timed input
+				tsf.searching( table, true, true, column );
+			})
+			// include change for select - fixes #473
+			.bind( 'search change keypress input '.split( ' ' ).join( namespace + ' ' ), function( event ) {
+				// don't get cached data, in case data-column changes dynamically
+				var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
+					liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
+						wo.filter_liveSearch :
+						ts.getColumnData( table, wo.filter_liveSearch, column );
+				if ( table.config.widgetOptions.filter_initialized &&
+					// immediate search if user presses enter
+					( event.which === tskeyCodes.enter ||
+						// immediate search if a "search" is triggered on the input
+						event.type === 'search' ||
+						// change & input events must be ignored if liveSearch !== true
+						( event.type === 'change' || event.type === 'input' ) &&
+						// prevent search if liveSearch is a number
+						liveSearch === true &&
+						// don't allow 'change' or 'input' event to process if the input value
+						// is the same - fixes #685
+						this.value !== c.lastSearch[column]
+					)
+				) {
+					event.preventDefault();
+					// init search with no delay
+					$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
+					tsf.searching( table, event.type !== 'keypress', true, column );
+				}
+			});
+		},
+		searching: function( table, filter, skipFirst, column ) {
+			var liveSearch,
+				wo = table.config.widgetOptions;
+			if (typeof column === 'undefined') {
+				// no delay
+				liveSearch = false;
+			} else {
+				liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
+					wo.filter_liveSearch :
+					// get column setting, or set to fallback value, or default to false
+					ts.getColumnData( table, wo.filter_liveSearch, column );
+				if ( typeof liveSearch === 'undefined' ) {
+					liveSearch = wo.filter_liveSearch.fallback || false;
+				}
+			}
+			clearTimeout( wo.filter_searchTimer );
+			if ( typeof filter === 'undefined' || filter === true ) {
+				// delay filtering
+				wo.filter_searchTimer = setTimeout( function() {
+					tsf.checkFilters( table, filter, skipFirst );
+				}, liveSearch ? wo.filter_searchDelay : 10 );
+			} else {
+				// skip delay
+				tsf.checkFilters( table, filter, skipFirst );
+			}
+		},
+		checkFilters: function( table, filter, skipFirst ) {
+			var c = table.config,
+				wo = c.widgetOptions,
+				filterArray = $.isArray( filter ),
+				filters = ( filterArray ) ? filter : ts.getFilters( table, true ),
+				combinedFilters = ( filters || [] ).join( '' ); // combined filter values
+			// prevent errors if delay init is set
+			if ( $.isEmptyObject( c.cache ) ) {
+				// update cache if delayInit set & pager has initialized ( after user initiates a search )
+				if ( c.delayInit && ( !c.pager || c.pager && c.pager.initialized ) ) {
+					ts.updateCache( c, function() {
+						tsf.checkFilters( table, false, skipFirst );
+					});
+				}
+				return;
+			}
+			// add filter array back into inputs
+			if ( filterArray ) {
+				ts.setFilters( table, filters, false, skipFirst !== true );
+				if ( !wo.filter_initialized ) { c.lastCombinedFilter = ''; }
+			}
+			if ( wo.filter_hideFilters ) {
+				// show/hide filter row as needed
+				c.$table
+					.find( '.' + tscss.filterRow )
+					.triggerHandler( tsf.hideFiltersCheck( c ) ? 'mouseleave' : 'mouseenter' );
+			}
+			// return if the last search is the same; but filter === false when updating the search
+			// see example-widget-filter.html filter toggle buttons
+			if ( c.lastCombinedFilter === combinedFilters && filter !== false ) {
+				return;
+			} else if ( filter === false ) {
+				// force filter refresh
+				c.lastCombinedFilter = null;
+				c.lastSearch = [];
+			}
+			// define filter inside it is false
+			filters = filters || [];
+			// convert filters to strings - see #1070
+			filters = Array.prototype.map ?
+				filters.map( String ) :
+				// for IE8 & older browsers - maybe not the best method
+				filters.join( '\ufffd' ).split( '\ufffd' );
+
+			if ( wo.filter_initialized ) {
+				c.$table.triggerHandler( 'filterStart', [ filters ] );
+			}
+			if ( c.showProcessing ) {
+				// give it time for the processing icon to kick in
+				setTimeout( function() {
+					tsf.findRows( table, filters, combinedFilters );
+					return false;
+				}, 30 );
+			} else {
+				tsf.findRows( table, filters, combinedFilters );
+				return false;
+			}
+		},
+		hideFiltersCheck: function( c ) {
+			if (typeof c.widgetOptions.filter_hideFilters === 'function') {
+				var val = c.widgetOptions.filter_hideFilters( c );
+				if (typeof val === 'boolean') {
+					return val;
+				}
+			}
+			return ts.getFilters( c.$table ).join( '' ) === '';
+		},
+		hideFilters: function( c, $table ) {
+			var timer;
+			( $table || c.$table )
+				.find( '.' + tscss.filterRow )
+				.addClass( tscss.filterRowHide )
+				.bind( 'mouseenter mouseleave', function( e ) {
+					// save event object - http://bugs.jquery.com/ticket/12140
+					var event = e,
+						$row = $( this );
+					clearTimeout( timer );
+					timer = setTimeout( function() {
+						if ( /enter|over/.test( event.type ) ) {
+							$row.removeClass( tscss.filterRowHide );
+						} else {
+							// don't hide if input has focus
+							// $( ':focus' ) needs jQuery 1.6+
+							if ( $( document.activeElement ).closest( 'tr' )[0] !== $row[0] ) {
+								// don't hide row if any filter has a value
+								$row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) );
+							}
+						}
+					}, 200 );
+				})
+				.find( 'input, select' ).bind( 'focus blur', function( e ) {
+					var event = e,
+						$row = $( this ).closest( 'tr' );
+					clearTimeout( timer );
+					timer = setTimeout( function() {
+						clearTimeout( timer );
+						// don't hide row if any filter has a value
+						$row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) && event.type !== 'focus' );
+					}, 200 );
+				});
+		},
+		defaultFilter: function( filter, mask ) {
+			if ( filter === '' ) { return filter; }
+			var regex = tsfRegex.iQuery,
+				maskLen = mask.match( tsfRegex.igQuery ).length,
+				query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
+				len = query.length - 1,
+				indx = 0,
+				val = mask;
+			if ( len < 1 && maskLen > 1 ) {
+				// only one 'word' in query but mask has >1 slots
+				query[1] = query[0];
+			}
+			// 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'
+			while ( regex.test( val ) ) {
+				val = val.replace( regex, query[indx++] || '' );
+				if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) {
+					val = mask.replace( regex, val );
+				}
+			}
+			return val;
+		},
+		getLatestSearch: function( $input ) {
+			if ( $input ) {
+				return $input.sort( function( a, b ) {
+					return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' );
+				});
+			}
+			return $input || $();
+		},
+		findRange: function( c, val, ignoreRanges ) {
+			// look for multiple columns '1-3,4-6,8' in data-column
+			var temp, ranges, range, start, end, singles, i, indx, len,
+				columns = [];
+			if ( /^[0-9]+$/.test( val ) ) {
+				// always return an array
+				return [ parseInt( val, 10 ) ];
+			}
+			// process column range
+			if ( !ignoreRanges && /-/.test( val ) ) {
+				ranges = val.match( /(\d+)\s*-\s*(\d+)/g );
+				len = ranges ? ranges.length : 0;
+				for ( indx = 0; indx < len; indx++ ) {
+					range = ranges[indx].split( /\s*-\s*/ );
+					start = parseInt( range[0], 10 ) || 0;
+					end = parseInt( range[1], 10 ) || ( c.columns - 1 );
+					if ( start > end ) {
+						temp = start; start = end; end = temp; // swap
+					}
+					if ( end >= c.columns ) {
+						end = c.columns - 1;
+					}
+					for ( ; start <= end; start++ ) {
+						columns[ columns.length ] = start;
+					}
+					// remove processed range from val
+					val = val.replace( ranges[ indx ], '' );
+				}
+			}
+			// process single columns
+			if ( !ignoreRanges && /,/.test( val ) ) {
+				singles = val.split( /\s*,\s*/ );
+				len = singles.length;
+				for ( i = 0; i < len; i++ ) {
+					if ( singles[ i ] !== '' ) {
+						indx = parseInt( singles[ i ], 10 );
+						if ( indx < c.columns ) {
+							columns[ columns.length ] = indx;
+						}
+					}
+				}
+			}
+			// return all columns
+			if ( !columns.length ) {
+				for ( indx = 0; indx < c.columns; indx++ ) {
+					columns[ columns.length ] = indx;
+				}
+			}
+			return columns;
+		},
+		getColumnElm: function( c, $elements, column ) {
+			// data-column may contain multiple columns '1-3,5-6,8'
+			// replaces: c.$filters.filter( '[data-column="' + column + '"]' );
+			return $elements.filter( function() {
+				var cols = tsf.findRange( c, $( this ).attr( 'data-column' ) );
+				return $.inArray( column, cols ) > -1;
+			});
+		},
+		multipleColumns: function( c, $input ) {
+			// look for multiple columns '1-3,4-6,8' in data-column
+			var wo = c.widgetOptions,
+				// only target 'all' column inputs on initialization
+				// & don't target 'all' column inputs if they don't exist
+				targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
+				val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
+			return tsf.findRange( c, val, !targets );
+		},
+		processTypes: function( c, data, vars ) {
+			var ffxn,
+				filterMatched = null,
+				matches = null;
+			for ( ffxn in tsf.types ) {
+				if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
+					matches = tsf.types[ffxn]( c, data, vars );
+					if ( matches !== null ) {
+						filterMatched = matches;
+					}
+				}
+			}
+			return filterMatched;
+		},
+		matchType: function( c, columnIndex ) {
+			var isMatch,
+				wo = c.widgetOptions,
+				$el = c.$headerIndexed[ columnIndex ];
+			// filter-exact > filter-match > filter_matchType for type
+			if ( $el.hasClass( 'filter-exact' ) ) {
+				isMatch = false;
+			} else if ( $el.hasClass( 'filter-match' ) ) {
+				isMatch = true;
+			} else {
+				// filter-select is not applied when filter_functions are used, so look for a select
+				if ( wo.filter_columnFilters ) {
+					$el = c.$filters
+						.find( '.' + tscss.filter )
+						.add( wo.filter_$externalFilters )
+						.filter( '[data-column="' + columnIndex + '"]' );
+				} else if ( wo.filter_$externalFilters ) {
+					$el = wo.filter_$externalFilters.filter( '[data-column="' + columnIndex + '"]' );
+				}
+				isMatch = $el.length ?
+					c.widgetOptions.filter_matchType[ ( $el[ 0 ].nodeName || '' ).toLowerCase() ] === 'match' :
+					// default to exact, if no inputs found
+					false;
+			}
+			return isMatch;
+		},
+		processRow: function( c, data, vars ) {
+			var result, filterMatched,
+				fxn, ffxn, txt,
+				wo = c.widgetOptions,
+				showRow = true,
+				hasAnyMatchInput = wo.filter_$anyMatch && wo.filter_$anyMatch.length,
+
+				// 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
+				columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
+					// look for multiple columns '1-3,4-6,8'
+					tsf.multipleColumns( c, wo.filter_$anyMatch ) :
+					[];
+			data.$cells = data.$row.children();
+			if ( data.anyMatchFlag && columnIndex.length > 1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
+				data.anyMatch = true;
+				data.isMatch = true;
+				data.rowArray = data.$cells.map( function( i ) {
+					if ( $.inArray( i, columnIndex ) > -1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
+						if ( data.parsed[ i ] ) {
+							txt = data.cacheArray[ i ];
+						} else {
+							txt = data.rawArray[ i ];
+							txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
+							if ( c.sortLocaleCompare ) {
+								txt = ts.replaceAccents( txt );
+							}
+						}
+						return txt;
+					}
+				}).get();
+				data.filter = data.anyMatchFilter;
+				data.iFilter = data.iAnyMatchFilter;
+				data.exact = data.rowArray.join( ' ' );
+				data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
+				data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
+				vars.excludeMatch = vars.noAnyMatch;
+				filterMatched = tsf.processTypes( c, data, vars );
+				if ( filterMatched !== null ) {
+					showRow = filterMatched;
+				} else {
+					if ( wo.filter_startsWith ) {
+						showRow = false;
+						// data.rowArray may not contain all columns
+						columnIndex = Math.min( c.columns, data.rowArray.length );
+						while ( !showRow && columnIndex > 0 ) {
+							columnIndex--;
+							showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;
+						}
+					} else {
+						showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0;
+					}
+				}
+				data.anyMatch = false;
+				// no other filters to process
+				if ( data.filters.join( '' ) === data.filter ) {
+					return showRow;
+				}
+			}
+
+			for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
+				data.filter = data.filters[ columnIndex ];
+				data.index = columnIndex;
+
+				// filter types to exclude, per column
+				vars.excludeMatch = vars.excludeFilter[ columnIndex ];
+
+				// ignore if filter is empty or disabled
+				if ( data.filter ) {
+					data.cache = data.cacheArray[ columnIndex ];
+					result = data.parsed[ columnIndex ] ? data.cache : data.rawArray[ columnIndex ] || '';
+					data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405
+					data.iExact = !tsfRegex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
+						data.exact.toLowerCase() : data.exact;
+					data.isMatch = tsf.matchType( c, columnIndex );
+
+					result = showRow; // if showRow is true, show that row
+
+					// in case select filter option has a different value vs text 'a - z|A through Z'
+					ffxn = wo.filter_columnFilters ?
+						c.$filters.add( wo.filter_$externalFilters )
+							.filter( '[data-column="' + columnIndex + '"]' )
+							.find( 'select option:selected' )
+							.attr( 'data-function-name' ) || '' : '';
+					// replace accents - see #357
+					if ( c.sortLocaleCompare ) {
+						data.filter = ts.replaceAccents( data.filter );
+					}
+
+					// replace column specific default filters - see #1088
+					if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
+						data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
+					}
+
+					// data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ),
+					// data.filter = case sensitive
+					data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
+					fxn = vars.functions[ columnIndex ];
+					filterMatched = null;
+					if ( fxn ) {
+						if ( fxn === true ) {
+							// default selector uses exact match unless 'filter-match' class is found
+							filterMatched = data.isMatch ?
+								// data.iExact may be a number
+								( '' + data.iExact ).search( data.iFilter ) >= 0 :
+								data.filter === data.exact;
+						} else if ( typeof fxn === 'function' ) {
+							// filter callback( exact cell content, parser normalized content,
+							// filter input value, column index, jQuery row object )
+							filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
+						} else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) {
+							// selector option function
+							txt = ffxn || data.filter;
+							filterMatched =
+								fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
+						}
+					}
+					if ( filterMatched === null ) {
+						// cycle through the different filters
+						// filters return a boolean or null if nothing matches
+						filterMatched = tsf.processTypes( c, data, vars );
+						if ( filterMatched !== null ) {
+							result = filterMatched;
+						// Look for match, and add child row data for matching
+						} else {
+							txt = ( data.iExact + data.childRowText ).indexOf( tsf.parseFilter( c, data.iFilter, data ) );
+							result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
+						}
+					} else {
+						result = filterMatched;
+					}
+					showRow = ( result ) ? showRow : false;
+				}
+			}
+			return showRow;
+		},
+		findRows: function( table, filters, combinedFilters ) {
+			if ( table.config.lastCombinedFilter === combinedFilters ||
+				!table.config.widgetOptions.filter_initialized ) {
+				return;
+			}
+			var len, norm_rows, rowData, $rows, $row, rowIndex, tbodyIndex, $tbody, columnIndex,
+				isChild, childRow, lastSearch, showRow, showParent, time, val, indx,
+				notFiltered, searchFiltered, query, injected, res, id, txt,
+				storedFilters = $.extend( [], filters ),
+				c = table.config,
+				wo = c.widgetOptions,
+				// data object passed to filters; anyMatch is a flag for the filters
+				data = {
+					anyMatch: false,
+					filters: filters,
+					// regex filter type cache
+					filter_regexCache : []
+				},
+				vars = {
+					// anyMatch really screws up with these types of filters
+					noAnyMatch: [ 'range',  'operators' ],
+					// cache filter variables that use ts.getColumnData in the main loop
+					functions : [],
+					excludeFilter : [],
+					defaultColFilter : [],
+					defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || ''
+				};
+
+			// parse columns after formatter, in case the class is added at that point
+			data.parsed = [];
+			for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
+				data.parsed[ columnIndex ] = wo.filter_useParsedData ||
+					// parser has a "parsed" parameter
+					( c.parsers && c.parsers[ columnIndex ] && c.parsers[ columnIndex ].parsed ||
+					// getData may not return 'parsed' if other 'filter-' class names exist
+					// ( e.g. <th class="filter-select filter-parsed"> )
+					ts.getData && ts.getData( c.$headerIndexed[ columnIndex ],
+						ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' ||
+					c.$headerIndexed[ columnIndex ].hasClass( 'filter-parsed' ) );
+
+				vars.functions[ columnIndex ] =
+					ts.getColumnData( table, wo.filter_functions, columnIndex ) ||
+					c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
+				vars.defaultColFilter[ columnIndex ] =
+					ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || '';
+				vars.excludeFilter[ columnIndex ] =
+					( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ );
+			}
+
+			if ( c.debug ) {
+				console.log( 'Filter: Starting filter widget search', filters );
+				time = new Date();
+			}
+			// filtered rows count
+			c.filteredRows = 0;
+			c.totalRows = 0;
+			// combindedFilters are undefined on init
+			combinedFilters = ( storedFilters || [] ).join( '' );
+
+			for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true );
+				// skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel!
+				// $rows = $tbody.children( 'tr' ).not( c.selectorRemove );
+				columnIndex = c.columns;
+				// convert stored rows into a jQuery object
+				norm_rows = c.cache[ tbodyIndex ].normalized;
+				$rows = $( $.map( norm_rows, function( el ) {
+					return el[ columnIndex ].$row.get();
+				}) );
+
+				if ( combinedFilters === '' || wo.filter_serversideFiltering ) {
+					$rows
+						.removeClass( wo.filter_filteredRow )
+						.not( '.' + c.cssChildRow )
+						.css( 'display', '' );
+				} else {
+					// filter out child rows
+					$rows = $rows.not( '.' + c.cssChildRow );
+					len = $rows.length;
+
+					if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) ||
+						typeof filters[c.columns] !== 'undefined' ) {
+						data.anyMatchFlag = true;
+						data.anyMatchFilter = '' + (
+							filters[ c.columns ] ||
+							wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
+							''
+						);
+						if ( wo.filter_columnAnyMatch ) {
+							// specific columns search
+							query = data.anyMatchFilter.split( tsfRegex.andSplit );
+							injected = false;
+							for ( indx = 0; indx < query.length; indx++ ) {
+								res = query[ indx ].split( ':' );
+								if ( res.length > 1 ) {
+									// make the column a one-based index ( non-developers start counting from one :P )
+									if ( isNaN( res[0] ) ) {
+										$.each( c.headerContent, function( i, txt ) {
+											// multiple matches are possible
+											if ( txt.toLowerCase().indexOf( res[0] ) > -1 ) {
+												id = i;
+												filters[ id ] = res[1];
+											}
+										});
+									} else {
+										id = parseInt( res[0], 10 ) - 1;
+									}
+									if ( id >= 0 && id < c.columns ) { // if id is an integer
+										filters[ id ] = res[1];
+										query.splice( indx, 1 );
+										indx--;
+										injected = true;
+									}
+								}
+							}
+							if ( injected ) {
+								data.anyMatchFilter = query.join( ' && ' );
+							}
+						}
+					}
+
+					// optimize searching only through already filtered rows - see #313
+					searchFiltered = wo.filter_searchFiltered;
+					lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || [];
+					if ( searchFiltered ) {
+						// cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669
+						for ( indx = 0; indx < columnIndex + 1; indx++ ) {
+							val = filters[indx] || '';
+							// break out of loop if we've already determined not to search filtered rows
+							if ( !searchFiltered ) { indx = columnIndex; }
+							// search already filtered rows if...
+							searchFiltered = searchFiltered && lastSearch.length &&
+								// there are no changes from beginning of filter
+								val.indexOf( lastSearch[indx] || '' ) === 0 &&
+								// if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
+								!tsfRegex.alreadyFiltered.test( val ) &&
+								// if we are not doing exact matches, using '|' ( logical or ) or not '!'
+								!tsfRegex.exactTest.test( val ) &&
+								// don't search only filtered if the value is negative
+								// ( '> -10' => '> -100' will ignore hidden rows )
+								!( tsfRegex.isNeg1.test( val ) || tsfRegex.isNeg2.test( val ) ) &&
+								// if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
+								!( val !== '' && c.$filters && c.$filters.filter( '[data-column="' + indx + '"]' ).find( 'select' ).length &&
+									!tsf.matchType( c, indx ) );
+						}
+					}
+					notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length;
+					// can't search when all rows are hidden - this happens when looking for exact matches
+					if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; }
+					if ( c.debug ) {
+						console.log( 'Filter: Searching through ' +
+							( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' );
+					}
+					if ( data.anyMatchFlag ) {
+						if ( c.sortLocaleCompare ) {
+							// replace accents
+							data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
+						}
+						if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultAnyFilter ) ) {
+							data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
+							// clear search filtered flag because default filters are not saved to the last search
+							searchFiltered = false;
+						}
+						// make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true
+						// when c.ignoreCase is true, the cache contains all lower case data
+						data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ?
+							data.anyMatchFilter :
+							data.anyMatchFilter.toLowerCase();
+					}
+
+					// loop through the rows
+					for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
+
+						txt = $rows[ rowIndex ].className;
+						// the first row can never be a child row
+						isChild = rowIndex && tsfRegex.child.test( txt );
+						// skip child rows & already filtered rows
+						if ( isChild || ( searchFiltered && tsfRegex.filtered.test( txt ) ) ) {
+							continue;
+						}
+
+						data.$row = $rows.eq( rowIndex );
+						data.rowIndex = rowIndex;
+						data.cacheArray = norm_rows[ rowIndex ];
+						rowData = data.cacheArray[ c.columns ];
+						data.rawArray = rowData.raw;
+						data.childRowText = '';
+
+						if ( !wo.filter_childByColumn ) {
+							txt = '';
+							// child row cached text
+							childRow = rowData.child;
+							// 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 ( indx = 0; indx < childRow.length; indx++ ) {
+								txt += ' ' + childRow[indx].join( ' ' ) || '';
+							}
+							data.childRowText = wo.filter_childRows ?
+								( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) :
+								'';
+						}
+
+						showRow = false;
+						showParent = tsf.processRow( c, data, vars );
+						$row = rowData.$row;
+
+						// don't pass reference to val
+						val = showParent ? true : false;
+						childRow = rowData.$row.filter( ':gt(0)' );
+						if ( wo.filter_childRows && childRow.length ) {
+							if ( wo.filter_childByColumn ) {
+								if ( !wo.filter_childWithSibs ) {
+									// hide all child rows
+									childRow.addClass( wo.filter_filteredRow );
+									// if only showing resulting child row, only include parent
+									$row = $row.eq( 0 );
+								}
+								// cycle through each child row
+								for ( indx = 0; indx < childRow.length; indx++ ) {
+									data.$row = childRow.eq( indx );
+									data.cacheArray = rowData.child[ indx ];
+									data.rawArray = data.cacheArray;
+									val = tsf.processRow( c, data, vars );
+									// use OR comparison on child rows
+									showRow = showRow || val;
+									if ( !wo.filter_childWithSibs && val ) {
+										childRow.eq( indx ).removeClass( wo.filter_filteredRow );
+									}
+								}
+							}
+							// keep parent row match even if no child matches... see #1020
+							showRow = showRow || showParent;
+						} else {
+							showRow = val;
+						}
+						$row
+							.toggleClass( wo.filter_filteredRow, !showRow )[0]
+							.display = showRow ? '' : 'none';
+					}
+				}
+				c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length;
+				c.totalRows += $rows.length;
+				ts.processTbody( table, $tbody, false );
+			}
+			c.lastCombinedFilter = combinedFilters; // save last search
+			// don't save 'filters' directly since it may have altered ( AnyMatch column searches )
+			c.lastSearch = storedFilters;
+			c.$table.data( 'lastSearch', storedFilters );
+			if ( wo.filter_saveFilters && ts.storage ) {
+				ts.storage( table, 'tablesorter-filters', tsf.processFilters( storedFilters, true ) );
+			}
+			if ( c.debug ) {
+				console.log( 'Completed filter widget search' + ts.benchmark(time) );
+			}
+			if ( wo.filter_initialized ) {
+				c.$table.triggerHandler( 'filterBeforeEnd', c );
+				c.$table.triggerHandler( 'filterEnd', c );
+			}
+			setTimeout( function() {
+				ts.applyWidget( c.table ); // make sure zebra widget is applied
+			}, 0 );
+		},
+		getOptionSource: function( table, column, onlyAvail ) {
+			table = $( table )[0];
+			var c = table.config,
+				wo = c.widgetOptions,
+				arry = false,
+				source = wo.filter_selectSource,
+				last = c.$table.data( 'lastSearch' ) || [],
+				fxn = typeof source === 'function' ? true : ts.getColumnData( table, source, column );
+
+			if ( onlyAvail && last[column] !== '' ) {
+				onlyAvail = false;
+			}
+
+			// filter select source option
+			if ( fxn === true ) {
+				// OVERALL source
+				arry = source( table, column, onlyAvail );
+			} else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '</option>' ) >= 0 ) ) {
+				// selectSource is a jQuery object or string of options
+				return fxn;
+			} else if ( $.isArray( fxn ) ) {
+				arry = fxn;
+			} else if ( $.type( source ) === 'object' && fxn ) {
+				// custom select source function for a SPECIFIC COLUMN
+				arry = fxn( table, column, onlyAvail );
+			}
+			if ( arry === false ) {
+				// fall back to original method
+				arry = tsf.getOptions( table, column, onlyAvail );
+			}
+
+			return tsf.processOptions( table, column, arry );
+
+		},
+		processOptions: function( table, column, arry ) {
+			if ( !$.isArray( arry ) ) {
+				return false;
+			}
+			table = $( table )[0];
+			var cts, txt, indx, len, parsedTxt, str,
+				c = table.config,
+				validColumn = typeof column !== 'undefined' && column !== null && column >= 0 && column < c.columns,
+				direction = validColumn ? c.$headerIndexed[ column ].hasClass( 'filter-select-sort-desc' ) : false,
+				parsed = [];
+			// get unique elements and sort the list
+			// if $.tablesorter.sortText exists ( not in the original tablesorter ),
+			// then natural sort the list otherwise use a basic sort
+			arry = $.grep( arry, function( value, indx ) {
+				if ( value.text ) {
+					return true;
+				}
+				return $.inArray( value, arry ) === indx;
+			});
+			if ( validColumn && c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) {
+				// unsorted select options
+				return arry;
+			} else {
+				len = arry.length;
+				// parse select option values
+				for ( indx = 0; indx < len; indx++ ) {
+					txt = arry[ indx ];
+					// check for object
+					str = txt.text ? txt.text : txt;
+					// sortNatural breaks if you don't pass it strings
+					parsedTxt = ( validColumn && c.parsers && c.parsers.length &&
+						c.parsers[ column ].format( str, table, [], column ) || str ).toString();
+					parsedTxt = c.widgetOptions.filter_ignoreCase ? parsedTxt.toLowerCase() : parsedTxt;
+					// parse array data using set column parser; this DOES NOT pass the original
+					// table cell to the parser format function
+					if ( txt.text ) {
+						txt.parsed = parsedTxt;
+						parsed[ parsed.length ] = txt;
+					} else {
+						parsed[ parsed.length ] = {
+							text : txt,
+							// check parser length - fixes #934
+							parsed : parsedTxt
+						};
+					}
+				}
+				// sort parsed select options
+				cts = c.textSorter || '';
+				parsed.sort( function( a, b ) {
+					var x = direction ? b.parsed : a.parsed,
+						y = direction ? a.parsed : b.parsed;
+					if ( validColumn && typeof cts === 'function' ) {
+						// custom OVERALL text sorter
+						return cts( x, y, true, column, table );
+					} else if ( validColumn && typeof cts === 'object' && cts.hasOwnProperty( column ) ) {
+						// custom text sorter for a SPECIFIC COLUMN
+						return cts[column]( x, y, true, column, table );
+					} else if ( ts.sortNatural ) {
+						// fall back to natural sort
+						return ts.sortNatural( x, y );
+					}
+					// using an older version! do a basic sort
+					return true;
+				});
+				// rebuild arry from sorted parsed data
+				arry = [];
+				len = parsed.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					arry[ arry.length ] = parsed[indx];
+				}
+				return arry;
+			}
+		},
+		getOptions: function( table, column, onlyAvail ) {
+			table = $( table )[0];
+			var rowIndex, tbodyIndex, len, row, cache, indx, child, childLen,
+				c = table.config,
+				wo = c.widgetOptions,
+				arry = [];
+			for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
+				cache = c.cache[tbodyIndex];
+				len = c.cache[tbodyIndex].normalized.length;
+				// loop through the rows
+				for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
+					// get cached row from cache.row ( old ) or row data object
+					// ( new; last item in normalized array )
+					row = cache.row ?
+						cache.row[ rowIndex ] :
+						cache.normalized[ rowIndex ][ c.columns ].$row[0];
+					// check if has class filtered
+					if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) {
+						continue;
+					}
+					// get non-normalized cell content
+					if ( wo.filter_useParsedData ||
+						c.parsers[column].parsed ||
+						c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) {
+						arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ column ];
+						// child row parsed data
+						if ( wo.filter_childRows && wo.filter_childByColumn ) {
+							childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length - 1;
+							for ( indx = 0; indx < childLen; indx++ ) {
+								arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ c.columns ].child[ indx ][ column ];
+							}
+						}
+					} else {
+						// get raw cached data instead of content directly from the cells
+						arry[ arry.length ] = cache.normalized[ rowIndex ][ c.columns ].raw[ column ];
+						// child row unparsed data
+						if ( wo.filter_childRows && wo.filter_childByColumn ) {
+							childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length;
+							for ( indx = 1; indx < childLen; indx++ ) {
+								child =  cache.normalized[ rowIndex ][ c.columns ].$row.eq( indx ).children().eq( column );
+								arry[ arry.length ] = '' + ts.getElementText( c, child, column );
+							}
+						}
+					}
+				}
+			}
+			return arry;
+		},
+		buildSelect: function( table, column, arry, updating, onlyAvail ) {
+			table = $( table )[0];
+			column = parseInt( column, 10 );
+			if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) {
+				return;
+			}
+
+			var indx, val, txt, t, $filters, $filter, option,
+				c = table.config,
+				wo = c.widgetOptions,
+				node = c.$headerIndexed[ column ],
+				// t.data( 'placeholder' ) won't work in jQuery older than 1.4.3
+				options = '<option value="">' +
+					( node.data( 'placeholder' ) ||
+						node.attr( 'data-placeholder' ) ||
+						wo.filter_placeholder.select || ''
+					) + '</option>',
+				// Get curent filter value
+				currentValue = c.$table
+					.find( 'thead' )
+					.find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
+					.val();
+
+			// nothing included in arry ( external source ), so get the options from
+			// filter_selectSource or column data
+			if ( typeof arry === 'undefined' || arry === '' ) {
+				arry = tsf.getOptionSource( table, column, onlyAvail );
+			}
+
+			if ( $.isArray( arry ) ) {
+				// build option list
+				for ( indx = 0; indx < arry.length; indx++ ) {
+					option = arry[ indx ];
+					if ( option.text ) {
+						// OBJECT!! add data-function-name in case the value is set in filter_functions
+						option['data-function-name'] = typeof option.value === 'undefined' ? option.text : option.value;
+
+						// support jQuery < v1.8, otherwise the below code could be shortened to
+						// options += $( '<option>', option )[ 0 ].outerHTML;
+						options += '<option';
+						for ( val in option ) {
+							if ( option.hasOwnProperty( val ) && val !== 'text' ) {
+								options += ' ' + val + '="' + option[ val ] + '"';
+							}
+						}
+						if ( !option.value ) {
+							options += ' value="' + option.text + '"';
+						}
+						options += '>' + option.text + '</option>';
+						// above code is needed in jQuery < v1.8
+
+						// make sure we don't turn an object into a string (objects without a "text" property)
+					} else if ( '' + option !== '[object Object]' ) {
+						txt = option = ( '' + option ).replace( tsfRegex.quote, '&quot;' );
+						val = txt;
+						// allow including a symbol in the selectSource array
+						// 'a-z|A through Z' so that 'a-z' becomes the option value
+						// and 'A through Z' becomes the option text
+						if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
+							t = txt.split( wo.filter_selectSourceSeparator );
+							val = t[0];
+							txt = t[1];
+						}
+						// replace quotes - fixes #242 & ignore empty strings
+						// see http://stackoverflow.com/q/14990971/145346
+						options += option !== '' ?
+							'<option ' +
+								( val === txt ? '' : 'data-function-name="' + option + '" ' ) +
+								'value="' + val + '">' + txt +
+							'</option>' : '';
+					}
+				}
+				// clear arry so it doesn't get appended twice
+				arry = [];
+			}
+
+			// update all selects in the same column ( clone thead in sticky headers &
+			// any external selects ) - fixes 473
+			$filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) )
+				.find( '.' + tscss.filter );
+			if ( wo.filter_$externalFilters ) {
+				$filters = $filters && $filters.length ?
+					$filters.add( wo.filter_$externalFilters ) :
+					wo.filter_$externalFilters;
+			}
+			$filter = $filters.filter( 'select[data-column="' + column + '"]' );
+
+			// make sure there is a select there!
+			if ( $filter.length ) {
+				$filter[ updating ? 'html' : 'append' ]( options );
+				if ( !$.isArray( arry ) ) {
+					// append options if arry is provided externally as a string or jQuery object
+					// options ( default value ) was already added
+					$filter.append( arry ).val( currentValue );
+				}
+				$filter.val( currentValue );
+			}
+		},
+		buildDefault: function( table, updating ) {
+			var columnIndex, $header, noSelect,
+				c = table.config,
+				wo = c.widgetOptions,
+				columns = c.columns;
+			// build default select dropdown
+			for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) {
+				$header = c.$headerIndexed[columnIndex];
+				noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
+				// look for the filter-select class; build/update it if found
+				if ( ( $header.hasClass( 'filter-select' ) ||
+					ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
+					tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
+				}
+			}
+		}
+	};
+
+	// filter regex variable
+	tsfRegex = tsf.regex;
+
+	ts.getFilters = function( table, getRaw, setFilters, skipFirst ) {
+		var i, $filters, $column, cols,
+			filters = [],
+			c = table ? $( table )[0].config : '',
+			wo = c ? c.widgetOptions : '';
+		if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) ||
+			// setFilters called, but last search is exactly the same as the current
+			// fixes issue #733 & #903 where calling update causes the input values to reset
+			( $.isArray(setFilters) && setFilters.join('') === c.lastCombinedFilter ) ) {
+			return $( table ).data( 'lastSearch' );
+		}
+		if ( c ) {
+			if ( c.$filters ) {
+				$filters = c.$filters.find( '.' + tscss.filter );
+			}
+			if ( wo.filter_$externalFilters ) {
+				$filters = $filters && $filters.length ?
+					$filters.add( wo.filter_$externalFilters ) :
+					wo.filter_$externalFilters;
+			}
+			if ( $filters && $filters.length ) {
+				filters = setFilters || [];
+				for ( i = 0; i < c.columns + 1; i++ ) {
+					cols = ( i === c.columns ?
+						// 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' )
+						wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector :
+						'[data-column="' + i + '"]' );
+					$column = $filters.filter( cols );
+					if ( $column.length ) {
+						// move the latest search to the first slot in the array
+						$column = tsf.getLatestSearch( $column );
+						if ( $.isArray( setFilters ) ) {
+							// skip first ( latest input ) to maintain cursor position while typing
+							if ( skipFirst && $column.length > 1 ) {
+								$column = $column.slice( 1 );
+							}
+							if ( i === c.columns ) {
+								// prevent data-column='all' from filling data-column='0,1' ( etc )
+								cols = $column.filter( wo.filter_anyColumnSelector );
+								$column = cols.length ? cols : $column;
+							}
+							$column
+								.val( setFilters[ i ] )
+								// must include a namespace here; but not c.namespace + 'filter'?
+								.trigger( 'change' + c.namespace );
+						} else {
+							filters[i] = $column.val() || '';
+							// don't change the first... it will move the cursor
+							if ( i === c.columns ) {
+								// don't update range columns from 'all' setting
+								$column
+									.slice( 1 )
+									.filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' )
+									.val( filters[ i ] );
+							} else {
+								$column
+									.slice( 1 )
+									.val( filters[ i ] );
+							}
+						}
+						// save any match input dynamically
+						if ( i === c.columns && $column.length ) {
+							wo.filter_$anyMatch = $column;
+						}
+					}
+				}
+			}
+		}
+		return filters;
+	};
+
+	ts.setFilters = function( table, filter, apply, skipFirst ) {
+		var c = table ? $( table )[0].config : '',
+			valid = ts.getFilters( table, true, filter, skipFirst );
+		// default apply to "true"
+		if ( typeof apply === 'undefined' ) {
+			apply = true;
+		}
+		if ( c && apply ) {
+			// ensure new set filters are applied, even if the search is the same
+			c.lastCombinedFilter = null;
+			c.lastSearch = [];
+			tsf.searching( c.table, filter, skipFirst );
+			c.$table.triggerHandler( 'filterFomatterUpdate' );
+		}
+		return valid.length !== 0;
+	};
+
+})( jQuery );
+
+/*! Widget: stickyHeaders - updated 1/6/2017 (v2.28.4) *//*
+ * Requires tablesorter v2.8+ and jQuery 1.4.3+
+ * by Rob Garrison
+ */
+;(function ($, window) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	$.extend(ts.css, {
+		sticky    : 'tablesorter-stickyHeader', // stickyHeader
+		stickyVis : 'tablesorter-sticky-visible',
+		stickyHide: 'tablesorter-sticky-hidden',
+		stickyWrap: 'tablesorter-sticky-wrapper'
+	});
+
+	// Add a resize event to table headers
+	ts.addHeaderResizeEvent = function(table, disable, settings) {
+		table = $(table)[0]; // make sure we're using a dom element
+		if ( !table.config ) { return; }
+		var defaults = {
+				timer : 250
+			},
+			options = $.extend({}, defaults, settings),
+			c = table.config,
+			wo = c.widgetOptions,
+			checkSizes = function( triggerEvent ) {
+				var index, headers, $header, sizes, width, height,
+					len = c.$headers.length;
+				wo.resize_flag = true;
+				headers = [];
+				for ( index = 0; index < len; index++ ) {
+					$header = c.$headers.eq( index );
+					sizes = $header.data( 'savedSizes' ) || [ 0, 0 ]; // fixes #394
+					width = $header[0].offsetWidth;
+					height = $header[0].offsetHeight;
+					if ( width !== sizes[0] || height !== sizes[1] ) {
+						$header.data( 'savedSizes', [ width, height ] );
+						headers.push( $header[0] );
+					}
+				}
+				if ( headers.length && triggerEvent !== false ) {
+					c.$table.triggerHandler( 'resize', [ headers ] );
+				}
+				wo.resize_flag = false;
+			};
+		clearInterval(wo.resize_timer);
+		if (disable) {
+			wo.resize_flag = false;
+			return false;
+		}
+		checkSizes( false );
+		wo.resize_timer = setInterval(function() {
+			if (wo.resize_flag) { return; }
+			checkSizes();
+		}, options.timer);
+	};
+
+	// Sticky headers based on this awesome article:
+	// http://css-tricks.com/13465-persistent-headers/
+	// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
+	// **************************
+	ts.addWidget({
+		id: 'stickyHeaders',
+		priority: 54, // sticky widget must be initialized after the filter & before pager widget!
+		options: {
+			stickyHeaders : '',       // extra class name added to the sticky header row
+			stickyHeaders_appendTo : null, // jQuery selector or object to phycially attach the sticky headers
+			stickyHeaders_attachTo : null, // jQuery selector or object to attach scroll listener to (overridden by xScroll & yScroll settings)
+			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: true, // scroll table top into view after filtering
+			stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists
+			stickyHeaders_addResizeEvent : true, // trigger 'resize' event on headers
+			stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header
+			stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs
+		},
+		format: function(table, c, wo) {
+			// filter widget doesn't initialize on an empty table. Fixes #449
+			if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) {
+				return;
+			}
+			var index, len, $t,
+				$table = c.$table,
+				// add position: relative to attach element, hopefully it won't cause trouble.
+				$attach = $(wo.stickyHeaders_attachTo),
+				namespace = c.namespace + 'stickyheaders ',
+				// element to watch for the scroll event
+				$yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window),
+				$xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window),
+				$thead = $table.children('thead:first'),
+				$header = $thead.children('tr').not('.sticky-false').children(),
+				$tfoot = $table.children('tfoot'),
+				$stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '',
+				stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0,
+				// is this table nested? If so, find parent sticky header wrapper (div, not table)
+				$nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ?
+					$table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [],
+				nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0,
+				// clone table, then wrap to make sticky header
+				$stickyTable = wo.$sticky = $table.clone()
+					.addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders + ' ' + c.namespace.slice(1) + '_extra_table' )
+					.wrap('<div class="' + ts.css.stickyWrap + '">'),
+				$stickyWrap = $stickyTable.parent()
+					.addClass(ts.css.stickyHide)
+					.css({
+						position   : $attach.length ? 'absolute' : 'fixed',
+						padding    : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ),
+						top        : stickyOffset + nestedStickyTop,
+						left       : 0,
+						visibility : 'hidden',
+						zIndex     : wo.stickyHeaders_zIndex || 2
+					}),
+				$stickyThead = $stickyTable.children('thead:first'),
+				$stickyCells,
+				laststate = '',
+				spacing = 0,
+				setWidth = function($orig, $clone){
+					var index, width, border, $cell, $this,
+						$cells = $orig.filter(':visible'),
+						len = $cells.length;
+					for ( index = 0; index < len; index++ ) {
+						$cell = $clone.filter(':visible').eq(index);
+						$this = $cells.eq(index);
+						// code from https://github.com/jmosbech/StickyTableHeaders
+						if ($this.css('box-sizing') === 'border-box') {
+							width = $this.outerWidth();
+						} else {
+							if ($cell.css('border-collapse') === 'collapse') {
+								if (window.getComputedStyle) {
+									width = parseFloat( window.getComputedStyle($this[0], null).width );
+								} else {
+									// ie8 only
+									border = parseFloat( $this.css('border-width') );
+									width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border;
+								}
+							} else {
+								width = $this.width();
+							}
+						}
+						$cell.css({
+							'width': width,
+							'min-width': width,
+							'max-width': width
+						});
+					}
+				},
+				resizeHeader = function() {
+					stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0;
+					spacing = 0;
+					$stickyWrap.css({
+						left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 :
+								$table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing,
+						width: $table.outerWidth()
+					});
+					setWidth( $table, $stickyTable );
+					setWidth( $header, $stickyCells );
+				},
+				scrollSticky = function( resizing ) {
+					if (!$table.is(':visible')) { return; } // fixes #278
+					// Detect nested tables - fixes #724
+					nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
+					var offset = $table.offset(),
+						yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
+						xWindow = $.isWindow( $xScroll[0] ),
+						attachTop = $attach.length ?
+							( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) :
+							$yScroll.scrollTop(),
+						captionHeight = wo.stickyHeaders_includeCaption ? 0 : $table.children( 'caption' ).height() || 0,
+						scrollTop = attachTop + stickyOffset + nestedStickyTop - captionHeight,
+						tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)) - captionHeight,
+						isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
+						cssSettings = { visibility : isVisible };
+					if ($attach.length) {
+						cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
+					}
+					if (xWindow) {
+						// adjust when scrolling horizontally - fixes issue #143
+						cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
+					}
+					if ($nestedSticky.length) {
+						cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
+					}
+					$stickyWrap
+						.removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
+						.addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide )
+						.css(cssSettings);
+					if (isVisible !== laststate || resizing) {
+						// make sure the column widths match
+						resizeHeader();
+						laststate = isVisible;
+					}
+				};
+			// only add a position relative if a position isn't already defined
+			if ($attach.length && !$attach.css('position')) {
+				$attach.css('position', 'relative');
+			}
+			// fix clone ID, if it exists - fixes #271
+			if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.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
+			$stickyTable.find('thead:gt(0), tr.sticky-false').hide();
+			$stickyTable.find('tbody, tfoot').remove();
+			$stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption);
+			// issue #172 - find td/th in sticky header
+			$stickyCells = $stickyThead.children().children();
+			$stickyTable.css({ height:0, width:0, margin: 0 });
+			// remove resizable block
+			$stickyCells.find('.' + ts.css.resizer).remove();
+			// update sticky header class names to match real header after sorting
+			$table
+				.addClass('hasStickyHeaders')
+				.bind('pagerComplete' + namespace, function() {
+					resizeHeader();
+				});
+
+			ts.bindEvents(table, $stickyThead.children().children('.' + ts.css.header));
+
+			if (wo.stickyHeaders_appendTo) {
+				$(wo.stickyHeaders_appendTo).append( $stickyWrap );
+			} else {
+				// add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned.
+				$table.after( $stickyWrap );
+			}
+
+			// onRenderHeader is defined, we need to do something about it (fixes #641)
+			if (c.onRenderHeader) {
+				$t = $stickyThead.children('tr').children();
+				len = $t.length;
+				for ( index = 0; index < len; index++ ) {
+					// send second parameter
+					c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] );
+				}
+			}
+
+			// make it sticky!
+			$xScroll.add($yScroll)
+				.unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
+				.bind('scroll resize '.split(' ').join( namespace ), function( event ) {
+					scrollSticky( event.type === 'resize' );
+				});
+			c.$table
+				.unbind('stickyHeadersUpdate' + namespace)
+				.bind('stickyHeadersUpdate' + namespace, function(){
+					scrollSticky( true );
+				});
+
+			if (wo.stickyHeaders_addResizeEvent) {
+				ts.addHeaderResizeEvent(table);
+			}
+
+			// look for filter widget
+			if ($table.hasClass('hasFilters') && wo.filter_columnFilters) {
+				// scroll table into view after filtering, if sticky header is active - #482
+				$table.bind('filterEnd' + namespace, function() {
+					// $(':focus') needs jQuery 1.6+
+					var $td = $(document.activeElement).closest('td'),
+						column = $td.parent().children().index($td);
+					// only scroll if sticky header is active
+					if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) {
+						// scroll to original table (not sticky clone)
+						window.scrollTo(0, $table.position().top);
+						// give same input/select focus; check if c.$filters exists; fixes #594
+						if (column >= 0 && c.$filters) {
+							c.$filters.eq(column).find('a, select, input').filter(':visible').focus();
+						}
+					}
+				});
+				ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) );
+				// support hideFilters
+				if (wo.filter_hideFilters) {
+					ts.filter.hideFilters(c, $stickyTable);
+				}
+			}
+
+			// resize table (Firefox)
+			if (wo.stickyHeaders_addResizeEvent) {
+				$table.bind('resize' + c.namespace + 'stickyheaders', function() {
+					resizeHeader();
+				});
+			}
+
+			$table.triggerHandler('stickyHeadersInit');
+
+		},
+		remove: function(table, c, wo) {
+			var namespace = c.namespace + 'stickyheaders ';
+			c.$table
+				.removeClass('hasStickyHeaders')
+				.unbind( ('pagerComplete resize filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
+				.next('.' + ts.css.stickyWrap).remove();
+			if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
+			$(window)
+				.add(wo.stickyHeaders_xScroll)
+				.add(wo.stickyHeaders_yScroll)
+				.add(wo.stickyHeaders_attachTo)
+				.unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') );
+			ts.addHeaderResizeEvent(table, true);
+		}
+	});
+
+})(jQuery, window);
+
+/*! Widget: resizable - updated 12/15/2016 (v2.28.2) */
+/*jshint browser:true, jquery:true, unused:false */
+;(function ($, window) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	$.extend(ts.css, {
+		resizableContainer : 'tablesorter-resizable-container',
+		resizableHandle    : 'tablesorter-resizable-handle',
+		resizableNoSelect  : 'tablesorter-disableSelection',
+		resizableStorage   : 'tablesorter-resizable'
+	});
+
+	// Add extra scroller css
+	$(function(){
+		var s = '<style>' +
+			'body.' + ts.css.resizableNoSelect + ' { -ms-user-select: none; -moz-user-select: -moz-none;' +
+				'-khtml-user-select: none; -webkit-user-select: none; user-select: none; }' +
+			'.' + ts.css.resizableContainer + ' { position: relative; height: 1px; }' +
+			// make handle z-index > than stickyHeader z-index, so the handle stays above sticky header
+			'.' + ts.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>';
+		$('head').append(s);
+	});
+
+	ts.resizable = {
+		init : function( c, wo ) {
+			if ( c.$table.hasClass( 'hasResizable' ) ) { return; }
+			c.$table.addClass( 'hasResizable' );
+
+			var noResize, $header, column, storedSizes, tmp,
+				$table = c.$table,
+				$parent = $table.parent(),
+				marginTop = parseInt( $table.css( 'margin-top' ), 10 ),
+
+			// internal variables
+			vars = wo.resizable_vars = {
+				useStorage : ts.storage && wo.resizable !== false,
+				$wrap : $parent,
+				mouseXPosition : 0,
+				$target : null,
+				$next : null,
+				overflow : $parent.css('overflow') === 'auto' ||
+					$parent.css('overflow') === 'scroll' ||
+					$parent.css('overflow-x') === 'auto' ||
+					$parent.css('overflow-x') === 'scroll',
+				storedSizes : []
+			};
+
+			// set default widths
+			ts.resizableReset( c.table, true );
+
+			// now get measurements!
+			vars.tableWidth = $table.width();
+			// attempt to autodetect
+			vars.fullWidth = Math.abs( $parent.width() - vars.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>');
+			}
+			*/
+
+			if ( vars.useStorage && vars.overflow ) {
+				// save table width
+				ts.storage( c.table, 'tablesorter-table-original-css-width', vars.tableWidth );
+				tmp = ts.storage( c.table, 'tablesorter-table-resized-width' ) || 'auto';
+				ts.resizable.setWidth( $table, tmp, true );
+			}
+			wo.resizable_vars.storedSizes = storedSizes = ( vars.useStorage ?
+				ts.storage( c.table, ts.css.resizableStorage ) :
+				[] ) || [];
+			ts.resizable.setWidths( c, wo, storedSizes );
+			ts.resizable.updateStoredSizes( c, wo );
+
+			wo.$resizable_container = $( '<div class="' + ts.css.resizableContainer + '">' )
+				.css({ top : marginTop })
+				.insertBefore( $table );
+			// add container
+			for ( column = 0; column < c.columns; column++ ) {
+				$header = c.$headerIndexed[ column ];
+				tmp = ts.getColumnData( c.table, c.headers, column );
+				noResize = ts.getData( $header, tmp, 'resizable' ) === 'false';
+				if ( !noResize ) {
+					$( '<div class="' + ts.css.resizableHandle + '">' )
+						.appendTo( wo.$resizable_container )
+						.attr({
+							'data-column' : column,
+							'unselectable' : 'on'
+						})
+						.data( 'header', $header )
+						.bind( 'selectstart', false );
+				}
+			}
+			ts.resizable.bindings( c, wo );
+		},
+
+		updateStoredSizes : function( c, wo ) {
+			var column, $header,
+				len = c.columns,
+				vars = wo.resizable_vars;
+			vars.storedSizes = [];
+			for ( column = 0; column < len; column++ ) {
+				$header = c.$headerIndexed[ column ];
+				vars.storedSizes[ column ] = $header.is(':visible') ? $header.width() : 0;
+			}
+		},
+
+		setWidth : function( $el, width, overflow ) {
+			// overflow tables need min & max width set as well
+			$el.css({
+				'width' : width,
+				'min-width' : overflow ? width : '',
+				'max-width' : overflow ? width : ''
+			});
+		},
+
+		setWidths : function( c, wo, storedSizes ) {
+			var column, $temp,
+				vars = wo.resizable_vars,
+				$extra = $( c.namespace + '_extra_headers' ),
+				$col = c.$table.children( 'colgroup' ).children( 'col' );
+			storedSizes = storedSizes || vars.storedSizes || [];
+			// process only if table ID or url match
+			if ( storedSizes.length ) {
+				for ( column = 0; column < c.columns; column++ ) {
+					// set saved resizable widths
+					ts.resizable.setWidth( c.$headerIndexed[ column ], storedSizes[ column ], vars.overflow );
+					if ( $extra.length ) {
+						// stickyHeaders needs to modify min & max width as well
+						$temp = $extra.eq( column ).add( $col.eq( column ) );
+						ts.resizable.setWidth( $temp, storedSizes[ column ], vars.overflow );
+					}
+				}
+				$temp = $( c.namespace + '_extra_table' );
+				if ( $temp.length && !ts.hasWidget( c.table, 'scroller' ) ) {
+					ts.resizable.setWidth( $temp, c.$table.outerWidth(), vars.overflow );
+				}
+			}
+		},
+
+		setHandlePosition : function( c, wo ) {
+			var startPosition,
+				tableHeight = c.$table.height(),
+				$handles = wo.$resizable_container.children(),
+				handleCenter = Math.floor( $handles.width() / 2 );
+
+			if ( ts.hasWidget( c.table, 'scroller' ) ) {
+				tableHeight = 0;
+				c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function(){
+					var $this = $(this);
+					// center table has a max-height set
+					tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height();
+				});
+			}
+			// subtract out table left position from resizable handles. Fixes #864
+			startPosition = c.$table.position().left;
+			$handles.each( function() {
+				var $this = $(this),
+					column = parseInt( $this.attr( 'data-column' ), 10 ),
+					columns = c.columns - 1,
+					$header = $this.data( 'header' );
+				if ( !$header ) { return; } // see #859
+				if ( !$header.is(':visible') ) {
+					$this.hide();
+				} else if ( column < columns || column === columns && wo.resizable_addLastColumn ) {
+					$this.css({
+						display: 'inline-block',
+						height : tableHeight,
+						left : $header.position().left - startPosition + $header.outerWidth() - handleCenter
+					});
+				}
+			});
+		},
+
+		// prevent text selection while dragging resize bar
+		toggleTextSelection : function( c, wo, toggle ) {
+			var namespace = c.namespace + 'tsresize';
+			wo.resizable_vars.disabled = toggle;
+			$( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle );
+			if ( toggle ) {
+				$( 'body' )
+					.attr( 'unselectable', 'on' )
+					.bind( 'selectstart' + namespace, false );
+			} else {
+				$( 'body' )
+					.removeAttr( 'unselectable' )
+					.unbind( 'selectstart' + namespace );
+			}
+		},
+
+		bindings : function( c, wo ) {
+			var namespace = c.namespace + 'tsresize';
+			wo.$resizable_container.children().bind( 'mousedown', function( event ) {
+				// save header cell and mouse position
+				var column,
+					vars = wo.resizable_vars,
+					$extras = $( c.namespace + '_extra_headers' ),
+					$header = $( event.target ).data( 'header' );
+
+				column = parseInt( $header.attr( 'data-column' ), 10 );
+				vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') );
+				vars.target = column;
+
+				// if table is not as wide as it's parent, then resize the table
+				vars.$next = event.shiftKey || wo.resizable_targetLast ?
+					$header.parent().children().not( '.resizable-false' ).filter( ':last' ) :
+					$header.nextAll( ':not(.resizable-false)' ).eq( 0 );
+
+				column = parseInt( vars.$next.attr( 'data-column' ), 10 );
+				vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') );
+				vars.next = column;
+
+				vars.mouseXPosition = event.pageX;
+				ts.resizable.updateStoredSizes( c, wo );
+				ts.resizable.toggleTextSelection(c, wo, true );
+			});
+
+			$( document )
+				.bind( 'mousemove' + namespace, function( event ) {
+					var vars = wo.resizable_vars;
+					// ignore mousemove if no mousedown
+					if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; }
+					if ( wo.resizable_throttle ) {
+						clearTimeout( vars.timer );
+						vars.timer = setTimeout( function() {
+							ts.resizable.mouseMove( c, wo, event );
+						}, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle );
+					} else {
+						ts.resizable.mouseMove( c, wo, event );
+					}
+				})
+				.bind( 'mouseup' + namespace, function() {
+					if (!wo.resizable_vars.disabled) { return; }
+					ts.resizable.toggleTextSelection( c, wo, false );
+					ts.resizable.stopResize( c, wo );
+					ts.resizable.setHandlePosition( c, wo );
+				});
+
+			// resizeEnd event triggered by scroller widget
+			$( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() {
+				ts.resizable.setHandlePosition( c, wo );
+			});
+
+			// right click to reset columns to default widths
+			c.$table
+				.bind( 'columnUpdate' + namespace + ' pagerComplete' + namespace, function() {
+					ts.resizable.setHandlePosition( c, wo );
+				})
+				.find( 'thead:first' )
+				.add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) )
+				.bind( 'contextmenu' + namespace, function() {
+					// $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
+					var allowClick = wo.resizable_vars.storedSizes.length === 0;
+					ts.resizableReset( c.table );
+					ts.resizable.setHandlePosition( c, wo );
+					wo.resizable_vars.storedSizes = [];
+					return allowClick;
+				});
+
+		},
+
+		mouseMove : function( c, wo, event ) {
+			if ( wo.resizable_vars.mouseXPosition === 0 || !wo.resizable_vars.$target ) { return; }
+			// resize columns
+			var column,
+				total = 0,
+				vars = wo.resizable_vars,
+				$next = vars.$next,
+				tar = vars.storedSizes[ vars.target ],
+				leftEdge = event.pageX - vars.mouseXPosition;
+			if ( vars.overflow ) {
+				if ( tar + leftEdge > 0 ) {
+					vars.storedSizes[ vars.target ] += leftEdge;
+					ts.resizable.setWidth( vars.$target, vars.storedSizes[ vars.target ], true );
+					// update the entire table width
+					for ( column = 0; column < c.columns; column++ ) {
+						total += vars.storedSizes[ column ];
+					}
+					ts.resizable.setWidth( c.$table.add( $( c.namespace + '_extra_table' ) ), total );
+				}
+				if ( !$next.length ) {
+					// if expanding right-most column, scroll the wrapper
+					vars.$wrap[0].scrollLeft = c.$table.width();
+				}
+			} else if ( vars.fullWidth ) {
+				vars.storedSizes[ vars.target ] += leftEdge;
+				vars.storedSizes[ vars.next ] -= leftEdge;
+				ts.resizable.setWidths( c, wo );
+			} else {
+				vars.storedSizes[ vars.target ] += leftEdge;
+				ts.resizable.setWidths( c, wo );
+			}
+			vars.mouseXPosition = event.pageX;
+			// dynamically update sticky header widths
+			c.$table.triggerHandler('stickyHeadersUpdate');
+		},
+
+		stopResize : function( c, wo ) {
+			var vars = wo.resizable_vars;
+			ts.resizable.updateStoredSizes( c, wo );
+			if ( vars.useStorage ) {
+				// save all column widths
+				ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
+				ts.storage( c.table, 'tablesorter-table-resized-width', c.$table.width() );
+			}
+			vars.mouseXPosition = 0;
+			vars.$target = vars.$next = null;
+			// will update stickyHeaders, just in case, see #912
+			c.$table.triggerHandler('stickyHeadersUpdate');
+		}
+	};
+
+	// this widget saves the column widths if
+	// $.tablesorter.storage function is included
+	// **************************
+	ts.addWidget({
+		id: 'resizable',
+		priority: 40,
+		options: {
+			resizable : true, // save column widths to storage
+			resizable_addLastColumn : false,
+			resizable_widths : [],
+			resizable_throttle : false, // set to true (5ms) or any number 0-10 range
+			resizable_targetLast : false,
+			resizable_fullWidth : null
+		},
+		init: function(table, thisWidget, c, wo) {
+			ts.resizable.init( c, wo );
+		},
+		format: function( table, c, wo ) {
+			ts.resizable.setHandlePosition( c, wo );
+		},
+		remove: function( table, c, wo, refreshing ) {
+			if (wo.$resizable_container) {
+				var namespace = c.namespace + 'tsresize';
+				c.$table.add( $( c.namespace + '_extra_table' ) )
+					.removeClass('hasResizable')
+					.children( 'thead' )
+					.unbind( 'contextmenu' + namespace );
+
+				wo.$resizable_container.remove();
+				ts.resizable.toggleTextSelection( c, wo, false );
+				ts.resizableReset( table, refreshing );
+				$( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace );
+			}
+		}
+	});
+
+	ts.resizableReset = function( table, refreshing ) {
+		$( table ).each(function(){
+			var index, $t,
+				c = this.config,
+				wo = c && c.widgetOptions,
+				vars = wo.resizable_vars;
+			if ( table && c && c.$headerIndexed.length ) {
+				// restore the initial table width
+				if ( vars.overflow && vars.tableWidth ) {
+					ts.resizable.setWidth( c.$table, vars.tableWidth, true );
+					if ( vars.useStorage ) {
+						ts.storage( table, 'tablesorter-table-resized-width', 'auto' );
+					}
+				}
+				for ( index = 0; index < c.columns; index++ ) {
+					$t = c.$headerIndexed[ index ];
+					if ( wo.resizable_widths && wo.resizable_widths[ index ] ) {
+						ts.resizable.setWidth( $t, wo.resizable_widths[ index ], vars.overflow );
+					} else if ( !$t.hasClass( 'resizable-false' ) ) {
+						// don't clear the width of any column that is not resizable
+						ts.resizable.setWidth( $t, '', vars.overflow );
+					}
+				}
+
+				// reset stickyHeader widths
+				c.$table.triggerHandler( 'stickyHeadersUpdate' );
+				if ( ts.storage && !refreshing ) {
+					ts.storage( this, ts.css.resizableStorage, {} );
+				}
+			}
+		});
+	};
+
+})( jQuery, window );
+
+/*! Widget: saveSort - updated 10/31/2015 (v2.24.0) *//*
+* Requires tablesorter v2.16+
+* by Rob Garrison
+*/
+;(function ($) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	// this widget saves the last sort only if the
+	// saveSort widget option is true AND the
+	// $.tablesorter.storage function is included
+	// **************************
+	ts.addWidget({
+		id: 'saveSort',
+		priority: 20,
+		options: {
+			saveSort : true
+		},
+		init: function(table, thisWidget, c, wo) {
+			// run widget format before all other widgets are applied to the table
+			thisWidget.format(table, c, wo, true);
+		},
+		format: function(table, c, wo, init) {
+			var stored, time,
+				$table = c.$table,
+				saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true
+				sortList = { 'sortList' : c.sortList };
+			if (c.debug) {
+				time = new Date();
+			}
+			if ($table.hasClass('hasSaveSort')) {
+				if (saveSort && table.hasInitialized && ts.storage) {
+					ts.storage( table, 'tablesorter-savesort', sortList );
+					if (c.debug) {
+						console.log('saveSort widget: Saving last sort: ' + c.sortList + ts.benchmark(time));
+					}
+				}
+			} else {
+				// set table sort on initial run of the widget
+				$table.addClass('hasSaveSort');
+				sortList = '';
+				// get data
+				if (ts.storage) {
+					stored = ts.storage( table, 'tablesorter-savesort' );
+					sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : '';
+					if (c.debug) {
+						console.log('saveSort: Last sort loaded: "' + sortList + '"' + ts.benchmark(time));
+					}
+					$table.bind('saveSortReset', function(event) {
+						event.stopPropagation();
+						ts.storage( table, 'tablesorter-savesort', '' );
+					});
+				}
+				// init is true when widget init is run, this will run this widget before all other widgets have initialized
+				// this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice.
+				if (init && sortList && sortList.length > 0) {
+					c.sortList = sortList;
+				} else if (table.hasInitialized && sortList && sortList.length > 0) {
+					// update sort change
+					ts.sortOn( c, sortList );
+				}
+			}
+		},
+		remove: function(table, c) {
+			c.$table.removeClass('hasSaveSort');
+			// clear storage
+			if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); }
+		}
+	});
+
+})(jQuery);
+
+return jQuery.tablesorter;
+}));
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.widgets.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.widgets.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..c0fc008d28287bd6e29c11b420c20bc29f51084e
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/jquery.tablesorter.widgets.min.js
@@ -0,0 +1,3 @@
+/*! tablesorter (FORK) - updated 01-06-2017 (v2.28.4)*/
+!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,b,c){"use strict";var d=a.tablesorter||{};d.storage=function(e,f,g,h){e=a(e)[0];var i,j,k,l=!1,m={},n=e.config,o=n&&n.widgetOptions,p=h&&h.useSessionStorage||o&&o.storage_useSessionStorage?"sessionStorage":"localStorage",q=a(e),r=h&&h.id||q.attr(h&&h.group||o&&o.storage_group||"data-table-group")||o&&o.storage_tableId||e.id||a(".tablesorter").index(q),s=h&&h.url||q.attr(h&&h.page||o&&o.storage_page||"data-table-page")||o&&o.storage_fixedUrl||n&&n.fixedUrl||b.location.pathname;if(a.extend(!0,d.defaults,{fixedUrl:"",widgetOptions:{storage_fixedUrl:"",storage_group:"",storage_page:"",storage_tableId:"",storage_useSessionStorage:""}}),p in b)try{b[p].setItem("_tmptest","temp"),l=!0,b[p].removeItem("_tmptest")}catch(a){n&&n.debug&&console.warn(p+" is not supported in this browser")}return a.parseJSON&&(l?m=a.parseJSON(b[p][f]||"null")||{}:(j=c.cookie.split(/[;\s|=]/),i=a.inArray(f,j)+1,m=0!==i?a.parseJSON(j[i]||"null")||{}:{})),"undefined"!=typeof g&&b.JSON&&JSON.hasOwnProperty("stringify")?(m[s]||(m[s]={}),m[s][r]=g,l?b[p][f]=JSON.stringify(m):(k=new Date,k.setTime(k.getTime()+31536e6),c.cookie=f+"="+JSON.stringify(m).replace(/\"/g,'"')+"; expires="+k.toGMTString()+"; path=/"),void 0):m&&m[s]?m[s][r]:""}}(a,window,document),function(a){"use strict";var b=a.tablesorter||{};b.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",sortNone:"",sortAsc:"",sortDesc:"",active:"",hover:"",icons:"",iconSortNone:"bootstrap-icon-unsorted",iconSortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",iconSortDesc:"icon-chevron-down glyphicon glyphicon-chevron-down",filterRow:"",footerRow:"",footerCells:"",even:"",odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",caption:"ui-widget-content",header:"ui-widget-header ui-corner-all ui-state-default",sortNone:"",sortAsc:"",sortDesc:"",active:"ui-state-active",hover:"ui-state-hover",icons:"ui-icon",iconSortNone:"ui-icon-carat-2-n-s ui-icon-caret-2-n-s",iconSortAsc:"ui-icon-carat-1-n ui-icon-caret-1-n",iconSortDesc:"ui-icon-carat-1-s ui-icon-caret-1-s",filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",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,s=b.themes,t=d.$table.add(a(d.namespace+"_extra_table")),u=d.$headers.add(a(d.namespace+"_extra_headers")),v=d.theme||"jui",w=s[v]||{},x=a.trim([w.sortNone,w.sortDesc,w.sortAsc,w.active].join(" ")),y=a.trim([w.iconSortNone,w.iconSortDesc,w.iconSortAsc].join(" "));for(d.debug&&(j=new Date),t.hasClass("tablesorter-"+v)&&d.theme===d.appliedTheme&&e.uitheme_applied||(e.uitheme_applied=!0,o=s[d.appliedTheme]||{},r=!a.isEmptyObject(o),p=r?[o.sortNone,o.sortDesc,o.sortAsc,o.active].join(" "):"",q=r?[o.iconSortNone,o.iconSortDesc,o.iconSortAsc].join(" "):"",r&&(e.zebra[0]=a.trim(" "+e.zebra[0].replace(" "+o.even,"")),e.zebra[1]=a.trim(" "+e.zebra[1].replace(" "+o.odd,"")),d.$tbodies.children().removeClass([o.even,o.odd].join(" "))),w.even&&(e.zebra[0]+=" "+w.even),w.odd&&(e.zebra[1]+=" "+w.odd),t.children("caption").removeClass(o.caption||"").addClass(w.caption),m=t.removeClass((d.appliedTheme?"tablesorter-"+(d.appliedTheme||""):"")+" "+(o.table||"")).addClass("tablesorter-"+v+" "+(w.table||"")).children("tfoot"),d.appliedTheme=d.theme,m.length&&m.children("tr").removeClass(o.footerRow||"").addClass(w.footerRow).children("th, td").removeClass(o.footerCells||"").addClass(w.footerCells),u.removeClass((r?[o.header,o.hover,p].join(" "):"")||"").addClass(w.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(b){a(this)["mouseenter"===b.type?"addClass":"removeClass"](w.hover||"")}),u.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&&u.find("."+b.css.icon).removeClass(r?[o.icons,q].join(" "):"").addClass(w.icons||""),b.hasWidget(d.table,"filter")&&(g=function(){t.children("thead").children("."+b.css.filterRow).removeClass(r?o.filterRow||"":"").addClass(w.filterRow||"")},e.filter_initialized?g():t.one("filterInit",function(){g()}))),f=0;f<d.columns;f++)k=d.$headers.add(a(d.namespace+"_extra_headers")).not(".sorter-false").filter('[data-column="'+f+'"]'),l=b.css.icon?k.find("."+b.css.icon):a(),n=u.not(".sorter-false").filter('[data-column="'+f+'"]:last'),n.length&&(k.removeClass(x),l.removeClass(y),n[0].sortDisabled?l.removeClass(w.icons||""):(h=w.sortNone,i=w.iconSortNone,n.hasClass(b.css.sortAsc)?(h=[w.sortAsc,w.active].join(" "),i=w.iconSortAsc):n.hasClass(b.css.sortDesc)&&(h=[w.sortDesc,w.active].join(" "),i=w.iconSortDesc),k.addClass(h),l.addClass(i||"")));d.debug&&console.log("Applying "+v+" theme"+b.benchmark(j))},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))}}})}(a),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,r=e&&e.columns||["primary","secondary","tertiary"],s=r.length-1;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;m<q;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;m<q;m++)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)}})}(a),function(a){"use strict";var b,c,d=a.tablesorter||{},e=d.css,f=d.keyCodes;a.extend(e,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",filterDisabled:"disabled",filterRowHide:"hideme"}),a.extend(f,{backSpace:8,escape:27,space:32,left:37,down:40}),d.addWidget({id:"filter",priority:50,options:{filter_cellFilter:"",filter_childRows:!1,filter_childByColumn:!1,filter_childWithSibs:!0,filter_columnAnyMatch:!0,filter_columnFilters:!0,filter_cssFilter:"",filter_defaultAttrib:"data-value",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_formatter:null,filter_functions:null,filter_hideEmpty:!0,filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_matchType:{input:"exact",select:"exact"},filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_resetOnEsc:!0,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_selectSourceSeparator:"|",filter_serversideFiltering:!1,filter_startsWith:!1,filter_useParsedData:!1},format:function(a,c,d){c.$table.hasClass("hasFilters")||b.init(a,c,d)},remove:function(b,c,f,g){var h,i,j=c.$table,k=c.$tbodies,l="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(c.namespace+"filter ");if(j.removeClass("hasFilters").unbind(l.replace(d.regex.spaces," ")).find("."+e.filterRow).remove(),f.filter_initialized=!1,!g){for(h=0;h<k.length;h++)i=d.processTbody(b,k.eq(h),!0),i.children().removeClass(f.filter_filteredRow).show(),d.processTbody(b,i,!1);f.filter_reset&&a(document).undelegate(f.filter_reset,"click"+c.namespace+"filter")}}}),b=d.filter={regex:{regex:/^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/,child:/tablesorter-childRow/,filtered:/filtered/,type:/undefined|number/,exact:/(^[\"\'=]+)|([\"\'=]+$)/g,operators:/[<>=]/g,query:"(q|query)",wild01:/\?/g,wild0More:/\*/g,quote:/\"/g,isNeg1:/(>=?\s*-\d)/,isNeg2:/(<=?\s*\d)/},types:{or:function(d,e,f){if((c.orTest.test(e.iFilter)||c.orSplit.test(e.filter))&&!c.regex.test(e.filter)){var g,h,i,j,k=a.extend({},e),l=e.filter.split(c.orSplit),m=e.iFilter.split(c.orSplit),n=l.length;for(g=0;g<n;g++){k.nestedFilters=!0,k.filter=""+(b.parseFilter(d,l[g],e)||""),k.iFilter=""+(b.parseFilter(d,m[g],e)||""),i="("+(b.parseFilter(d,k.filter,e)||"")+")";try{if(j=new RegExp(e.isMatch?i:"^"+i+"$",d.widgetOptions.filter_ignoreCase?"i":""),h=j.test(k.exact)||b.processTypes(d,k,f))return h}catch(a){return null}}return h||!1}return null},and:function(d,e,f){if(c.andTest.test(e.filter)){var g,h,i,j,k,l=a.extend({},e),m=e.filter.split(c.andSplit),n=e.iFilter.split(c.andSplit),o=m.length;for(g=0;g<o;g++){l.nestedFilters=!0,l.filter=""+(b.parseFilter(d,m[g],e)||""),l.iFilter=""+(b.parseFilter(d,n[g],e)||""),j=("("+(b.parseFilter(d,l.filter,e)||"")+")").replace(c.wild01,"\\S{1}").replace(c.wild0More,"\\S*");try{k=new RegExp(e.isMatch?j:"^"+j+"$",d.widgetOptions.filter_ignoreCase?"i":""),i=k.test(l.exact)||b.processTypes(d,l,f),h=0===g?i:h&&i}catch(a){return null}}return h||!1}return null},regex:function(a,b){if(c.regex.test(b.filter)){var d,e=b.filter_regexCache[b.index]||c.regex.exec(b.filter),f=e instanceof RegExp;try{f||(b.filter_regexCache[b.index]=e=new RegExp(e[1],e[2])),d=e.test(b.exact)}catch(a){d=!1}return d}return null},operators:function(e,f){if(c.operTest.test(f.iFilter)&&""!==f.iExact){var g,h,i,j=e.table,k=f.parsed[f.index],l=d.formatFloat(f.iFilter.replace(c.operators,""),j),m=e.parsers[f.index]||{},n=l;return(k||"numeric"===m.type)&&(i=a.trim(""+f.iFilter.replace(c.operators,"")),h=b.parseFilter(e,i,f,!0),l="number"!=typeof h||""===h||isNaN(h)?l:h),!k&&"numeric"!==m.type||isNaN(l)||"undefined"==typeof f.cache?(i=isNaN(f.iExact)?f.iExact.replace(d.regex.nondigit,""):f.iExact,g=d.formatFloat(i,j)):g=f.cache,c.gtTest.test(f.iFilter)?h=c.gteTest.test(f.iFilter)?g>=l:g>l:c.ltTest.test(f.iFilter)&&(h=c.lteTest.test(f.iFilter)?g<=l:g<l),h||""!==n||(h=!0),h}return null},notMatch:function(d,e){if(c.notTest.test(e.iFilter)){var f,g=e.iFilter.replace("!",""),h=b.parseFilter(d,g,e)||"";return c.exact.test(h)?(h=h.replace(c.exact,""),""===h||a.trim(h)!==e.iExact):(f=e.iExact.search(a.trim(h)),""===h||(e.anyMatch?f<0:!(d.widgetOptions.filter_startsWith?0===f:f>=0)))}return null},exact:function(d,e){if(c.exact.test(e.iFilter)){var f=e.iFilter.replace(c.exact,""),g=b.parseFilter(d,f,e)||"";return e.anyMatch?a.inArray(g,e.rowArray)>=0:g==e.iExact}return null},range:function(a,e){if(c.toTest.test(e.iFilter)){var f,g,h,i,j=a.table,k=e.index,l=e.parsed[k],m=e.iFilter.split(c.toSplit);return g=m[0].replace(d.regex.nondigit,"")||"",h=d.formatFloat(b.parseFilter(a,g,e),j),g=m[1].replace(d.regex.nondigit,"")||"",i=d.formatFloat(b.parseFilter(a,g,e),j),(l||"numeric"===a.parsers[k].type)&&(f=a.parsers[k].format(""+m[0],j,a.$headers.eq(k),k),h=""===f||isNaN(f)?h:f,f=a.parsers[k].format(""+m[1],j,a.$headers.eq(k),k),i=""===f||isNaN(f)?i:f),!l&&"numeric"!==a.parsers[k].type||isNaN(h)||isNaN(i)?(g=isNaN(e.iExact)?e.iExact.replace(d.regex.nondigit,""):e.iExact,f=d.formatFloat(g,j)):f=e.cache,h>i&&(g=h,h=i,i=g),f>=h&&f<=i||""===h||""===i}return null},wild:function(a,d){if(c.wildOrTest.test(d.iFilter)){var e=""+(b.parseFilter(a,d.iFilter,d)||"");!c.wildTest.test(e)&&d.nestedFilters&&(e=d.isMatch?e:"^("+e+")$");try{return new RegExp(e.replace(c.wild01,"\\S{1}").replace(c.wild0More,"\\S*"),a.widgetOptions.filter_ignoreCase?"i":"").test(d.exact)}catch(a){return null}}return null},fuzzy:function(a,d){if(c.fuzzyTest.test(d.iFilter)){var e,f=0,g=d.iExact.length,h=d.iFilter.slice(1),i=b.parseFilter(a,h,d)||"";for(e=0;e<g;e++)d.iExact[e]===i[f]&&(f+=1);return f===i.length}return null}},init:function(f){d.language=a.extend(!0,{},{to:"to",or:"or",and:"and"},d.language);var g,h,i,j,k,l,m,n,o=f.config,p=o.widgetOptions;if(o.$table.addClass("hasFilters"),o.lastSearch=[],p.filter_searchTimer=null,p.filter_initTimer=null,p.filter_formatterCount=0,p.filter_formatterInit=[],p.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',p.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',l="\\{"+c.query+"\\}",a.extend(c,{child:new RegExp(o.cssChildRow),filtered:new RegExp(p.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+d.language.or+"|-|"+d.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+d.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+d.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+d.language.and+"|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+d.language.and+"|&&)\\s+)","gi"),orTest:new RegExp("(\\||\\s+"+d.language.or+"\\s+)","i"),orSplit:new RegExp("(?:\\s+(?:"+d.language.or+")\\s+|\\|)","gi"),iQuery:new RegExp(l,"i"),igQuery:new RegExp(l,"ig"),operTest:/^[<>]=?/,gtTest:/>/,gteTest:/>=/,ltTest:/</,lteTest:/<=/,notTest:/^\!/,wildOrTest:/[\?\*\|]/,wildTest:/\?\*/,fuzzyTest:/^~/,exactTest:/[=\"\|!]/}),l=o.$headers.filter(".filter-false, .parser-false").length,p.filter_columnFilters!==!1&&l!==o.$headers.length&&b.buildRow(f,o,p),i="addRows updateCell update updateRows updateComplete appendCache filterReset "+"filterResetSaved filterEnd search ".split(" ").join(o.namespace+"filter "),o.$table.bind(i,function(c,g){return l=p.filter_hideEmpty&&a.isEmptyObject(o.cache)&&!(o.delayInit&&"appendCache"===c.type),o.$table.find("."+e.filterRow).toggleClass(p.filter_filteredRow,l),/(search|filter)/.test(c.type)||(c.stopPropagation(),b.buildDefault(f,!0)),"filterReset"===c.type?(o.$table.find("."+e.filter).add(p.filter_$externalFilters).val(""),b.searching(f,[])):"filterResetSaved"===c.type?d.storage(f,"tablesorter-filters",""):"filterEnd"===c.type?b.buildDefault(f,!0):(g="search"===c.type?g:"updateComplete"===c.type?o.$table.data("lastSearch"):"",/(update|add)/.test(c.type)&&"updateComplete"!==c.type&&(o.lastCombinedFilter=null,o.lastSearch=[],setTimeout(function(){o.$table.triggerHandler("filterFomatterUpdate")},100)),b.searching(f,g,!0)),!1}),p.filter_reset&&(p.filter_reset instanceof a?p.filter_reset.click(function(){o.$table.triggerHandler("filterReset")}):a(p.filter_reset).length&&a(document).undelegate(p.filter_reset,"click"+o.namespace+"filter").delegate(p.filter_reset,"click"+o.namespace+"filter",function(){o.$table.triggerHandler("filterReset")})),p.filter_functions)for(k=0;k<o.columns;k++)if(m=d.getColumnData(f,p.filter_functions,k))if(j=o.$headerIndexed[k].removeClass("filter-select"),n=!(j.hasClass("filter-false")||j.hasClass("parser-false")),g="",m===!0&&n)b.buildSelect(f,k);else if("object"==typeof m&&n){for(h in m)"string"==typeof h&&(g+=""===g?'<option value="">'+(j.data("placeholder")||j.attr("data-placeholder")||p.filter_placeholder.select||"")+"</option>":"",l=h,i=h,h.indexOf(p.filter_selectSourceSeparator)>=0&&(l=h.split(p.filter_selectSourceSeparator),i=l[1],l=l[0]),g+="<option "+(i===l?"":'data-function-name="'+h+'" ')+'value="'+l+'">'+i+"</option>");o.$table.find("thead").find("select."+e.filter+'[data-column="'+k+'"]').append(g),i=p.filter_selectSource,m="function"==typeof i||d.getColumnData(f,i,k),m&&b.buildSelect(o.table,k,"",!0,j.hasClass(p.filter_onlyAvail))}b.buildDefault(f,!0),b.bindSearch(f,o.$table.find("."+e.filter),!0),p.filter_external&&b.bindSearch(f,p.filter_external),p.filter_hideFilters&&b.hideFilters(o),o.showProcessing&&(i="filterStart filterEnd ".split(" ").join(o.namespace+"filter "),o.$table.unbind(i.replace(d.regex.spaces," ")).bind(i,function(b,c){j=c?o.$table.find("."+e.header).filter("[data-column]").filter(function(){return""!==c[a(this).data("column")]}):"",d.isProcessing(f,"filterStart"===b.type,c?j:"")})),o.filteredRows=o.totalRows,i="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(o.namespace+"filter "),o.$table.unbind(i.replace(d.regex.spaces," ")).bind(i,function(){b.completeInit(this)}),o.pager&&o.pager.initialized&&!p.filter_initialized?(o.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){b.filterInitComplete(o)},100)):p.filter_initialized||b.completeInit(f)},completeInit:function(a){var c=a.config,e=c.widgetOptions,f=b.setDefaults(a,c,e)||[];f.length&&(c.delayInit&&""===f.join("")||d.setFilters(a,f,!0)),c.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){e.filter_initialized||b.filterInitComplete(c)},100)},formatterUpdated:function(a,b){var c=a&&a.closest("table")[0].config.widgetOptions;c&&!c.filter_initialized&&(c.filter_formatterInit[b]=1)},filterInitComplete:function(c){var d,e,f=c.widgetOptions,g=0,h=function(){f.filter_initialized=!0,c.lastSearch=c.$table.data("lastSearch"),c.$table.triggerHandler("filterInit",c),b.findRows(c.table,c.lastSearch||[])};if(a.isEmptyObject(f.filter_formatter))h();else{for(e=f.filter_formatterInit.length,d=0;d<e;d++)1===f.filter_formatterInit[d]&&g++;clearTimeout(f.filter_initTimer),f.filter_initialized||g!==f.filter_formatterCount?f.filter_initialized||(f.filter_initTimer=setTimeout(function(){h()},500)):h()}},processFilters:function(a,b){var c,d=[],e=b?encodeURIComponent:decodeURIComponent,f=a.length;for(c=0;c<f;c++)a[c]&&(d[c]=e(a[c]));return d},setDefaults:function(c,e,f){var g,h,i,j,k,l=d.getFilters(c)||[];if(f.filter_saveFilters&&d.storage&&(h=d.storage(c,"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||c.parsed[c.index]?a.parsers[c.index].format(b,a.table,[],c.index):b},buildRow:function(c,f,g){var h,i,j,k,l,m,n,o,p,q=g.filter_cellFilter,r=f.columns,s=a.isArray(q),t='<tr role="row" class="'+e.filterRow+" "+f.cssIgnoreRow+'">';for(j=0;j<r;j++)f.$headerIndexed[j].length&&(p=f.$headerIndexed[j]&&f.$headerIndexed[j][0].colSpan||0,t+=p>1?'<td data-column="'+j+"-"+(j+p-1)+'" colspan="'+p+'"':'<td data-column="'+j+'"',t+=s?q[j]?' class="'+q[j]+'"':"":""!==q?' class="'+q+'"':"",t+="></td>");for(f.$filters=a(t+="</tr>").appendTo(f.$table.children("thead").eq(0)).children("td"),j=0;j<r;j++)m=!1,k=f.$headerIndexed[j],k&&k.length&&(h=b.getColumnElm(f,f.$filters,j),o=d.getColumnData(c,g.filter_functions,j),l=g.filter_functions&&o&&"function"!=typeof o||k.hasClass("filter-select"),i=d.getColumnData(c,f.headers,j),m="false"===d.getData(k[0],i,"filter")||"false"===d.getData(k[0],i,"parser"),l?t=a("<select>").appendTo(h):(o=d.getColumnData(c,g.filter_formatter,j),o?(g.filter_formatterCount++,t=o(h,j),t&&0===t.length&&(t=h.children("input")),t&&(0===t.parent().length||t.parent().length&&t.parent()[0]!==h[0])&&h.append(t)):t=a('<input type="search">').appendTo(h),t&&(p=k.data("placeholder")||k.attr("data-placeholder")||g.filter_placeholder.search||"",t.attr("placeholder",p))),t&&(n=(a.isArray(g.filter_cssFilter)?"undefined"!=typeof g.filter_cssFilter[j]?g.filter_cssFilter[j]||"":"":g.filter_cssFilter)||"",t.addClass(e.filter+" "+n).attr("data-column",h.attr("data-column")),m&&(t.attr("placeholder","").addClass(e.filterDisabled)[0].disabled=!0)))},bindSearch:function(c,e,g){if(c=a(c)[0],e=a(e),e.length){var h,i=c.config,j=i.widgetOptions,k=i.namespace+"filter",l=j.filter_$externalFilters;g!==!0&&(h=j.filter_anyColumnSelector+","+j.filter_multipleColumnSelector,j.filter_$anyMatch=e.filter(h),l&&l.length?j.filter_$externalFilters=j.filter_$externalFilters.add(e):j.filter_$externalFilters=e,d.setFilters(c,i.$table.data("lastSearch")||[],g===!1)),h="keypress keyup keydown search change input ".split(" ").join(k+" "),e.attr("data-lastSearchTime",(new Date).getTime()).unbind(h.replace(d.regex.spaces," ")).bind("keydown"+k,function(a){if(a.which===f.escape&&!c.config.widgetOptions.filter_resetOnEsc)return!1}).bind("keyup"+k,function(e){j=c.config.widgetOptions;var g=parseInt(a(this).attr("data-column"),10),h="boolean"==typeof j.filter_liveSearch?j.filter_liveSearch:d.getColumnData(c,j.filter_liveSearch,g);if("undefined"==typeof h&&(h=j.filter_liveSearch.fallback||!1),a(this).attr("data-lastSearchTime",(new Date).getTime()),e.which===f.escape)this.value=j.filter_resetOnEsc?"":i.lastSearch[g];else{if(h===!1)return;if(""!==this.value&&("number"==typeof h&&this.value.length<h||e.which!==f.enter&&e.which!==f.backSpace&&(e.which<f.space||e.which>=f.left&&e.which<=f.down)))return}b.searching(c,!0,!0,g)}).bind("search change keypress input ".split(" ").join(k+" "),function(e){var g=parseInt(a(this).attr("data-column"),10),h="boolean"==typeof j.filter_liveSearch?j.filter_liveSearch:d.getColumnData(c,j.filter_liveSearch,g);!c.config.widgetOptions.filter_initialized||e.which!==f.enter&&"search"!==e.type&&("change"!==e.type&&"input"!==e.type||h!==!0||this.value===i.lastSearch[g])||(e.preventDefault(),a(this).attr("data-lastSearchTime",(new Date).getTime()),b.searching(c,"keypress"!==e.type,!0,g))})}},searching:function(a,c,e,f){var g,h=a.config.widgetOptions;"undefined"==typeof f?g=!1:(g="boolean"==typeof h.filter_liveSearch?h.filter_liveSearch:d.getColumnData(a,h.filter_liveSearch,f),"undefined"==typeof g&&(g=h.filter_liveSearch.fallback||!1)),clearTimeout(h.filter_searchTimer),"undefined"==typeof c||c===!0?h.filter_searchTimer=setTimeout(function(){b.checkFilters(a,c,e)},g?h.filter_searchDelay:10):b.checkFilters(a,c,e)},checkFilters:function(c,f,g){var h=c.config,i=h.widgetOptions,j=a.isArray(f),k=j?f:d.getFilters(c,!0),l=(k||[]).join("");return a.isEmptyObject(h.cache)?void(h.delayInit&&(!h.pager||h.pager&&h.pager.initialized)&&d.updateCache(h,function(){b.checkFilters(c,!1,g)})):(j&&(d.setFilters(c,k,!1,g!==!0),i.filter_initialized||(h.lastCombinedFilter="")),i.filter_hideFilters&&h.$table.find("."+e.filterRow).triggerHandler(b.hideFiltersCheck(h)?"mouseleave":"mouseenter"),h.lastCombinedFilter!==l||f===!1?(f===!1&&(h.lastCombinedFilter=null,h.lastSearch=[]),k=k||[],k=Array.prototype.map?k.map(String):k.join("�").split("�"),i.filter_initialized&&h.$table.triggerHandler("filterStart",[k]),h.showProcessing?void setTimeout(function(){return b.findRows(c,k,l),!1},30):(b.findRows(c,k,l),!1)):void 0)},hideFiltersCheck:function(a){if("function"==typeof a.widgetOptions.filter_hideFilters){var b=a.widgetOptions.filter_hideFilters(a);if("boolean"==typeof b)return b}return""===d.getFilters(a.$table).join("")},hideFilters:function(c,d){var f;(d||c.$table).find("."+e.filterRow).addClass(e.filterRowHide).bind("mouseenter mouseleave",function(d){var g=d,h=a(this);clearTimeout(f),f=setTimeout(function(){/enter|over/.test(g.type)?h.removeClass(e.filterRowHide):a(document.activeElement).closest("tr")[0]!==h[0]&&h.toggleClass(e.filterRowHide,b.hideFiltersCheck(c))},200)}).find("input, select").bind("focus blur",function(d){var g=d,h=a(this).closest("tr");clearTimeout(f),f=setTimeout(function(){clearTimeout(f),h.toggleClass(e.filterRowHide,b.hideFiltersCheck(c)&&"focus"!==g.type)},200)})},defaultFilter:function(b,d){if(""===b)return b;var e=c.iQuery,f=d.match(c.igQuery).length,g=f>1?a.trim(b).split(/\s/):[a.trim(b)],h=g.length-1,i=0,j=d;for(h<1&&f>1&&(g[1]=g[0]);e.test(j);)j=j.replace(e,g[i++]||""),e.test(j)&&i<h&&""!==(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()},findRange:function(a,b,c){var d,e,f,g,h,i,j,k,l,m=[];if(/^[0-9]+$/.test(b))return[parseInt(b,10)];if(!c&&/-/.test(b))for(e=b.match(/(\d+)\s*-\s*(\d+)/g),l=e?e.length:0,k=0;k<l;k++){for(f=e[k].split(/\s*-\s*/),g=parseInt(f[0],10)||0,h=parseInt(f[1],10)||a.columns-1,g>h&&(d=g,g=h,h=d),h>=a.columns&&(h=a.columns-1);g<=h;g++)m[m.length]=g;b=b.replace(e[k],"")}if(!c&&/,/.test(b))for(i=b.split(/\s*,\s*/),l=i.length,j=0;j<l;j++)""!==i[j]&&(k=parseInt(i[j],10),k<a.columns&&(m[m.length]=k));if(!m.length)for(k=0;k<a.columns;k++)m[m.length]=k;return m},getColumnElm:function(c,d,e){return d.filter(function(){var d=b.findRange(c,a(this).attr("data-column"));return a.inArray(e,d)>-1})},multipleColumns:function(c,d){var e=c.widgetOptions,f=e.filter_initialized||!d.filter(e.filter_anyColumnSelector).length,g=a.trim(b.getLatestSearch(d).attr("data-column")||"");return b.findRange(c,g,!f)},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},matchType:function(a,b){var c,d=a.widgetOptions,f=a.$headerIndexed[b];return f.hasClass("filter-exact")?c=!1:f.hasClass("filter-match")?c=!0:(d.filter_columnFilters?f=a.$filters.find("."+e.filter).add(d.filter_$externalFilters).filter('[data-column="'+b+'"]'):d.filter_$externalFilters&&(f=d.filter_$externalFilters.filter('[data-column="'+b+'"]')),c=!!f.length&&"match"===a.widgetOptions.filter_matchType[(f[0].nodeName||"").toLowerCase()]),c},processRow:function(e,f,g){var h,i,j,k,l,m=e.widgetOptions,n=!0,o=m.filter_$anyMatch&&m.filter_$anyMatch.length,p=m.filter_$anyMatch&&m.filter_$anyMatch.length?b.multipleColumns(e,m.filter_$anyMatch):[];if(f.$cells=f.$row.children(),f.anyMatchFlag&&p.length>1||f.anyMatchFilter&&!o){if(f.anyMatch=!0,f.isMatch=!0,f.rowArray=f.$cells.map(function(b){if(a.inArray(b,p)>-1||f.anyMatchFilter&&!o)return f.parsed[b]?l=f.cacheArray[b]:(l=f.rawArray[b],l=a.trim(m.filter_ignoreCase?l.toLowerCase():l),e.sortLocaleCompare&&(l=d.replaceAccents(l))),l}).get(),f.filter=f.anyMatchFilter,f.iFilter=f.iAnyMatchFilter,f.exact=f.rowArray.join(" "),f.iExact=m.filter_ignoreCase?f.exact.toLowerCase():f.exact,f.cache=f.cacheArray.slice(0,-1).join(" "),g.excludeMatch=g.noAnyMatch,i=b.processTypes(e,f,g),null!==i)n=i;else if(m.filter_startsWith)for(n=!1,p=Math.min(e.columns,f.rowArray.length);!n&&p>0;)p--,n=n||0===f.rowArray[p].indexOf(f.iFilter);else n=(f.iExact+f.childRowText).indexOf(f.iFilter)>=0;if(f.anyMatch=!1,f.filters.join("")===f.filter)return n}for(p=0;p<e.columns;p++)f.filter=f.filters[p],f.index=p,g.excludeMatch=g.excludeFilter[p],f.filter&&(f.cache=f.cacheArray[p],h=f.parsed[p]?f.cache:f.rawArray[p]||"",f.exact=e.sortLocaleCompare?d.replaceAccents(h):h,f.iExact=!c.type.test(typeof f.exact)&&m.filter_ignoreCase?f.exact.toLowerCase():f.exact,f.isMatch=b.matchType(e,p),h=n,k=m.filter_columnFilters?e.$filters.add(m.filter_$externalFilters).filter('[data-column="'+p+'"]').find("select option:selected").attr("data-function-name")||"":"",e.sortLocaleCompare&&(f.filter=d.replaceAccents(f.filter)),m.filter_defaultFilter&&c.iQuery.test(g.defaultColFilter[p])&&(f.filter=b.defaultFilter(f.filter,g.defaultColFilter[p])),f.iFilter=m.filter_ignoreCase?(f.filter||"").toLowerCase():f.filter,j=g.functions[p],i=null,j&&(j===!0?i=f.isMatch?(""+f.iExact).search(f.iFilter)>=0:f.filter===f.exact:"function"==typeof j?i=j(f.exact,f.cache,f.filter,p,f.$row,e,f):"function"==typeof j[k||f.filter]&&(l=k||f.filter,i=j[l](f.exact,f.cache,f.filter,p,f.$row,e,f))),null===i?(i=b.processTypes(e,f,g),null!==i?h=i:(l=(f.iExact+f.childRowText).indexOf(b.parseFilter(e,f.iFilter,f)),h=!m.filter_startsWith&&l>=0||m.filter_startsWith&&0===l)):h=i,n=!!h&&n);return n},findRows:function(e,f,g){if(e.config.lastCombinedFilter!==g&&e.config.widgetOptions.filter_initialized){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F=a.extend([],f),G=e.config,H=G.widgetOptions,I={anyMatch:!1,filters:f,filter_regexCache:[]},J={noAnyMatch:["range","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:d.getColumnData(e,H.filter_defaultFilter,G.columns,!0)||""};for(I.parsed=[],p=0;p<G.columns;p++)I.parsed[p]=H.filter_useParsedData||G.parsers&&G.parsers[p]&&G.parsers[p].parsed||d.getData&&"parsed"===d.getData(G.$headerIndexed[p],d.getColumnData(e,G.headers,p),"filter")||G.$headerIndexed[p].hasClass("filter-parsed"),J.functions[p]=d.getColumnData(e,H.filter_functions,p)||G.$headerIndexed[p].hasClass("filter-select"),J.defaultColFilter[p]=d.getColumnData(e,H.filter_defaultFilter,p)||"",J.excludeFilter[p]=(d.getColumnData(e,H.filter_excludeFilter,p,!0)||"").split(/\s+/);for(G.debug&&(console.log("Filter: Starting filter widget search",f),v=new Date),G.filteredRows=0,G.totalRows=0,g=(F||[]).join(""),n=0;n<G.$tbodies.length;n++){if(o=d.processTbody(e,G.$tbodies.eq(n),!0),p=G.columns,i=G.cache[n].normalized,k=a(a.map(i,function(a){return a[p].$row.get()})),""===g||H.filter_serversideFiltering)k.removeClass(H.filter_filteredRow).not("."+G.cssChildRow).css("display","");else{if(k=k.not("."+G.cssChildRow),h=k.length,(H.filter_$anyMatch&&H.filter_$anyMatch.length||"undefined"!=typeof f[G.columns])&&(I.anyMatchFlag=!0,I.anyMatchFilter=""+(f[G.columns]||H.filter_$anyMatch&&b.getLatestSearch(H.filter_$anyMatch).val()||""),H.filter_columnAnyMatch)){for(A=I.anyMatchFilter.split(c.andSplit),B=!1,x=0;x<A.length;x++)C=A[x].split(":"),C.length>1&&(isNaN(C[0])?a.each(G.headerContent,function(a,b){b.toLowerCase().indexOf(C[0])>-1&&(D=a,f[D]=C[1])}):D=parseInt(C[0],10)-1,D>=0&&D<G.columns&&(f[D]=C[1],A.splice(x,1),x--,B=!0));B&&(I.anyMatchFilter=A.join(" && "))}if(z=H.filter_searchFiltered,s=G.lastSearch||G.$table.data("lastSearch")||[],z)for(x=0;x<p+1;x++)w=f[x]||"",z||(x=p),z=z&&s.length&&0===w.indexOf(s[x]||"")&&!c.alreadyFiltered.test(w)&&!c.exactTest.test(w)&&!(c.isNeg1.test(w)||c.isNeg2.test(w))&&!(""!==w&&G.$filters&&G.$filters.filter('[data-column="'+x+'"]').find("select").length&&!b.matchType(G,x));for(y=k.not("."+H.filter_filteredRow).length,z&&0===y&&(z=!1),G.debug&&console.log("Filter: Searching through "+(z&&y<h?y:"all")+" rows"),I.anyMatchFlag&&(G.sortLocaleCompare&&(I.anyMatchFilter=d.replaceAccents(I.anyMatchFilter)),H.filter_defaultFilter&&c.iQuery.test(J.defaultAnyFilter)&&(I.anyMatchFilter=b.defaultFilter(I.anyMatchFilter,J.defaultAnyFilter),z=!1),I.iAnyMatchFilter=H.filter_ignoreCase&&G.ignoreCase?I.anyMatchFilter.toLowerCase():I.anyMatchFilter),m=0;m<h;m++)if(E=k[m].className,q=m&&c.child.test(E),!(q||z&&c.filtered.test(E))){if(I.$row=k.eq(m),I.rowIndex=m,I.cacheArray=i[m],j=I.cacheArray[G.columns],I.rawArray=j.raw,I.childRowText="",!H.filter_childByColumn){for(E="",r=j.child,x=0;x<r.length;x++)E+=" "+r[x].join(" ")||"";I.childRowText=H.filter_childRows?H.filter_ignoreCase?E.toLowerCase():E:""}if(t=!1,u=b.processRow(G,I,J),l=j.$row,w=!!u,r=j.$row.filter(":gt(0)"),H.filter_childRows&&r.length){if(H.filter_childByColumn)for(H.filter_childWithSibs||(r.addClass(H.filter_filteredRow),l=l.eq(0)),x=0;x<r.length;x++)I.$row=r.eq(x),I.cacheArray=j.child[x],I.rawArray=I.cacheArray,w=b.processRow(G,I,J),t=t||w,!H.filter_childWithSibs&&w&&r.eq(x).removeClass(H.filter_filteredRow);t=t||u}else t=w;l.toggleClass(H.filter_filteredRow,!t)[0].display=t?"":"none"}}G.filteredRows+=k.not("."+H.filter_filteredRow).length,G.totalRows+=k.length,d.processTbody(e,o,!1)}G.lastCombinedFilter=g,G.lastSearch=F,G.$table.data("lastSearch",F),H.filter_saveFilters&&d.storage&&d.storage(e,"tablesorter-filters",b.processFilters(F,!0)),G.debug&&console.log("Completed filter widget search"+d.benchmark(v)),H.filter_initialized&&(G.$table.triggerHandler("filterBeforeEnd",G),G.$table.triggerHandler("filterEnd",G)),setTimeout(function(){d.applyWidget(G.table)},0)}},getOptionSource:function(c,e,f){c=a(c)[0];var g=c.config,h=g.widgetOptions,i=!1,j=h.filter_selectSource,k=g.$table.data("lastSearch")||[],l="function"==typeof j||d.getColumnData(c,j,e);
+if(f&&""!==k[e]&&(f=!1),l===!0)i=j(c,e,f);else{if(l instanceof a||"string"===a.type(l)&&l.indexOf("</option>")>=0)return l;a.isArray(l)?i=l:"object"===a.type(j)&&l&&(i=l(c,e,f))}return i===!1&&(i=b.getOptions(c,e,f)),b.processOptions(c,e,i)},processOptions:function(b,c,e){if(!a.isArray(e))return!1;b=a(b)[0];var f,g,h,i,j,k,l=b.config,m="undefined"!=typeof c&&null!==c&&c>=0&&c<l.columns,n=!!m&&l.$headerIndexed[c].hasClass("filter-select-sort-desc"),o=[];if(e=a.grep(e,function(b,c){return!!b.text||a.inArray(b,e)===c}),m&&l.$headerIndexed[c].hasClass("filter-select-nosort"))return e;for(i=e.length,h=0;h<i;h++)g=e[h],k=g.text?g.text:g,j=(m&&l.parsers&&l.parsers.length&&l.parsers[c].format(k,b,[],c)||k).toString(),j=l.widgetOptions.filter_ignoreCase?j.toLowerCase():j,g.text?(g.parsed=j,o[o.length]=g):o[o.length]={text:g,parsed:j};for(f=l.textSorter||"",o.sort(function(a,e){var g=n?e.parsed:a.parsed,h=n?a.parsed:e.parsed;return m&&"function"==typeof f?f(g,h,!0,c,b):m&&"object"==typeof f&&f.hasOwnProperty(c)?f[c](g,h,!0,c,b):!d.sortNatural||d.sortNatural(g,h)}),e=[],i=o.length,h=0;h<i;h++)e[e.length]=o[h];return e},getOptions:function(b,c,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++)for(j=n.cache[g],h=n.cache[g].normalized.length,f=0;f<h;f++)if(i=j.row?j.row[f]:j.normalized[f][n.columns].$row[0],!e||!i.className.match(o.filter_filteredRow))if(o.filter_useParsedData||n.parsers[c].parsed||n.$headerIndexed[c].hasClass("filter-parsed")){if(p[p.length]=""+j.normalized[f][c],o.filter_childRows&&o.filter_childByColumn)for(m=j.normalized[f][n.columns].$row.length-1,k=0;k<m;k++)p[p.length]=""+j.normalized[f][n.columns].child[k][c]}else if(p[p.length]=j.normalized[f][n.columns].raw[c],o.filter_childRows&&o.filter_childByColumn)for(m=j.normalized[f][n.columns].$row.length,k=1;k<m;k++)l=j.normalized[f][n.columns].$row.eq(k).children().eq(c),p[p.length]=""+d.getElementText(n,l,c);return p},buildSelect:function(d,f,g,h,i){if(d=a(d)[0],f=parseInt(f,10),d.config.cache&&!a.isEmptyObject(d.config.cache)){var j,k,l,m,n,o,p,q=d.config,r=q.widgetOptions,s=q.$headerIndexed[f],t='<option value="">'+(s.data("placeholder")||s.attr("data-placeholder")||r.filter_placeholder.select||"")+"</option>",u=q.$table.find("thead").find("select."+e.filter+'[data-column="'+f+'"]').val();if("undefined"!=typeof g&&""!==g||(g=b.getOptionSource(d,f,i)),a.isArray(g)){for(j=0;j<g.length;j++)if(p=g[j],p.text){p["data-function-name"]="undefined"==typeof p.value?p.text:p.value,t+="<option";for(k in p)p.hasOwnProperty(k)&&"text"!==k&&(t+=" "+k+'="'+p[k]+'"');p.value||(t+=' value="'+p.text+'"'),t+=">"+p.text+"</option>"}else""+p!="[object Object]"&&(l=p=(""+p).replace(c.quote,"&quot;"),k=l,l.indexOf(r.filter_selectSourceSeparator)>=0&&(m=l.split(r.filter_selectSourceSeparator),k=m[0],l=m[1]),t+=""!==p?"<option "+(k===l?"":'data-function-name="'+p+'" ')+'value="'+k+'">'+l+"</option>":"");g=[]}n=(q.$filters?q.$filters:q.$table.children("thead")).find("."+e.filter),r.filter_$externalFilters&&(n=n&&n.length?n.add(r.filter_$externalFilters):r.filter_$externalFilters),o=n.filter('select[data-column="'+f+'"]'),o.length&&(o[h?"html":"append"](t),a.isArray(g)||o.append(g).val(u),o.val(u))}},buildDefault:function(a,c){var e,f,g,h=a.config,i=h.widgetOptions,j=h.columns;for(e=0;e<j;e++)f=h.$headerIndexed[e],g=!(f.hasClass("filter-false")||f.hasClass("parser-false")),(f.hasClass("filter-select")||d.getColumnData(a,i.filter_functions,e)===!0)&&g&&b.buildSelect(a,e,"",c,f.hasClass(i.filter_onlyAvail))}},c=b.regex,d.getFilters=function(c,d,f,g){var h,i,j,k,l=[],m=c?a(c)[0].config:"",n=m?m.widgetOptions:"";if(d!==!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("."+e.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 l},d.setFilters=function(c,e,f,g){var h=c?a(c)[0].config:"",i=d.getFilters(c,!0,e,g);return"undefined"==typeof f&&(f=!0),h&&f&&(h.lastCombinedFilter=null,h.lastSearch=[],b.searching(h.table,e,g),h.$table.triggerHandler("filterFomatterUpdate")),0!==i.length}}(a),function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),c.addHeaderResizeEvent=function(b,c,d){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;b<j;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.triggerHandler("resize",[c]),h.resize_flag=!1};if(clearInterval(h.resize_timer),c)return h.resize_flag=!1,!1;i(!1),h.resize_timer=setInterval(function(){h.resize_flag||i()},f.timer)}},c.addWidget({id:"stickyHeaders",priority:54,options:{stickyHeaders:"",stickyHeaders_appendTo:null,stickyHeaders_attachTo:null,stickyHeaders_xScroll:null,stickyHeaders_yScroll:null,stickyHeaders_offset:0,stickyHeaders_filteredToTop:!0,stickyHeaders_cloneId:"-sticky",stickyHeaders_addResizeEvent:!0,stickyHeaders_includeCaption:!0,stickyHeaders_zIndex:2},format:function(d,e,f){if(!(e.$table.hasClass("hasStickyHeaders")||a.inArray("filter",e.widgets)>=0&&!e.$table.hasClass("hasFilters"))){var g,h,i,j,k=e.$table,l=a(f.stickyHeaders_attachTo),m=e.namespace+"stickyheaders ",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,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,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;d<j;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")){v=u.length?u.offset().top-n.scrollTop()+u.height():0;var d=k.offset(),e=a.isWindow(n[0]),g=a.isWindow(o[0]),h=l.length?e?n.scrollTop():n.offset().top:n.scrollTop(),i=f.stickyHeaders_includeCaption?0:k.children("caption").height()||0,j=h+t+v-i,m=k.height()-(x.height()+(r.height()||0))-i,p=j>d.top&&j<d.top+m?"visible":"hidden",q={visibility:p};l.length&&(q.top=e?j-l.offset().top:l.scrollTop()),g&&(q.left=k.offset().left-parseInt(k.css("margin-left"),10)-o.scrollLeft()-A),u.length&&(q.top=(q.top||0)+t+v),x.removeClass(c.css.stickyVis+" "+c.css.stickyHide).addClass("visible"===p?c.css.stickyVis:c.css.stickyHide).css(q),(p!==z||b)&&(C(),z=p)}};if(l.length&&!l.css("position")&&l.css("position","relative"),w.attr("id")&&(w[0].id+=f.stickyHeaders_cloneId),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)),f.stickyHeaders_appendTo?a(f.stickyHeaders_appendTo).append(x):k.after(x),e.onRenderHeader)for(i=y.children("tr").children(),h=i.length,g=0;g<h;g++)e.onRenderHeader.apply(i.eq(g),[g,e,w]);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),k.hasClass("hasFilters")&&f.filter_columnFilters&&(k.bind("filterEnd"+m,function(){var d=a(document.activeElement).closest("td"),g=d.parent().children().index(d);x.hasClass(c.css.stickyVis)&&f.stickyHeaders_filteredToTop&&(b.scrollTo(0,k.position().top),g>=0&&e.$filters&&e.$filters.eq(g).find("a, select, input").filter(":visible").focus())}),c.filter.bindSearch(k,j.find("."+c.css.filter)),f.filter_hideFilters&&c.filter.hideFilters(e,w)),f.stickyHeaders_addResizeEvent&&k.bind("resize"+e.namespace+"stickyheaders",function(){C()}),k.triggerHandler("stickyHeadersInit")}},remove:function(d,e,f){var g=e.namespace+"stickyheaders ";e.$table.removeClass("hasStickyHeaders").unbind("pagerComplete resize filterEnd stickyHeadersUpdate ".split(" ").join(g).replace(/\s+/g," ")).next("."+c.css.stickyWrap).remove(),f.$sticky&&f.$sticky.length&&f.$sticky.remove(),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,!0)}})}(a,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"}),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("head").append(b)}),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),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:[]};for(c.resizableReset(b.table,!0),m.tableWidth=j.width(),m.fullWidth=Math.abs(k.width()-m.tableWidth)<20,m.useStorage&&m.overflow&&(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);c.resizable.bindings(b,d)}},updateStoredSizes:function(a,b){var c,d,e=a.columns,f=b.resizable_vars;for(f.storedSizes=[],c=0;c<e;c++)d=a.$headerIndexed[c],f.storedSizes[c]=d.is(":visible")?d.width():0},setWidth:function(a,b,c){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");if(e=e||h.storedSizes||[],e.length){for(f=0;f<b.columns;f++)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=b.$table.height(),g=d.$resizable_container.children(),h=Math.floor(g.width()/2);c.hasWidget(b.table,"scroller")&&(f=0,b.$table.closest("."+c.css.scrollerWrap).children().each(function(){var b=a(this);f+=b.filter('[style*="height"]').length?b.height():b.children("table").height()})),e=b.$table.position().left,g.each(function(){var c=a(this),g=parseInt(c.attr("data-column"),10),i=b.columns-1,j=c.data("header");j&&(j.is(":visible")?(g<i||g===i&&d.resizable_addLastColumn)&&c.css({display:"inline-block",height:f,left:j.position().left-e+j.outerWidth()-h}):c.hide())})},toggleTextSelection:function(b,d,e){var f=b.namespace+"tsresize";d.resizable_vars.disabled=e,a("body").toggleClass(c.css.resizableNoSelect,e),e?a("body").attr("unselectable","on").bind("selectstart"+f,!1):a("body").removeAttr("unselectable").unbind("selectstart"+f)},bindings:function(d,e){var f=d.namespace+"tsresize";e.$resizable_container.children().bind("mousedown",function(b){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,e,!0)}),a(document).bind("mousemove"+f,function(a){var b=e.resizable_vars;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,e,!1),c.resizable.stopResize(d,e),c.resizable.setHandlePosition(d,e))}),a(b).bind("resize"+f+" resizeEnd"+f,function(){c.resizable.setHandlePosition(d,e)}),d.$table.bind("columnUpdate"+f+" pagerComplete"+f,function(){c.resizable.setHandlePosition(d,e)}).find("thead:first").add(a(d.namespace+"_extra_table").find("thead:first")).bind("contextmenu"+f,function(){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){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){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||(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,b.$table.triggerHandler("stickyHeadersUpdate")}},stopResize:function(a,b){var d=b.resizable_vars;c.resizable.updateStoredSizes(a,b),d.useStorage&&(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,a.$table.triggerHandler("stickyHeadersUpdate")}},c.addWidget({id:"resizable",priority:40,options:{resizable:!0,resizable_addLastColumn:!1,resizable_widths:[],resizable_throttle:!1,resizable_targetLast:!1,resizable_fullWidth:null},init:function(a,b,d,e){c.resizable.init(d,e)},format:function(a,b,d){c.resizable.setHandlePosition(b,d)},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,e,!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(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);f.$table.triggerHandler("stickyHeadersUpdate"),c.storage&&!d&&c.storage(this,c.css.resizableStorage,{})}})}}(a,window),function(a){"use strict";var b=a.tablesorter||{};b.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(a,b,c,d){b.format(a,c,d,!0)},format:function(c,d,e,f){var g,h,i=d.$table,j=e.saveSort!==!1,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))):(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"),b.storage&&b.storage(a,"tablesorter-savesort","")}})}(a),a.tablesorter});
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-extract.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-extract.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..240dc3e50bc0e8f19fcdfeff44b36ea01e77cfc9
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-extract.min.js
@@ -0,0 +1,6 @@
+/*! Parser: Extract out date - updated 10/26/2014 (v2.18.0) */
+!function(a){"use strict";var b={usLong:/[A-Z]{3,10}\.?\s+\d{1,2},?\s+(?:\d{4})(?:\s+\d{1,2}:\d{2}(?::\d{2})?(?:\s+[AP]M)?)?/i,mdy:/(\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i,dmy:/(\d{1,2}[\/\s]\d{1,2}[\/\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i,dmyreplace:/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{4})/,ymd:/(\d{4}[\/\s]\d{1,2}[\/\s]\d{1,2}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/i,ymdreplace:/(\d{4})[\/\s](\d{1,2})[\/\s](\d{1,2})/};/*! extract US Long Date */
+a.tablesorter.addParser({id:"extractUSLongDate",is:function(){return!1},format:function(a){var c,d=a?a.match(b.usLong):a;return d?(c=new Date(d[0]),c instanceof Date&&isFinite(c)?c.getTime():a):a},type:"numeric"}),/*! extract MMDDYYYY */
+a.tablesorter.addParser({id:"extractMMDDYYYY",is:function(){return!1},format:function(a){var c,d=a?a.replace(/\s+/g," ").replace(/[\-.,]/g,"/").match(b.mdy):a;return d?(c=new Date(d[0]),c instanceof Date&&isFinite(c)?c.getTime():a):a},type:"numeric"}),/*! extract DDMMYYYY */
+a.tablesorter.addParser({id:"extractDDMMYYYY",is:function(){return!1},format:function(a){var c,d=a?a.replace(/\s+/g," ").replace(/[\-.,]/g,"/").match(b.dmy):a;return d?(c=new Date(d[0].replace(b.dmyreplace,"$2/$1/$3")),c instanceof Date&&isFinite(c)?c.getTime():a):a},type:"numeric"}),/*! extract YYYYMMDD */
+a.tablesorter.addParser({id:"extractYYYYMMDD",is:function(){return!1},format:function(a){var c,d=a?a.replace(/\s+/g," ").replace(/[\-.,]/g,"/").match(b.ymd):a;return d?(c=new Date(d[0].replace(b.ymdreplace,"$2/$3/$1")),c instanceof Date&&isFinite(c)?c.getTime():a):a},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-iso8601.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-iso8601.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..0b5f6604bbd9643b780968f51ddd014aa08fb9dd
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-iso8601.min.js
@@ -0,0 +1,2 @@
+/*! Parser: ISO-8601 date - updated 10/26/2014 (v2.18.0) */
+!function(a){"use strict";var b=/^([0-9]{4})(-([0-9]{2})(-([0-9]{2})(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?$/;a.tablesorter.addParser({id:"iso8601date",is:function(a){return!!a&&a.match(b)},format:function(a){var c=a?a.match(b):a;if(c){var d=new Date(c[1],0,1);return c[3]&&d.setMonth(c[3]-1),c[5]&&d.setDate(c[5]),c[7]&&d.setHours(c[7]),c[8]&&d.setMinutes(c[8]),c[10]&&d.setSeconds(c[10]),c[12]&&d.setMilliseconds(1e3*Number("0."+c[12])),d.getTime()}return a},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-month.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-month.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..470a4f2d84998f16522927cb6289095f44518817
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-month.min.js
@@ -0,0 +1,2 @@
+/*! Parser: Month - updated 11/22/2015 (v2.24.6) */
+!function(a){"use strict";var b=a.tablesorter;b.dates||(b.dates={}),b.dates.months||(b.dates.months={}),b.dates.months.en={1:"Jan",2:"Feb",3:"Mar",4:"Apr",5:"May",6:"Jun",7:"Jul",8:"Aug",9:"Sep",10:"Oct",11:"Nov",12:"Dec"},b.addParser({id:"month",is:function(){return!1},format:function(a,c,d,e){if(a){var f,g,h=c.config,i=h.globalize&&(h.globalize[e]||h.globalize)||{},j=b.dates.months[i.lang||"en"];h.ignoreCase&&(a=a.toLowerCase());for(g in j)if("string"==typeof g&&(f=j[g],h.ignoreCase&&(f=f.toLowerCase()),a.match(f)))return parseInt(g,10)}return a},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-range.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-range.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..ee38e631f52c9915ededb20b2df04aaf9665d813
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-range.min.js
@@ -0,0 +1,6 @@
+/*! Parser: date ranges -updated 11/22/2015 (v2.24.6) */
+!function(a){"use strict";var b,c=a.tablesorter,d={mdy:/(\d{1,2}[-\s]\d{1,2}[-\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/gi,dmy:/(\d{1,2}[-\s]\d{1,2}[-\s]\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/gi,dmyreplace:/(\d{1,2})[-\s](\d{1,2})[-\s](\d{4})/,ymd:/(\d{4}[-\s]\d{1,2}[-\s]\d{1,2}(\s+\d{1,2}:\d{2}(:\d{2})?(\s+[AP]M)?)?)/gi,ymdreplace:/(\d{4})[-\s](\d{1,2})[-\s](\d{1,2})/,overall_dMMMyyyy:/(\d{1,2}\s+\w+\s+\d{4}(\s+\d{1,2}:\d{2}(:\d{2})?(\s\w+)?)?)/g,matches_dMMMyyyy:/(\d{1,2})\s+(\w+)\s+(\d{4})/};/*! date-range MMDDYYYY */
+a.tablesorter.addParser({id:"date-range-mdy",is:function(){return!1},format:function(a){var b,c,e,f,g=[];if(c=a.replace(/\s+/g," ").replace(/[\/\-.,]/g,"-").match(d.mdy),f=c&&c.length){for(e=0;e<f;e++)b=new Date(c[e]),g.push(b instanceof Date&&isFinite(b)?b.getTime():c[e]);return g.sort().join(" - ")}return a},type:"text"}),/*! date-range DDMMYYYY */
+a.tablesorter.addParser({id:"date-range-dmy",is:function(){return!1},format:function(a){var b,c,e,f,g=[];if(c=a.replace(/\s+/g," ").replace(/[\/\-.,]/g,"-").match(d.dmy),f=c&&c.length){for(e=0;e<f;e++)b=new Date((""+c[e]).replace(d.dmyreplace,"$2/$1/$3")),g.push(b instanceof Date&&isFinite(b)?b.getTime():c[e]);return g.sort().join(" - ")}return a},type:"text"}),/*! date-range DDMMYYYY */
+a.tablesorter.addParser({id:"date-range-ymd",is:function(){return!1},format:function(a){var b,c,e,f,g=[];if(c=a.replace(/\s+/g," ").replace(/[\/\-.,]/g,"-").match(d.ymd),f=c&&c.length){for(e=0;e<f;e++)b=new Date((""+c[e]).replace(d.ymdreplace,"$2/$3/$1")),g.push(b instanceof Date&&isFinite(b)?b.getTime():c[e]);return g.sort().join(" - ")}return a},type:"text"}),c.dates||(c.dates={}),c.dates.months||(c.dates.months={}),c.dates.months.en={1:"Jan",2:"Feb",3:"Mar",4:"Apr",5:"May",6:"Jun",7:"Jul",8:"Aug",9:"Sep",10:"Oct",11:"Nov",12:"Dec"},b=function(a,b,d){var e,f,g=b.globalize&&(b.globalize[d]||b.globalize)||{},h=c.dates.months[g.lang||"en"];b.ignoreCase&&(a=a.toLowerCase());for(f in h)if("string"==typeof f&&(e=h[f],b.ignoreCase&&(e=e.toLowerCase()),a.match(e)))return parseInt(f,10);return a},/*! date-range "dd MMM yyyy - dd MMM yyyy" */
+c.addParser({id:"date-range-dMMMyyyy",is:function(){return!1},format:function(a,e,f,g){var h,i,j,k,l=[],m=a.replace(/\s+/g," ").match(d.overall_dMMMyyyy),n=m&&m.length;if(n){for(k=0;k<n;k++)h="",j=m[k].match(d.matches_dMMMyyyy),j&&j.length>=4&&(j.shift(),i=b(j[1],e.config,g),isNaN(i)||(m[k]=m[k].replace(j[1],i)),h=new Date((""+m[k]).replace(c.regex.shortDateXXY,"$3/$2/$1"))),l.push(h instanceof Date&&isFinite(h)?h.getTime():m[k]);return l.sort().join(" - ")}return a},type:"text"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-two-digit-year.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-two-digit-year.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..464c55c9213dfbf020a8696b2fd257c72d9645d0
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-two-digit-year.min.js
@@ -0,0 +1,2 @@
+/*! Parser: two digit year - updated 11/26/2016 (v2.28.0) */
+!function(a){"use strict";var b=50,c=a.tablesorter,d=(new Date).getFullYear();c.defaults.dataRange="",c.dates||(c.dates={}),c.dates.regxxxxyy=/(\d{1,2})[\/\s](\d{1,2})[\/\s](\d{2})/,c.dates.regyyxxxx=/(\d{2})[\/\s](\d{1,2})[\/\s](\d{1,2})/,c.formatDate=function(a,c,e,f){if(a){var g,h,i=a.replace(/\s+/g," ").replace(/[-.,]/g,"/").replace(c,e),j=new Date(i);if(j instanceof Date&&isFinite(j)){for(g=j.getFullYear(),h=f&&f.config.dateRange||b;d-g>h;)g+=100;return j.setFullYear(g)}}return a},a.tablesorter.addParser({id:"ddmmyy",is:function(){return!1},format:function(a,b){return c.formatDate(a,c.dates.regxxxxyy,"$2/$1/19$3",b)},type:"numeric"}),a.tablesorter.addParser({id:"mmddyy",is:function(){return!1},format:function(a,b){return c.formatDate(a,c.dates.regxxxxyy,"$1/$2/19$3",b)},type:"numeric"}),a.tablesorter.addParser({id:"yymmdd",is:function(){return!1},format:function(a,b){return c.formatDate(a,c.dates.regyyxxxx,"$2/$3/19$1",b)},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-weekday.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-weekday.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..a252b08ce99369a832e3c5f625da0fac04fedb4d
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date-weekday.min.js
@@ -0,0 +1,2 @@
+/*! Parser: weekday - updated 11/22/2015 (v2.24.6) */
+!function(a){"use strict";var b=a.tablesorter;b.dates||(b.dates={}),b.dates.weekdays||(b.dates.weekdays={}),b.dates.weekdays.en={sun:"Sun",mon:"Mon",tue:"Tue",wed:"Wed",thu:"Thu",fri:"Fri",sat:"Sat"},b.dates.weekStartList={sun:"1995",mon:"1996",fri:"1999",sat:"2000"},b.dates.weekdaysXref=["sun","mon","tue","wed","thu","fri","sat"],b.addParser({id:"weekday",is:function(){return!1},format:function(c,d,e,f){if(c){var g,h,i,j=d.config,k=j.globalize&&(j.globalize[f]||j.globalize)||{},l=b.dates.weekdays[k.lang||"en"],m=b.dates.weekdaysXref;j.ignoreCase&&(c=c.toLowerCase());for(h in l)if("string"==typeof h&&(g=l[h],j.ignoreCase&&(g=g.toLowerCase()),c.match(g)))return i=a.inArray(h,m),i>-1?i:c}return c},type:"numeric"}),b.addParser({id:"weekday-index",is:function(){return!1},format:function(a,c){if(a){var d=c.config,e=new Date(a);if(e instanceof Date&&isFinite(e))return new Date("1/"+(e.getDay()+1)+"/"+b.dates.weekStartList[d.weekStarts||"sun"])}return a},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..380cd2be83478b7abc6fac93fa6ffddc351dcf17
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-date.min.js
@@ -0,0 +1,4 @@
+/*! Parser: dates - updated 8/22/2016 (v2.27.5) */
+!function(a){"use strict";/*! Sugar (https://sugarjs.com/docs/#/DateParsing) */
+a.tablesorter.addParser({id:"sugar",is:function(){return!1},format:function(a){var b=Date.create||Sugar.Date.create,c=b?b(a):a?new Date(a):a;return c instanceof Date&&isFinite(c)?c.getTime():a},type:"numeric"}),/*! Datejs (http://www.datejs.com/) */
+a.tablesorter.addParser({id:"datejs",is:function(){return!1},format:function(a){var b=Date.parse?Date.parse(a):a?new Date(a):a;return b instanceof Date&&isFinite(b)?b.getTime():a},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-duration.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-duration.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..d335d434d1d734c443a9ec4a319dd4989ddedcfe
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-duration.min.js
@@ -0,0 +1,3 @@
+/*! Parser: duration & countdown - updated 2/7/2015 (v2.19.0) */
+!function(a){"use strict";a.tablesorter.addParser({id:"duration",is:function(){return!1},format:function(a,b){var c,d,e=b.config,f="",g="",h=e.durationLength||4,i=new Array(h+1).join("0"),j=(e.durationLabels||"(?:years|year|y),(?:days|day|d),(?:hours|hour|h),(?:minutes|minute|min|m),(?:seconds|second|sec|s)").split(/\s*,\s*/),k=j.length;if(!e.durationRegex){for(c=0;c<k;c++)f+="(?:(\\d+)\\s*"+j[c]+"\\s*)?";e.durationRegex=new RegExp(f,"i")}for(d=(e.usNumberFormat?a.replace(/,/g,""):a.replace(/(\d)(?:\.|\s*)(\d)/g,"$1$2")).match(e.durationRegex),c=1;c<k+1;c++)g+=(i+(d[c]||0)).slice(-h);return g},type:"text"}),/*! Countdown parser ( hh:mm:ss ) */
+a.tablesorter.addParser({id:"countdown",is:function(){return!1},format:function(a,b){for(var c=b.config.durationLength||4,d=new Array(c+1).join("0"),e=a.split(/\s*:\s*/),f=e.length,g=[];f;)g.push((d+(e[--f]||0)).slice(-c));return g.length?g.reverse().join(""):a},type:"text"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-feet-inch-fraction.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-feet-inch-fraction.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..a1f72aba93c607a08921d2aba3913f626e9f7852
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-feet-inch-fraction.min.js
@@ -0,0 +1,2 @@
+/*! Parser: distance */
+!function(a){"use strict";var b=a.tablesorter;b.symbolRegex=/[\u215b\u215c\u215d\u215e\u00bc\u00bd\u00be]/g,b.processFractions=function(c,d){if(c){var e,f=0;c=a.trim(c.replace(/\"/,"")),/\s/.test(c)&&(f=b.formatFloat(c.split(" ")[0],d),c=a.trim(c.substring(c.indexOf(" "),c.length))),/\//g.test(c)?(e=c.split("/"),c=f+parseInt(e[0],10)/parseInt(e[1]||1,10)):b.symbolRegex.test(c)&&(c=f+c.replace(b.symbolRegex,function(a){return{"⅛":".125","⅜":".375","⅝":".625","⅞":".875","¼":".25","½":".5","¾":".75"}[a]}))}return c||0},a.tablesorter.addParser({id:"distance",is:function(){return!1},format:function(a,c){if(""===a)return"";var d=/^\s*\S*(\s+\S+)?\s*\'/.test(a)?a.split(/\'/):[0,a],e=b.processFractions(d[0],c),f=b.processFractions(d[1],c);return/[\'\"]/.test(a)?parseFloat(e)+(parseFloat(f)/12||0):parseFloat(e)+parseFloat(f)},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-file-type.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-file-type.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..1a3b8db48f041868bb816f449e8dad2858b1d525
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-file-type.min.js
@@ -0,0 +1,2 @@
+/*! Parser: filetype - updated 11/10/2015 (v2.24.4) */
+!function(a){"use strict";a.tablesorter.fileTypes={separator:"|",equivalents:{"3D Image":"3dm|3ds|dwg|max|obj",Audio:"aif|aac|ape|flac|la|m4a|mid|midi|mp2|mp3|ogg|ra|raw|rm|wav|wma",Compressed:"7z|bin|cab|cbr|gz|gzip|iso|lha|lz|rar|tar|tgz|zip|zipx|zoo",Database:"csv|dat|db|dbf|json|ldb|mdb|myd|pdb|sql|tsv|wdb|wmdb|xlr|xls|xlsx|xml",Development:"asm|c|class|cls|cpp|cc|cs|cxx|cbp|cs|dba|fla|h|java|lua|pl|py|pyc|pyo|sh|sln|r|rb|vb",Document:"doc|docx|odt|ott|pages|pdf|rtf|tex|wpd|wps|wrd|wri",Executable:"apk|app|com|exe|gadget|lnk|msi",Fonts:"eot|fnt|fon|otf|ttf|woff",Icons:"ani|cur|icns|ico",Images:"bmp|gif|jpg|jpeg|jpe|jp2|pic|png|psd|tga|tif|tiff|wmf|webp",Presentation:"pps|ppt",Published:"chp|epub|lit|pub|ppp|fm|mobi",Script:"as|bat|cgi|cmd|jar|js|lua|scpt|scptd|sh|vbs|vb|wsf",Styles:"css|less|sass",Text:"info|log|md|markdown|nfo|tex|text|txt",Vectors:"awg|ai|eps|cdr|ps|svg",Video:"asf|avi|flv|m4v|mkv|mov|mp4|mpe|mpeg|mpg|ogg|rm|rv|swf|vob|wmv",Web:"asp|aspx|cer|cfm|htm|html|php|url|xhtml"}},a.tablesorter.addParser({id:"filetype",is:function(){return!1},format:function(b,c){var d,e=c.config,f=e.widgetOptions,g=f.group_separator||"-",h=b.lastIndexOf("."),i=a.tablesorter.fileTypes.separator,j=a.tablesorter.fileTypes.matching,k=a.tablesorter.fileTypes.equivalents;if(j||(d=[],a.each(k,function(a,b){d.push(b)}),j=a.tablesorter.fileTypes.matching=i+d.join(i)+i),h>=0&&(d=i+b.substring(h+1,b.length)+i,j.indexOf(d)>=0))for(h in k)if((i+k[h]+i).indexOf(d)>=0)return h+("/"!==g.toString().charAt(0)?f.group_separator:"-")+b;return b},type:"text"}),a.tablesorter.addParser({id:"file-extension",is:function(){return!1},format:function(a){var b,c=a.split(".");return c.length?(b=c.pop(),c.unshift(b),c.join(".")):a},type:"text"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-globalize.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-globalize.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..e6474a7f167b3c2fcfdc278b828fe2de32ad7e24
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-globalize.min.js
@@ -0,0 +1,4 @@
+/*! Parser: jQuery Globalize - updated 11/2/2015 (v2.24.1) */
+!function(a){"use strict";/*! jQuery Globalize date parser (https://github.com/jquery/globalize#date-module) */
+a.tablesorter.addParser({id:"globalize-date",is:function(){return!1},format:function(a,b,c,d){var e,f,g=b.config,h=g.globalize&&(g.globalize[d]||g.globalize)||{};return Globalize&&(e="object"==typeof h.Globalize?h.Globalize:Globalize(h.lang||"en"),h.Globalize||(h.Globalize=e)),f=e&&e.dateParser?e.dateParser(h)(a):a?new Date(a):a,f instanceof Date&&isFinite(f)?f.getTime():a},type:"numeric"}),/*! jQuery Globalize number parser (https://github.com/jquery/globalize#number-module) */
+a.tablesorter.addParser({id:"globalize-number",is:function(){return!1},format:function(b,c,d,e){var f,g,h=c.config,i=h.globalize&&(h.globalize[e]||h.globalize)||{};return Globalize&&(f="object"==typeof i.Globalize?i.Globalize:Globalize(i.lang||"en"),i.Globalize||(i.Globalize=f)),g=f&&f.numberParser?f.numberParser(i)(b):b?a.tablesorter.formatFloat((b||"").replace(/[^\w,. \-()]/g,""),c):b,b&&"number"==typeof g?g:b},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-huge-numbers.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-huge-numbers.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..1c37d6230d4b2c3bd1074ef10c39d6208f7dd0f8
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-huge-numbers.min.js
@@ -0,0 +1,2 @@
+/*! Parser: hugeNumbers - updated 3/1/2016 (v2.25.5) */
+!function(a){"use strict";a.tablesorter.addParser({id:"hugeNumbers",is:function(){return!1},format:function(a){return a.replace(/\B(?=(\d{12})+(?!\d))/g,",")},type:"text"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-ignore-articles.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-ignore-articles.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..41771a1c3db1d0f3f19e6e067cbce363f7c44e8f
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-ignore-articles.min.js
@@ -0,0 +1,2 @@
+/*! Parser: ignoreArticles - updated 9/15/2014 (v2.17.8) */
+!function(a){"use strict";var b=a.tablesorter;b.ignoreArticles={en:"the, a, an",de:"der, die, das, des, dem, den, ein, eine, einer, eines, einem, einen",nl:"de, het, de, een",es:"el, la, lo, los, las, un, una, unos, unas",pt:"o, a, os, as, um, uma, uns, umas",fr:"le, la, l'_, les, un, une, des",it:"il, lo, la, l'_, i, gli, le, un', uno, una, un",hu:"a, az, egy"},b.addParser({id:"ignoreArticles",is:function(){return!1},format:function(c,d,e,f){var g,h,i,j=d.config,k=c||"";return j.headers&&j.headers[f]&&j.headers[f].ignoreArticlesRegex||(j.headers||(j.headers={}),j.headers[f]||(j.headers[f]={}),i=b.getData(j.$headers.eq(f),b.getColumnData(d,j.headers,f),"ignoreArticles"),g=(b.ignoreArticles[i]||"the, a, an")+"",j.headers[f].ignoreArticlesRegex=new RegExp("^("+a.trim(g.split(/\s*\,\s*/).join("\\s|")+"\\s").replace("_\\s","")+")","i"),h=b.getData(j.$headers.eq(f),b.getColumnData(d,j.headers,f),"ignoreArticlesExcept"),j.headers[f].ignoreArticlesRegex2=""!==h?new RegExp("^("+h.replace(/\s/g,"\\s")+")","i"):""),g=j.headers[f].ignoreArticlesRegex,!g.test(k)||(h=j.headers[f].ignoreArticlesRegex2,h&&h.test(k))?k:k.replace(g,"")},type:"text"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-image.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-image.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..624029b3440c7d21b19e20581003b17dcb41a2f7
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-image.min.js
@@ -0,0 +1,2 @@
+/*! Parser: image - new 7/17/2014 (v2.17.5) */
+!function(a){"use strict";a.tablesorter.addParser({id:"image",is:function(){return!1},format:function(b,c,d){return a(d).find("img").attr(c.config.imgAttr||"alt")||b},parsed:!0,type:"text"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-input-select.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-input-select.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..144c14b6b092ef74f0c40a487fafee77a751832c
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-input-select.min.js
@@ -0,0 +1,2 @@
+/*! Parser: input & select - updated 11/26/2016 (v2.28.0) */
+!function(a){"use strict";var b=function(a,b,c){};a.tablesorter.addParser({id:"inputs",is:function(){return!1},format:function(b,c,d){var e=a(d).find("input");return e.length?e.val():b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"inputs-numeric",is:function(){return!1},format:function(b,c,d){var e=a(d).find("input"),f=e.length?e.val():b,g=a.tablesorter.formatFloat((f||"").replace(/[^\w,. \-()]/g,""),c);return b&&"number"==typeof g?g:b?a.trim(b&&c.config.ignoreCase?b.toLocaleLowerCase():b):b},parsed:!0,type:"numeric"}),a.tablesorter.addParser({id:"checkbox",is:function(){return!1},format:function(b,c,d){var e=a(d),f=c.config.widgetOptions,g=f.group_checkbox?f.group_checkbox:["checked","unchecked"],h=e.find('input[type="checkbox"]'),i=h.length?h[0].checked:"";return h.length?g[i?0:1]:b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"select",is:function(){return!1},format:function(b,c,d){var e=a(d).find("select");return e.length?e.val():b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"select-text",is:function(){return!1},format:function(b,c,d){var e=a(d).find("select");return e.length?e.find("option:selected").text()||"":b},parsed:!0,type:"text"}),a.tablesorter.addParser({id:"textarea",is:function(){return!1},format:function(b,c,d){var e=a(d).find("textarea");return e.length?e.val():b},parsed:!0,type:"text"}),a.tablesorter.defaults.checkboxClass="",a.tablesorter.defaults.checkboxVisible="",a(function(){if(a.fn.on){var c=function(a,b,c,d){a.toggleClass(b+"-"+c,d),(a[0].className||"").match(b+"-")?a.addClass(b):a.removeClass(b)},d=function(b,c){var d=window.navigator.userAgent,e=b.children("tbody").children(":visible"),f=e.length;b.children("thead").find('input[type="checkbox"]').each(function(){var b=a(this).closest("td, th").attr("data-column"),g=e.filter("."+c+"-"+b).length,h=g===f&&f>0;0===g||h?(this.checked=h,this.indeterminate=!1):(this.checked=!(d.indexOf("Trident/")>-1||d.indexOf("Edge/")>-1),this.indeterminate=!0)})};a("table").on("tablesorter-initialized updateComplete",function(){this.tablesorterBusy=!1;var e=".parser-forms";a(this).children("tbody").off(e).on("mouseleave"+e,function(b){"TBODY"===b.target.nodeName&&a(":focus").blur()}).on("focus"+e,"select, input:not([type=checkbox]), textarea",function(){a(this).data("ts-original-value",this.value)}).on("blur"+e,"input:not([type=checkbox]), textarea",function(){this.value=a(this).data("ts-original-value")}).on("change keyup ".split(" ").join(e+" "),"select, input, textarea",function(e){if(27===e.which&&("INPUT"!==this.nodeName||"checkbox"!==this.type))return void(this.value=a(this).data("ts-original-value"));if("change"===e.type||"keyup"===e.type&&13===e.which&&("INPUT"===e.target.nodeName||"TEXTAREA"===e.target.nodeName&&e.altKey)){var f,g,h=a(e.target),i="checkbox"===e.target.type,j=h.closest("td"),k=j.closest("table"),l=j[0].cellIndex,m=k[0].config||!1,n=k.length&&k[0].tablesorterBusy,o=m&&m.$headerIndexed&&m.$headerIndexed[l]||[],p=i?e.target.checked:h.val();if(a.isEmptyObject(m)||n!==!1)return;if(i&&(g=m.checkboxClass||"checked",c(j.closest("tr"),g,l,p),d(k,g)),o.length&&(o.hasClass("parser-false")||o.hasClass("sorter-false")&&o.hasClass("filter-false"))||"change"===e.type&&m.table.isUpdating)return;(m&&p!==h.data("ts-original-value")||i)&&(h.data("ts-original-value",p),k[0].tablesorterBusy=!0,a.tablesorter.updateCell(m,j,f,function(){b(e,k,h),k[0].tablesorterBusy=!1}))}}),a(this).children("thead").find('input[type="checkbox"]')&&a(this).off(e).on("tablesorter-ready"+e,function(){var b,c=a(this),e=c.length&&c[0].config;a.isEmptyObject(e)||(this.tablesorterBusy=!0,b=e&&e.checkboxClass||"checked",d(c,b),this.tablesorterBusy=!1)}).children("thead").off(e).on("click"+e+" change"+e,'input[type="checkbox"]',function(e){var f,g,h,i,j,k,l=a(this),m=l.closest("table"),n=m.length&&m[0].config,o=this.checked;return!(!m.length||!n||m[0].tablesorterBusy)&&(h=parseInt(l.closest("td, th").attr("data-column"),10),j="checkbox"===n.parsers[h].id,g=m.length&&n.checkboxVisible,m[0].tablesorterBusy=!0,i=m.children("tbody").children("tr"+("undefined"==typeof g||g===!0?":visible":"")).children(":nth-child("+(h+1)+")").find('input[type="checkbox"]').prop("checked",o),k=n.checkboxClass||"checked",i.each(function(){c(a(this).closest("tr"),k,h,o)}),d(m,k),j?a.tablesorter.update(n,f,function(){b(e,m,i),m[0].tablesorterBusy=!1}):(b(e,m,i),m[0].tablesorterBusy=!1),!0)})})}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-metric.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-metric.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..b24f5020d5e905d61f811022ca34d7bef068c322
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-metric.min.js
@@ -0,0 +1,2 @@
+/*! Parser: metric */
+!function(a){"use strict";var b={"Y|Yotta|yotta":[1e24,Math.pow(1024,8)],"Z|Zetta|zetta":[1e21,Math.pow(1024,7)],"E|Exa|exa":[1e18,Math.pow(1024,6)],"P|Peta|peta":[1e15,Math.pow(1024,5)],"T|Tera|tera":[1e12,Math.pow(1024,4)],"G|Giga|giga":[1e9,Math.pow(1024,3)],"M|Mega|mega":[1e6,Math.pow(1024,2)],"k|Kilo|kilo":[1e3,1024],"h|hecto":[100,100],"da|deka":[10,10],"d|deci":[.1,.1],"c|centi":[.01,.01],"m|milli":[.001,.001],"µ|micro":[1e-6,1e-6],"n|nano":[1e-9,1e-9],"p|pico":[1e-12,1e-12],"f|femto":[1e-15,1e-15],"a|atto":[1e-18,1e-18],"z|zepto":[1e-21,1e-21],"y|yocto":[1e-24,1e-24]},c="(\\d+)(\\s+)?([Zz]etta|[Ee]xa|[Pp]eta|[Tt]era|[Gg]iga|[Mm]ega|kilo|hecto|deka|deci|centi|milli|micro|nano|pico|femto|atto|zepto|yocto)(",d="(\\d+)(\\s+)?(Z|E|P|T|G|M|k|h|da|d|c|m|µ|n|p|f|a|z|y)(",e=/^[b|bit|byte|o|octet]/i;a.tablesorter.addParser({id:"metric",is:function(){return!1},format:function(f,g,h,i){var j,k,l,m,n="m|meter",o=a.tablesorter.formatFloat(f.replace(/[^\w,. \-()]/g,""),g),p=g.config.$headerIndexed[i],q=p.data("metric");if(q||(j=(p.attr("data-metric-name")||n).split("|"),l=p.attr("data-metric-name-full")||"",m=p.attr("data-metric-name-abbr")||"",q=[l||j[1]||j[0].substring(1),m||j[0]],k=e.test(q.join("")),q[2]=new RegExp(c+((""===l?"":l+"|"+m)||(k?q[0].toLowerCase()+"|"+q[0].toUpperCase():q[0])+"|"+(k?q[1].toLowerCase()+"|"+q[1].toUpperCase():q[1]))+")"),q[3]=new RegExp(d+(m||(k?q[1].toLowerCase()+"|"+q[1].toUpperCase():q[1]))+")"),p.data("metric",q)),j=f.match(q[2])||f.match(q[3]))for(n in b)if(j[3].match(n))return k=e.test(j[4])?1:0,o*b[n][k];return o},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-named-numbers.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-named-numbers.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..250ff8ad1dba6f5227e3ad6d46c9ec709088c47b
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-named-numbers.min.js
@@ -0,0 +1,2 @@
+/*! Parser: namedNumbers - updated 10/26/2014 (v2.18.0) */
+!function(a){"use strict";var b,c,d={negative:["negative","minus"],numbers:{zero:0,one:1,two:2,three:3,four:4,five:5,six:6,seven:7,eight:8,nine:9,ten:10,eleven:11,twelve:12,thirteen:13,fourteen:14,fifteen:15,sixteen:16,seventeen:17,eighteen:18,nineteen:19,twenty:20,thirty:30,forty:40,fourty:40,fifty:50,sixty:60,seventy:70,eighty:80,ninety:90},hundred:"hundred",powers:{thousand:1e3,million:1e6,billion:1e9,trillion:1e12,quadrillion:1e15,quintillion:1e18,sextillion:1e21,septillion:1e24,octillion:1e27,nonillion:1e30,decillion:1e33,undecillion:1e36,duodecillion:1e39,tredecillion:1e42,quattuordecillion:1e45,quindecillion:1e48,sexdecillion:1e51,septendecillion:1e54,octodecillion:1e57,novemdecillion:1e60,vigintillion:1e63,unvigintillion:1e66,duovigintillion:1e69,trevigintillion:1e72,quattuorvigintillion:1e75,quinvigintillion:1e78,sexvigintillion:1e81,septenvigintillion:1e84,octovigintillion:1e87,novemvigintillion:1e90,trigintillion:1e93,untrigintillion:1e96,duotrigintillion:1e99,googl:1e100}},e=new RegExp("("+d.negative.join("|")+")"),f=function(e,f){var g=e.replace(/[,."']/g,""),h=a.tablesorter.formatFloat(e||"",f),i=d.powers.hasOwnProperty(g)?d.powers[g]:null;h="number"==typeof h?h:d.numbers.hasOwnProperty(g)?d.numbers[g]:null,null!==h?c+=h:g===d.hundred?c*=100:null!==i&&(b+=c*i,c=0)};a.tablesorter.addParser({id:"namedNumbers",is:function(){return!1},format:function(g,h){b=0,c=0;var i,j=(g||"").split(/[\s-]+/),k=j.length;for(i=0;i<k;i++)f(j[i].toLowerCase(),h);return b=(b+c)*(g.match(e)?-1:1),b||d.numbers.hasOwnProperty(g)?b:a.tablesorter.formatFloat(g||"",h)},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-network.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-network.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..eefd239d6f0b9473bc5dc0efa7edb913a3d8d658
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-network.min.js
@@ -0,0 +1,5 @@
+/*! Parser: network - updated 5/17/2015 (v2.22.0) */
+!function(a){"use strict";var b,c,d=a.tablesorter;/*! IPv6 Address parser (WIP) */
+a.extend(d.regex,{},{ipv4Validate:/((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})/,ipv4Extract:/([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})/,ipv6Validate:/^\s*((([0-9a-f]{1,4}:){7}([0-9a-f]{1,4}|:))|(([0-9a-f]{1,4}:){6}(:[0-9a-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){5}(((:[0-9a-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9a-f]{1,4}:){4}(((:[0-9a-f]{1,4}){1,3})|((:[0-9a-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){3}(((:[0-9a-f]{1,4}){1,4})|((:[0-9a-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){2}(((:[0-9a-f]{1,4}){1,5})|((:[0-9a-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9a-f]{1,4}:){1}(((:[0-9a-f]{1,4}){1,6})|((:[0-9a-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9a-f]{1,4}){1,7})|((:[0-9a-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/i}),d.addParser({id:"ipv6Address",is:function(a){return d.regex.ipv6Validate.test(a)},format:function(a,b){var c,e,f,g,h,i=!!b&&("boolean"==typeof b?b:b&&b.config.ipv6HexFormat||!1),j="",k="",l=8;if(a=a.replace(/\s*/g,""),d.regex.ipv4Validate.test(a)){for(g=a.match(d.regex.ipv4Extract),e="",c=1;c<g.length;c++)e+=("00"+parseInt(g[c],10).toString(16)).slice(-2)+(2===c?":":"");a=a.replace(d.regex.ipv4Extract,e)}if(a.indexOf("::")==-1)j=a;else{for(f=a.split("::"),h=0,c=0;c<f.length;c++)h+=f[c].split(":").length;for(j+=f[0]+":",c=0;c<l-h;c++)j+="0000:";j+=f[1]}for(g=j.split(":"),c=0;c<l;c++)g[c]=i?("0000"+g[c]).slice(-4):("00000"+(parseInt(g[c],16)||0)).slice(-5),k+=c!=l-1?g[c]+":":g[c];return i?k:k.replace(/:/g,"")},type:"numeric"}),c=function(a){return/^\d{1,3}[\.]\d{1,3}[\.]\d{1,3}[\.]\d{1,3}$/.test(a)},b=function(a,b){var c,e=a?a.split("."):"",f="",g=e.length;for(c=0;c<g;c++)f+=("000"+e[c]).slice(-3);return a?d.formatFloat(f,b):a},/*! Parser: ipv4Address (a.k.a. ipAddress) */
+d.addParser({id:"ipAddress",is:c,format:b,type:"numeric"}),d.addParser({id:"ipv4Address",is:c,format:b,type:"numeric"}),/*! Parser: MAC address */
+d.addParser({id:"MAC",is:function(){return!1},format:function(a){var b,c,d="",e=(a||"").replace(/[:.-]/g,"").match(/\w{2}/g);if(e){for(c=e.length,b=0;b<c;b++)d+=("000"+parseInt(e[b],16)).slice(-3);return d}return a},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-roman.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-roman.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..ee1fc7e940343b8b730f8b4fff7984751143f851
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/parsers/parser-roman.min.js
@@ -0,0 +1,2 @@
+/*! Parser: roman - updated 6/28/MMXIV (v2.17.3) */
+!function(a){"use strict";var b=/^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/i,c=/\b([MCDLXVI]+\b)/gi,d={I:1,V:5,X:10,L:50,C:100,D:500,M:1e3};a.tablesorter.addParser({id:"roman",is:function(){return!1},format:function(a){var c,e=a.toUpperCase().split(""),f=0;if(!a||!b.test(a))return a;for(;e.length;)c=d[e.shift()],f+=c*(c<d[e[0]]?-1:1);return f},type:"numeric"}),a.tablesorter.addParser({id:"roman-ignore",is:function(){return!1},format:function(e,f,g,h){var i,j,k=f.config,l=a.isArray(k.roman_ignore)?k.roman_ignore[h]:0,m=(isNaN(l)?a.trim(e.replace(l,"")):a.trim(e.substring(0,e.length-l))).match(c),n=b.test(m),o=0;if(!n)return e;for(j=m[0],m=j.toUpperCase().split("");m.length;)i=d[m.shift()],i&&(o+=i*(i<d[m[0]]?-1:1));return o?e.replace(j,o):e},type:"text"}),a.tablesorter.addParser({id:"roman-extract",is:function(){return!1},format:function(e){var f,g=a.grep(e.split(/\b/),function(a,c){return b.test(a)?a:""}).join("").match(c),h=g?b.test(g):0,i=0;if(!h)return e;for(g=g[0].toUpperCase().split("");g.length;)f=d[g.shift()],f&&(i+=f*(f<d[g[0]]?-1:1));return i?i:e},type:"numeric"})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-alignChar.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-alignChar.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..93190d4442432d8dbb00c484206a4f6346f53927
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-alignChar.min.js
@@ -0,0 +1,2 @@
+/*! Widget: alignChar - updated 2/7/2015 (v2.19.0) */
+!function(a){"use strict";var b=a.tablesorter;b.alignChar={init:function(c,d,e){d.$headers.filter("["+e.alignChar_charAttrib+"]").each(function(){var f=a(this),g={column:this.column,align:f.attr(e.alignChar_charAttrib),alignIndex:parseInt(f.attr(e.alignChar_indexAttrib)||0,10),adjust:parseFloat(f.attr(e.alignChar_adjustAttrib))||0};g.regex=new RegExp("\\"+g.align,"g"),"undefined"!=typeof g.align&&(e.alignChar_savedVars[this.column]=g,b.alignChar.setup(c,d,e,g))})},setup:function(b,c,d,e){if(!a.isEmptyObject(c.cache)){var f,g,h,i,j,k,l,m,n,o,p,q,r,s,t=[],u=[];for(f=0;f<c.$tbodies.length;f++)for(l=c.cache[f],o=l.normalized.length,g=0;g<o;g++){if(s=l.row?l.row[g]:l.normalized[g][c.columns].$row,m=s.find("td").eq(e.column).text().replace(/[ ]/g," "),n=(m.match(e.regex)||[]).length,n>0&&e.alignIndex>0)for(i=Math.min(e.alignIndex,n),h=0,k=0,j=0;h++<i;)j=m.indexOf(e.align,j+1),k=j<0?k:j;else k=m.indexOf(e.align);k>=0?(t.push(m.substring(0,k)||""),u.push(m.substring(k,m.length)||"")):(t.push(n>=1&&e.alignIndex>=n?"":m||""),u.push(n>=1&&e.alignIndex>=n?m||"":""))}for(p=a.extend([],t).sort(function(a,b){return b.length-a.length})[0],q=a.extend([],u).sort(function(a,b){return b.length-a.length})[0],e.width=e.width||Math.floor(p.length/(p.length+q.length)*100)+e.adjust,p="min-width:"+e.width+"%",q="min-width:"+(100-e.width)+"%",f=0;f<c.$tbodies.length;f++)for(l=c.cache[f],o=l.normalized.length,g=0;g<o;g++)r=a(d.alignChar_wrap).length?a(d.alignChar_wrap).html(e.align)[0].outerHTML:e.align,s=l.row?l.row[g]:l.normalized[g][c.columns].$row,j=u[g].slice(e.align.length),s.find("td").eq(e.column).html('<span class="ts-align-wrap"><span class="ts-align-left" style="'+p+'">'+t[g]+'</span><span class="ts-align-right" style="'+q+'">'+(j.length?r+j:"")+"</span></span>");d.alignChar_initialized=!0}},remove:function(b,c,d){if(!a.isEmptyObject(c.cache)){var e,f,g,h,i,j;for(e=0;e<c.$tbodies.length;e++)for(h=c.cache[e],g=h.normalized.length,f=0;f<g;f++)i=h.row?h.row[f]:h.normalized[f][c.columns].$row,j=i.find("td").eq(d),j.html(j.text().replace(/\s/g," "))}}},b.addWidget({id:"alignChar",priority:100,options:{alignChar_wrap:"",alignChar_charAttrib:"data-align-char",alignChar_indexAttrib:"data-align-index",alignChar_adjustAttrib:"data-align-adjust"},init:function(a,c,d,e){e.alignChar_initialized=!1,e.alignChar_savedVars=[],b.alignChar.init(a,d,e),d.$table.on("pagerEnd refreshAlign",function(){d.$headers.filter("["+e.alignChar_charAttrib+"]").each(function(){b.alignChar.remove(a,d,this.column)}),b.alignChar.init(a,d,e)})},format:function(a,b,c){c.alignChar_initialized||b.$table.triggerHandler("refreshAlign")},remove:function(a,c,d,e){e||(c.$headers.filter("["+d.alignChar_charAttrib+"]").each(function(){b.alignChar.remove(a,c,this.column)}),d.alignChar_initialized=!1)}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-build-table.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-build-table.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..0581b520054226587b5df20075d485835cc6c38e
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-build-table.min.js
@@ -0,0 +1,2 @@
+/*! Widget: Build Table - updated 11/26/2016 (v2.28.0) */
+!function(a){"use strict";var b=a.tablesorter=a.tablesorter||{},c=b.buildTable=function(d,e){var f="TABLE"===d.nodeName?a(d):a("<table>").appendTo(d),g=f[0],h=e.widgetOptions=a.extend(!0,{},c.defaults,e.widgetOptions),i=h.build_processing,j=h.build_type,k=h.build_source||e.data,l=function(b){var d=a.type(b),f=b instanceof jQuery;if("function"==typeof i&&(b=i(b,h)),e.data=b,f||"string"===d){if(f||/<\s*\/tr\s*>/.test(b))return c.html(g,b,h);try{if(b=a.parseJSON(b||"null"))return c.object(g,b,h)}catch(a){}}return"array"===d||"string"===d||"array"===j||"csv"===j?c.csv(g,b,h):c.object(g,b,h)};return g.config=e,b.buildTable.hasOwnProperty(j)||""===j?void(k instanceof jQuery?l(a.trim(k.html())):k&&(k.hasOwnProperty("url")||"json"===j)?a.ajax(h.build_source).done(function(a){l(a)}).fail(function(a,b,c){e.debug&&console.error("aborting build table widget, failed ajax load"),f.html('<tr><td class="error">'+a.status+" "+b+"</td></tr>")}):l(k)):(e.debug&&console.error("aborting build table widget, incorrect build type"),!1)};b.defaults.data="",c.defaults={build_type:"",build_source:"",build_processing:null,build_complete:"tablesorter-build-complete",build_headers:{rows:1,classes:[],text:[],widths:[]},build_footers:{rows:1,classes:[],text:[]},build_numbers:{addColumn:!1,sortable:!1},build_csvStartLine:0,build_csvSeparator:",",build_objectRowKey:"rows",build_objectCellKey:"cells",build_objectHeaderKey:"headers",build_objectFooterKey:"footers"},c.build={colgroup:function(b){var c="";return b&&b.length&&(c+="<colgroup>",a.each(b,function(a,b){c+="<col"+(b?' style="width:'+b+'"':"")+">"}),c+="</colgroup>"),c},cell:function(b,c,d,e,f){var g,h,i=f?a("<col>"):"",j=c.build_headers.classes,k=c.build_headers.widths;if(/string|number/.test(typeof b))h=a("<"+d+(j&&j[e]?' class="'+j[e]+'"':"")+">"+b+"</"+d+">"),f&&k&&k[e]&&i.width(k[e]||"");else{h=a("<"+d+">");for(g in b)b.hasOwnProperty(g)&&("text"===g||"html"===g?h[g](b[g]):f&&"width"===g?i.width(b[g]||""):h.attr(g,b[g]))}return[h,i]},header:function(b,c){var d=c.build_headers.text,e=c.build_headers.classes,f="<tr>"+(c.build_numbers.addColumn?"<th"+(c.build_numbers.sortable?"":' class="sorter-false"')+">"+c.build_numbers.addColumn+"</th>":"");return a.each(b,function(a,b){f+=/<\s*\/t(d|h)\s*>/.test(b)?b:"<th"+(e&&e[a]?' class="'+e[a]+'"':"")+">"+(d&&d[a]?d[a]:b)+"</th>"}),f+"</tr>"},rows:function(b,c,d,e,f,g){var h=g?"th":"td",i="<tr>"+(e.build_numbers.addColumn?"<"+h+">"+(g?"":f)+"</"+h+">":"");return a.each(b,function(a,b){i+=/<\s*\/t(d|h)\s*>/.test(b)?b:"<"+(g?h+(d&&d[a]?' class="'+d[a]+'"':""):h)+">"+(g&&c&&c.length&&c[a]?c[a]:b)+"</"+h+">"}),i+"</tr>"}},c.buildComplete=function(c,d){a(c).triggerHandler(d.build_complete),b.setup(c,c.config)},c.array=function(a,b,d){return c.csv(a,b,d)},c.csv=function(b,d,e){var f,g,h,i="csv"===e.build_type||"string"==typeof d,j=a(b),k=i?d.replace("\r","").split("\n"):d,l=k.length,m=0,n=!1,o=e.build_headers.rows+(i?e.build_csvStartLine:0),p=e.build_footers.rows,q=0,r="",s=c.build.colgroup(e.build_headers.widths)+"<thead>";a.each(k,function(a,b){a>=l-p&&(n=!0),(!i||a>=e.build_csvStartLine)&&a<o?(g=i?c.splitCSV(b,e.build_csvSeparator):b,q=g.length,s+=c.build.header(g,e)):a>=o&&(a===o&&(s+="</thead><tbody>"),h=i?c.splitCSV(b,e.build_csvSeparator):b,n&&p>0&&(s+=(a===l-p?"</tbody><tfoot>":"")+(a===l?"</tfoot>":"")),h.length>1&&(m++,h.length!==q&&(r+="error on line "+a+": Item count ("+h.length+") does not match header count ("+q+") \n"),f=n?e.build_footers.classes:"",s+=c.build.rows(h,e.build_footers.text,f,e,m,n)))}),s+=p>0?"":"</tbody>",r?j.html(r):(j.html(s),c.buildComplete(b,e))},c.splitCSV=function(b,c){var d,e,f=a.trim(b).split(c=c||",");for(d=f.length-1;d>=0;d--)'"'===f[d].replace(/\"\s+$/,'"').charAt(f[d].length-1)?(e=f[d].replace(/^\s+\"/,'"')).length>1&&'"'===e.charAt(0)?f[d]=f[d].replace(/^\s*"|"\s*$/g,"").replace(/""/g,'"'):d?f.splice(d-1,2,[f[d-1],f[d]].join(c)):f=f.shift().split(c).concat(f):f[d].replace(/""/g,'"');return f},c.html=function(b,d,e){var f=a(b);d instanceof jQuery?f.empty().append(d):f.html(d),c.buildComplete(b,e)},c.object=function(b,d,e){var f,g,h,i,j,k,l,m=b.config,n=e.build_objectHeaderKey,o=e.build_objectRowKey,p=d.hasOwnProperty(n)&&!a.isEmptyObject(d.kh)?d.kh:!!d.hasOwnProperty("headers")&&d.headers,q=d.hasOwnProperty(o)&&!a.isEmptyObject(d.kr)?d.kr:!!d.hasOwnProperty("rows")&&d.rows;return p&&q&&0!==p.length&&0!==q.length?(i=a("<colgroup>"),j=a("<table><thead/></table>"),a.each(p,function(b,d){for(l=a("<tr>").appendTo(j.find("thead")),g=d.length,f=0;f<g;f++)h=c.build.cell(d[f],e,"th",f,0===b),h[0]&&h[0].length&&h[0].appendTo(l),0===b&&h[1]&&h[1].appendTo(i)}),i.find("col[style]").length&&j.prepend(i),k=a("<tbody>"),a.each(q,function(b,d){var f;if(h="object"===a.type(d),h&&d.newTbody){k=a("<tbody>").appendTo(j);for(f in d)d.hasOwnProperty(f)&&"newTbody"!==f&&k.attr(f,d[f])}else{if(0===b&&k.appendTo(j),l=a("<tr>").appendTo(k),h){for(f in d)d.hasOwnProperty(f)&&f!==e.build_objectCellKey&&l.attr(f,d[f]);d.hasOwnProperty(e.build_objectCellKey)&&(d=d.cells)}for(g=d.length,f=0;f<g;f++)i=c.build.cell(d[f],e,"td",f),i[0]&&i[0].length&&i[0].appendTo(l)}}),d.hasOwnProperty(e.build_objectFooterKey)&&(h=d[e.build_objectFooterKey],"clone"===h?(i=j.find("thead").html(),j.append("<tfoot>"+i+"</tfoot>")):(i=a("<tfoot>").appendTo(j),a.each(h,function(b,d){for(l=a("<tr>").appendTo(i),g=d.length,f=0;f<g;f++)k=c.build.cell(d[f],e,"th",f),k[0]&&k[0].length&&k[0].appendTo(l)}))),a(b).html(j.html()),void c.buildComplete(b,e)):(m.debug&&console.error("aborting build table widget, missing data for object build"),!1)},c.ajax=c.json=function(a,b,d){return c.object(a,b,d)}}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-chart.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-chart.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..e02b26fac16e62f353106326e8c69d145fdcb665
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-chart.min.js
@@ -0,0 +1 @@
+!function(a){"use strict";var b=a.tablesorter,c=[],d=[],e=[],f=[],g=[],h=[],i=[],j=[],k=b.chart={nonDigit:/[^\d,.\-()]/g,init:function(a,b){a.$table.off(b.chart_event).on(b.chart_event,function(){if(this.hasInitialized){var a=this.config;k.getCols(a,a.widgetOptions),k.getData(a,a.widgetOptions)}})},getCols:function(d,e){var f;for(c=[],h=[],j=[],f=0;f<d.columns;f++)e.chart_useSelector&&b.hasWidget(d.table,"columnSelector")&&!d.selector.auto?(d.selector.states[f]&&a.inArray(f,e.chart_ignoreColumns)<0||f===e.chart_labelCol||f===e.chart_sort[0][0])&&c.push(f):(a.inArray(f,e.chart_ignoreColumns)<0||f===e.chart_labelCol||f===e.chart_sort[0][0])&&c.push(f)},getData:function(b,c){k.getHeaders(b,c),k.getRows(b,c),f=[d],a.each(e,function(a,b){f.push(b)}),b.chart={data:f,categories:g,series:h,category:i,dataset:j}},getHeaders:function(b,e){var f;d=[],h=[],j=[],d.push(b.headerContent[e.chart_labelCol]),a.each(c,function(a,c){return c===e.chart_labelCol||(f=b.headerContent[c],d.push(f),h.push({name:f,data:[]}),void j.push({seriesname:f,data:[]}))})},getRows:function(c,d){var f=c.cache[0].normalized,l=[];e=[],g=[],i=[],a.each(f,function(b,e){var f,g,h=e[c.columns].$row,i=h.children("th,td"),j=[];if(/v/i.test(d.chart_incRows)&&h.is(":visible")||/f/i.test(d.chart_incRows)&&!h.hasClass(d.filter_filteredRow||"filtered")||!/(v|f)/i.test(d.chart_incRows)){for(f=0;f<c.columns;f++)a.inArray(b,d.chart_parsed)>=0?j.push(e[f]):(g=i[f].getAttribute(c.textAttribute)||i[f].textContent||i.eq(f).text(),j.push(a.trim(g)));l.push(j)}}),l.sort(function(a,c){return 1===d.chart_sort[0][1]?b.sortNatural(c[d.chart_sort[0][0]],a[d.chart_sort[0][0]]):b.sortNatural(a[d.chart_sort[0][0]],c[d.chart_sort[0][0]])}),a.each(l,function(f,l){var m,n=0,o=[],p=l[d.chart_labelCol];o.push(""+p),a.each(l,function(e,f){var l;return e===d.chart_labelCol?(g.push(f),i.push({label:f}),!0):(m=!1,d.chart_useSelector&&b.hasWidget(c.table,"columnSelector")&&!c.selector.auto?c.selector.states[e]&&a.inArray(e,d.chart_ignoreColumns)<0&&(m=""+f):a.inArray(e,d.chart_ignoreColumns)<0&&(m=""+f),void(m!==!1&&(/s/i.test(""+d.chart_layout[e])?(o.push(m),h[n].data.push(m),j[n].data.push(m)):(l=b.formatFloat(m.replace(k.nonDigit,""),c.table),l=isNaN(l)?m:l,o.push(l),h[n].data.push(l),j[n].data.push({value:l})),n++)))}),e.push(o)})},remove:function(a,b){a.$table.off(b.chart_event)}};b.addWidget({id:"chart",options:{chart_incRows:"filtered",chart_useSelector:!1,chart_ignoreColumns:[],chart_parsed:[],chart_layout:{0:"string"},chart_labelCol:0,chart_sort:[[0,0]],chart_event:"chartData"},init:function(a,b,c,d){k.init(c,d)},remove:function(a,b,c){k.remove(b,c)}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-columnSelector.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-columnSelector.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..de0c0445b41174d27d00a5bdc3007c40eda86ab0
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-columnSelector.min.js
@@ -0,0 +1 @@
+!function(a){"use strict";var b=a.tablesorter,c=".tscolsel",d=b.columnSelector={queryAll:"@media only all { [columns] { display: none; } } ",queryBreak:"@media all and (min-width: [size]) { [columns] { display: table-cell; } } ",init:function(b,e,f){var g,h;return g=a(f.columnSelector_layout),g.find("input").add(g.filter("input")).length?(e.$table.addClass(e.namespace.slice(1)+"columnselector"),h=e.selector={$container:a(f.columnSelector_container||"<div>")},h.$style=a("<style></style>").prop("disabled",!0).appendTo("head"),h.$breakpoints=a("<style></style>").prop("disabled",!0).appendTo("head"),h.isInitializing=!0,d.setUpColspan(e,f),d.setupSelector(e,f),f.columnSelector_mediaquery&&d.setupBreakpoints(e,f),h.isInitializing=!1,h.$container.length?d.updateCols(e,f):e.debug&&console.warn("ColumnSelector: >> container not found"),void e.$table.off("refreshColumnSelector"+c).on("refreshColumnSelector"+c,function(a,b,c){d.refreshColumns(this.config,b,c)})):void(e.debug&&console.error("ColumnSelector: >> ERROR: Column Selector aborting, no input found in the layout! ***"))},refreshColumns:function(b,c,e){var f,g,h,i,j=b.selector,k=a.isArray(e||c),l=b.widgetOptions;if("undefined"!=typeof c&&null!==c&&j.$container.length){if("selectors"===c&&(j.$container.empty(),d.setupSelector(b,l),d.setupBreakpoints(b,l),"undefined"==typeof e&&null!==e&&(e=j.auto)),k)for(g=e||c,a.each(g,function(a,b){g[a]=parseInt(b,10)}),f=0;f<b.columns;f++)i=a.inArray(f,g)>=0,h=j.$container.find("input[data-column="+f+"]"),h.length&&(h.prop("checked",i),j.states[f]=i);i=e===!0||c===!0||"auto"===c&&e!==!1,h=j.$container.find('input[data-column="auto"]').prop("checked",i),d.updateAuto(b,l,h)}else d.updateBreakpoints(b,l),d.updateCols(b,l);d.saveValues(b,l),d.adjustColspans(b,l)},setupSelector:function(c,e){var f,g,h,i,j,k,l,m=c.selector,n=m.$container,o=e.columnSelector_saveColumns&&b.storage,p=o?b.storage(c.table,"tablesorter-columnSelector"):[],q=o?b.storage(c.table,"tablesorter-columnSelector-auto"):{};for(m.auto=a.isEmptyObject(q)||"boolean"!==a.type(q.auto)?e.columnSelector_mediaqueryState:q.auto,m.states=[],m.$column=[],m.$wrapper=[],m.$checkbox=[],f=0;f<c.columns;f++)h=c.$headerIndexed[f],i=h.attr(e.columnSelector_priority)||1,k=h.attr("data-column"),j=b.getColumnData(c.table,c.headers,k),q=b.getData(h,j,"columnSelector"),isNaN(i)&&i.length>0||"disable"===q||e.columnSelector_columns[k]&&"disable"===e.columnSelector_columns[k]?m.states[k]=null:(m.states[k]=p&&"undefined"!=typeof p[k]&&null!==p[k]?p[k]:"undefined"!=typeof e.columnSelector_columns[k]&&null!==e.columnSelector_columns[k]?e.columnSelector_columns[k]:"true"===q||"false"!==q,m.$column[k]=a(this),n.length&&(g=h.attr(e.columnSelector_name)||h.text().trim(),"function"==typeof e.columnSelector_layoutCustomizer&&(l=h.find("."+b.css.headerIn),g=e.columnSelector_layoutCustomizer(l.length?l:h,g,parseInt(k,10))),m.$wrapper[k]=a(e.columnSelector_layout.replace(/\{name\}/g,g)).appendTo(n),m.$checkbox[k]=m.$wrapper[k].find("input").add(m.$wrapper[k].filter("input")).attr("data-column",k).toggleClass(e.columnSelector_cssChecked,m.states[k]).prop("checked",m.states[k]).on("change",function(){if(!m.isInitializing){var b=a(this).attr("data-column");if(!d.checkChange(c,this.checked))return this.checked=!this.checked,!1;c.selector.states[b]=this.checked,d.updateCols(c,e)}}).change()))},checkChange:function(a,b){for(var c=a.widgetOptions,d=c.columnSelector_maxVisible,e=c.columnSelector_minVisible,f=a.selector.states,g=f.length,h=0;g-- >=0;)f[g]&&h++;return!(b&null!==d&&h>=d||!b&&null!==e&&h<=e)},setupBreakpoints:function(b,e){var f=b.selector;e.columnSelector_mediaquery&&(f.lastIndex=-1,d.updateBreakpoints(b,e),b.$table.off("updateAll"+c).on("updateAll"+c,function(){d.setupSelector(b,e),d.setupBreakpoints(b,e),d.updateBreakpoints(b,e),d.updateCols(b,e)})),f.$container.length&&(e.columnSelector_mediaquery&&(f.$auto=a(e.columnSelector_layout.replace(/\{name\}/g,e.columnSelector_mediaqueryName)).prependTo(f.$container),f.$auto.find("input").add(f.$auto.filter("input")).attr("data-column","auto").prop("checked",f.auto).toggleClass(e.columnSelector_cssChecked,f.auto).on("change",function(){d.updateAuto(b,e,a(this))}).change()),b.$table.off("update"+c).on("update"+c,function(){d.updateCols(b,e)}))},updateAuto:function(b,c,e){var f=b.selector;f.auto=e.prop("checked")||!1,a.each(f.$checkbox,function(a,b){b&&(b[0].disabled=f.auto,f.$wrapper[a].toggleClass("disabled",f.auto))}),c.columnSelector_mediaquery&&d.updateBreakpoints(b,c),d.updateCols(b,c),b.selector.$popup&&b.selector.$popup.find(".tablesorter-column-selector").html(f.$container.html()).find("input").each(function(){var b=a(this).attr("data-column");a(this).prop("checked","auto"===b?f.auto:f.states[b])}),d.saveValues(b,c),d.adjustColspans(b,c),f.auto&&b.$table.triggerHandler(c.columnSelector_updated)},addSelectors:function(a,b){var c=[],d=" col:nth-child("+b+")";return c.push(a+d+","+a+"_extra_table"+d),d=' tr:not(.hasSpan) th[data-column="'+(b-1)+'"]',c.push(a+d+","+a+"_extra_table"+d),d=" tr:not(.hasSpan) td:nth-child("+b+")",c.push(a+d+","+a+"_extra_table"+d),d=" tr td:not("+a+'HasSpan)[data-column="'+(b-1)+'"]',c.push(a+d+","+a+"_extra_table"+d),c},updateBreakpoints:function(c,e){var f,g,h,i,j=[],k=c.selector,l=c.namespace+"columnselector",m=[],n="";if(e.columnSelector_mediaquery&&!k.auto)return k.$breakpoints.prop("disabled",!0),void k.$style.prop("disabled",!1);if(e.columnSelector_mediaqueryHidden)for(h=0;h<c.columns;h++)g=b.getColumnData(c.table,c.headers,h),j[h+1]="false"===b.getData(c.$headerIndexed[h],g,"columnSelector"),j[h+1]&&(m=m.concat(d.addSelectors(l,h+1)));for(f=0;f<e.columnSelector_maxPriorities;f++)i=[],c.$headers.filter("["+e.columnSelector_priority+"="+(f+1)+"]").each(function(){h=parseInt(a(this).attr("data-column"),10)+1,j[h]||(i=i.concat(d.addSelectors(l,h)))}),i.length&&(m=m.concat(i),n+=d.queryBreak.replace(/\[size\]/g,e.columnSelector_breakpoints[f]).replace(/\[columns\]/g,i.join(",")));k.$style&&k.$style.prop("disabled",!0),m.length&&k.$breakpoints.prop("disabled",!1).text(d.queryAll.replace(/\[columns\]/g,m.join(","))+n)},updateCols:function(b,c){if(!(c.columnSelector_mediaquery&&b.selector.auto||b.selector.isInitializing)){var e,f=b.selector,g=[],h=b.namespace+"columnselector";f.$container.find("input[data-column]").filter('[data-column!="auto"]').each(function(){this.checked||(e=parseInt(a(this).attr("data-column"),10)+1,g=g.concat(d.addSelectors(h,e))),a(this).toggleClass(c.columnSelector_cssChecked,this.checked)}),c.columnSelector_mediaquery&&f.$breakpoints.prop("disabled",!0),f.$style&&f.$style.prop("disabled",!1).text(g.length?g.join(",")+" { display: none; }":""),d.saveValues(b,c),d.adjustColspans(b,c),b.$table.triggerHandler(c.columnSelector_updated)}},setUpColspan:function(c,e){var f,g,h,i=a(window),j=!1,k=c.$table.add(a(c.namespace+"_extra_table")).children().children("tr").children("th, td"),l=k.length;for(f=0;f<l;f++)g=k[f].colSpan,g>1&&(j=!0,k.eq(f).addClass(c.namespace.slice(1)+"columnselectorHasSpan").attr("data-col-span",g),b.computeColumnIndex(k.eq(f).parent().addClass("hasSpan")));j&&e.columnSelector_mediaquery&&(h=c.namespace+"columnselector",i.off(h).on("resize"+h,b.window_resize).on("resizeEnd"+h,function(){i.off("resize"+h,b.window_resize),d.adjustColspans(c,e),i.on("resize"+h,b.window_resize)}))},adjustColspans:function(b,c){var d,e,f,g,h,i,j=b.selector,k=c.filter_filteredRow||"filtered",l=c.columnSelector_mediaquery&&j.auto,m=b.$table.children("thead, tfoot").children().children().add(a(b.namespace+"_extra_table").children("thead, tfoot").children().children()),n=m.length;for(d=0;d<n;d++)if(i=m.eq(d),f=parseInt(i.attr("data-column"),10)||i[0].cellIndex,g=parseInt(i.attr("data-col-span"),10)||1,h=f+g,g>1){for(e=f;e<h;e++)(!l&&j.states[e]===!1||l&&b.$headerIndexed[e]&&!b.$headerIndexed[e].is(":visible"))&&g--;g?i.removeClass(k)[0].colSpan=g:i.addClass(k)}else"undefined"!=typeof j.states[f]&&null!==j.states[f]&&i.toggleClass(k,!j.states[f])},saveValues:function(a,c){if(c.columnSelector_saveColumns&&b.storage){var d=a.selector;b.storage(a.$table[0],"tablesorter-columnSelector-auto",{auto:d.auto}),b.storage(a.$table[0],"tablesorter-columnSelector",d.states)}},attachTo:function(b,c){b=a(b)[0];var e,f,g,h=b.config,i=a(c);i.length&&h&&(i.find(".tablesorter-column-selector").length||i.append('<span class="tablesorter-column-selector"></span>'),e=h.selector,f=h.widgetOptions,i.find(".tablesorter-column-selector").html(e.$container.html()).find("input").each(function(){var b=a(this).attr("data-column"),c="auto"===b?e.auto:e.states[b];a(this).toggleClass(f.columnSelector_cssChecked,c).prop("checked",c)}),e.$popup=i.on("change","input",function(){if(!e.isInitializing){if(!d.checkChange(h,this.checked))return this.checked=!this.checked,!1;g=a(this).toggleClass(f.columnSelector_cssChecked,this.checked).attr("data-column"),e.$container.find('input[data-column="'+g+'"]').prop("checked",this.checked).trigger("change")}}))}};b.window_resize=function(){b.timer_resize&&clearTimeout(b.timer_resize),b.timer_resize=setTimeout(function(){a(window).trigger("resizeEnd")},250)},b.addWidget({id:"columnSelector",priority:10,options:{columnSelector_container:null,columnSelector_columns:{},columnSelector_saveColumns:!0,columnSelector_layout:'<label><input type="checkbox">{name}</label>',columnSelector_layoutCustomizer:null,columnSelector_name:"data-selector-name",columnSelector_mediaquery:!0,columnSelector_mediaqueryName:"Auto: ",columnSelector_mediaqueryState:!0,columnSelector_mediaqueryHidden:!1,columnSelector_maxVisible:null,columnSelector_minVisible:null,columnSelector_breakpoints:["20em","30em","40em","50em","60em","70em"],columnSelector_maxPriorities:6,columnSelector_priority:"data-priority",columnSelector_cssChecked:"checked",columnSelector_updated:"columnUpdate"},init:function(a,b,c,e){d.init(a,c,e)},remove:function(b,d,e,f){var g=d.selector;g&&g.$container.empty(),!f&&g&&(g.$popup&&g.$popup.empty(),g.$style.remove(),g.$breakpoints.remove(),a(d.namespace+"columnselectorHasSpan").removeClass(e.filter_filteredRow||"filtered"),d.$table.off("updateAll"+c+" update"+c))}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-columns.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-columns.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..6ccebd276de7b9c755757b5e22187a9a912edecf
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-columns.min.js
@@ -0,0 +1,2 @@
+/*! Widget: columns */
+!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,r=e&&e.columns||["primary","secondary","tertiary"],s=r.length-1;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;m<q;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;m<q;m++)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);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-cssStickyHeaders.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-cssStickyHeaders.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..0e2ce3918ac82b0e814fe69b0eb0428faaf819b9
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-cssStickyHeaders.min.js
@@ -0,0 +1,2 @@
+/*! Widget: cssStickyHeaders - updated 2/9/2015 (v2.19.1) */
+!function(a,b){"use strict";var c=a.tablesorter;c.addWidget({id:"cssStickyHeaders",priority:10,options:{cssStickyHeaders_offset:0,cssStickyHeaders_addCaption:!1,cssStickyHeaders_attachTo:null,cssStickyHeaders_filteredToTop:!0},init:function(d,e,f,g){var h,i,j,k=f.$table,l=a(g.cssStickyHeaders_attachTo),m="ActiveXObject"in b,n=f.namespace+"cssstickyheader ",o=k.children("thead"),p=k.children("caption"),q=l.length?l:a(b),r=k.parent().closest("table."+c.css.table),s=r.length&&c.hasWidget(r[0],"cssStickyHeaders")?r.children("thead"):[],t=parseInt(k.css("border-top-width"),10)||0,u=g.cssStickyHeaders_addCaption,v=!1,w=!1,x=function(a,b){var c=0===b?"":"translate(0px,"+b+"px)";a.css({transform:c,"-ms-transform":c,"-webkit-transform":c})};p.length&&(h=k.height(),p.hide(),w=k.height()===h,p.show(),i=k.offset().top,x(p,20),v=k.offset().top!==i,x(p,0)),q.unbind("scroll resize ".split(" ").join(n).replace(/\s+/g," ")).bind("scroll resize ".split(" ").join(n),function(){g=f.widgetOptions,v&&(x(p,0),j=k.offset().top);var a=l.length?l.offset().top:q.scrollTop(),b=(p.outerHeight(!0)||0)+(parseInt(k.css("padding-top"),10)||0)+(parseInt(k.css("border-spacing"),10)||0),c=k.height()+(w&&g.cssStickyHeaders_addCaption?b:0)-o.height()-(k.children("tfoot").height()||0)-(g.cssStickyHeaders_addCaption?b:w?0:b),d=s.length?s.height():0,e=s.length?m?r.data("cssStickyHeaderBottom")+d:s.offset().top+d-q.scrollTop():0,h=v?j:k.offset().top,i=w?h-(g.cssStickyHeaders_addCaption?b:0):h,n=a-i+e+t+(g.cssStickyHeaders_offset||0)-(g.cssStickyHeaders_addCaption?w?b:0:b),y=n>0&&n<=c?n:0,z=m?o.children().children():o;m&&f.$table.data("cssStickyHeaderBottom",(s.length?d:0)-(g.cssStickyHeaders_addCaption?b:0)),g.cssStickyHeaders_addCaption&&(z=z.add(p)),u!==g.cssStickyHeaders_addCaption&&(u=g.cssStickyHeaders_addCaption,u||x(p,0)),x(z,y)}),k.unbind(("filterEnd"+n).replace(/\s+/g," ")).bind("filterEnd"+n,function(){g.cssStickyHeaders_filteredToTop&&b.scrollTo(0,k.position().top)})},remove:function(c,d,e,f){if(!f){var g=d.namespace+"cssstickyheader ";a(b).unbind("scroll resize ".split(" ").join(g).replace(/\s+/g," ")),d.$table.unbind("filterEnd scroll resize ".split(" ").join(g).replace(/\s+/g," ")).add(d.$table.children("thead").children().children()).children("thead, caption").css({transform:"","-ms-transform":"","-webkit-transform":""})}}})}(jQuery,window);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-currentSort.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-currentSort.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..66d079982d82b2a2209cbb27075799fe95a43646
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-currentSort.min.js
@@ -0,0 +1,2 @@
+/*! Widget: currentSort - 7/31/2016 (v2.27.0) */
+!function(a){"use strict";var b=a.tablesorter;b.currentSortLanguage={0:"asc",1:"desc",2:"unsorted"},b.currentSort={init:function(a){a.$table.on("sortEnd.tscurrentSort",function(){b.currentSort.update(this.config)})},update:function(a){if(a){var c,d=a.widgetOptions,e=b.currentSortLanguage,f=e[2],g=Array.apply(null,Array(a.columns)).map(String.prototype.valueOf,f),h=a.sortList,i=h.length;for(c=0;c<i;c++)g[h[c][0]]=e[h[c][1]];a.currentSort=g,"function"==typeof d.currentSort_callback&&d.currentSort_callback(a,g)}}},b.addWidget({id:"currentSort",options:{currentSort_callback:null},init:function(a,c,d,e){b.currentSort.init(d,e)},remove:function(a,b){b.$table.off("sortEnd.tscurrentSort")}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-editable.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-editable.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..af6d0a641a7b42cbfaf7077f150c4e2fa55ef7f6
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-editable.min.js
@@ -0,0 +1,2 @@
+/*! Widget: editable - updated 3/1/2016 (v2.25.5) */
+!function(a){"use strict";var b=a.tablesorter.editable={namespace:".tseditable",lastEdited:"tseditable-last-edited-cell",editComplete:function(a,c,d,e){a.$table.find("."+b.lastEdited).removeClass(b.lastEdited).trigger(c.editable_editComplete,[a]),e&&setTimeout(function(){d.focus()},50)},selectAll:function(a){setTimeout(function(){if(document.queryCommandSupported("SelectAll"))document.execCommand("selectAll",!1,null);else{var b,c;document.body.createTextRange?(b=document.body.createTextRange(),b.moveToElementText(a),b.select()):window.getSelection&&(c=window.getSelection(),b=document.createRange(),b.selectNodeContents(a),c.removeAllRanges(),c.addRange(b))}},100)},getColumns:function(b,c){var d,e,f,g,h,i=c.editable_columns,j=[];if("string"==typeof i)for(d=i.replace(/\s+/,"").split(/,/),g=d.length-1;g>=0;){if(d[g].indexOf("-")>=0)for(f=d[g].split("-"),e=parseInt(f[0],10)||0,f=parseInt(f[1],10)||b.columns-1,e>f&&(h=e,e=f,f=h);e<=f;e++)j.push("td:nth-child("+(e+1)+")");else j.push("td:nth-child("+((parseInt(d[g],10)||0)+1)+")");g--}else if(a.isArray(i))for(g=i.length,e=0;e<g;e++)i[e]<b.columns&&j.push("td:nth-child("+(i[e]+1)+")");return j},update:function(c,d){var e,f,g,h,i,j,k,l=a("<div>").wrapInner(d.editable_wrapContent).children().length||a.isFunction(d.editable_wrapContent),m=b.getColumns(c,d).join(",");for(c.$tbodies.find(m).find("[contenteditable]").prop("contenteditable",!1),f=c.$tbodies.find(m).not("."+d.editable_noEdit),h=f.length,g=0;g<h;g++)if(e=f.eq(g),l&&0===e.children("div, span").length&&e.wrapInner(d.editable_wrapContent),i=e.children("div, span").not("."+d.editable_noEdit),k=i.length)for(j=0;j<k;j++){var n=i.eq(j);d.editable_trimContent&&n.html(function(b,c){return a.trim(c)}),n.prop("contenteditable",!0)}else d.editable_trimContent&&e.html(function(b,c){return a.trim(c)}),e.prop("contenteditable",!0)},bindEvents:function(c,d){var e=b.namespace;c.$table.off("updateComplete pagerComplete ".split(" ").join(e+" ").replace(/\s+/g," ")).on("updateComplete pagerComplete ".split(" ").join(e+" "),function(){b.update(c,c.widgetOptions)}).children("thead").add(a(c.namespace+"_extra_table").children("thead")).off("mouseenter"+e).on("mouseenter"+e,function(){c.$table.data("contentFocused")&&(c.$table.data("contentFocused",!0),a(":focus").trigger("focusout"))}),c.$tbodies.off("focus blur focusout keydown ".split(" ").join(e+" ").replace(/\s+/g," ")).on("focus"+e,"[contenteditable]",function(f){clearTimeout(a(this).data("timer")),c.$table.data("contentFocused",f.target),c.table.isUpdating=!0;var g=a(this),h=d.editable_selectAll,i=g.closest("td").index(),j=g.html();d.editable_trimContent&&(j=a.trim(j)),g.off("keydown"+e).on("keydown"+e,function(a){d.editable_enterToAccept&&13===a.which&&!a.shiftKey&&a.preventDefault()}),g.data({before:j,original:j}),"function"==typeof d.editable_focused&&d.editable_focused(j,i,g),h&&("function"==typeof h?h(j,i,g)&&b.selectAll(g[0]):b.selectAll(g[0]))}).on("blur focusout keydown ".split(" ").join(e+" "),"[contenteditable]",function(f){if(c.$table.data("contentFocused")){var g,h,i=!1,j=a(f.target),k=j.html(),l=j.closest("td").index();if(d.editable_trimContent&&(k=a.trim(k)),27===f.which)return j.html(j.data("original")).trigger("blur"+e),c.$table.data("contentFocused",!1),c.table.isUpdating=!1,!1;if(g=13===f.which&&!f.shiftKey&&(d.editable_enterToAccept||f.altKey)||d.editable_autoAccept&&"keydown"!==f.type,g&&j.data("before")!==k){if(h=d.editable_validate,i=k,"function"==typeof h?i=h(k,j.data("original"),l,j):"function"==typeof(h=a.tablesorter.getColumnData(c.table,h,l))&&(i=h(k,j.data("original"),l,j)),g&&i!==!1)return c.$table.find("."+b.lastEdited).removeClass(b.lastEdited),j.addClass(b.lastEdited).html(i).data("before",i).data("original",i).trigger("change"),c.table.hasInitialized&&a.tablesorter.updateCell(c,j.closest("td"),!1,function(){d.editable_autoResort?setTimeout(function(){a.tablesorter.sortOn(c,c.sortList,function(){b.editComplete(c,d,c.$table.data("contentFocused"),!0)},!0)},10):b.editComplete(c,d,c.$table.data("contentFocused"))}),!1}else i||"keydown"===f.type||(clearTimeout(j.data("timer")),j.data("timer",setTimeout(function(){c.table.isUpdating=!1,a.isFunction(d.editable_blur)&&(k=j.html(),d.editable_blur(d.editable_trimContent?a.trim(k):k,l,j))},100)),j.html(j.data("original")))}}).on("paste"+e,"[contenteditable]",function(){var b,c=a(this);setTimeout(function(){c.is(":focus")&&(b="<div>"+c.html()+"</div>",c.html(a(b).text().trim()))},0)})},destroy:function(a,c){var d=b.namespace,e=b.getColumns(a,c),f="updateComplete pagerComplete ".split(" ").join(d+" ").replace(/\s+/g," ");a.$table.off(f),f="focus blur focusout keydown paste ".split(" ").join(d+" ").replace(/\s+/g," "),a.$tbodies.off(f).find(e.join(",")).find("[contenteditable]").prop("contenteditable",!1)}};a.tablesorter.addWidget({id:"editable",options:{editable_columns:[],editable_enterToAccept:!0,editable_autoAccept:!0,editable_autoResort:!1,editable_wrapContent:"<div>",editable_trimContent:!0,editable_validate:null,editable_focused:null,editable_blur:null,editable_selectAll:!1,editable_noEdit:"no-edit",editable_editComplete:"editComplete"},init:function(a,c,d,e){e.editable_columns.length&&(b.update(d,e),b.bindEvents(d,e))},remove:function(a,c,d,e){e||b.destroy(c,d)}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-formatter-html5.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-formatter-html5.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..253df9a16de9bcfe2727f3bc4afcda5b36477416
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-formatter-html5.min.js
@@ -0,0 +1,2 @@
+/*! Widget: filter, html5 formatter functions - updated 7/17/2014 (v2.17.5) */
+!function(a){"use strict";var b=a.tablesorter||{},c=".compare-select",d=b.filterFormatter=a.extend({},b.filterFormatter,{addCompare:function(b,d,e){if(e.compare&&a.isArray(e.compare)&&e.compare.length>1){var f="",g=[c.slice(1)," "+c.slice(1),""],h=e.cellText?'<label class="'+g.join("-label")+d+'">'+e.cellText+"</label>":"";a.each(e.compare,function(a,b){f+="<option "+(e.selected===a?"selected":"")+">"+b+"</option>"}),b.wrapInner('<div class="'+g.join("-wrapper")+d+'" />').prepend(h+'<select class="'+g.join("")+d+'" />').find("select").append(f)}},updateCompare:function(b,d,e){var f=d.val()||"",g=f.replace(/\s*?[><=]\s*?/g,""),h=f.match(/[><=]/g)||"";return e.compare&&(a.isArray(e.compare)&&(h=(h||[]).join("")||e.compare[e.selected||0]),b.find(c).val(h)),[f,g]},html5Number:function(e,f,g){var h,i,j=a.extend({value:0,min:0,max:100,step:1,delayed:!0,disabled:!1,addToggle:!1,exactMatch:!1,cellText:"",compare:"",skipTest:!1},g),k=a('<input type="number" style="visibility:hidden;" value="test">').appendTo(e),l=j.skipTest||"number"===k.attr("type")&&"test"!==k.val(),m=[],n=e.closest("table")[0].config,o=function(b,d){var f=!j.addToggle||e.find(".toggle").is(":checked"),g=e.find(".number").val(),h=(a.isArray(j.compare)?e.find(c).val()||j.compare[j.selected||0]:j.compare)||"",k=!n.$table[0].hasInitialized||((b?b:j.delayed)||"");i.val(!j.addToggle||f?(h?h:j.exactMatch?"=":"")+g:"").trigger(d?"":"search",k).end().find(".number").val(g),e.find(".number").length&&(e.find(".number")[0].disabled=j.disabled||!f),m.length&&(m.find(".number").val(g)[0].disabled=j.disabled||!f,m.find(c).val(h),j.addToggle&&(m.find(".toggle")[0].checked=f))};return k.remove(),l&&(h=j.addToggle?'<div class="button"><input id="html5button'+f+'" type="checkbox" class="toggle" /><label for="html5button'+f+'"></label></div>':"",h+='<input class="number" type="number" min="'+j.min+'" max="'+j.max+'" value="'+j.value+'" step="'+j.step+'" />',e.append(h+'<input type="hidden" />').find(".toggle, .number").bind("change",function(){o()}).closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed").closest("table").bind("filterReset",function(){a.isArray(j.compare)&&e.add(m).find(c).val(j.compare[j.selected||0]),j.addToggle&&(e.find(".toggle")[0].checked=!1,m.length&&(m.find(".toggle")[0].checked=!1)),e.find(".number").val(j.value),setTimeout(function(){o()},0)}),i=e.find("input[type=hidden]").bind("change",function(){e.find(".number").val(this.value),o()}),n.$table.bind("filterFomatterUpdate",function(){var a=d.updateCompare(e,i,j)[0]||j.value;e.find(".number").val(((a||"")+"").replace(/[><=]/g,"")),o(!1,!0),b.filter.formatterUpdated(e,f)}),j.compare&&(d.addCompare(e,f,j),e.find(c).bind("change",function(){o()})),n.$table.bind("stickyHeadersInit",function(){m=n.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),m.append(h).find(".toggle, .number").bind("change",function(){e.find(".number").val(a(this).val()),o()}),j.compare&&(d.addCompare(m,f,j),m.find(c).bind("change",function(){e.find(c).val(a(this).val()),o()})),o()}),o()),l?e.find('input[type="hidden"]'):a('<input type="search">')},html5Range:function(e,f,g){var h,i=a.extend({value:0,min:0,max:100,step:1,delayed:!0,valueToHeader:!0,exactMatch:!0,cellText:"",compare:"",allText:"all",skipTest:!1},g),j=a('<input type="range" style="visibility:hidden;" value="test">').appendTo(e),k=i.skipTest||"range"===j.attr("type")&&"test"!==j.val(),l=[],m=e.closest("table")[0].config,n=function(b,d,g){b=("undefined"==typeof b?h.val():b).toString().replace(/[<>=]/g,"")||i.value;var j=(a.isArray(i.compare)?e.find(c).val()||i.compare[i.selected||0]:i.compare)||"",k=" ("+(j?j+b:b==i.min?i.allText:b)+")",n=!m.$table[0].hasInitialized||((d?d:i.delayed)||"");e.find("input[type=hidden]").val(j?j+b:b==i.min?"":(i.exactMatch?"=":"")+b).trigger(g?"":"search",n).end().find(".range").val(b),e.closest("thead").find("th[data-column="+f+"]").find(".curvalue").html(k),l.length&&(l.find(".range").val(b).end().find(c).val(j),l.closest("thead").find("th[data-column="+f+"]").find(".curvalue").html(k))};return j.remove(),k&&(e.html('<input type="hidden"><input class="range" type="range" min="'+i.min+'" max="'+i.max+'" value="'+i.value+'" />').closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed").find(".tablesorter-header-inner").append('<span class="curvalue" />'),h=e.find("input[type=hidden]").bind("change"+m.namespace+"filter",function(){var b=this.value,d=(a.isArray(i.compare)?e.find(c).val()||i.compare[i.selected||0]:i.compare)||"";b!==this.lastValue&&(this.lastValue=d?d+b:b==i.min?"":(i.exactMatch?"=":"")+b,this.value=this.lastValue,n(b))}),e.find(".range").bind("change",function(){n(this.value)}),m.$table.bind("filterFomatterUpdate",function(){var a=d.updateCompare(e,h,i)[0];e.find(".range").val(a),n(a,!1,!0),b.filter.formatterUpdated(e,f)}),i.compare&&(d.addCompare(e,f,i),e.find(c).bind("change",function(){n()})),m.$table.bind("stickyHeadersInit",function(){l=m.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),l.html('<input class="range" type="range" min="'+i.min+'" max="'+i.max+'" value="'+i.value+'" />').find(".range").bind("change",function(){n(l.find(".range").val())}),n(),i.compare&&(d.addCompare(l,f,i),l.find(c).bind("change",function(){e.find(c).val(a(this).val()),n()}))}),e.closest("table").bind("filterReset",function(){a.isArray(i.compare)&&e.add(l).find(c).val(i.compare[i.selected||0]),setTimeout(function(){n(i.value,!1,!0)},0)}),n()),k?e.find('input[type="hidden"]'):a('<input type="search">')},html5Color:function(c,d,e){var f,g,h=a.extend({value:"#000000",disabled:!1,addToggle:!0,exactMatch:!0,valueToHeader:!1,skipTest:!1},e),i=a('<input type="color" style="visibility:hidden;" value="test">').appendTo(c),j=h.skipTest||"color"===i.attr("type")&&"test"!==i.val(),k=[],l=c.closest("table")[0].config,m=function(a,b){a=("undefined"==typeof a?g.val():a).toString().replace("=","")||h.value;var e=!0,f=" ("+a+")";h.addToggle&&(e=c.find(".toggle").is(":checked")),c.find(".colorpicker").length&&(c.find(".colorpicker").val(a)[0].disabled=h.disabled||!e),g.val(e?a+(h.exactMatch?"=":""):"").trigger(!l.$table[0].hasInitialized||b?"":"search"),h.valueToHeader?c.closest("thead").find("th[data-column="+d+"]").find(".curcolor").html(f):c.find(".currentColor").html(f),k.length&&(k.find(".colorpicker").val(a)[0].disabled=h.disabled||!e,h.addToggle&&(k.find(".toggle")[0].checked=e),h.valueToHeader?k.closest("thead").find("th[data-column="+d+"]").find(".curcolor").html(f):k.find(".currentColor").html(f))};return i.remove(),j&&(f=""+d+Math.round(100*Math.random()),f='<div class="color-controls-wrapper">'+(h.addToggle?'<div class="button"><input id="colorbutton'+f+'" type="checkbox" class="toggle" /><label for="colorbutton'+f+'"></label></div>':"")+'<input type="hidden"><input class="colorpicker" type="color" />'+(h.valueToHeader?"":'<span class="currentColor">(#000000)</span>')+"</div>",c.html(f),h.valueToHeader&&c.closest("thead").find("th[data-column="+d+"]").find(".tablesorter-header-inner").append('<span class="curcolor" />'),c.find(".toggle, .colorpicker").bind("change",function(){m(c.find(".colorpicker").val())}),g=c.find("input[type=hidden]").bind("change"+l.namespace+"filter",function(){m(this.value)}),l.$table.bind("filterFomatterUpdate",function(){m(g.val(),!0),b.filter.formatterUpdated(c,d)}),c.closest("table").bind("filterReset",function(){h.addToggle&&(c.find(".toggle")[0].checked=!1),setTimeout(function(){m()},0)}),l.$table.bind("stickyHeadersInit",function(){k=l.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(d),k.html(f).find(".toggle, .colorpicker").bind("change",function(){m(k.find(".colorpicker").val())}),m(k.find(".colorpicker").val())}),m(h.value)),j?c.find('input[type="hidden"]'):a('<input type="search">')}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-formatter-jui.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-formatter-jui.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..87528aec71ad87cbaa37a90cb8ccae1c98fc257e
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-formatter-jui.min.js
@@ -0,0 +1,2 @@
+/*! Widget: filter jQuery UI formatter functions - updated 7/17/2014 (v2.17.5) */
+!function(a){"use strict";var b=a.tablesorter||{},c=".compare-select",d=b.filterFormatter=a.extend({},b.filterFormatter,{addCompare:function(b,d,e){if(e.compare&&a.isArray(e.compare)&&e.compare.length>1){var f="",g=[c.slice(1)," "+c.slice(1),""],h=e.cellText?'<label class="'+g.join("-label")+d+'">'+e.cellText+"</label>":"";a.each(e.compare,function(a,b){f+="<option "+(e.selected===a?"selected":"")+">"+b+"</option>"}),b.wrapInner('<div class="'+g.join("-wrapper")+d+'" />').prepend(h+'<select class="'+g.join("")+d+'" />').find("select").append(f)}},updateCompare:function(b,d,e){var f=d.val()||"",g=f.replace(/\s*?[><=]\s*?/g,""),h=f.match(/[><=]/g)||"";return e.compare&&(a.isArray(e.compare)&&(h=(h||[]).join("")||e.compare[e.selected||0]),b.find(c).val(h)),[f,g]},uiSpinner:function(e,f,g){var h=a.extend({delayed:!0,addToggle:!0,exactMatch:!0,value:1,cellText:"",compare:"",min:0,max:100,step:1,disabled:!1},g),i=e.closest("table")[0].config,j=a('<input class="filter" type="hidden">').appendTo(e).bind("change"+i.namespace+"filter",function(){l({value:this.value,delayed:!1})}),k=[],l=function(d,f){var g,j=!0,l=d&&d.value&&b.formatFloat((d.value+"").replace(/[><=]/g,""))||e.find(".spinner").val()||h.value,m=(a.isArray(h.compare)?e.find(c).val()||h.compare[h.selected||0]:h.compare)||"",n=d&&"boolean"==typeof d.delayed?d.delayed:!i.$table[0].hasInitialized||(h.delayed||"");h.addToggle&&(j=e.find(".toggle").is(":checked")),g=h.disabled||!j?"disable":"enable",e.find(".filter").val(j?(m?m:h.exactMatch?"=":"")+l:"").trigger(f?"":"search",n).end().find(".spinner").spinner(g).val(l),k.length&&(k.find(".spinner").spinner(g).val(l).end().find(c).val(m),h.addToggle&&(k.find(".toggle")[0].checked=j))};return h.oldcreate=h.create,h.oldspin=h.spin,h.create=function(a,b){l(),"function"==typeof h.oldcreate&&h.oldcreate(a,b)},h.spin=function(a,b){l(b),"function"==typeof h.oldspin&&h.oldspin(a,b)},h.addToggle&&a('<div class="button"><input id="uispinnerbutton'+f+'" type="checkbox" class="toggle" /><label for="uispinnerbutton'+f+'"></label></div>').appendTo(e).find(".toggle").bind("change",function(){l()}),e.closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed"),a('<input class="spinner spinner'+f+'" />').val(h.value).appendTo(e).spinner(h).bind("change keyup",function(){l()}),i.$table.bind("filterFomatterUpdate",function(){var a=d.updateCompare(e,j,h)[0];e.find(".spinner").val(a),l({value:a},!0),b.filter.formatterUpdated(e,f)}),h.compare&&(d.addCompare(e,f,h),e.find(c).bind("change",function(){l()})),i.$table.bind("stickyHeadersInit",function(){k=i.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),h.addToggle&&a('<div class="button"><input id="stickyuispinnerbutton'+f+'" type="checkbox" class="toggle" /><label for="stickyuispinnerbutton'+f+'"></label></div>').appendTo(k).find(".toggle").bind("change",function(){e.find(".toggle")[0].checked=this.checked,l()}),a('<input class="spinner spinner'+f+'" />').val(h.value).appendTo(k).spinner(h).bind("change keyup",function(){e.find(".spinner").val(this.value),l()}),h.compare&&(d.addCompare(k,f,h),k.find(c).bind("change",function(){e.find(c).val(a(this).val()),l()}))}),i.$table.bind("filterReset",function(){a.isArray(h.compare)&&e.add(k).find(c).val(h.compare[h.selected||0]),h.addToggle&&(e.find(".toggle")[0].checked=!1),e.find(".spinner").spinner("value",h.value),setTimeout(function(){l()},0)}),l(),j},uiSlider:function(e,f,g){var h=a.extend({delayed:!0,valueToHeader:!1,exactMatch:!0,cellText:"",compare:"",allText:"all",value:0,min:0,max:100,step:1,range:"min"},g),i=e.closest("table")[0].config,j=a('<input class="filter" type="hidden">').appendTo(e).bind("change"+i.namespace+"filter",function(){l({value:this.value})}),k=[],l=function(d,g){var j="undefined"!=typeof d?b.formatFloat((d.value+"").replace(/[><=]/g,""))||h.value:h.value,l=h.compare?j:j===h.min?h.allText:j,m=(a.isArray(h.compare)?e.find(c).val()||h.compare[h.selected||0]:h.compare)||"",n=m+l,o=d&&"boolean"==typeof d.delayed?d.delayed:!i.$table[0].hasInitialized||(h.delayed||"");h.valueToHeader?e.closest("thead").find("th[data-column="+f+"]").find(".curvalue").html(" ("+n+")"):e.find(".ui-slider-handle").addClass("value-popup").attr("data-value",n),e.find(".filter").val(m?m+j:j===h.min?"":(h.exactMatch?"=":"")+j).trigger(g?"":"search",o).end().find(".slider").slider("value",j),k.length&&(k.find(c).val(m).end().find(".slider").slider("value",j),h.valueToHeader?k.closest("thead").find("th[data-column="+f+"]").find(".curvalue").html(" ("+n+")"):k.find(".ui-slider-handle").addClass("value-popup").attr("data-value",n))};return e.closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed"),h.valueToHeader&&e.closest("thead").find("th[data-column="+f+"]").find(".tablesorter-header-inner").append('<span class="curvalue" />'),h.oldcreate=h.create,h.oldslide=h.slide,h.create=function(a,b){l(),"function"==typeof h.oldcreate&&h.oldcreate(a,b)},h.slide=function(a,b){l(b),"function"==typeof h.oldslide&&h.oldslide(a,b)},a('<div class="slider slider'+f+'"/>').appendTo(e).slider(h),i.$table.bind("filterFomatterUpdate",function(){var a=d.updateCompare(e,j,h)[0];e.find(".slider").slider("value",a),l({value:a},!1),b.filter.formatterUpdated(e,f)}),h.compare&&(d.addCompare(e,f,h),e.find(c).bind("change",function(){l({value:e.find(".slider").slider("value")})})),i.$table.bind("filterReset",function(){a.isArray(h.compare)&&e.add(k).find(c).val(h.compare[h.selected||0]),setTimeout(function(){l({value:h.value})},0)}),i.$table.bind("stickyHeadersInit",function(){k=i.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),a('<div class="slider slider'+f+'"/>').val(h.value).appendTo(k).slider(h).bind("change keyup",function(){e.find(".slider").slider("value",this.value),l()}),h.compare&&(d.addCompare(k,f,h),k.find(c).bind("change",function(){e.find(c).val(a(this).val()),l()}))}),j},uiRange:function(c,d,e){var f=a.extend({delayed:!0,valueToHeader:!1,values:[0,100],min:0,max:100,range:!0},e),g=c.closest("table")[0].config,h=a('<input class="filter" type="hidden">').appendTo(c).bind("change"+g.namespace+"filter",function(){j()}),i=[],j=function(){var a=h.val(),b=a.split(" - ");""===a&&(b=[f.min,f.max]),b&&b[1]&&k({values:b,delay:!1},!0)},k=function(a,b){var e=a&&a.values||f.values,h=e[0]+" - "+e[1],j=e[0]===f.min&&e[1]===f.max?"":h,k=a&&"boolean"==typeof a.delayed?a.delayed:!g.$table[0].hasInitialized||(f.delayed||"");f.valueToHeader?c.closest("thead").find("th[data-column="+d+"]").find(".currange").html(" ("+h+")"):c.find(".ui-slider-handle").addClass("value-popup").eq(0).attr("data-value",e[0]).end().eq(1).attr("data-value",e[1]),c.find(".filter").val(j).trigger(b?"":"search",k).end().find(".range").slider("values",e),i.length&&(i.find(".range").slider("values",e),f.valueToHeader?i.closest("thead").find("th[data-column="+d+"]").find(".currange").html(" ("+h+")"):i.find(".ui-slider-handle").addClass("value-popup").eq(0).attr("data-value",e[0]).end().eq(1).attr("data-value",e[1]))};return c.closest("thead").find("th[data-column="+d+"]").addClass("filter-parsed"),f.valueToHeader&&c.closest("thead").find("th[data-column="+d+"]").find(".tablesorter-header-inner").append('<span class="currange"/>'),f.oldcreate=f.create,f.oldslide=f.slide,f.create=function(a,b){k(),"function"==typeof f.oldcreate&&f.oldcreate(a,b)},f.slide=function(a,b){k(b),"function"==typeof f.oldslide&&f.oldslide(a,b)},a('<div class="range range'+d+'"/>').appendTo(c).slider(f),g.$table.bind("filterFomatterUpdate",function(){j(),b.filter.formatterUpdated(c,d)}),g.$table.bind("filterReset",function(){c.find(".range").slider("values",f.values),setTimeout(function(){k()},0)}),g.$table.bind("stickyHeadersInit",function(){i=g.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(d).empty(),a('<div class="range range'+d+'"/>').val(f.value).appendTo(i).slider(f).bind("change keyup",function(){c.find(".range").val(this.value),k()})}),h},uiDateCompare:function(e,f,g){var h,i,j=a.extend({cellText:"",compare:"",endOfDay:!0,defaultDate:"",changeMonth:!0,changeYear:!0,numberOfMonths:1},g),k=e.closest("table")[0].config,l=e.closest("thead").find("th[data-column="+f+"]").addClass("filter-parsed"),m=a('<input class="dateCompare" type="hidden">').appendTo(e).bind("change"+k.namespace+"filter",function(){var a=this.value;a&&j.onClose(a)}),n=[],o=function(b){var d,f,g=h.datepicker("getDate")||"",i=(a.isArray(j.compare)?e.find(c).val()||j.compare[j.selected||0]:j.compare)||"",l=!k.$table[0].hasInitialized||(j.delayed||"");h.datepicker("setDate",(""===g?"":g)||null),""===g&&(b=!1),d=h.datepicker("getDate"),f=d?(j.endOfDay&&/<=/.test(i)?d.setHours(23,59,59,999):d.getTime())||"":"",d&&j.endOfDay&&"="===i&&(i="",f+=" - "+d.setHours(23,59,59,999),b=!1),e.find(".dateCompare").val(i+f).trigger(b?"":"search",l).end(),n.length&&n.find(".dateCompare").val(i+f).end().find(c).val(i)};return i='<input type="text" class="date date'+f+'" placeholder="'+(l.data("placeholder")||l.attr("data-placeholder")||k.widgetOptions.filter_placeholder.search||"")+'" />',h=a(i).appendTo(e),j.oldonClose=j.onClose,j.onClose=function(a,b){o(),"function"==typeof j.oldonClose&&j.oldonClose(a,b)},h.datepicker(j),k.$table.bind("filterReset",function(){a.isArray(j.compare)&&e.add(n).find(c).val(j.compare[j.selected||0]),e.add(n).find(".date").val(j.defaultDate).datepicker("setDate",j.defaultDate||null),setTimeout(function(){o()},0)}),k.$table.bind("filterFomatterUpdate",function(){var a,g=m.val();/\s+-\s+/.test(g)?(e.find(c).val("="),a=g.split(/\s+-\s+/)[0],h.datepicker("setDate",a||null)):(a=d.updateCompare(e,m,j)[1].toString()||"",a=""!==a?/\d{5}/g.test(a)?new Date(Number(a)):a||"":""),e.add(n).find(".date").datepicker("setDate",a||null),setTimeout(function(){o(!0),b.filter.formatterUpdated(e,f)},0)}),j.compare&&(d.addCompare(e,f,j),e.find(c).bind("change",function(){o()})),k.$table.bind("stickyHeadersInit",function(){n=k.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(f).empty(),n.append(i).find(".date").datepicker(j),j.compare&&(d.addCompare(n,f,j),n.find(c).bind("change",function(){e.find(c).val(a(this).val()),o()}))}),m.val(j.defaultDate?j.defaultDate:"")},uiDatepicker:function(c,d,e){var f,g,h=a.extend({endOfDay:!0,textFrom:"from",textTo:"to",from:"",to:"",changeMonth:!0,changeYear:!0,numberOfMonths:1},e),i=[],j=c.closest("table")[0].config,k=function(a){return a instanceof Date&&isFinite(a)},l=a('<input class="dateRange" type="hidden">').appendTo(c).bind("change"+j.namespace+"filter",function(){var a=this.value;a.match(" - ")?(a=a.split(" - "),c.find(".dateTo").val(a[1]),g(a[0])):a.match(">=")?g(a.replace(">=","")):a.match("<=")&&g(a.replace("<=",""))}),m=c.closest("thead").find("th[data-column="+d+"]").addClass("filter-parsed");return f="<label>"+h.textFrom+'</label><input type="text" class="dateFrom" placeholder="'+(m.data("placeholderFrom")||m.attr("data-placeholder-from")||j.widgetOptions.filter_placeholder.from||"")+'" /><label>'+h.textTo+'</label><input type="text" class="dateTo" placeholder="'+(m.data("placeholderTo")||m.attr("data-placeholder-to")||j.widgetOptions.filter_placeholder.to||"")+'" />',a(f).appendTo(c),h.oldonClose=h.onClose,g=h.onClose=function(a,b){var d,e=c.find(".dateFrom").datepicker("getDate"),f=c.find(".dateTo").datepicker("getDate");e=k(e)?e.getTime():"",f=k(f)?(h.endOfDay?f.setHours(23,59,59,999):f.getTime())||"":"",d=e?f?e+" - "+f:">="+e:f?"<="+f:"",c.add(i).find(".dateRange").val(d).trigger("search"),e=e?new Date(e):"",f=f?new Date(f):"",/<=/.test(d)?c.add(i).find(".dateFrom").datepicker("option","maxDate",f||null).end().find(".dateTo").datepicker("option","minDate",null).datepicker("setDate",f||null):/>=/.test(d)?c.add(i).find(".dateFrom").datepicker("option","maxDate",null).datepicker("setDate",e||null).end().find(".dateTo").datepicker("option","minDate",e||null):c.add(i).find(".dateFrom").datepicker("option","maxDate",null).datepicker("setDate",e||null).end().find(".dateTo").datepicker("option","minDate",null).datepicker("setDate",f||null),"function"==typeof h.oldonClose&&h.oldonClose(a,b)},h.defaultDate=h.from||"",c.find(".dateFrom").datepicker(h),h.defaultDate=h.to||"+7d",c.find(".dateTo").datepicker(h),j.$table.bind("filterFomatterUpdate",function(){var a=l.val()||"",e="",f="";/\s+-\s+/.test(a)?(a=a.split(/\s+-\s+/)||[],e=a[0]||"",f=a[1]||""):/>=/.test(a)?e=a.replace(/>=/,"")||"":/<=/.test(a)&&(f=a.replace(/<=/,"")||""),e=""!==e?/\d{5}/g.test(e)?new Date(Number(e)):e||"":"",f=""!==f?/\d{5}/g.test(f)?new Date(Number(f)):f||"":"",c.add(i).find(".dateFrom").datepicker("setDate",e||null),c.add(i).find(".dateTo").datepicker("setDate",f||null),setTimeout(function(){g(),b.filter.formatterUpdated(c,d)},0)}),j.$table.bind("stickyHeadersInit",function(){i=j.widgetOptions.$sticky.find(".tablesorter-filter-row").children().eq(d).empty(),i.append(f),h.defaultDate=h.from||"",i.find(".dateFrom").datepicker(h),h.defaultDate=h.to||"+7d",i.find(".dateTo").datepicker(h)}),c.closest("table").bind("filterReset",function(){c.add(i).find(".dateFrom").val("").datepicker("setDate",h.from||null),c.add(i).find(".dateTo").val("").datepicker("setDate",h.to||null),setTimeout(function(){g()},0)}),l.val(h.from?h.to?h.from+" - "+h.to:">="+h.from:h.to?"<="+h.to:"")}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-formatter-select2.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-formatter-select2.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..a4493c378a5fef4bb35e910b7449b6851f315c0c
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-formatter-select2.min.js
@@ -0,0 +1,2 @@
+/*! Widget: filter, select2 formatter function - updated 7/11/2016 (v2.26.6) */
+!function(a){"use strict";var b=a.tablesorter||{};b.filterFormatter=b.filterFormatter||{},b.filterFormatter.select2=function(c,d,e){var f,g,h=a.extend({cellText:"",match:!0,value:"",multiple:!0,width:"100%"},e),i=c.addClass("select2col"+d).closest("table")[0].config,j=i.widgetOptions,k=a('<input class="filter" type="hidden">').appendTo(c).bind("change"+i.namespace+"filter",function(){var a=q(this.value);i.$table.find(".select2col"+d+" .select2").select2("val",a),r()}),l=i.$headerIndexed[d],m=l.hasClass(j.filter_onlyAvail),n=h.match?"":"^",o=h.match?"":"$",p=j.filter_ignoreCase?"i":"",q=function(a){return a.replace(/^\/\(\^?/,"").replace(/\$\|\^/g,"|").replace(/\$?\)\/i?$/g,"").replace(/\\/g,"").split("|")},r=function(){var b=!1,c=i.$table.find(".select2col"+d+" .select2").select2("val")||h.value||"";a.isArray(c)&&(b=!0,c=c.join("\0")),c=c.replace(/[-[\]{}()*+?.,\/\\^$|#\s]/g,"\\$&"),b&&(c=c.split("\0")),k.val(a.isArray(c)&&c.length&&""!==c.join("")?"/("+n+(c||[]).join(o+"|"+n)+o+")/"+p:"").trigger("search").end().find(".select2").select2("val",c),i.widgetOptions.$sticky&&i.widgetOptions.$sticky.find(".select2col"+d+" .select2").select2("val",c)},s=function(){g=[],f=b.filter.getOptionSource(i.$table[0],d,m)||[],a.each(f,function(a,b){g.push({id:""+b.parsed,text:b.text})}),h.data=g};return l.toggleClass("filter-match",h.match),h.cellText&&c.prepend("<label>"+h.cellText+"</label>"),h.ajax&&!a.isEmptyObject(h.ajax)||h.data||(s(),i.$table.bind("filterEnd",function(){s(),i.$table.find(".select2col"+d).add(i.widgetOptions.$sticky&&i.widgetOptions.$sticky.find(".select2col"+d)).find(".select2").select2(h)})),a('<input class="select2 select2-'+d+'" type="hidden" />').val(h.value).appendTo(c).select2(h).bind("change",function(){r()}),i.$table.bind("filterFomatterUpdate",function(){var a=q(i.$table.data("lastSearch")[d]||"");c=i.$table.find(".select2col"+d),c.find(".select2").select2("val",a),r(),b.filter.formatterUpdated(c,d)}),i.$table.bind("stickyHeadersInit",function(){var b=i.widgetOptions.$sticky.find(".select2col"+d).empty();a('<input class="select2 select2-'+d+'" type="hidden">').val(h.value).appendTo(b).select2(h).bind("change",function(){i.$table.find(".select2col"+d).find(".select2").select2("val",i.widgetOptions.$sticky.find(".select2col"+d+" .select2").select2("val")),r()}),h.cellText&&b.prepend("<label>"+h.cellText+"</label>")}),i.$table.bind("filterReset",function(){i.$table.find(".select2col"+d).find(".select2").select2("val",h.value||""),setTimeout(function(){r()},0)}),r(),k}}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-type-insideRange.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-type-insideRange.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..1910902abe4fd8861b3878b792f3ee66028d3cfc
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter-type-insideRange.min.js
@@ -0,0 +1,2 @@
+/*! Widget: filter, insideRange filter type - updated 12/10/2015 (v2.25.0) */
+!function(a){"use strict";var b=a.tablesorter,c=/\d+/,d=/\s+-\s+/,e=function(a){return isNaN(a)?a:parseFloat(a)};b.filter.types.insideRange=function(a,b){if(!b.anyMatch&&c.test(b.iFilter)&&d.test(b.iExact)){var f,g,h,i,j=b.index,k=b.$cells[j],l=b.iExact.split(d),m=a.parsers[b.index]&&a.parsers[b.index].format;return l&&l.length<2||"function"!=typeof m?null:(h=e(m(l[0],a.table,k,j)),i=e(m(l[1],a.table,k,j)),g=e(m(b.iFilter,a.table,k,j)),i<h&&(f=i,i=h,h=f),h<=g&&g<=i)}return null}}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..2f7b3dc450e21b464183e88739aa448d1c18f2a2
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-filter.min.js
@@ -0,0 +1,2 @@
+/*! Widget: filter - updated 12/8/2016 (v2.28.1) */
+!function(a){"use strict";var b,c,d=a.tablesorter||{},e=d.css,f=d.keyCodes;a.extend(e,{filterRow:"tablesorter-filter-row",filter:"tablesorter-filter",filterDisabled:"disabled",filterRowHide:"hideme"}),a.extend(f,{backSpace:8,escape:27,space:32,left:37,down:40}),d.addWidget({id:"filter",priority:50,options:{filter_cellFilter:"",filter_childRows:!1,filter_childByColumn:!1,filter_childWithSibs:!0,filter_columnAnyMatch:!0,filter_columnFilters:!0,filter_cssFilter:"",filter_defaultAttrib:"data-value",filter_defaultFilter:{},filter_excludeFilter:{},filter_external:"",filter_filteredRow:"filtered",filter_formatter:null,filter_functions:null,filter_hideEmpty:!0,filter_hideFilters:!1,filter_ignoreCase:!0,filter_liveSearch:!0,filter_matchType:{input:"exact",select:"exact"},filter_onlyAvail:"filter-onlyAvail",filter_placeholder:{search:"",select:""},filter_reset:null,filter_resetOnEsc:!0,filter_saveFilters:!1,filter_searchDelay:300,filter_searchFiltered:!0,filter_selectSource:null,filter_selectSourceSeparator:"|",filter_serversideFiltering:!1,filter_startsWith:!1,filter_useParsedData:!1},format:function(a,c,d){c.$table.hasClass("hasFilters")||b.init(a,c,d)},remove:function(b,c,f,g){var h,i,j=c.$table,k=c.$tbodies,l="addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search ".split(" ").join(c.namespace+"filter ");if(j.removeClass("hasFilters").unbind(l.replace(d.regex.spaces," ")).find("."+e.filterRow).remove(),f.filter_initialized=!1,!g){for(h=0;h<k.length;h++)i=d.processTbody(b,k.eq(h),!0),i.children().removeClass(f.filter_filteredRow).show(),d.processTbody(b,i,!1);f.filter_reset&&a(document).undelegate(f.filter_reset,"click"+c.namespace+"filter")}}}),b=d.filter={regex:{regex:/^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/,child:/tablesorter-childRow/,filtered:/filtered/,type:/undefined|number/,exact:/(^[\"\'=]+)|([\"\'=]+$)/g,operators:/[<>=]/g,query:"(q|query)",wild01:/\?/g,wild0More:/\*/g,quote:/\"/g,isNeg1:/(>=?\s*-\d)/,isNeg2:/(<=?\s*\d)/},types:{or:function(d,e,f){if((c.orTest.test(e.iFilter)||c.orSplit.test(e.filter))&&!c.regex.test(e.filter)){var g,h,i,j,k=a.extend({},e),l=e.filter.split(c.orSplit),m=e.iFilter.split(c.orSplit),n=l.length;for(g=0;g<n;g++){k.nestedFilters=!0,k.filter=""+(b.parseFilter(d,l[g],e)||""),k.iFilter=""+(b.parseFilter(d,m[g],e)||""),i="("+(b.parseFilter(d,k.filter,e)||"")+")";try{if(j=new RegExp(e.isMatch?i:"^"+i+"$",d.widgetOptions.filter_ignoreCase?"i":""),h=j.test(k.exact)||b.processTypes(d,k,f))return h}catch(a){return null}}return h||!1}return null},and:function(d,e,f){if(c.andTest.test(e.filter)){var g,h,i,j,k,l=a.extend({},e),m=e.filter.split(c.andSplit),n=e.iFilter.split(c.andSplit),o=m.length;for(g=0;g<o;g++){l.nestedFilters=!0,l.filter=""+(b.parseFilter(d,m[g],e)||""),l.iFilter=""+(b.parseFilter(d,n[g],e)||""),j=("("+(b.parseFilter(d,l.filter,e)||"")+")").replace(c.wild01,"\\S{1}").replace(c.wild0More,"\\S*");try{k=new RegExp(e.isMatch?j:"^"+j+"$",d.widgetOptions.filter_ignoreCase?"i":""),i=k.test(l.exact)||b.processTypes(d,l,f),h=0===g?i:h&&i}catch(a){return null}}return h||!1}return null},regex:function(a,b){if(c.regex.test(b.filter)){var d,e=b.filter_regexCache[b.index]||c.regex.exec(b.filter),f=e instanceof RegExp;try{f||(b.filter_regexCache[b.index]=e=new RegExp(e[1],e[2])),d=e.test(b.exact)}catch(a){d=!1}return d}return null},operators:function(e,f){if(c.operTest.test(f.iFilter)&&""!==f.iExact){var g,h,i,j=e.table,k=f.parsed[f.index],l=d.formatFloat(f.iFilter.replace(c.operators,""),j),m=e.parsers[f.index]||{},n=l;return(k||"numeric"===m.type)&&(i=a.trim(""+f.iFilter.replace(c.operators,"")),h=b.parseFilter(e,i,f,!0),l="number"!=typeof h||""===h||isNaN(h)?l:h),!k&&"numeric"!==m.type||isNaN(l)||"undefined"==typeof f.cache?(i=isNaN(f.iExact)?f.iExact.replace(d.regex.nondigit,""):f.iExact,g=d.formatFloat(i,j)):g=f.cache,c.gtTest.test(f.iFilter)?h=c.gteTest.test(f.iFilter)?g>=l:g>l:c.ltTest.test(f.iFilter)&&(h=c.lteTest.test(f.iFilter)?g<=l:g<l),h||""!==n||(h=!0),h}return null},notMatch:function(d,e){if(c.notTest.test(e.iFilter)){var f,g=e.iFilter.replace("!",""),h=b.parseFilter(d,g,e)||"";return c.exact.test(h)?(h=h.replace(c.exact,""),""===h||a.trim(h)!==e.iExact):(f=e.iExact.search(a.trim(h)),""===h||(e.anyMatch?f<0:!(d.widgetOptions.filter_startsWith?0===f:f>=0)))}return null},exact:function(d,e){if(c.exact.test(e.iFilter)){var f=e.iFilter.replace(c.exact,""),g=b.parseFilter(d,f,e)||"";return e.anyMatch?a.inArray(g,e.rowArray)>=0:g==e.iExact}return null},range:function(a,e){if(c.toTest.test(e.iFilter)){var f,g,h,i,j=a.table,k=e.index,l=e.parsed[k],m=e.iFilter.split(c.toSplit);return g=m[0].replace(d.regex.nondigit,"")||"",h=d.formatFloat(b.parseFilter(a,g,e),j),g=m[1].replace(d.regex.nondigit,"")||"",i=d.formatFloat(b.parseFilter(a,g,e),j),(l||"numeric"===a.parsers[k].type)&&(f=a.parsers[k].format(""+m[0],j,a.$headers.eq(k),k),h=""===f||isNaN(f)?h:f,f=a.parsers[k].format(""+m[1],j,a.$headers.eq(k),k),i=""===f||isNaN(f)?i:f),!l&&"numeric"!==a.parsers[k].type||isNaN(h)||isNaN(i)?(g=isNaN(e.iExact)?e.iExact.replace(d.regex.nondigit,""):e.iExact,f=d.formatFloat(g,j)):f=e.cache,h>i&&(g=h,h=i,i=g),f>=h&&f<=i||""===h||""===i}return null},wild:function(a,d){if(c.wildOrTest.test(d.iFilter)){var e=""+(b.parseFilter(a,d.iFilter,d)||"");!c.wildTest.test(e)&&d.nestedFilters&&(e=d.isMatch?e:"^("+e+")$");try{return new RegExp(e.replace(c.wild01,"\\S{1}").replace(c.wild0More,"\\S*"),a.widgetOptions.filter_ignoreCase?"i":"").test(d.exact)}catch(a){return null}}return null},fuzzy:function(a,d){if(c.fuzzyTest.test(d.iFilter)){var e,f=0,g=d.iExact.length,h=d.iFilter.slice(1),i=b.parseFilter(a,h,d)||"";for(e=0;e<g;e++)d.iExact[e]===i[f]&&(f+=1);return f===i.length}return null}},init:function(f){d.language=a.extend(!0,{},{to:"to",or:"or",and:"and"},d.language);var g,h,i,j,k,l,m,n,o=f.config,p=o.widgetOptions;if(o.$table.addClass("hasFilters"),o.lastSearch=[],p.filter_searchTimer=null,p.filter_initTimer=null,p.filter_formatterCount=0,p.filter_formatterInit=[],p.filter_anyColumnSelector='[data-column="all"],[data-column="any"]',p.filter_multipleColumnSelector='[data-column*="-"],[data-column*=","]',l="\\{"+c.query+"\\}",a.extend(c,{child:new RegExp(o.cssChildRow),filtered:new RegExp(p.filter_filteredRow),alreadyFiltered:new RegExp("(\\s+("+d.language.or+"|-|"+d.language.to+")\\s+)","i"),toTest:new RegExp("\\s+(-|"+d.language.to+")\\s+","i"),toSplit:new RegExp("(?:\\s+(?:-|"+d.language.to+")\\s+)","gi"),andTest:new RegExp("\\s+("+d.language.and+"|&&)\\s+","i"),andSplit:new RegExp("(?:\\s+(?:"+d.language.and+"|&&)\\s+)","gi"),orTest:new RegExp("(\\||\\s+"+d.language.or+"\\s+)","i"),orSplit:new RegExp("(?:\\s+(?:"+d.language.or+")\\s+|\\|)","gi"),iQuery:new RegExp(l,"i"),igQuery:new RegExp(l,"ig"),operTest:/^[<>]=?/,gtTest:/>/,gteTest:/>=/,ltTest:/</,lteTest:/<=/,notTest:/^\!/,wildOrTest:/[\?\*\|]/,wildTest:/\?\*/,fuzzyTest:/^~/,exactTest:/[=\"\|!]/}),l=o.$headers.filter(".filter-false, .parser-false").length,p.filter_columnFilters!==!1&&l!==o.$headers.length&&b.buildRow(f,o,p),i="addRows updateCell update updateRows updateComplete appendCache filterReset "+"filterResetSaved filterEnd search ".split(" ").join(o.namespace+"filter "),o.$table.bind(i,function(c,g){return l=p.filter_hideEmpty&&a.isEmptyObject(o.cache)&&!(o.delayInit&&"appendCache"===c.type),o.$table.find("."+e.filterRow).toggleClass(p.filter_filteredRow,l),/(search|filter)/.test(c.type)||(c.stopPropagation(),b.buildDefault(f,!0)),"filterReset"===c.type?(o.$table.find("."+e.filter).add(p.filter_$externalFilters).val(""),b.searching(f,[])):"filterResetSaved"===c.type?d.storage(f,"tablesorter-filters",""):"filterEnd"===c.type?b.buildDefault(f,!0):(g="search"===c.type?g:"updateComplete"===c.type?o.$table.data("lastSearch"):"",/(update|add)/.test(c.type)&&"updateComplete"!==c.type&&(o.lastCombinedFilter=null,o.lastSearch=[],setTimeout(function(){o.$table.triggerHandler("filterFomatterUpdate")},100)),b.searching(f,g,!0)),!1}),p.filter_reset&&(p.filter_reset instanceof a?p.filter_reset.click(function(){o.$table.triggerHandler("filterReset")}):a(p.filter_reset).length&&a(document).undelegate(p.filter_reset,"click"+o.namespace+"filter").delegate(p.filter_reset,"click"+o.namespace+"filter",function(){o.$table.triggerHandler("filterReset")})),p.filter_functions)for(k=0;k<o.columns;k++)if(m=d.getColumnData(f,p.filter_functions,k))if(j=o.$headerIndexed[k].removeClass("filter-select"),n=!(j.hasClass("filter-false")||j.hasClass("parser-false")),g="",m===!0&&n)b.buildSelect(f,k);else if("object"==typeof m&&n){for(h in m)"string"==typeof h&&(g+=""===g?'<option value="">'+(j.data("placeholder")||j.attr("data-placeholder")||p.filter_placeholder.select||"")+"</option>":"",l=h,i=h,h.indexOf(p.filter_selectSourceSeparator)>=0&&(l=h.split(p.filter_selectSourceSeparator),i=l[1],l=l[0]),g+="<option "+(i===l?"":'data-function-name="'+h+'" ')+'value="'+l+'">'+i+"</option>");o.$table.find("thead").find("select."+e.filter+'[data-column="'+k+'"]').append(g),i=p.filter_selectSource,m="function"==typeof i||d.getColumnData(f,i,k),m&&b.buildSelect(o.table,k,"",!0,j.hasClass(p.filter_onlyAvail))}b.buildDefault(f,!0),b.bindSearch(f,o.$table.find("."+e.filter),!0),p.filter_external&&b.bindSearch(f,p.filter_external),p.filter_hideFilters&&b.hideFilters(o),o.showProcessing&&(i="filterStart filterEnd ".split(" ").join(o.namespace+"filter "),o.$table.unbind(i.replace(d.regex.spaces," ")).bind(i,function(b,c){j=c?o.$table.find("."+e.header).filter("[data-column]").filter(function(){return""!==c[a(this).data("column")]}):"",d.isProcessing(f,"filterStart"===b.type,c?j:"")})),o.filteredRows=o.totalRows,i="tablesorter-initialized pagerBeforeInitialized ".split(" ").join(o.namespace+"filter "),o.$table.unbind(i.replace(d.regex.spaces," ")).bind(i,function(){b.completeInit(this)}),o.pager&&o.pager.initialized&&!p.filter_initialized?(o.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){b.filterInitComplete(o)},100)):p.filter_initialized||b.completeInit(f)},completeInit:function(a){var c=a.config,e=c.widgetOptions,f=b.setDefaults(a,c,e)||[];f.length&&(c.delayInit&&""===f.join("")||d.setFilters(a,f,!0)),c.$table.triggerHandler("filterFomatterUpdate"),setTimeout(function(){e.filter_initialized||b.filterInitComplete(c)},100)},formatterUpdated:function(a,b){var c=a&&a.closest("table")[0].config.widgetOptions;c&&!c.filter_initialized&&(c.filter_formatterInit[b]=1)},filterInitComplete:function(c){var d,e,f=c.widgetOptions,g=0,h=function(){f.filter_initialized=!0,c.lastSearch=c.$table.data("lastSearch"),c.$table.triggerHandler("filterInit",c),b.findRows(c.table,c.lastSearch||[])};if(a.isEmptyObject(f.filter_formatter))h();else{for(e=f.filter_formatterInit.length,d=0;d<e;d++)1===f.filter_formatterInit[d]&&g++;clearTimeout(f.filter_initTimer),f.filter_initialized||g!==f.filter_formatterCount?f.filter_initialized||(f.filter_initTimer=setTimeout(function(){h()},500)):h()}},processFilters:function(a,b){var c,d=[],e=b?encodeURIComponent:decodeURIComponent,f=a.length;for(c=0;c<f;c++)a[c]&&(d[c]=e(a[c]));return d},setDefaults:function(c,e,f){var g,h,i,j,k,l=d.getFilters(c)||[];if(f.filter_saveFilters&&d.storage&&(h=d.storage(c,"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||c.parsed[c.index]?a.parsers[c.index].format(b,a.table,[],c.index):b},buildRow:function(c,f,g){var h,i,j,k,l,m,n,o,p,q=g.filter_cellFilter,r=f.columns,s=a.isArray(q),t='<tr role="row" class="'+e.filterRow+" "+f.cssIgnoreRow+'">';for(j=0;j<r;j++)f.$headerIndexed[j].length&&(p=f.$headerIndexed[j]&&f.$headerIndexed[j][0].colSpan||0,t+=p>1?'<td data-column="'+j+"-"+(j+p-1)+'" colspan="'+p+'"':'<td data-column="'+j+'"',t+=s?q[j]?' class="'+q[j]+'"':"":""!==q?' class="'+q+'"':"",t+="></td>");for(f.$filters=a(t+="</tr>").appendTo(f.$table.children("thead").eq(0)).children("td"),j=0;j<r;j++)m=!1,k=f.$headerIndexed[j],k&&k.length&&(h=b.getColumnElm(f,f.$filters,j),o=d.getColumnData(c,g.filter_functions,j),l=g.filter_functions&&o&&"function"!=typeof o||k.hasClass("filter-select"),i=d.getColumnData(c,f.headers,j),m="false"===d.getData(k[0],i,"filter")||"false"===d.getData(k[0],i,"parser"),l?t=a("<select>").appendTo(h):(o=d.getColumnData(c,g.filter_formatter,j),o?(g.filter_formatterCount++,t=o(h,j),t&&0===t.length&&(t=h.children("input")),t&&(0===t.parent().length||t.parent().length&&t.parent()[0]!==h[0])&&h.append(t)):t=a('<input type="search">').appendTo(h),t&&(p=k.data("placeholder")||k.attr("data-placeholder")||g.filter_placeholder.search||"",t.attr("placeholder",p))),t&&(n=(a.isArray(g.filter_cssFilter)?"undefined"!=typeof g.filter_cssFilter[j]?g.filter_cssFilter[j]||"":"":g.filter_cssFilter)||"",t.addClass(e.filter+" "+n).attr("data-column",h.attr("data-column")),m&&(t.attr("placeholder","").addClass(e.filterDisabled)[0].disabled=!0)))},bindSearch:function(c,e,g){if(c=a(c)[0],e=a(e),e.length){var h,i=c.config,j=i.widgetOptions,k=i.namespace+"filter",l=j.filter_$externalFilters;g!==!0&&(h=j.filter_anyColumnSelector+","+j.filter_multipleColumnSelector,j.filter_$anyMatch=e.filter(h),l&&l.length?j.filter_$externalFilters=j.filter_$externalFilters.add(e):j.filter_$externalFilters=e,d.setFilters(c,i.$table.data("lastSearch")||[],g===!1)),h="keypress keyup keydown search change input ".split(" ").join(k+" "),e.attr("data-lastSearchTime",(new Date).getTime()).unbind(h.replace(d.regex.spaces," ")).bind("keydown"+k,function(a){if(a.which===f.escape&&!c.config.widgetOptions.filter_resetOnEsc)return!1}).bind("keyup"+k,function(e){j=c.config.widgetOptions;var g=parseInt(a(this).attr("data-column"),10),h="boolean"==typeof j.filter_liveSearch?j.filter_liveSearch:d.getColumnData(c,j.filter_liveSearch,g);if("undefined"==typeof h&&(h=j.filter_liveSearch.fallback||!1),a(this).attr("data-lastSearchTime",(new Date).getTime()),e.which===f.escape)this.value=j.filter_resetOnEsc?"":i.lastSearch[g];else{if(h===!1)return;if(""!==this.value&&("number"==typeof h&&this.value.length<h||e.which!==f.enter&&e.which!==f.backSpace&&(e.which<f.space||e.which>=f.left&&e.which<=f.down)))return}b.searching(c,!0,!0,g)}).bind("search change keypress input ".split(" ").join(k+" "),function(e){var g=parseInt(a(this).attr("data-column"),10),h="boolean"==typeof j.filter_liveSearch?j.filter_liveSearch:d.getColumnData(c,j.filter_liveSearch,g);!c.config.widgetOptions.filter_initialized||e.which!==f.enter&&"search"!==e.type&&("change"!==e.type&&"input"!==e.type||h!==!0||this.value===i.lastSearch[g])||(e.preventDefault(),a(this).attr("data-lastSearchTime",(new Date).getTime()),b.searching(c,"keypress"!==e.type,!0,g))})}},searching:function(a,c,e,f){var g,h=a.config.widgetOptions;"undefined"==typeof f?g=!1:(g="boolean"==typeof h.filter_liveSearch?h.filter_liveSearch:d.getColumnData(a,h.filter_liveSearch,f),"undefined"==typeof g&&(g=h.filter_liveSearch.fallback||!1)),clearTimeout(h.filter_searchTimer),"undefined"==typeof c||c===!0?h.filter_searchTimer=setTimeout(function(){b.checkFilters(a,c,e)},g?h.filter_searchDelay:10):b.checkFilters(a,c,e)},checkFilters:function(c,f,g){var h=c.config,i=h.widgetOptions,j=a.isArray(f),k=j?f:d.getFilters(c,!0),l=(k||[]).join("");return a.isEmptyObject(h.cache)?void(h.delayInit&&(!h.pager||h.pager&&h.pager.initialized)&&d.updateCache(h,function(){b.checkFilters(c,!1,g)})):(j&&(d.setFilters(c,k,!1,g!==!0),i.filter_initialized||(h.lastCombinedFilter="")),i.filter_hideFilters&&h.$table.find("."+e.filterRow).triggerHandler(b.hideFiltersCheck(h)?"mouseleave":"mouseenter"),h.lastCombinedFilter!==l||f===!1?(f===!1&&(h.lastCombinedFilter=null,h.lastSearch=[]),k=k||[],k=Array.prototype.map?k.map(String):k.join("�").split("�"),i.filter_initialized&&h.$table.triggerHandler("filterStart",[k]),h.showProcessing?void setTimeout(function(){return b.findRows(c,k,l),!1},30):(b.findRows(c,k,l),!1)):void 0)},hideFiltersCheck:function(a){if("function"==typeof a.widgetOptions.filter_hideFilters){var b=a.widgetOptions.filter_hideFilters(a);if("boolean"==typeof b)return b}return""===d.getFilters(a.$table).join("")},hideFilters:function(c,d){var f;(d||c.$table).find("."+e.filterRow).addClass(e.filterRowHide).bind("mouseenter mouseleave",function(d){var g=d,h=a(this);clearTimeout(f),f=setTimeout(function(){/enter|over/.test(g.type)?h.removeClass(e.filterRowHide):a(document.activeElement).closest("tr")[0]!==h[0]&&h.toggleClass(e.filterRowHide,b.hideFiltersCheck(c))},200)}).find("input, select").bind("focus blur",function(d){var g=d,h=a(this).closest("tr");clearTimeout(f),f=setTimeout(function(){clearTimeout(f),h.toggleClass(e.filterRowHide,b.hideFiltersCheck(c)&&"focus"!==g.type)},200)})},defaultFilter:function(b,d){if(""===b)return b;var e=c.iQuery,f=d.match(c.igQuery).length,g=f>1?a.trim(b).split(/\s/):[a.trim(b)],h=g.length-1,i=0,j=d;for(h<1&&f>1&&(g[1]=g[0]);e.test(j);)j=j.replace(e,g[i++]||""),e.test(j)&&i<h&&""!==(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()},findRange:function(a,b,c){var d,e,f,g,h,i,j,k,l,m=[];if(/^[0-9]+$/.test(b))return[parseInt(b,10)];if(!c&&/-/.test(b))for(e=b.match(/(\d+)\s*-\s*(\d+)/g),l=e?e.length:0,k=0;k<l;k++){for(f=e[k].split(/\s*-\s*/),g=parseInt(f[0],10)||0,h=parseInt(f[1],10)||a.columns-1,g>h&&(d=g,g=h,h=d),h>=a.columns&&(h=a.columns-1);g<=h;g++)m[m.length]=g;b=b.replace(e[k],"")}if(!c&&/,/.test(b))for(i=b.split(/\s*,\s*/),l=i.length,j=0;j<l;j++)""!==i[j]&&(k=parseInt(i[j],10),k<a.columns&&(m[m.length]=k));if(!m.length)for(k=0;k<a.columns;k++)m[m.length]=k;return m},getColumnElm:function(c,d,e){return d.filter(function(){var d=b.findRange(c,a(this).attr("data-column"));return a.inArray(e,d)>-1})},multipleColumns:function(c,d){var e=c.widgetOptions,f=e.filter_initialized||!d.filter(e.filter_anyColumnSelector).length,g=a.trim(b.getLatestSearch(d).attr("data-column")||"");return b.findRange(c,g,!f)},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},matchType:function(a,b){var c,d=a.widgetOptions,f=a.$headerIndexed[b];return f.hasClass("filter-exact")?c=!1:f.hasClass("filter-match")?c=!0:(d.filter_columnFilters?f=a.$filters.find("."+e.filter).add(d.filter_$externalFilters).filter('[data-column="'+b+'"]'):d.filter_$externalFilters&&(f=d.filter_$externalFilters.filter('[data-column="'+b+'"]')),c=!!f.length&&"match"===a.widgetOptions.filter_matchType[(f[0].nodeName||"").toLowerCase()]),c},processRow:function(e,f,g){var h,i,j,k,l,m=e.widgetOptions,n=!0,o=m.filter_$anyMatch&&m.filter_$anyMatch.length,p=m.filter_$anyMatch&&m.filter_$anyMatch.length?b.multipleColumns(e,m.filter_$anyMatch):[];if(f.$cells=f.$row.children(),f.anyMatchFlag&&p.length>1||f.anyMatchFilter&&!o){if(f.anyMatch=!0,f.isMatch=!0,f.rowArray=f.$cells.map(function(b){if(a.inArray(b,p)>-1||f.anyMatchFilter&&!o)return f.parsed[b]?l=f.cacheArray[b]:(l=f.rawArray[b],l=a.trim(m.filter_ignoreCase?l.toLowerCase():l),e.sortLocaleCompare&&(l=d.replaceAccents(l))),l}).get(),f.filter=f.anyMatchFilter,f.iFilter=f.iAnyMatchFilter,f.exact=f.rowArray.join(" "),f.iExact=m.filter_ignoreCase?f.exact.toLowerCase():f.exact,f.cache=f.cacheArray.slice(0,-1).join(" "),g.excludeMatch=g.noAnyMatch,i=b.processTypes(e,f,g),null!==i)n=i;else if(m.filter_startsWith)for(n=!1,p=Math.min(e.columns,f.rowArray.length);!n&&p>0;)p--,n=n||0===f.rowArray[p].indexOf(f.iFilter);else n=(f.iExact+f.childRowText).indexOf(f.iFilter)>=0;if(f.anyMatch=!1,f.filters.join("")===f.filter)return n}for(p=0;p<e.columns;p++)f.filter=f.filters[p],f.index=p,g.excludeMatch=g.excludeFilter[p],f.filter&&(f.cache=f.cacheArray[p],h=f.parsed[p]?f.cache:f.rawArray[p]||"",f.exact=e.sortLocaleCompare?d.replaceAccents(h):h,f.iExact=!c.type.test(typeof f.exact)&&m.filter_ignoreCase?f.exact.toLowerCase():f.exact,f.isMatch=b.matchType(e,p),h=n,k=m.filter_columnFilters?e.$filters.add(m.filter_$externalFilters).filter('[data-column="'+p+'"]').find("select option:selected").attr("data-function-name")||"":"",e.sortLocaleCompare&&(f.filter=d.replaceAccents(f.filter)),m.filter_defaultFilter&&c.iQuery.test(g.defaultColFilter[p])&&(f.filter=b.defaultFilter(f.filter,g.defaultColFilter[p])),f.iFilter=m.filter_ignoreCase?(f.filter||"").toLowerCase():f.filter,j=g.functions[p],i=null,j&&(j===!0?i=f.isMatch?(""+f.iExact).search(f.iFilter)>=0:f.filter===f.exact:"function"==typeof j?i=j(f.exact,f.cache,f.filter,p,f.$row,e,f):"function"==typeof j[k||f.filter]&&(l=k||f.filter,i=j[l](f.exact,f.cache,f.filter,p,f.$row,e,f))),null===i?(i=b.processTypes(e,f,g),null!==i?h=i:(l=(f.iExact+f.childRowText).indexOf(b.parseFilter(e,f.iFilter,f)),h=!m.filter_startsWith&&l>=0||m.filter_startsWith&&0===l)):h=i,n=!!h&&n);return n},findRows:function(e,f,g){if(e.config.lastCombinedFilter!==g&&e.config.widgetOptions.filter_initialized){var h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F=a.extend([],f),G=e.config,H=G.widgetOptions,I={anyMatch:!1,filters:f,filter_regexCache:[]},J={noAnyMatch:["range","operators"],functions:[],excludeFilter:[],defaultColFilter:[],defaultAnyFilter:d.getColumnData(e,H.filter_defaultFilter,G.columns,!0)||""};for(I.parsed=[],p=0;p<G.columns;p++)I.parsed[p]=H.filter_useParsedData||G.parsers&&G.parsers[p]&&G.parsers[p].parsed||d.getData&&"parsed"===d.getData(G.$headerIndexed[p],d.getColumnData(e,G.headers,p),"filter")||G.$headerIndexed[p].hasClass("filter-parsed"),J.functions[p]=d.getColumnData(e,H.filter_functions,p)||G.$headerIndexed[p].hasClass("filter-select"),J.defaultColFilter[p]=d.getColumnData(e,H.filter_defaultFilter,p)||"",J.excludeFilter[p]=(d.getColumnData(e,H.filter_excludeFilter,p,!0)||"").split(/\s+/);for(G.debug&&(console.log("Filter: Starting filter widget search",f),v=new Date),G.filteredRows=0,G.totalRows=0,g=(F||[]).join(""),n=0;n<G.$tbodies.length;n++){if(o=d.processTbody(e,G.$tbodies.eq(n),!0),p=G.columns,i=G.cache[n].normalized,k=a(a.map(i,function(a){return a[p].$row.get()})),""===g||H.filter_serversideFiltering)k.removeClass(H.filter_filteredRow).not("."+G.cssChildRow).css("display","");else{if(k=k.not("."+G.cssChildRow),h=k.length,(H.filter_$anyMatch&&H.filter_$anyMatch.length||"undefined"!=typeof f[G.columns])&&(I.anyMatchFlag=!0,I.anyMatchFilter=""+(f[G.columns]||H.filter_$anyMatch&&b.getLatestSearch(H.filter_$anyMatch).val()||""),H.filter_columnAnyMatch)){for(A=I.anyMatchFilter.split(c.andSplit),B=!1,x=0;x<A.length;x++)C=A[x].split(":"),C.length>1&&(isNaN(C[0])?a.each(G.headerContent,function(a,b){b.toLowerCase().indexOf(C[0])>-1&&(D=a,f[D]=C[1])}):D=parseInt(C[0],10)-1,D>=0&&D<G.columns&&(f[D]=C[1],A.splice(x,1),x--,B=!0));B&&(I.anyMatchFilter=A.join(" && "))}if(z=H.filter_searchFiltered,s=G.lastSearch||G.$table.data("lastSearch")||[],z)for(x=0;x<p+1;x++)w=f[x]||"",z||(x=p),z=z&&s.length&&0===w.indexOf(s[x]||"")&&!c.alreadyFiltered.test(w)&&!c.exactTest.test(w)&&!(c.isNeg1.test(w)||c.isNeg2.test(w))&&!(""!==w&&G.$filters&&G.$filters.filter('[data-column="'+x+'"]').find("select").length&&!b.matchType(G,x));for(y=k.not("."+H.filter_filteredRow).length,z&&0===y&&(z=!1),G.debug&&console.log("Filter: Searching through "+(z&&y<h?y:"all")+" rows"),I.anyMatchFlag&&(G.sortLocaleCompare&&(I.anyMatchFilter=d.replaceAccents(I.anyMatchFilter)),H.filter_defaultFilter&&c.iQuery.test(J.defaultAnyFilter)&&(I.anyMatchFilter=b.defaultFilter(I.anyMatchFilter,J.defaultAnyFilter),z=!1),I.iAnyMatchFilter=H.filter_ignoreCase&&G.ignoreCase?I.anyMatchFilter.toLowerCase():I.anyMatchFilter),m=0;m<h;m++)if(E=k[m].className,q=m&&c.child.test(E),!(q||z&&c.filtered.test(E))){if(I.$row=k.eq(m),I.rowIndex=m,I.cacheArray=i[m],j=I.cacheArray[G.columns],I.rawArray=j.raw,I.childRowText="",!H.filter_childByColumn){for(E="",r=j.child,x=0;x<r.length;x++)E+=" "+r[x].join(" ")||"";I.childRowText=H.filter_childRows?H.filter_ignoreCase?E.toLowerCase():E:""}if(t=!1,u=b.processRow(G,I,J),l=j.$row,w=!!u,r=j.$row.filter(":gt(0)"),H.filter_childRows&&r.length){if(H.filter_childByColumn)for(H.filter_childWithSibs||(r.addClass(H.filter_filteredRow),l=l.eq(0)),x=0;x<r.length;x++)I.$row=r.eq(x),I.cacheArray=j.child[x],I.rawArray=I.cacheArray,w=b.processRow(G,I,J),t=t||w,!H.filter_childWithSibs&&w&&r.eq(x).removeClass(H.filter_filteredRow);t=t||u}else t=w;l.toggleClass(H.filter_filteredRow,!t)[0].display=t?"":"none"}}G.filteredRows+=k.not("."+H.filter_filteredRow).length,G.totalRows+=k.length,d.processTbody(e,o,!1)}G.lastCombinedFilter=g,G.lastSearch=F,G.$table.data("lastSearch",F),H.filter_saveFilters&&d.storage&&d.storage(e,"tablesorter-filters",b.processFilters(F,!0)),G.debug&&console.log("Completed filter widget search"+d.benchmark(v)),H.filter_initialized&&(G.$table.triggerHandler("filterBeforeEnd",G),G.$table.triggerHandler("filterEnd",G)),setTimeout(function(){d.applyWidget(G.table)},0)}},getOptionSource:function(c,e,f){c=a(c)[0];var g=c.config,h=g.widgetOptions,i=!1,j=h.filter_selectSource,k=g.$table.data("lastSearch")||[],l="function"==typeof j||d.getColumnData(c,j,e);if(f&&""!==k[e]&&(f=!1),l===!0)i=j(c,e,f);else{if(l instanceof a||"string"===a.type(l)&&l.indexOf("</option>")>=0)return l;a.isArray(l)?i=l:"object"===a.type(j)&&l&&(i=l(c,e,f))}return i===!1&&(i=b.getOptions(c,e,f)),b.processOptions(c,e,i)},processOptions:function(b,c,e){if(!a.isArray(e))return!1;b=a(b)[0];var f,g,h,i,j,k,l=b.config,m="undefined"!=typeof c&&null!==c&&c>=0&&c<l.columns,n=!!m&&l.$headerIndexed[c].hasClass("filter-select-sort-desc"),o=[];if(e=a.grep(e,function(b,c){return!!b.text||a.inArray(b,e)===c}),m&&l.$headerIndexed[c].hasClass("filter-select-nosort"))return e;for(i=e.length,h=0;h<i;h++)g=e[h],k=g.text?g.text:g,j=(m&&l.parsers&&l.parsers.length&&l.parsers[c].format(k,b,[],c)||k).toString(),j=l.widgetOptions.filter_ignoreCase?j.toLowerCase():j,g.text?(g.parsed=j,o[o.length]=g):o[o.length]={text:g,parsed:j};for(f=l.textSorter||"",o.sort(function(a,e){var g=n?e.parsed:a.parsed,h=n?a.parsed:e.parsed;return m&&"function"==typeof f?f(g,h,!0,c,b):m&&"object"==typeof f&&f.hasOwnProperty(c)?f[c](g,h,!0,c,b):!d.sortNatural||d.sortNatural(g,h)}),e=[],i=o.length,h=0;h<i;h++)e[e.length]=o[h];return e},getOptions:function(b,c,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++)for(j=n.cache[g],h=n.cache[g].normalized.length,f=0;f<h;f++)if(i=j.row?j.row[f]:j.normalized[f][n.columns].$row[0],!e||!i.className.match(o.filter_filteredRow))if(o.filter_useParsedData||n.parsers[c].parsed||n.$headerIndexed[c].hasClass("filter-parsed")){if(p[p.length]=""+j.normalized[f][c],o.filter_childRows&&o.filter_childByColumn)for(m=j.normalized[f][n.columns].$row.length-1,k=0;k<m;k++)p[p.length]=""+j.normalized[f][n.columns].child[k][c]}else if(p[p.length]=j.normalized[f][n.columns].raw[c],o.filter_childRows&&o.filter_childByColumn)for(m=j.normalized[f][n.columns].$row.length,k=1;k<m;k++)l=j.normalized[f][n.columns].$row.eq(k).children().eq(c),p[p.length]=""+d.getElementText(n,l,c);return p},buildSelect:function(d,f,g,h,i){if(d=a(d)[0],f=parseInt(f,10),d.config.cache&&!a.isEmptyObject(d.config.cache)){var j,k,l,m,n,o,p,q=d.config,r=q.widgetOptions,s=q.$headerIndexed[f],t='<option value="">'+(s.data("placeholder")||s.attr("data-placeholder")||r.filter_placeholder.select||"")+"</option>",u=q.$table.find("thead").find("select."+e.filter+'[data-column="'+f+'"]').val();if("undefined"!=typeof g&&""!==g||(g=b.getOptionSource(d,f,i)),a.isArray(g)){for(j=0;j<g.length;j++)if(p=g[j],p.text){p["data-function-name"]="undefined"==typeof p.value?p.text:p.value,t+="<option";for(k in p)p.hasOwnProperty(k)&&"text"!==k&&(t+=" "+k+'="'+p[k]+'"');p.value||(t+=' value="'+p.text+'"'),t+=">"+p.text+"</option>"}else""+p!="[object Object]"&&(l=p=(""+p).replace(c.quote,"&quot;"),k=l,l.indexOf(r.filter_selectSourceSeparator)>=0&&(m=l.split(r.filter_selectSourceSeparator),k=m[0],l=m[1]),t+=""!==p?"<option "+(k===l?"":'data-function-name="'+p+'" ')+'value="'+k+'">'+l+"</option>":"");g=[]}n=(q.$filters?q.$filters:q.$table.children("thead")).find("."+e.filter),r.filter_$externalFilters&&(n=n&&n.length?n.add(r.filter_$externalFilters):r.filter_$externalFilters),o=n.filter('select[data-column="'+f+'"]'),o.length&&(o[h?"html":"append"](t),a.isArray(g)||o.append(g).val(u),o.val(u))}},buildDefault:function(a,c){var e,f,g,h=a.config,i=h.widgetOptions,j=h.columns;for(e=0;e<j;e++)f=h.$headerIndexed[e],g=!(f.hasClass("filter-false")||f.hasClass("parser-false")),(f.hasClass("filter-select")||d.getColumnData(a,i.filter_functions,e)===!0)&&g&&b.buildSelect(a,e,"",c,f.hasClass(i.filter_onlyAvail))}},c=b.regex,d.getFilters=function(c,d,f,g){var h,i,j,k,l=[],m=c?a(c)[0].config:"",n=m?m.widgetOptions:"";if(d!==!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("."+e.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 l},d.setFilters=function(c,e,f,g){var h=c?a(c)[0].config:"",i=d.getFilters(c,!0,e,g);return"undefined"==typeof f&&(f=!0),h&&f&&(h.lastCombinedFilter=null,h.lastSearch=[],b.searching(h.table,e,g),h.$table.triggerHandler("filterFomatterUpdate")),0!==i.length}}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-formatter.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-formatter.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..7ab9593a6cd74b92e96af2ca4152e1266610501b
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-formatter.min.js
@@ -0,0 +1,2 @@
+/*! Widget: formatter - 2/9/2015 (v2.19.1) */
+!function(a){"use strict";var b=a.tablesorter;b.formatter={init:function(a){var c=a.widgetOptions.formatter_event+" pagerComplete updateComplete ".split(" ").join(".tsformatter ");a.$table.off(c.replace(/\s+/g," ")).on(c,function(){b.formatter.setup(a)}),b.formatter.setup(a)},setup:function(c){if(!a.isEmptyObject(c.cache)){var d,e,f,g,h,i,j,k=c.widgetOptions,l={config:c,wo:k},m=[],n=[];for(j=0;j<c.columns;j++)n[j]=c.$headerIndexed[j],m[j]=b.getColumnData(c.table,k.formatter_column,j)||!1;for(e=0;e<c.$tbodies.length;e++){for(d=b.processTbody(c.table,c.$tbodies.eq(e),!0),g=c.cache[e],i=g.normalized.length,f=0;f<i;f++)for(l.$row=g.normalized[f][c.columns].$row,l.$cells=l.$row.children("th, td"),j=0;j<c.columns;j++)m[j]&&(l.columnIndex=j,l.$header=n[j],l.$cell=l.$cells.eq(j),h=l.$cell[0],l.text=h.getAttribute(c.textAttribute)||h.textContent||l.$cell.text(),h.innerHTML=m[j](l.text,l));b.processTbody(c.table,d,!1)}}}},b.addWidget({id:"formatter",priority:100,options:{formatter_column:{},formatter_event:"applyFormatter"},init:function(a){b.formatter.init(a.config)}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-grouping.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-grouping.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..8f527f2c389be79478bbad11a541450f789c8d72
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-grouping.min.js
@@ -0,0 +1,2 @@
+/*! Widget: grouping - updated 11/26/2016 (v2.28.0) */
+!function(a){"use strict";var b=a.tablesorter,c=b.grouping={types:{number:function(a,c,d,e){var f,g=c.hasClass(b.css.sortAsc);return e>1&&""!==d?(f=g?Math.floor(parseFloat(d)/e)*e:Math.ceil(parseFloat(d)/e)*e,f+=" - "+(f+(e-1)*(g?1:-1))):f=parseFloat(d)||d,f},separator:function(b,c,d,e){var f=(d+"").split(b.widgetOptions.group_separator);return a.trim(f[e-1]||"")},text:function(a,b,c){return c},word:function(a,b,c,d){var e=(c+" ").match(/\w+/g)||[];return e[d-1]||""},letter:function(a,b,c,d){return c?(c+" ").substring(0,d):""},date:function(a,b,d,e,f){var g,h,i=a.widgetOptions,j=new Date(d||"");return j instanceof Date&&isFinite(j)?(g=j.getFullYear(),h=c.findMonth(i,j.getMonth()),"year"===e?g:"month"===e?h:"monthyear"===e?h+" "+g:"day"===e?h+" "+j.getDate():"week"===e?c.findWeek(i,j.getDay()):"time"===e?c.findTime(i,j):"hour"===e?c.findTime(i,j,"hour"):i.group_dateString(j,a,b)):i.group_dateInvalid}},findMonth:function(a,b){return a.group_months[b+(""===(a.group_months[0]||"")?1:0)]},findWeek:function(b,c){if(a.isArray(b.group_week))return b.group_week[c];if(!a.isEmptyObject(b.group_week)){var d=["sun","mon","tue","wed","thu","fri","sat"];return b.group_week[d[c]]}},findTime:function(a,b,c){var d,e=a.group_time.am&&a.group_time.pm,f=b.getHours(),g=f>=12?1:0,h=a.group_time24Hour&&f>12?f-12:a.group_time24Hour&&0===f?f+12:f,i=("00"+h).slice(-2),j=("00"+b.getMinutes()).slice(-2);return d=a.group_time[e?["am","pm"][g]:g],"hour"===c?i:i+":"+j+(a.group_time24Hour?"":" "+(d||""))},update:function(b){if(!a.isEmptyObject(b.config.cache)){var d=b.config,e=d.widgetOptions,f="undefined"!=typeof d.sortList[0],g={},h=a.isArray(e.group_forceColumn)&&"undefined"!=typeof e.group_forceColumn[0]?e.group_enforceSort&&!f?-1:e.group_forceColumn[0]:f?d.sortList[0][0]:-1;d.$table.find("tr.group-hidden").removeClass("group-hidden").end().find("tr.group-header").remove(),e.group_collapsible&&d.$table.data("pagerSavedHeight",0),h>=0&&h<d.columns&&!d.$headerIndexed[h].hasClass("group-false")&&(e.group_collapsedGroup="",e.group_collapsedGroups={},g.column=h,g.groupClass=(d.$headerIndexed[h].attr("class")||"").match(/(group-\w+(-\w+)?)/g),g.grouping=g.groupClass?g.groupClass[0].split("-"):["group","letter",1],g.savedGroup=c.saveCurrentGrouping(d,e,g),c.findColumnGroups(d,e,g),c.processHeaders(d,e,g),d.$table.triggerHandler(e.group_complete))}},processHeaders:function(b,c,d){var e,f,g,h,i,j,k=b.$table.find("tr.group-header"),l=k.length;for(k.bind("selectstart",!1),e=0;e<l;e++)j=k.eq(e),i=j.nextUntil("tr.group-header").filter(":visible"),(c.group_count||a.isFunction(c.group_callback))&&(g=j.find(".group-count"),g.length&&(c.group_count&&g.html(c.group_count.toString().replace(/\{num\}/g,i.length)),a.isFunction(c.group_callback)&&c.group_callback(j.find("td"),i,d.column,b.table))),c.group_saveGroups&&!a.isEmptyObject(c.group_collapsedGroups)&&c.group_collapsedGroups[c.group_collapsedGroup].length?(h=j.find(".group-name").text().toLowerCase()+j.attr("data-group-index"),f=a.inArray(h,c.group_collapsedGroups[c.group_collapsedGroup])>-1,j.toggleClass("collapsed",f),i.toggleClass("group-hidden",f)):c.group_collapsed&&c.group_collapsible&&(j.addClass("collapsed"),i.addClass("group-hidden"))},groupHeaderHTML:function(a,b,c){var d=(c.currentGroup||"").toString().replace(/</g,"&lt;").replace(/>/g,"&gt;");return'<tr class="group-header '+a.selectorRemove.slice(1)+'" unselectable="on" '+(a.tabIndex?'tabindex="0" ':"")+'data-group-index="'+c.groupIndex+'"><td colspan="'+a.columns+'">'+(b.group_collapsible?"<i/>":"")+'<span class="group-name">'+d+'</span><span class="group-count"></span></td></tr>'},saveCurrentGrouping:function(a,c,d){var e,f,g=!1;return c.group_collapsible&&c.group_saveGroups&&(c.group_collapsedGroups=b.storage&&b.storage(a.table,"tablesorter-groups")||{},f="dir"+a.sortList[0][1],e=c.group_collapsedGroup=""+a.sortList[0][0]+f+d.grouping.join(""),c.group_collapsedGroups[e]?g=!0:c.group_collapsedGroups[e]=[]),g},findColumnGroups:function(a,d,e){var f,g,h,i,j,k=b.hasWidget(a.table,"pager"),l=a.pager||{};for(e.groupIndex=0,f=0;f<a.$tbodies.length;f++)for(g=a.cache[f].normalized,e.group=j,h=k&&!l.ajax?l.startRow-1:0,i=k?l.endRow-(l.ajax?l.startRow:0):g.length;h<i;h++)e.rowData=g[h],e.rowData&&(e.$row=e.rowData[a.columns].$row,e.$row.is(":visible")&&c.types[e.grouping[1]]&&c.insertGroupHeader(a,d,e))},insertGroupHeader:function(b,d,e){var f=b.$headerIndexed[e.column],g=e.rowData[e.column],h=/date/.test(e.groupClass)?e.grouping[2]:parseInt(e.grouping[2]||1,10)||1;e.currentGroup=e.rowData?c.types[e.grouping[1]](b,f,g,h,e.group):e.currentGroup,e.group!==e.currentGroup&&(e.group=e.currentGroup,a.isFunction(d.group_formatter)&&(e.currentGroup=d.group_formatter((e.group||"").toString(),e.column,b.table,b,d,e)||e.group),e.$row.first().before(c.groupHeaderHTML(b,d,e)),d.group_saveGroups&&!e.savedGroup&&d.group_collapsed&&d.group_collapsible&&d.group_collapsedGroups[d.group_collapsedGroup].push(e.currentGroup+e.groupIndex),e.groupIndex++)},bindEvents:function(d,e,f){f.group_collapsible&&(f.group_collapsedGroups=[],e.$table.on("click toggleGroup keyup","tr.group-header",function(c){if(c.stopPropagation(),"keyup"!==c.type||13===c.which){var g,h,i,j=a(this),k=j.find(".group-name").text().toLowerCase()+j.attr("data-group-index");!c.shiftKey||"click"!==c.type&&"keyup"!==c.type||j.siblings(".group-header").trigger("toggleGroup"),j.toggleClass("collapsed"),j.nextUntil("tr.group-header").toggleClass("group-hidden",j.hasClass("collapsed")),g=j.hasClass("collapsed"),!g&&b.hasWidget(e.$table,"zebra")&&b.applyWidgetId(e.$table,"zebra"),f.group_saveGroups&&b.storage&&(h=e.$table.find(".group-header"),f.group_collapsedGroups[f.group_collapsedGroup]||(f.group_collapsedGroups[f.group_collapsedGroup]=[]),g&&f.group_collapsedGroup?f.group_collapsedGroups[f.group_collapsedGroup].push(k):f.group_collapsedGroup&&(i=a.inArray(k,f.group_collapsedGroups[f.group_collapsedGroup]),i>-1&&f.group_collapsedGroups[f.group_collapsedGroup].splice(i,1)),b.storage(d,"tablesorter-groups",f.group_collapsedGroups))}})),a(f.group_saveReset).on("click",function(){c.clearSavedGroups(d)}),e.$table.on("pagerChange.tsgrouping",function(){c.update(d)})},clearSavedGroups:function(a){a&&b.storage&&(b.storage(a,"tablesorter-groups",""),c.update(a))}};b.addWidget({id:"group",priority:100,options:{group_collapsible:!0,group_collapsed:!1,group_saveGroups:!0,group_saveReset:null,group_count:" ({num})",group_separator:"-",group_formatter:null,group_callback:null,group_complete:"groupingComplete",group_forceColumn:[],group_enforceSort:!0,group_checkbox:["checked","unchecked"],group_months:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],group_week:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],group_time:["AM","PM"],group_time24Hour:!1,group_dateInvalid:"Invalid Date",group_dateString:function(a){return a.toLocaleString()}},init:function(a,b,d,e){c.bindEvents(a,d,e)},format:function(a,b,d){c.update(a)},remove:function(a,b,c){b.$table.off("click","tr.group-header").off("pagerChange.tsgrouping").find(".group-hidden").removeClass("group-hidden").end().find("tr.group-header").remove()}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-headerTitles.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-headerTitles.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..80a5572bf07c6a532bd1c9fddbdb1185607db819
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-headerTitles.min.js
@@ -0,0 +1,2 @@
+/*! Widget: headerTitles - updated 11/10/2015 (v2.24.4) */
+!function(a){"use strict";var b=a.tablesorter;b.addWidget({id:"headerTitles",options:{headerTitle_useAria:!1,headerTitle_tooltip:"",headerTitle_cur_text:[" sort: A - Z"," sort: Z - A","ly unsorted"],headerTitle_cur_numeric:[" sort: 0 - 9"," sort: 9 - 0","ly unsorted"],headerTitle_nxt_text:[" sort: A - Z"," sort: Z - A","remove sort"],headerTitle_nxt_numeric:[" sort: 0 - 9"," sort: 9 - 0","remove sort"],headerTitle_output_sorted:"current{current}; activate to {next}",headerTitle_output_unsorted:"current{current}; activate to {next} ",headerTitle_output_nosort:"No sort available",headerTitle_type:[],headerTitle_callback:null},init:function(b,c,d,e){d.$table.on("refreshHeaderTitle",function(){c.format(b,d,e)}),a.isArray(e.headerTitle_tooltip)?d.$headers.each(function(){a(this).addClass(e.headerTitle_tooltip[this.column]||"")}):""!==e.headerTitle_tooltip&&d.$headers.addClass(e.headerTitle_tooltip)},format:function(c,d,e){var f;d.$headers.each(function(){var c=a(this),g=parseInt(c.attr("data-column"),10),h=e.headerTitle_type[g]||d.parsers[g].type||"text",i=c.hasClass(b.css.sortAsc)?0:c.hasClass(b.css.sortDesc)?1:2,j=d.sortVars[g].order[(d.sortVars[g].count+1)%(d.sortReset?3:2)];e.headerTitle_useAria?f=c.attr("aria-label")||e.headerTitle_output_nosort||"":(f=(e.headerTitle_prefix||"")+(c.hasClass("sorter-false")?e.headerTitle_output_nosort:b.isValueInArray(g,d.sortList)>=0?e.headerTitle_output_sorted:e.headerTitle_output_unsorted),f=f.replace(/\{(current|next|name)\}/gi,function(a){return{"{name}":c.text(),"{current}":e["headerTitle_cur_"+h][i]||"","{next}":e["headerTitle_nxt_"+h][j]||""}[a.toLowerCase()]})),c.attr("title",a.isFunction(e.headerTitle_callback)?e.headerTitle_callback(c,f):f)})},remove:function(b,c,d){c.$headers.attr("title",""),c.$table.off("refreshHeaderTitle"),a.isArray(d.headerTitle_tooltip)?c.$headers.each(function(){a(this).removeClass(d.headerTitle_tooltip[this.column]||"")}):""!==d.headerTitle_tooltip&&c.$headers.removeClass(d.headerTitle_tooltip)}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-lazyload.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-lazyload.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..a2c41d1a6e5a8749b1032044c4d06cd8916619aa
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-lazyload.min.js
@@ -0,0 +1,16 @@
+/*! Widget: lazyload (BETA) - 4/1/2016 (v2.25.7) */
+!function(a,b){"use strict";var c=a.tablesorter;c.lazyload={init:function(d,e){"scrollstop"!==e.lazyload_event||c.addScrollStopDone||(c.addScrollStop(),c.addScrollStopDone=!0,a.event.special.scrollstop.latency=e.lazyload_latency||250),c.lazyload.update(d,e);var f=d.namespace+"lazyload ",g=[e.lazyload_update,"pagerUpdate",e.columnSelector_updated||"columnUpdate",""].join(f);d.$table.on(g,function(){c.lazyload.update(d,d.widgetOptions)}).on("filterEnd"+f,function(){a(b).scroll()})},update:function(c,d){var e=(/(\.|#)/.test(d.lazyload_imageClass)?"":".")+d.lazyload_imageClass;c.$table.find(e).lazyload({threshold:d.lazyload_threshold,failure_limit:d.lazyload_failure_limit,event:d.lazyload_event,effect:d.lazyload_effect,container:d.lazyload_container,data_attribute:d.lazyload_data_attribute,skip_invisible:d.lazyload_skip_invisible,appear:d.lazyload_appear,load:d.lazyload_load,placeholder:d.lazyload_placeholder}),setTimeout(function(){a(b).scroll()},1)},remove:function(a,b){a.$table.off(a.namespace+"lazyload")}},c.addWidget({id:"lazyload",options:{lazyload_imageClass:"lazy",lazyload_update:"lazyloadUpdate",lazyload_latency:250,lazyload_threshold:0,lazyload_failure_limit:0,lazyload_event:"scrollstop",lazyload_effect:"show",lazyload_container:b,lazyload_data_attribute:"original",lazyload_skip_invisible:!0,lazyload_appear:null,lazyload_load:null,lazyload_placeholder:"data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="},init:function(a,b,d,e){c.lazyload.init(d,e)},remove:function(a,b,d){c.lazyload.remove(b,d)}}),c.addScrollStop=function(){var b=a.event.dispatch||a.event.handle,c=a.event.special,d="D"+ +new Date,e="D"+(+new Date+1);c.scrollstart={setup:function(e){var f,g=a.extend({latency:c.scrollstop.latency},e),h=function(a){var c=this,d=arguments;f?clearTimeout(f):(a.type="scrollstart",b.apply(c,d)),f=setTimeout(function(){f=null},g.latency)};a(this).bind("scroll",h).data(d,h)},teardown:function(){a(this).unbind("scroll",a(this).data(d))}},c.scrollstop={latency:250,setup:function(d){var f,g=a.extend({latency:c.scrollstop.latency},d),h=function(a){var c=this,d=arguments;f&&clearTimeout(f),f=setTimeout(function(){f=null,a.type="scrollstop",b.apply(c,d)},g.latency)};a(this).bind("scroll",h).data(e,h)},teardown:function(){a(this).unbind("scroll",a(this).data(e))}}}}(jQuery,window),/*!
+* Lazy Load - jQuery plugin for lazy loading images
+*
+* Copyright (c) 2007-2015 Mika Tuupola
+*
+* Licensed under the MIT license:
+*   http://www.opensource.org/licenses/mit-license.php
+*
+* Project home:
+*   http://www.appelsiini.net/projects/lazyload
+*
+* Version:  1.9.7
+*
+*/
+function(a,b,c,d){var e=a(b);a.fn.lazyload=function(f){function g(){var b=0;i.each(function(){var c=a(this);if(!j.skip_invisible||c.is(":visible"))if(a.abovethetop(this,j)||a.leftofbegin(this,j));else if(a.belowthefold(this,j)||a.rightoffold(this,j)){if(++b>j.failure_limit)return!1}else c.trigger("appear"),b=0})}var h,i=this,j={threshold:0,failure_limit:0,event:"scroll",effect:"show",container:b,data_attribute:"original",skip_invisible:!1,appear:null,load:null,placeholder:"data:image/gif;base64,R0lGODlhAQABAIABAP///wAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="};return f&&(d!==f.failurelimit&&(f.failure_limit=f.failurelimit,delete f.failurelimit),d!==f.effectspeed&&(f.effect_speed=f.effectspeed,delete f.effectspeed),a.extend(j,f)),h=j.container===d||j.container===b?e:a(j.container),0===j.event.indexOf("scroll")&&h.bind(j.event,function(){return g()}),this.each(function(){var b=this,c=a(b);b.loaded=!1,c.attr("src")!==d&&c.attr("src")!==!1||c.is("img")&&c.attr("src",j.placeholder),c.one("appear",function(){if(!this.loaded){if(j.appear){var d=i.length;j.appear.call(b,d,j)}a("<img />").bind("load",function(){var d=c.attr("data-"+j.data_attribute);c.hide(),c.is("img")?c.attr("src",d):c.css("background-image","url('"+d+"')"),c[j.effect](j.effect_speed),b.loaded=!0;var e=a.grep(i,function(a){return!a.loaded});if(i=a(e),j.load){var f=i.length;j.load.call(b,f,j)}}).attr("src",c.attr("data-"+j.data_attribute))}}),0!==j.event.indexOf("scroll")&&c.bind(j.event,function(){b.loaded||c.trigger("appear")})}),e.bind("resize",function(){g()}),/(?:iphone|ipod|ipad).*os 5/gi.test(navigator.appVersion)&&e.bind("pageshow",function(b){b.originalEvent&&b.originalEvent.persisted&&i.each(function(){a(this).trigger("appear")})}),a(c).ready(function(){g()}),this},a.belowthefold=function(c,f){var g;return g=f.container===d||f.container===b?(b.innerHeight?b.innerHeight:e.height())+e.scrollTop():a(f.container).offset().top+a(f.container).height(),g<=a(c).offset().top-f.threshold},a.rightoffold=function(c,f){var g;return g=f.container===d||f.container===b?e.width()+e.scrollLeft():a(f.container).offset().left+a(f.container).width(),g<=a(c).offset().left-f.threshold},a.abovethetop=function(c,f){var g;return g=f.container===d||f.container===b?e.scrollTop():a(f.container).offset().top,g>=a(c).offset().top+f.threshold+a(c).height()},a.leftofbegin=function(c,f){var g;return g=f.container===d||f.container===b?e.scrollLeft():a(f.container).offset().left,g>=a(c).offset().left+f.threshold+a(c).width()},a.inviewport=function(b,c){return!(a.rightoffold(b,c)||a.leftofbegin(b,c)||a.belowthefold(b,c)||a.abovethetop(b,c))},a.extend(a.expr[":"],{"below-the-fold":function(b){return a.belowthefold(b,{threshold:0})},"above-the-top":function(b){return!a.belowthefold(b,{threshold:0})},"right-of-screen":function(b){return a.rightoffold(b,{threshold:0})},"left-of-screen":function(b){return!a.rightoffold(b,{threshold:0})},"in-viewport":function(b){return a.inviewport(b,{threshold:0})},"above-the-fold":function(b){return!a.belowthefold(b,{threshold:0})},"right-of-fold":function(b){return a.rightoffold(b,{threshold:0})},"left-of-fold":function(b){return!a.rightoffold(b,{threshold:0})}})}(jQuery,window,document);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-mark.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-mark.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..8d6e2313f26f48645ac3973ca60d7c8cda290469
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-mark.min.js
@@ -0,0 +1,2 @@
+/*! Widget: mark.js - updated 9/23/2016 (v2.27.7) */
+!function(a){"use strict";var b=a.tablesorter;b.mark={init:function(c){if("function"==typeof a.fn.mark){var d,e=c.widgetOptions.mark_tsUpdate;c.$table.on("filterEnd.tsmark pagerComplete.tsmark"+(e?" "+e:""),function(a,d){b.mark.update(c,a.type===e?d:"")}),d="(?:<|=|>|\\||\"|\\'|\\s+(?:&&|-|"+(b.language.and||"and")+"|"+(b.language.or||"or")+"|"+(b.language.to||"to")+")\\s+)",b.mark.regex.filter=new RegExp(d,"gim")}else console.warn('Widget-mark not initialized: missing "jquery.mark.js"')},regex:{mark:/^mark_(.+)$/,pure:/^\/((?:\\\/|[^\/])+)\/([mig]{0,3})?$/},checkRegex:function(a){if(a instanceof RegExp){var b="".match(a);return null===b||b.length<5}return!1},cleanMatches:function(a){for(var b=[],c=a&&a.length||0;c--;)""!==a[c]&&(b[b.length]=a[c]);return b},ignoreColumns:function(b){for(var c=b.widgetOptions,d=b.columns,e=[];d--;)(c.mark_tsIgnore[d]||a(b.$headerIndexed[d]).hasClass("mark-ignore"))&&(e[e.length]=":nth-child("+(d+1)+")");return e.length?":not("+e.join(",")+")":""},update:function(c,d){var e={},f=c.widgetOptions,g=b.mark.regex,h=c.$table.find("tbody tr").unmark().not("."+(c.widgetOptions.filter_filteredRow||"filtered"));d=d||a.tablesorter.getFilters(c.$table),a.each(c.widgetOptions,function(a,b){var c=a.match(g.mark);c&&"undefined"!=typeof c[1]&&(e[c[1]]=b)}),a.each(d,function(d,i){if(i&&!a(c.$headerIndexed[d]).hasClass("mark-ignore")&&!f.mark_tsIgnore[d]){var j=null,k=i,l=!1,m=d===c.columns?b.mark.ignoreColumns(c):":nth-child("+(d+1)+")";if(g.pure.test(i)){k=g.pure.exec(i),".*"===k[1]&&(k[1]="");try{j=new RegExp(k[1],"gim"),k=new RegExp(k[1],k[2])}catch(a){k=null}return void(b.mark.checkRegex(j)&&h.children(m).markRegExp(k,e))}0===i.indexOf("~")?(l=!0,k=i.replace(/~/g,"").split("")):(i.indexOf("?")>-1&&(l=!0,i=i.replace(/\?/g,"\\S{1}")),i.indexOf("*")>-1&&(l=!0,i=i.replace(/\*/g,"\\S*")),k=i.split(g.filter)),l&&k&&k.length?(k=new RegExp(b.mark.cleanMatches(k).join(".*"),"gm"),b.mark.checkRegex(k)&&h.children(m).markRegExp(k,e)):h.children(m).mark(b.mark.cleanMatches(k),e)}})}},b.addWidget({id:"mark",options:{mark_tsUpdate:"markUpdate",mark_tsIgnore:{}},init:function(a,c,d,e){b.mark.init(d,e)},remove:function(a,b){var c=b.widgetOptions.mark_tsUpdate;b.$table.off("filterEnd.tsmark pagerComplete.tsmark"+(c?" "+c:""))}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-math.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-math.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..a321c4274e54cffe3100d989ddffe123331df098
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-math.min.js
@@ -0,0 +1,2 @@
+/*! Widget: math - updated 11/26/2016 (v2.28.0) */
+!function(a){"use strict";var b=a.tablesorter,c={error:{0:"Infinity result: Divide by zero",1:"Need more than one element to make this calculation",undef:"No elements found"},invalid:function(a,b,d){return console.warn(b,c.error[d]),a&&a.widgetOptions.math_none||""},events:"tablesorter-initialized update updateAll updateRows addRows updateCell filterReset ".split(" ").join(".tsmath "),processText:function(d,e){var f,g=b.getElementText(d,e,c.getCellIndex(e)),h=d.widgetOptions.math_prefix;return/</.test(h)&&(f=a("<div>"+h+"</div>").text().replace(/\{content\}/g,"").trim(),g=g.replace(f,"")),g=b.formatFloat(g.replace(/[^\w,. \-()]/g,""),d.table)||0,isNaN(g)?0:g},getRow:function(b,d,e){var f,g=b.widgetOptions,h=[],i=d.closest("tr"),j=i.hasClass(g.filter_filteredRow||"filtered");return e&&(i=i.filter(e)),!e&&j||(f=i.children().not("["+g.math_dataAttrib+"=ignore]"),g.math_ignore.length&&(f=f.filter(function(){return a.inArray(c.getCellIndex(a(this)),g.math_ignore)===-1})),h=f.not(d).map(function(){return c.processText(b,a(this))}).get()),h},getColumn:function(b,d,e,f){var g,h,i,j,k,l,m=b.widgetOptions,n=[],o=d.closest("tr"),p=m.math_dataAttrib,q="["+p+"=ignore]",r=m.filter_filteredRow||"filtered",s=c.getCellIndex(d),t=b.$table.children("tbody").children(),u=["["+p+"^=above]","["+p+"^=below]","["+p+"^=col]","["+p+"^=all]"];if("above"===e)for(j=t.index(o),g=j;g>=0;)i=t.eq(g),l=i.children().filter(u[0]).length,f&&(i=i.filter(f)),h=i.children().filter(function(){return c.getCellIndex(a(this))===s}),((f||!i.hasClass(r))&&i.not(q).length&&g!==j||l&&g!==j)&&(l?g=0:h.length&&(n[n.length]=c.processText(b,h))),g--;else if("below"===e)for(j=t.length,g=t.index(o)+1;g<j&&(i=t.eq(g),!i.children().filter(u[1]).length);g++)f&&(i=i.filter(f)),h=i.children().filter(function(){return c.getCellIndex(a(this))===s}),(f||!i.hasClass(r))&&i.not(q).length&&h.length&&(n[n.length]=c.processText(b,h));else for(k=t.not(q),j=k.length,g=0;g<j;g++)i=k.eq(g),f&&(i=i.filter(f)),h=i.children().filter(function(){return c.getCellIndex(a(this))===s}),!f&&i.hasClass(r)||!h.not(u.join(",")).length||h.is(d)||(n[n.length]=c.processText(b,h));return n},getAll:function(b,d){var e,f,g,h,i,j,k,l,m=[],n=b.widgetOptions,o=n.math_dataAttrib,p="["+o+"=ignore]",q=n.filter_filteredRow||"filtered",r=b.$table.children("tbody").children().not(p);for(i=r.length,h=0;h<i;h++)if(g=r.eq(h),d&&(g=g.filter(d)),d||!g.hasClass(q))for(j=g.children().not(p),l=j.length,k=0;k<l;k++)e=j.eq(k),f=c.getCellIndex(e),!e.filter("["+o+"]").length&&a.inArray(f,n.math_ignore)<0&&(m[m.length]=c.processText(b,e));return m},setColumnIndexes:function(c){var d=c.$table,e=1,f=d.children("tbody").children().filter(function(){var b,c,d=a(this),f=d.children("[colspan]").length>0;if(e>1?(e--,f=!0):e<1&&(e=1),d.children("[rowspan]").length>0)for(b=this.cells,c=0;c<b.length;c++)e=Math.max(b[c].rowSpan,e);return f});b.computeColumnIndex(f,c)},getCellIndex:function(a){var b=a.attr("data-column");return"undefined"==typeof b?a[0].cellIndex:parseInt(b,10)},recalculate:function(d,e,f){if(d&&(!e.math_isUpdating||f)){var g,h,i,j,k,l=!1,m={};for((d.debug||e.math_debug)&&(g=new Date),f&&c.setColumnIndexes(d),e.math_dataAttrib="data-"+(e.math_data||"math"),h=e.math_dataAttrib,i=d.$tbodies.children("tr").children("["+h+"]"),l=c.mathType(d,i,e.math_priority)||l,i=d.$table.children("."+d.cssInfoBlock+", tfoot").children("tr").children("["+h+"]"),c.mathType(d,i,e.math_priority),i=d.$table.children().children("tr").children("["+h+"^=all]"),k=i.length,j=0;j<k;j++){var n=i.eq(j),o=n.attr(h+"-filter")||e.math_rowFilter;m[o]=m[o]?m[o].add(n):n}a.each(m,function(a,b){l=c.mathType(d,b,["all"],a)||l}),l?(e.math_isUpdating=!0,(d.debug||e.math_debug)&&console[console.group?"group":"log"]("Math widget updating the cache after recalculation"),b.updateCache(d,function(){c.updateComplete(d),f||"function"!=typeof e.math_completed||e.math_completed(d),(d.debug||e.math_debug)&&console.log("Math widget update completed"+b.benchmark(g))})):(f||"function"!=typeof e.math_completed||e.math_completed(d),(d.debug||e.math_debug)&&console.log("Math widget found no changes in data"+b.benchmark(g)))}},updateComplete:function(a){var b=a.widgetOptions;b.math_isUpdating&&(a.debug||b.math_debug)&&console.groupEnd&&console.groupEnd(),b.math_isUpdating=!1},mathType:function(d,e,f,g){if(e.length){var h,i=!1,j=d.widgetOptions,k=j.math_dataAttrib,l=b.equations;return"all"===f[0]&&(h=c.getAll(d,g)),(d.debug||j.math_debug)&&console[console.group?"group":"log"]("Tablesorter Math widget recalculation"),a.each(f,function(a,b){var f,m,n,o,p,q=e.filter("["+k+"^="+b+"]"),r=q.length;if(r){for((d.debug||j.math_debug)&&console[console.group?"group":"log"](b),f=0;f<r;f++)p=q.eq(f),p.parent().hasClass(j.filter_filteredRow||"filtered")||(g=p.attr(k+"-filter")||j.math_rowFilter,n=(p.attr(k)||"").replace(b+"-",""),m="row"===b?c.getRow(d,p,g):"all"===b?h:c.getColumn(d,p,b,g),l[n]&&(m.length?(o=l[n](m,d),(d.debug||j.math_debug)&&console.log(p.attr(k),g?'("'+g+'")':"",m,"=",o)):o=c.invalid(d,n,"mean"===n?0:"undef"),i=c.output(p,d,o,m)||i));(d.debug||j.math_debug)&&console.groupEnd&&console.groupEnd()}}),(d.debug||j.math_debug)&&console.groupEnd&&console.groupEnd(),i}return!1},output:function(a,c,d,e){var f,g=c.widgetOptions,h=!1,i=a.html(),j=a.attr("data-"+g.math_data+"-mask")||g.math_mask,k=a.attr("data-"+g.math_data+"-target")||"",l=b.formatMask(j,d,g.math_prefix,g.math_suffix);return k&&(f=a.find(k),f.length&&(a=f)),"function"==typeof g.math_complete&&(l=g.math_complete(a,g,l,d,e)),l!==!1&&(h=i!==l,a.html(l)),!(h&&(f=a.closest("tbody"),!f.length||f.hasClass(c.cssInfoBlock)||f.parent()[0]!==c.table))&&h}};b.formatMask=function(a,b,c,d){if(!a||isNaN(+b))return b;var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t="",u=a.length,v=a.search(/[0-9\-\+#]/),w=v>0?a.substring(0,v):"",x=w;if(c&&(x=/\{content\}/.test(c||"")?(c||"").replace(/\{content\}/g,w||""):(c||"")+w),s=a.split("").reverse().join(""),r=s.search(/[0-9\-\+#]/),q=u-r,q+="."===a.substring(q,q+1)?1:0,w=r>0?a.substring(q,u):"",t=w,d&&(t=/\{content\}/.test(d||"")?(d||"").replace(/\{content\}/g,w||""):w+(d||"")),a=a.substring(v,q),b="-"==a.charAt(0)?-b:+b,e=b<0?b=-b:0,f=a.match(/[^\d\-\+#]/g),g=f&&f[f.length-1]||".",h=f&&f[1]&&f[0]||",",a=a.split(g),b=b.toFixed(a[1]&&a[1].length),b=+b+"",j=a[1]&&a[1].lastIndexOf("0"),l=b.split("."),(!l[1]||l[1]&&l[1].length<=j)&&(b=(+b).toFixed(j+1)),m=a[0].split(h),a[0]=m.join(""),i=a[0]&&a[0].indexOf("0"),i>-1)for(;l[0].length<a[0].length-i;)l[0]="0"+l[0];else 0===+l[0]&&(l[0]="");if(b=b.split("."),b[0]=l[0],k=m[1]&&m[m.length-1].length){for(n=b[0],o="",p=n.length%k,u=n.length,q=0;q<u;q++)o+=n.charAt(q),!((q-p+1)%k)&&q<u-k&&(o+=h);b[0]=o}return b[1]=a[1]&&b[1]?g+b[1]:"",x+((e?"-":"")+b[0]+b[1])+t},b.equations={count:function(a){return a.length},sum:function(a){var b,c=a.length,d=0;for(b=0;b<c;b++)d+=a[b];return d},mean:function(a){var c=b.equations.sum(a);return c/a.length},median:function(a,b){var d,e=a.length;return e>1?(a.sort(function(a,b){return a-b}),d=Math.floor(e/2),e%2?a[d]:(a[d-1]+a[d])/2):c.invalid(b,"median",1)},mode:function(a){var b,c,d,e={},f=1,g=[a[0]];for(b=0;b<a.length;b++)c=a[b],e[c]=e[c]?e[c]+1:1,d=e[c],d>f?(g=[c],f=d):d===f&&(g[g.length]=c,f=d);return g.sort(function(a,b){return a-b})},max:function(a){return Math.max.apply(Math,a)},min:function(a){return Math.min.apply(Math,a)},range:function(a){var b=a.sort(function(a,b){return a-b});return b[a.length-1]-b[0]},variance:function(a,d,e){for(var f,g=b.equations.mean(a),h=0,i=a.length;i--;)h+=Math.pow(a[i]-g,2);return f=a.length-(d?0:1),0===f?c.invalid(e,"variance",0):h/=f},varp:function(a,c){return b.equations.variance(a,!0,c)},vars:function(a,c){return b.equations.variance(a,!1,c)},stdevs:function(a,c){var d=b.equations.variance(a,!1,c);return Math.sqrt(d)},stdevp:function(a,c){var d=b.equations.variance(a,!0,c);return Math.sqrt(d)}},b.addWidget({id:"math",priority:100,options:{math_data:"math",math_debug:!1,math_ignore:[],math_mask:"#,##0.00",math_complete:null,math_priority:["row","above","below","col"],math_prefix:"",math_suffix:"",math_none:"N/A",math_event:"recalculate",math_rowFilter:""},init:function(a,d,e,f){var g=(b.hasWidget(a,"filter")?"filterEnd":"updateComplete")+".tsmath";c.events+=(b.hasWidget(a,"pager")?"pagerComplete":"filterEnd")+".tsmath ",e.$table.off((c.events+"updateComplete.tsmath "+f.math_event).replace(/\s+/g," ")).on(c.events+f.math_event,function(a){if(this.hasInitialized){var b="tablesorter-initialized"===a.type;f.math_isUpdating&&!b||(/filter/.test(a.type)||b||c.setColumnIndexes(e),c.recalculate(e,f,b))}}).on(g,function(){setTimeout(function(){c.updateComplete(e)},40)}),f.math_isUpdating=!1,a.hasInitialized&&c.recalculate(e,f,!0)},remove:function(a,b,d,e){e||b.$table.off((c.events+" updateComplete.tsmath "+d.math_event).replace(/\s+/g," ")).children().children("tr").children("[data-"+d.math_data+"]").empty()}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-output.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-output.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..2d9e96b99d225b31e3b67edfcfd2c9d077717f4c
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-output.min.js
@@ -0,0 +1,2 @@
+/*! Widget: output - updated 1/6/2017 (v2.28.4) */
+!function(a){"use strict";var b=a.tablesorter,c=b.output={event:"outputTable",noDblClick:600,lastEvent:0,busy:!1,regexQuote:/([\n\t\x09\x0d\x0a]|<[^<]+>)/,regexBR:/(<br([\s\/])?>|\n)/g,regexIMG:/<img[^>]+alt\s*=\s*['"]([^'"]+)['"][^>]*>/i,regexHTML:/<[^<]+>/g,replaceCR:"\r\n",replaceTab:"\t",popupTitle:"Output",popupStyle:"width:100%;height:100%;margin:0;resize:none;",message:"Your device does not support downloading. Please try again in desktop browser.",init:function(a){a.$table.off(c.event).on(c.event,function(b){b.stopPropagation(),!c.busy&&b.timeStamp-c.lastEvent>c.noDblClick&&(c.lastEvent=b.timeStamp,c.busy=!0,c.process(a,a.widgetOptions))})},processRow:function(d,e,f,g){var h,i,j,k,l,m,n,o,p,q,r=d.widgetOptions,s=[],t=r.output_duplicateSpans,u=f&&g&&r.output_headerRows&&a.isFunction(r.output_callbackJSON),v=0,w=e.length;for(k=0;k<w;k++)for(s[k]||(s[k]=[]),v=0,i=e.eq(k).children(),j=i.length,n=0;n<j;n++){if(h=i.eq(n),h.filter("[rowspan]").length)for(o=parseInt(h.attr("rowspan"),10)-1,q=c.formatData(d,r,h,f),l=1;l<=o;l++)s[k+l]||(s[k+l]=[]),s[k+l][v]=f?q:t?q:"";if(h.filter("[colspan]").length)for(p=parseInt(h.attr("colspan"),10)-1,q=c.formatData(d,r,h,f),m=1;m<=p;m++)if(h.filter("[rowspan]").length)for(o=parseInt(h.attr("rowspan"),10),l=0;l<o;l++)s[k+l]||(s[k+l]=[]),s[k+l][v+m]=u?r.output_callbackJSON(h,q,v+m)||q+"("+(v+m)+")":f?q:t?q:"";else s[k][v+m]=u?r.output_callbackJSON(h,q,v+m)||q+"("+(v+m)+")":f?q:t?q:"";for(;"undefined"!=typeof s[k][v];)v++;s[k][v]=s[k][v]||c.formatData(d,r,h,f),v++}return b.output.removeColumns(d,r,s)},removeColumns:function(a,b,c){var d,e,f,g=[],h=c.length;for(d=0;d<h;d++)for(e=c[d],g[d]=[],f=0;f<a.columns;f++)b.output_hiddenColumnArray[f]||g[d].push(e[f]);return g},process:function(d,e){var f,g,h,i,j,k,l,m,n=window.JSON&&JSON.hasOwnProperty("stringify"),o=0,p=(e.output_separator||",").toLowerCase(),q="json"===p,r="array"===p,s=q||r?",":e.output_separator,t=e.output_saveRows,u=d.$table;for(e.output_regex=new RegExp("("+(/\\/.test(s)?"\\":"")+s+")"),e.output_hiddenColumnArray=[],o=0;o<d.columns;o++)e.output_hiddenColumnArray[o]=a.inArray(o,e.output_ignoreColumns)>-1||!e.output_hiddenColumns&&"none"===d.$headerIndexed[o].css("display")&&!d.$headerIndexed[o].hasClass("tablesorter-scroller-hidden-column");if(g=u.children("thead").children("tr").not("."+(b.css.filterRow||"tablesorter-filter-row")).filter(function(){return e.output_hiddenColumns||"none"!==a(this).css("display")}),i=c.processRow(d,g,!0,q),h=u.children("tbody").children("tr").not(d.selectorRemove),h="function"==typeof t?h.filter(t):/^f/.test(t)?h.not("."+(e.filter_filteredRow||"filtered")):/^v/.test(t)?h.filter(":visible"):/^[.#:\[]/.test(t)?h.filter(t):h,j=c.processRow(d,h),e.output_includeFooter&&(j=j.concat(c.processRow(d,u.children("tfoot").children("tr:visible")))),k=i.length,q){for(p=[],l=j.length,o=0;o<l;o++)m=i[k>1&&e.output_headerRows?o%k:k-1],p.push(c.row2Hash(m,j[o]));f=n?JSON.stringify(p):p}else e.output_includeHeader?(m=[i[k>1&&e.output_headerRows?o%k:k-1]],p=c.row2CSV(e,e.output_headerRows?i:m,r).concat(c.row2CSV(e,j,r))):p=c.row2CSV(e,j,r),f=r&&n?JSON.stringify(p):p.join("\n");if(a.isFunction(e.output_callback)){if(m=e.output_callback(d,f,d.pager&&d.pager.ajaxObject.url||null),m===!1)return;"string"==typeof m&&(f=m)}/p/i.test(e.output_delivery||"")?c.popup(f,e.output_popupStyle,q||r):c.download(d,e,f),c.busy=!1},row2CSV:function(a,b,c){var d,e,f=[],g=b.length;for(e=0;e<g;e++)d=(b[e]||[]).join("").replace(/\"/g,""),(b[e]||[]).length>0&&""!==d&&(f[f.length]=c?b[e]:b[e].join(a.output_separator));return f},row2Hash:function(a,b){var c,d={},e=b.length;for(c=0;c<e;c++)c<a.length&&(d[a[c]]=b[c]);return d},formatData:function(b,d,e,f){var g=e.attr(d.output_dataAttrib),h="undefined"!=typeof g?g:e.html(),i=(d.output_separator||",").toLowerCase(),j="json"===i||"array"===i,k=h.replace(/\"/g,d.output_replaceQuote||"“");return k=d.output_trimSpaces?k.replace(c.regexBR,""):k.replace(c.regexBR,c.replaceCR).replace(/\t/g,c.replaceTab),h=k.match(c.regexIMG),d.output_includeHTML||null===h||(k=h[1]),k=d.output_includeHTML&&!f?k:k.replace(c.regexHTML,""),k=d.output_trimSpaces||f?a.trim(k):k,i=!j&&(d.output_wrapQuotes||d.output_regex.test(k)||c.regexQuote.test(k)),k=i?'"'+k+'"':k,"function"==typeof d.output_formatContent?d.output_formatContent(b,d,{isHeader:f,$cell:e,content:k}):k},popup:function(a,b,d){var e=window.open("",c.popupTitle,b);try{e.document.write("<html><head><title>"+c.popupTitle+'</title></head><body><textarea wrap="'+(d?"on":"off")+'" style="'+c.popupStyle+'">'+a+"\n</textarea></body></html>"),e.document.close(),e.focus()}catch(f){return e.close(),c.popup(a,b,d)}return!0},download:function(a,b,d){if("function"==typeof b.output_savePlugin)return b.output_savePlugin(a,b,d);var e,f,g,h,i=window.navigator,j=document.createElement("a");if(/(iP)/g.test(i.userAgent))return alert(c.message),!1;try{g=!!new Blob}catch(a){g=!1}return g?(window.URL=window.URL||window.webkitURL,h=/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(b.output_encoding)?["\ufeff",d]:[d],f=new Blob(h,{type:b.output_encoding}),i.msSaveBlob?i.msSaveBlob(f,b.output_saveFileName):(j.href=window.URL.createObjectURL(f),j.download=b.output_saveFileName,document.createEvent&&(e=document.createEvent("MouseEvents"),e.initMouseEvent("click",!0,!0,window,0,0,0,0,0,!1,!1,!1,!1,0,null),j.dispatchEvent(e))),!1):(window.open(b.output_encoding+encodeURIComponent(d)+"?download","_self"),!0)},remove:function(a){a.$table.off(c.event)}};b.addWidget({id:"output",options:{output_separator:",",output_ignoreColumns:[],output_hiddenColumns:!1,output_includeFooter:!1,output_includeHeader:!0,output_headerRows:!1,output_dataAttrib:"data-name",output_delivery:"popup",output_saveRows:"filtered",output_duplicateSpans:!0,output_replaceQuote:"“;",output_includeHTML:!1,output_trimSpaces:!0,output_wrapQuotes:!1,output_popupStyle:"width=500,height=300",output_saveFileName:"mytable.csv",output_formatContent:null,output_callback:function(a,b){return!0},output_callbackJSON:function(a,b,c){return b+"("+c+")"},output_encoding:"data:application/octet-stream;charset=utf8,",output_savePlugin:null},init:function(a,b,d){c.init(d)},remove:function(a,b){c.remove(b)}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-pager.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-pager.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..02f97685df6a799a6742996550b97e3589f51e8d
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-pager.min.js
@@ -0,0 +1,2 @@
+/*! Widget: Pager - updated 1/6/2017 (v2.28.4) */
+!function(a){"use strict";var b,c=a.tablesorter;c.addWidget({id:"pager",priority:55,options:{pager_output:"{startRow} to {endRow} of {totalRows} rows",pager_updateArrows:!0,pager_startPage:0,pager_pageReset:0,pager_size:10,pager_maxOptionSize:20,pager_savePages:!0,pager_storageKey:"tablesorter-pager",pager_fixedHeight:!1,pager_countChildRows:!1,pager_removeRows:!1,pager_ajaxUrl:null,pager_customAjaxUrl:function(a,b){return b},pager_ajaxError:null,pager_ajaxObject:{dataType:"json"},pager_processAjaxOnInit:!0,pager_ajaxProcessing:function(a){return[0,[],null]},pager_css:{container:"tablesorter-pager",errorRow:"tablesorter-errorRow",disabled:"disabled"},pager_selectors:{container:".pager",first:".first",prev:".prev",next:".next",last:".last",gotoPage:".gotoPage",pageDisplay:".pagedisplay",pageSize:".pagesize"}},init:function(a){b.init(a)},format:function(a,c){return c.pager&&c.pager.initialized?void b.moveToPage(c,c.pager,!1):b.initComplete(c)},remove:function(a,c,d,e){b.destroyPager(c,e)}}),b=c.pager={init:function(d){if(!(d.hasInitialized&&d.config.pager&&d.config.pager.initialized)){var e,f=d.config,g=f.widgetOptions,h=g.pager_selectors,i=f.pager=a.extend({totalPages:0,filteredRows:0,filteredPages:0,currentFilters:[],page:g.pager_startPage,startRow:0,endRow:0,ajaxCounter:0,$size:null,last:{},setSize:g.pager_size,setPage:g.pager_startPage},f.pager);i.isInitializing||(i.isInitializing=!0,f.debug&&console.log("Pager: Initializing"),i.size=a.data(d,"pagerLastSize")||g.pager_size,i.$container=a(h.container).addClass(g.pager_css.container).show(),i.totalRows=f.$tbodies.eq(0).children("tr").not(g.pager_countChildRows?"":"."+f.cssChildRow).length,i.oldAjaxSuccess=i.oldAjaxSuccess||g.pager_ajaxObject.success,f.appender=b.appender,i.initializing=!0,g.pager_savePages&&c.storage&&(e=c.storage(d,g.pager_storageKey)||{},i.page=(isNaN(e.page)?i.page:e.page)||i.setPage||0,i.size="all"===e.size?e.size:(isNaN(e.size)?i.size:e.size)||i.setSize||10,a.data(d,"pagerLastSize",i.size),i.$container.find(h.pageSize).val(i.size)),i.regexRows=new RegExp("("+(g.filter_filteredRow||"filtered")+"|"+f.selectorRemove.slice(1)+"|"+f.cssChildRow+")"),i.regexFiltered=new RegExp(g.filter_filteredRow||"filtered"),i.initialized=!1,f.$table.triggerHandler("pagerBeforeInitialized",f),b.enablePager(f,!1),i.ajaxObject=g.pager_ajaxObject,i.ajaxObject.url=g.pager_ajaxUrl,"string"==typeof g.pager_ajaxUrl?(i.ajax=!0,g.filter_serversideFiltering=!0,f.serverSideSorting=!0,b.moveToPage(f,i)):(i.ajax=!1,c.appendCache(f,!0)))}},initComplete:function(a){var d=a.pager;b.bindEvents(a),b.setPageSize(a,0),d.ajax||b.hideRowsSetup(a),d.initialized=!0,d.initializing=!1,d.isInitializing=!1,a.debug&&console.log("Pager: Triggering pagerInitialized"),a.$table.triggerHandler("pagerInitialized",a),a.widgetOptions.filter_initialized&&c.hasWidget(a.table,"filter")||b.updatePageDisplay(a,!d.ajax)},bindEvents:function(d){var e,f,g,h=d.pager,i=d.widgetOptions,j=d.namespace+"pager",k=i.pager_selectors;d.$table.off(j).on("filterInit filterStart ".split(" ").join(j+" "),function(b,c){h.currentFilters=a.isArray(c)?c:d.$table.data("lastSearch"),"filterStart"===b.type&&i.pager_pageReset!==!1&&(d.lastCombinedFilter||"")!==(h.currentFilters||[]).join("")&&(h.page=i.pager_pageReset)}).on("filterEnd sortEnd ".split(" ").join(j+" "),function(){h.currentFilters=d.$table.data("lastSearch"),(h.initialized||h.initializing)&&(d.delayInit&&d.rowsCopy&&0===d.rowsCopy.length&&b.updateCache(d),b.updatePageDisplay(d,!1),c.applyWidget(d.table))}).on("disablePager"+j,function(a){a.stopPropagation(),b.showAllRows(d)}).on("enablePager"+j,function(a){a.stopPropagation(),b.enablePager(d,!0)}).on("destroyPager"+j,function(a,b){a.stopPropagation(),c.removeWidget(d.table,"pager",!1)}).on("updateComplete"+j,function(a,e,f){if(a.stopPropagation(),e&&!f&&!h.ajax){var g=d.$tbodies.eq(0).children("tr").not(d.selectorRemove);h.totalRows=g.length-(i.pager_countChildRows?0:g.filter("."+d.cssChildRow).length),h.totalPages="all"===h.size?1:Math.ceil(h.totalRows/h.size),g.length&&d.rowsCopy&&0===d.rowsCopy.length&&b.updateCache(d),h.page>=h.totalPages&&b.moveToLastPage(d,h),b.hideRows(d),b.changeHeight(d),b.updatePageDisplay(d,!1),c.applyWidget(e),b.updatePageDisplay(d)}}).on("pageSize refreshComplete ".split(" ").join(j+" "),function(a,c){a.stopPropagation(),b.setPageSize(d,b.parsePageSize(d,c,"get")),b.hideRows(d),b.updatePageDisplay(d,!1)}).on("pageSet pagerUpdate ".split(" ").join(j+" "),function(a,c){a.stopPropagation(),"pagerUpdate"===a.type&&(c="undefined"==typeof c?h.page+1:c,h.last.page=!0),h.page=(parseInt(c,10)||1)-1,b.moveToPage(d,h,!0),b.updatePageDisplay(d,!1)}).on("pageAndSize"+j,function(a,c,e){a.stopPropagation(),h.page=(parseInt(c,10)||1)-1,b.setPageSize(d,b.parsePageSize(d,e,"get")),b.moveToPage(d,h,!0),b.hideRows(d),b.updatePageDisplay(d,!1)}),e=[k.first,k.prev,k.next,k.last],f=["moveToFirstPage","moveToPrevPage","moveToNextPage","moveToLastPage"],d.debug&&!h.$container.length&&console.warn("Pager: >> Container not found"),h.$container.find(e.join(",")).attr("tabindex",0).off("click"+j).on("click"+j,function(c){c.stopPropagation();var g,j=a(this),k=e.length;if(!j.hasClass(i.pager_css.disabled))for(g=0;g<k;g++)if(j.is(e[g])){b[f[g]](d,h);break}}),g=h.$container.find(i.pager_selectors.gotoPage),g.length?g.off("change"+j).on("change"+j,function(){h.page=a(this).val()-1,b.moveToPage(d,h,!0),b.updatePageDisplay(d,!1)}):d.debug&&console.warn("Pager: >> Goto selector not found"),g=h.$container.find(i.pager_selectors.pageSize),g.length?(g.find("option").removeAttr("selected"),g.off("change"+j).on("change"+j,function(){if(!a(this).hasClass(i.pager_css.disabled)){var c=a(this).val();h.$container.find(i.pager_selectors.pageSize).val(c),b.setPageSize(d,c),b.changeHeight(d)}return!1})):d.debug&&console.warn("Pager: >> Size selector not found")},pagerArrows:function(a,c){var d=a.pager,e=!!c,f=e||0===d.page,g=b.getTotalPages(a,d),h=e||d.page===g-1||0===g,i=a.widgetOptions,j=i.pager_selectors;i.pager_updateArrows&&(d.$container.find(j.first+","+j.prev).toggleClass(i.pager_css.disabled,f).prop("aria-disabled",f),d.$container.find(j.next+","+j.last).toggleClass(i.pager_css.disabled,h).prop("aria-disabled",h))},calcFilters:function(b){var c,d,e,f=b.widgetOptions,g=b.pager,h=b.$table.hasClass("hasFilters");if(h&&!g.ajax)if(a.isEmptyObject(b.cache))g.filteredRows=g.totalRows=b.$tbodies.eq(0).children("tr").not(f.pager_countChildRows?"":"."+b.cssChildRow).length;else for(g.filteredRows=0,c=b.cache[0].normalized,e=c.length,d=0;d<e;d++)g.filteredRows+=g.regexRows.test(c[d][b.columns].$row[0].className)?0:1;else h||(g.filteredRows=g.totalRows)},updatePageDisplay:function(d,e){if(!d.pager||!d.pager.initializing){var f,g,h,i,j,k,l,m=d.table,n=d.widgetOptions,o=d.pager,p=d.namespace+"pager",q=b.parsePageSize(d,o.size,"get");if("all"===q&&(q=o.totalRows),n.pager_countChildRows&&(g[g.length]=d.cssChildRow),o.$container.find(n.pager_selectors.pageSize+","+n.pager_selectors.gotoPage).removeClass(n.pager_css.disabled).removeAttr("disabled").prop("aria-disabled","false"),o.totalPages=Math.ceil(o.totalRows/q),d.totalRows=o.totalRows,b.parsePageNumber(d,o),b.calcFilters(d),d.filteredRows=o.filteredRows,o.filteredPages=Math.ceil(o.filteredRows/q)||0,b.getTotalPages(d,o)>=0){if(g=q*o.page>o.filteredRows&&e,o.page=g?n.pager_pageReset||0:o.page,o.startRow=g?q*o.page+1:0===o.filteredRows?0:q*o.page+1,o.endRow=Math.min(o.filteredRows,o.totalRows,q*(o.page+1)),h=o.$container.find(n.pager_selectors.pageDisplay),"function"==typeof n.pager_output?f=n.pager_output(m,o):(l=h.attr("data-pager-output"+(o.filteredRows<o.totalRows?"-filtered":""))||n.pager_output,f=(o.ajaxData&&o.ajaxData.output?o.ajaxData.output||l:l).replace(/\{page([\-+]\d+)?\}/gi,function(a,b){return o.totalPages?o.page+(b?parseInt(b,10):1):0}).replace(/\{\w+(\s*:\s*\w+)?\}/gi,function(a){var b,c,d=a.replace(/[{}\s]/g,""),e=d.split(":"),f=o.ajaxData,g=/(rows?|pages?)$/i.test(d)?0:"";return/(startRow|page)/.test(e[0])&&"input"===e[1]?(b=(""+("page"===e[0]?o.totalPages:o.totalRows)).length,c="page"===e[0]?o.page+1:o.startRow,'<input type="text" class="ts-'+e[0]+'" style="max-width:'+b+'em" value="'+c+'"/>'):e.length>1&&f&&f[e[0]]?f[e[0]][e[1]]:o[d]||(f?f[d]:g)||g})),o.$container.find(n.pager_selectors.gotoPage).length){for(g="",i=b.buildPageSelect(d,o),k=i.length,j=0;j<k;j++)g+='<option value="'+i[j]+'">'+i[j]+"</option>";o.$container.find(n.pager_selectors.gotoPage).html(g).val(o.page+1)}h.length&&(h["INPUT"===h[0].nodeName?"val":"html"](f),h.find(".ts-startRow, .ts-page").off("change"+p).on("change"+p,function(){var b=a(this).val(),c=a(this).hasClass("ts-startRow")?Math.floor(b/q)+1:b;d.$table.triggerHandler("pageSet"+p,[c])}))}b.pagerArrows(d),b.fixHeight(d),o.initialized&&e!==!1&&(d.debug&&console.log("Pager: Triggering pagerComplete"),d.$table.triggerHandler("pagerComplete",d),n.pager_savePages&&c.storage&&c.storage(m,n.pager_storageKey,{page:o.page,size:q===o.totalRows?"all":q}))}},buildPageSelect:function(c,d){var e,f,g,h,i,j,k=c.widgetOptions,l=b.getTotalPages(c,d)||1,m=5*Math.ceil(l/k.pager_maxOptionSize/5),n=l>k.pager_maxOptionSize,o=d.page+1,p=m,q=l-m,r=[1],s=n?m:1;for(e=s;e<=l;)r[r.length]=e,e+=n?m:1;if(r[r.length]=l,n){for(g=[],f=Math.max(Math.floor(k.pager_maxOptionSize/m)-1,5),p=o-f,p<1&&(p=1),q=o+f,q>l&&(q=l),e=p;e<=q;e++)g[g.length]=e;r=a.grep(r,function(b,c){return a.inArray(b,r)===c}),i=r.length,j=g.length,i-j>m/2&&i+j>k.pager_maxOptionSize&&(h=Math.floor(i/2)-Math.floor(j/2),Array.prototype.splice.apply(r,[h,j])),r=r.concat(g)}return r=a.grep(r,function(b,c){return a.inArray(b,r)===c}).sort(function(a,b){return a-b})},fixHeight:function(b){var c,d,e=b.table,f=b.pager,g=b.widgetOptions,h=b.$tbodies.eq(0);h.find("tr.pagerSavedHeightSpacer").remove(),g.pager_fixedHeight&&!f.isDisabled&&(d=a.data(e,"pagerSavedHeight"),d&&(c=d-h.height(),c>5&&a.data(e,"pagerLastSize")===f.size&&h.children("tr:visible").length<("all"===f.size?f.totalRows:f.size)&&h.append('<tr class="pagerSavedHeightSpacer '+b.selectorRemove.slice(1)+'" style="height:'+c+'px;"></tr>')))},changeHeight:function(c){var d,e=c.table,f=c.pager,g="all"===f.size?f.totalRows:f.size,h=c.$tbodies.eq(0);h.find("tr.pagerSavedHeightSpacer").remove(),h.children("tr:visible").length||h.append('<tr class="pagerSavedHeightSpacer '+c.selectorRemove.slice(1)+'"><td>&nbsp</td></tr>'),d=h.children("tr").eq(0).height()*g,a.data(e,"pagerSavedHeight",d),b.fixHeight(c),a.data(e,"pagerLastSize",f.size)},hideRows:function(a){if(!a.widgetOptions.pager_ajaxUrl){var b,d,e,f,g,h=(a.table,a.pager),i=a.widgetOptions,j=a.$tbodies.length,k="all"===h.size?h.totalRows:h.size,l=h.page*k,m=l+k,n=0,o=0;for(h.cacheIndex=[],b=0;b<j;b++){for(e=a.$tbodies.eq(b).children("tr"),f=e.length,g=0,n=0,o=0,d=0;d<f;d++)h.regexFiltered.test(e[d].className)||(o===l&&e[d].className.match(a.cssChildRow)?e[d].style.display="none":(e[d].style.display=o>=l&&o<m?"":"none",n!==o&&o>=l&&o<m&&(h.cacheIndex[h.cacheIndex.length]=d,n=o),o+=e[d].className.match(a.cssChildRow+"|"+a.selectorRemove.slice(1))&&!i.pager_countChildRows?0:1,o===m&&"none"!==e[d].style.display&&e[d].className.match(c.css.cssHasChild)&&(g=d)));if(g>0&&e[g].className.match(c.css.cssHasChild))for(;++g<f&&e[g].className.match(a.cssChildRow);)e[g].style.display=""}}},hideRowsSetup:function(c){var d=c.pager,e=c.namespace+"pager",f=d.$container.find(c.widgetOptions.pager_selectors.pageSize),g=f.val();d.size=b.parsePageSize(c,g,"get"),f.val(d.size),a.data(c.table,"pagerLastSize",d.size),b.pagerArrows(c),c.widgetOptions.pager_removeRows||(b.hideRows(c),c.$table.on("sortEnd filterEnd ".split(" ").join(e+" "),function(){b.hideRows(c)}))},renderAjax:function(d,e,f,g,h){var i=e.table,j=e.pager,k=e.widgetOptions;if(a.isFunction(k.pager_ajaxProcessing)){e.$tbodies.eq(0).empty();var l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A=e.$table,B="",C=k.pager_ajaxProcessing(d,i,f)||[0,[]];A.find("thead th").length;if(c.showError(i),h)e.debug&&console.error("Pager: >> Ajax Error",f,g,h),c.showError(i,f,g,h),e.$tbodies.eq(0).children("tr").detach(),j.totalRows=0;else{if(a.isArray(C)?(n=isNaN(C[0])&&!isNaN(C[1]),x=C[n?1:0],j.totalRows=isNaN(x)?j.totalRows||0:x,e.totalRows=e.filteredRows=j.filteredRows=j.totalRows,v=0===j.totalRows?[]:C[n?0:1]||[],u=C[2]):(j.ajaxData=C,e.totalRows=j.totalRows=C.total,e.filteredRows=j.filteredRows="undefined"!=typeof C.filteredRows?C.filteredRows:C.total,u=C.headers,v=C.rows||[]),w=v&&v.length,v instanceof jQuery)k.pager_processAjaxOnInit&&(e.$tbodies.eq(0).empty(),e.$tbodies.eq(0).append(v));else if(w){for(l=0;l<w;l++){for(B+="<tr>",m=0;m<v[l].length;m++)B+=/^\s*<td/.test(v[l][m])?a.trim(v[l][m]):"<td>"+v[l][m]+"</td>";B+="</tr>"}k.pager_processAjaxOnInit&&e.$tbodies.eq(0).html(B)}if(k.pager_processAjaxOnInit=!0,u){for(o=A.hasClass("hasStickyHeaders"),q=o?k.$sticky.children("thead:first").children("tr:not(."+e.cssIgnoreRow+")").children():"",p=A.find("tfoot tr:first").children(),r=e.$headers.filter("th"),y=r.length,m=0;m<y;m++)s=r.eq(m),s.find("."+c.css.icon).length?(t=s.find("."+c.css.icon).clone(!0),s.find("."+c.css.headerIn).html(u[m]).append(t),o&&q.length&&(t=q.eq(m).find("."+c.css.icon).clone(!0),q.eq(m).find("."+c.css.headerIn).html(u[m]).append(t))):(s.find("."+c.css.headerIn).html(u[m]),o&&q.length&&(j.$container=j.$container.add(k.$sticky),q.eq(m).find("."+c.css.headerIn).html(u[m]))),p.eq(m).html(u[m]);o&&b.bindEvents(e)}}e.showProcessing&&c.isProcessing(i),z=b.parsePageSize(e,j.size,"get"),j.totalPages="all"===z?1:Math.ceil(j.totalRows/z),j.last.totalRows=j.totalRows,j.last.currentFilters=j.currentFilters,j.last.sortList=(e.sortList||[]).join(","),j.initializing=!1,b.updatePageDisplay(e,!1),c.updateCache(e,function(){j.initialized&&setTimeout(function(){e.debug&&console.log("Pager: Triggering pagerChange"),A.triggerHandler("pagerChange",j),c.applyWidget(i),b.updatePageDisplay(e)},0)})}j.initialized||c.applyWidget(i)},getAjax:function(d){var e,f=b.getAjaxUrl(d),g=a(document),h=d.namespace+"pager",i=d.pager;""!==f&&(d.showProcessing&&c.isProcessing(d.table,!0),g.on("ajaxError"+h,function(a,c,e,f){b.renderAjax(null,d,c,e,f),g.off("ajaxError"+h)}),e=++i.ajaxCounter,i.last.ajaxUrl=f,i.ajaxObject.url=f,i.ajaxObject.success=function(a,c,f){e<i.ajaxCounter||(b.renderAjax(a,d,f),g.off("ajaxError"+h),"function"==typeof i.oldAjaxSuccess&&i.oldAjaxSuccess(a))},d.debug&&console.log("Pager: Ajax initialized",i.ajaxObject),a.ajax(i.ajaxObject))},getAjaxUrl:function(b){var c,d,e=b.pager,f=b.widgetOptions,g=f.pager_ajaxUrl?f.pager_ajaxUrl.replace(/\{page([\-+]\d+)?\}/,function(a,b){return e.page+(b?parseInt(b,10):0)}).replace(/\{size\}/g,e.size):"",h=b.sortList,i=e.currentFilters||b.$table.data("lastSearch")||[],j=g.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/),k=g.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/),l=[];if(j){for(j=j[1],d=h.length,c=0;c<d;c++)l[l.length]=j+"["+h[c][0]+"]="+h[c][1];g=g.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g,l.length?l.join("&"):j),l=[]}if(k){for(k=k[1],d=i.length,c=0;c<d;c++)i[c]&&(l[l.length]=k+"["+c+"]="+encodeURIComponent(i[c]));g=g.replace(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g,l.length?l.join("&"):k),e.currentFilters=i}return a.isFunction(f.pager_customAjaxUrl)&&(g=f.pager_customAjaxUrl(b.table,g)),b.debug&&console.log("Pager: Ajax url = "+g),g},renderTable:function(a,d){var e,f,g,h,i=a.table,j=a.pager,k=a.widgetOptions,l=a.$table.hasClass("hasFilters"),m=d&&d.length||0,n="all"===j.size?j.totalRows:j.size,o=j.page*n;if(m<1)return void(a.debug&&console.warn("Pager: >> No rows for pager to render"));if(j.page>=j.totalPages)return b.moveToLastPage(a,j);if(j.cacheIndex=[],j.isDisabled=!1,j.initialized&&(a.debug&&console.log("Pager: Triggering pagerChange"),a.$table.triggerHandler("pagerChange",a)),k.pager_removeRows){for(c.clearTableBody(i),e=c.processTbody(i,a.$tbodies.eq(0),!0),f=l?0:o,g=l?0:o,h=0;h<n&&f<d.length;)l&&j.regexFiltered.test(d[f][0].className)||(g++,g>o&&h<=n&&(h++,j.cacheIndex[j.cacheIndex.length]=f,e.append(d[f]))),f++;c.processTbody(i,e,!1)}else b.hideRows(a);b.updatePageDisplay(a),k.pager_startPage=j.page,k.pager_size=j.size,i.isUpdating&&(a.debug&&console.log("Pager: Triggering updateComplete"),a.$table.triggerHandler("updateComplete",[i,!0]))},showAllRows:function(d){var e,f,g,h=d.table,i=d.pager,j=d.widgetOptions;for(i.ajax?b.pagerArrows(d,!0):(a.data(h,"pagerLastPage",i.page),a.data(h,"pagerLastSize",i.size),i.page=0,i.size="all",i.totalPages=1,d.$table.addClass("pagerDisabled").removeAttr("aria-describedby").find("tr.pagerSavedHeightSpacer").remove(),b.renderTable(d,d.rowsCopy),i.isDisabled=!0,c.applyWidget(h),d.debug&&console.log("Pager: Disabled")),f=i.$container.find(j.pager_selectors.pageSize+","+j.pager_selectors.gotoPage+",.ts-startRow, .ts-page"),g=f.length,e=0;e<g;e++)f.eq(e).prop("aria-disabled","true").addClass(j.pager_css.disabled)[0].disabled=!0},updateCache:function(d){var e=d.pager;c.updateCache(d,function(){if(!a.isEmptyObject(d.cache)){var c,f=[],g=d.cache[0].normalized;for(e.totalRows=g.length,c=0;c<e.totalRows;c++)f[f.length]=g[c][d.columns].$row;d.rowsCopy=f,b.moveToPage(d,e,!0),e.last.currentFilters=[" "]}})},moveToPage:function(d,e,f){if(!e.isDisabled){if(f!==!1&&e.initialized&&a.isEmptyObject(d.cache))return b.updateCache(d);var g,h=d.table,i=d.widgetOptions,j=e.last;e.ajax&&!i.filter_initialized&&c.hasWidget(h,"filter")||(b.parsePageNumber(d,e),b.calcFilters(d),j.currentFilters=""===(j.currentFilters||[]).join("")?[]:j.currentFilters,e.currentFilters=""===(e.currentFilters||[]).join("")?[]:e.currentFilters,j.page===e.page&&j.size===e.size&&j.totalRows===e.totalRows&&(j.currentFilters||[]).join(",")===(e.currentFilters||[]).join(",")&&(j.ajaxUrl||"")===(e.ajaxObject.url||"")&&(j.optAjaxUrl||"")===(i.pager_ajaxUrl||"")&&j.sortList===(d.sortList||[]).join(",")||(d.debug&&console.log("Pager: Changing to page "+e.page),e.last={page:e.page,size:e.size,sortList:(d.sortList||[]).join(","),totalRows:e.totalRows,currentFilters:e.currentFilters||[],ajaxUrl:e.ajaxObject.url||"",optAjaxUrl:i.pager_ajaxUrl},e.ajax?i.pager_processAjaxOnInit||a.isEmptyObject(i.pager_initialRows)?e.initialized&&b.getAjax(d):(i.pager_processAjaxOnInit=!0,g=i.pager_initialRows,e.totalRows="undefined"!=typeof g.total?g.total:d.debug?console.error("Pager: no initial total page set!")||0:0,e.filteredRows="undefined"!=typeof g.filtered?g.filtered:d.debug?console.error("Pager: no initial filtered page set!")||0:0,b.updatePageDisplay(d,!1)):e.ajax||b.renderTable(d,d.rowsCopy),a.data(h,"pagerLastPage",e.page),e.initialized&&f!==!1&&(d.debug&&console.log("Pager: Triggering pageMoved"),d.$table.triggerHandler("pageMoved",d),c.applyWidget(h),!e.ajax&&h.isUpdating&&(d.debug&&console.log("Pager: Triggering updateComplete"),d.$table.triggerHandler("updateComplete",[h,!0])))))}},getTotalPages:function(a,b){return c.hasWidget(a.table,"filter")?Math.min(b.totalPages,b.filteredPages):b.totalPages},parsePageSize:function(a,b,c){var d=a.pager,e=parseInt(b,10)||d.size||a.widgetOptions.pager_size||10;return d.initialized&&(/all/i.test(b)||e===d.totalRows)?"all":"get"===c?e:d.size},parsePageNumber:function(a,c){var d=b.getTotalPages(a,c)-1;return c.page=parseInt(c.page,10),(c.page<0||isNaN(c.page))&&(c.page=0),c.page>d&&d>=0&&(c.page=d),c.page},setPageSize:function(c,d){var e=c.pager,f=c.table;e.size=b.parsePageSize(c,d,"get"),e.$container.find(c.widgetOptions.pager_selectors.pageSize).val(b.parsePageSize(c,e.size,"set")),a.data(f,"pagerLastPage",b.parsePageNumber(c,e)),a.data(f,"pagerLastSize",e.size),e.totalPages="all"===e.size?1:Math.ceil(e.totalRows/e.size),e.filteredPages="all"===e.size?1:Math.ceil(e.filteredRows/e.size),b.moveToPage(c,e,!0)},moveToFirstPage:function(a,c){c.page=0,b.moveToPage(a,c,!0)},moveToLastPage:function(a,c){c.page=b.getTotalPages(a,c)-1,b.moveToPage(a,c,!0)},moveToNextPage:function(a,c){c.page++;var d=b.getTotalPages(a,c)-1;c.page>=d&&(c.page=d),b.moveToPage(a,c,!0)},moveToPrevPage:function(a,c){c.page--,c.page<=0&&(c.page=0),b.moveToPage(a,c,!0)},destroyPager:function(a,d){var e=a.table,f=a.pager,g=a.widgetOptions.pager_selectors||{},h=[g.first,g.prev,g.next,g.last,g.gotoPage,g.pageSize].join(","),i=a.namespace+"pager";if(f){if(f.initialized=!1,a.$table.off(i),f.$container.hide().find(h).off(i),d)return;a.appender=null,b.showAllRows(a),c.storage&&c.storage(e,a.widgetOptions.pager_storageKey,""),f.$container=null,a.pager=null,a.rowsCopy=null}},enablePager:function(d,e){var f,g,h=d.table,i=d.pager,j=d.widgetOptions,k=i.$container.find(j.pager_selectors.pageSize);i.isDisabled=!1,i.page=a.data(h,"pagerLastPage")||i.page||0,g=k.find("option[selected]").val(),i.size=a.data(h,"pagerLastSize")||b.parsePageSize(d,g,"get"),k.val(i.size),i.totalPages="all"===i.size?1:Math.ceil(b.getTotalPages(d,i)/i.size),d.$table.removeClass("pagerDisabled"),h.id&&!d.$table.attr("aria-describedby")&&(k=i.$container.find(j.pager_selectors.pageDisplay),f=k.attr("id"),f||(f=h.id+"_pager_info",k.attr("id",f)),d.$table.attr("aria-describedby",f)),b.changeHeight(d),e&&(c.update(d),b.setPageSize(d,i.size),b.hideRowsSetup(d),d.debug&&console.log("Pager: Enabled"))},appender:function(c,d){var e=c.config,f=e.widgetOptions,g=e.pager;g.ajax?b.moveToPage(e,g,!0):(e.rowsCopy=d,g.totalRows=f.pager_countChildRows?e.$tbodies.eq(0).children("tr").length:d.length,g.size=a.data(c,"pagerLastSize")||g.size||f.pager_size||g.setSize||10,g.totalPages="all"===g.size?1:Math.ceil(g.totalRows/g.size),b.moveToPage(e,g),b.updatePageDisplay(e,!1))}},c.showError=function(b,c,d,e){var f,g=a(b),h=g[0].config,i=h&&h.widgetOptions,j=h.pager&&h.pager.cssErrorRow||i&&i.pager_css&&i.pager_css.errorRow||"tablesorter-errorRow",k=typeof c,l=!0,m="",n=function(){h.$table.find("thead").find("."+j).remove()};if(!g.length)return void console.error("tablesorter showError: no table parameter passed");if("function"==typeof h.pager.ajaxError){if(l=h.pager.ajaxError(h,c,d,e),l===!1)return n();m=l}else if("function"==typeof i.pager_ajaxError){if(l=i.pager_ajaxError(h,c,d,e),l===!1)return n();m=l}if(""===m)if("object"===k)m=0===c.status?"Not connected, verify Network":404===c.status?"Requested page not found [404]":500===c.status?"Internal Server Error [500]":"parsererror"===e?"Requested JSON parse failed":"timeout"===e?"Time out error":"abort"===e?"Ajax Request aborted":"Uncaught error: "+c.statusText+" ["+c.status+"]";else{if("string"!==k)return n();m=c}f=a(/tr\>/.test(m)?m:'<tr><td colspan="'+h.columns+'">'+m+"</td></tr>").click(function(){a(this).remove()}).appendTo(h.$table.find("thead:first")).addClass(j+" "+h.selectorRemove.slice(1)).attr({role:"alert","aria-live":"assertive"})}}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-print.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-print.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..ed2377a0064a9c044545571827d94529da0d1dd5
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-print.min.js
@@ -0,0 +1 @@
+!function(a){"use strict";var b=a.tablesorter,c=b.printTable={event:"printTable",basicStyle:"table, tr, td, th { border : solid 1px black; border-collapse : collapse; } td, th { padding: 2px; }",popupStyle:"width=500,height=300,scrollbars=1,resizable=1",init:function(a){a.$table.unbind(c.event).bind(c.event,function(){return c.process(a,a.widgetOptions),!1})},process:function(d,e){var f,g,h=a("<div/>").append(d.$table.clone()),i=c.basicStyle+"table { width: 100%; }."+(b.css.filterRow||"tablesorter-filter-row")+", ."+(e.filter_filteredRow||"filtered")+" { display: none; }."+(b.css.header||"tablesorter-header")+" { background-image: none !important; }@media print { .print_widget_hidden { display: none; } }";h.find("["+e.print_dataAttrib+"]").each(function(){f=a(this),f.text(f.attr(e.print_dataAttrib))}),g="data-"+(e.lazyload_data_attribute||"original"),h.find("img["+g+"]").each(function(){f=a(this),f.attr("src",f.attr(g))}),/^f/i.test(e.print_rows)?i+="tbody tr:not(."+(e.filter_filteredRow||"filtered")+") { display: table-row !important; }":/^a/i.test(e.print_rows)?i+="tbody tr { display: table-row !important; }":/^[.#:\[]/.test(e.print_rows)&&(i+="tbody tr"+e.print_rows+" { display: table-row !important; }"),/s/i.test(e.print_columns)&&d.selector&&b.hasWidget(d.table,"columnSelector")?i+=e.columnSelector_mediaquery&&d.selector.auto?"":d.selector.$style.text():/a/i.test(e.print_columns)&&(i+="td, th { display: table-cell !important; }"),i+=e.print_extraCSS,a.isFunction(e.print_callback)?e.print_callback(d,h,i):c.printOutput(d,h.html(),i)},printOutput:function(a,d,e){var f=a.widgetOptions,g=b.language,h=window.open("",f.print_title,c.popupStyle),i=f.print_title||a.$table.find("caption").text()||a.$table[0].id||document.title||"table",j=f.print_now?"":'<div class="print_widget_hidden"><a href="javascript:window.print();"><button type="button">'+g.button_print+'</button></a> <a href="javascript:window.close();"><button type="button">'+g.button_close+"</button></a><hr></div>";return h.document.write("<html><head><title>"+i+"</title>"+(f.print_styleSheet?'<link rel="stylesheet" href="'+f.print_styleSheet+'">':"")+"<style>"+e+"</style></head><body>"+j+d+"</body></html>"),h.document.close(),f.print_now&&setTimeout(function(){h.print(),h.close()},10),!0},remove:function(a){a.$table.off(c.event)}};b.language.button_close="Close",b.language.button_print="Print",b.addWidget({id:"print",options:{print_title:"",print_dataAttrib:"data-name",print_rows:"filtered",print_columns:"selected",print_extraCSS:"",print_styleSheet:"",print_now:!0,print_callback:null},init:function(a,b,d){c.init(d)},remove:function(a,b){c.remove(b)}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-reflow.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-reflow.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..d0091753be7e0dce7b8a176978a92f3b04ddd2cb
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-reflow.min.js
@@ -0,0 +1 @@
+!function(a){"use strict";var b=a.tablesorter,c={init:function(b,d,e){var f,g=e.reflow_dataAttrib,h=e.reflow_headerAttrib,i=[];d.$table.addClass(e.reflow_className).off("refresh.tsreflow updateComplete.tsreflow2").on("refresh.tsreflow updateComplete.tsreflow2",function(){c.init(b,d,e)}),d.$headers.each(function(){f=a(this),i.push(a.trim(f.attr(h)||f.text()))}),d.$tbodies.children().each(function(){a(this).children().each(function(b){a(this).attr(g,i[b])})})},init2:function(d,e,f){var g,h,i,j,k,l,m=e.columns,n=f.reflow2_headerAttrib,o=[];for(e.$table.addClass(f.reflow2_className).off("refresh.tsreflow2 updateComplete.tsreflow2").on("refresh.tsreflow2 updateComplete.tsreflow2",function(){c.init2(d,e,f)}),i=0;i<m;i++)j=e.$headers.filter('[data-column="'+i+'"]'),j.length>1?(k=[],j.each(function(){g=a(this),g.hasClass(f.reflow2_classIgnore)||k.push(g.attr(n)||g.text())})):k=[j.attr(n)||j.text()],o.push(k);k='<b class="'+e.selectorRemove.slice(1)+" "+f.reflow2_labelClass,e.$tbodies.children().each(function(){h=b.processTbody(d,a(this),!0),h.children().each(function(b){for(g=a(this),l=o[b].length,i=l-1;i>=0;)g.prepend(k+(0===i&&l>1?" "+f.reflow2_labelTop:"")+'">'+o[b][i]+"</b>"),i--}),b.processTbody(d,h,!1)})},remove:function(a,b,c){b.$table.removeClass(c.reflow_className)},remove2:function(a,b,c){b.$table.removeClass(c.reflow2_className)}};b.addWidget({id:"reflow",options:{reflow_className:"ui-table-reflow",reflow_headerAttrib:"data-name",reflow_dataAttrib:"data-title"},init:function(a,b,d,e){c.init(a,d,e)},remove:function(a,b,d){c.remove(a,b,d)}}),b.addWidget({id:"reflow2",options:{reflow2_className:"ui-table-reflow",reflow2_classIgnore:"ui-table-reflow-ignore",reflow2_headerAttrib:"data-name",reflow2_labelClass:"ui-table-cell-label",reflow2_labelTop:"ui-table-cell-label-top"},init:function(a,b,d,e){c.init2(a,d,e)},remove:function(a,b,d){c.remove2(a,b,d)}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-repeatheaders.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-repeatheaders.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..24d9552ab37180b2a12a0cd83c30e7b44633fe8a
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-repeatheaders.min.js
@@ -0,0 +1,2 @@
+/*! Widget: repeatHeaders - updated 9/23/2016 (v2.27.7) */
+!function(a){"use strict";a.tablesorter.addWidget({id:"repeatHeaders",priority:10,options:{rowsToSkip:4},format:function(b,c,d){var e,f,g,h,i="";if(!d.repeatHeaders){for(i='<tr class="repeated-header '+c.selectorRemove.slice(1)+'">',e=0;e<c.columns;e++)i+="<th>"+a.trim(c.$headers.eq(e).html())+"</th>";d.repeatHeaders=i+"</tr>"}for(h=d&&d.rowsToSkip||4,c.$table.find("tr.repeated-header").remove(),f=c.$tbodies.find("tr"),g=f.length,e=h;e<g;e+=h)f.eq(e).before(d.repeatHeaders)},remove:function(a,b,c){c.repeatHeaders="",b.$table.find("tr.repeated-header").remove()}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-resizable.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-resizable.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..e3a9fca882edc73a16c69a8761fe646aa9ddd9b1
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-resizable.min.js
@@ -0,0 +1,2 @@
+/*! Widget: resizable - updated 12/15/2016 (v2.28.2) */
+!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"}),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("head").append(b)}),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),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:[]};for(c.resizableReset(b.table,!0),m.tableWidth=j.width(),m.fullWidth=Math.abs(k.width()-m.tableWidth)<20,m.useStorage&&m.overflow&&(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);c.resizable.bindings(b,d)}},updateStoredSizes:function(a,b){var c,d,e=a.columns,f=b.resizable_vars;for(f.storedSizes=[],c=0;c<e;c++)d=a.$headerIndexed[c],f.storedSizes[c]=d.is(":visible")?d.width():0},setWidth:function(a,b,c){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");if(e=e||h.storedSizes||[],e.length){for(f=0;f<b.columns;f++)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=b.$table.height(),g=d.$resizable_container.children(),h=Math.floor(g.width()/2);c.hasWidget(b.table,"scroller")&&(f=0,b.$table.closest("."+c.css.scrollerWrap).children().each(function(){var b=a(this);f+=b.filter('[style*="height"]').length?b.height():b.children("table").height()})),e=b.$table.position().left,g.each(function(){var c=a(this),g=parseInt(c.attr("data-column"),10),i=b.columns-1,j=c.data("header");j&&(j.is(":visible")?(g<i||g===i&&d.resizable_addLastColumn)&&c.css({display:"inline-block",height:f,left:j.position().left-e+j.outerWidth()-h}):c.hide())})},toggleTextSelection:function(b,d,e){var f=b.namespace+"tsresize";d.resizable_vars.disabled=e,a("body").toggleClass(c.css.resizableNoSelect,e),e?a("body").attr("unselectable","on").bind("selectstart"+f,!1):a("body").removeAttr("unselectable").unbind("selectstart"+f)},bindings:function(d,e){var f=d.namespace+"tsresize";e.$resizable_container.children().bind("mousedown",function(b){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,e,!0)}),a(document).bind("mousemove"+f,function(a){var b=e.resizable_vars;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,e,!1),c.resizable.stopResize(d,e),c.resizable.setHandlePosition(d,e))}),a(b).bind("resize"+f+" resizeEnd"+f,function(){c.resizable.setHandlePosition(d,e)}),d.$table.bind("columnUpdate"+f+" pagerComplete"+f,function(){c.resizable.setHandlePosition(d,e)}).find("thead:first").add(a(d.namespace+"_extra_table").find("thead:first")).bind("contextmenu"+f,function(){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){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){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||(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,b.$table.triggerHandler("stickyHeadersUpdate")}},stopResize:function(a,b){var d=b.resizable_vars;c.resizable.updateStoredSizes(a,b),d.useStorage&&(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,a.$table.triggerHandler("stickyHeadersUpdate")}},c.addWidget({id:"resizable",priority:40,options:{resizable:!0,resizable_addLastColumn:!1,resizable_widths:[],resizable_throttle:!1,resizable_targetLast:!1,resizable_fullWidth:null},init:function(a,b,d,e){c.resizable.init(d,e)},format:function(a,b,d){c.resizable.setHandlePosition(b,d)},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,e,!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(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);f.$table.triggerHandler("stickyHeadersUpdate"),c.storage&&!d&&c.storage(this,c.css.resizableStorage,{})}})}}(jQuery,window);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-saveSort.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-saveSort.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..bc95c6872c447b952d49c3acc0bd118359160ff8
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-saveSort.min.js
@@ -0,0 +1,2 @@
+/*! Widget: saveSort - updated 10/31/2015 (v2.24.0) */
+!function(a){"use strict";var b=a.tablesorter||{};b.addWidget({id:"saveSort",priority:20,options:{saveSort:!0},init:function(a,b,c,d){b.format(a,c,d,!0)},format:function(c,d,e,f){var g,h,i=d.$table,j=e.saveSort!==!1,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))):(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"),b.storage&&b.storage(a,"tablesorter-savesort","")}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-scroller.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-scroller.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..c6b00d5ebd9f7bea6fbcc5ceb69224501af4846d
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-scroller.min.js
@@ -0,0 +1,2 @@
+/*! Widget: scroller - updated 7/31/2016 (v2.27.0) */
+!function(a,b){"use strict";var c=a.tablesorter,d=c.css;a.extend(c.css,{scrollerWrap:"tablesorter-scroller",scrollerHeader:"tablesorter-scroller-header",scrollerTable:"tablesorter-scroller-table",scrollerFooter:"tablesorter-scroller-footer",scrollerFixed:"tablesorter-scroller-fixed",scrollerFixedPanel:"tablesorter-scroller-fixed-panel",scrollerHasFix:"tablesorter-scroller-has-fixed-columns",scrollerHideColumn:"tablesorter-scroller-hidden-column",scrollerHideElement:"tablesorter-scroller-hidden",scrollerSpacerRow:"tablesorter-scroller-spacer",scrollerBarSpacer:"tablesorter-scroller-bar-spacer",scrollerAddedHeight:"tablesorter-scroller-added-height",scrollerHack:"tablesorter-scroller-scrollbar-hack",scrollerRtl:"ts-scroller-rtl"}),c.addWidget({id:"scroller",priority:60,options:{scroller_height:300,scroller_jumpToHeader:!0,scroller_upAfterSort:!0,scroller_fixedColumns:0,scroller_rowHighlight:"hover",scroller_addFixedOverlay:!1,scroller_barWidth:null},format:function(a,b,d){b.isScrolling?c.scroller.resize(b,d):c.scroller.setup(b,d)},remove:function(a,b,d){c.scroller.remove(b,d)}}),c.window_resize=function(){c.timer_resize&&clearTimeout(c.timer_resize),c.timer_resize=setTimeout(function(){a(b).trigger("resizeEnd")},250)},a(function(){var b="<style>."+d.scrollerWrap+" { position: relative; overflow: hidden; }."+d.scrollerWrap+" * { box-sizing: border-box; }."+d.scrollerHeader+", ."+d.scrollerFooter+" { position: relative; overflow: hidden; }."+d.scrollerHeader+" table."+d.table+" { margin-bottom: 0; }."+d.scrollerTable+" { position: relative; overflow: auto; }."+d.scrollerTable+" table."+d.table+" { border-top: 0; margin-top: 0; margin-bottom: 0; overflow: hidden; }."+d.scrollerTable+" tfoot, ."+d.scrollerHideElement+", ."+d.scrollerHideColumn+" { display: none; }."+d.scrollerFixed+", ."+d.scrollerFixed+" ."+d.scrollerFixedPanel+" { pointer-events: none; }."+d.scrollerFixed+" > div { pointer-events: all; }."+d.scrollerWrap+" ."+d.scrollerFixed+" { position: absolute; top: 0; z-index: 1; left: 0 } ."+d.scrollerWrap+" ."+d.scrollerFixed+"."+d.scrollerRtl+" { left: auto; right: 0 } ."+d.scrollerWrap+"."+d.scrollerHasFix+" > ."+d.scrollerTable+" { overflow: auto; }."+d.scrollerFixed+" ."+d.scrollerFooter+" { position: absolute; bottom: 0; }."+d.scrollerFixed+" ."+d.scrollerTable+" { position: relative; left: 0; overflow: auto; -ms-overflow-style: none; }."+d.scrollerFixed+" ."+d.scrollerTable+"::-webkit-scrollbar { display: none; }."+d.scrollerWrap+" ."+d.scrollerFixedPanel+" { position: absolute; top: 0; bottom: 0; z-index: 2; left: 0; right: 0; } </style>";a("head").append(b)}),c.scroller={isFirefox:navigator.userAgent.toLowerCase().indexOf("firefox")>-1,isOldIE:document.all&&!b.atob,isIE:document.all&&!b.atob||navigator.appVersion.indexOf("Trident/")>0,isSafari:navigator.userAgent.toLowerCase().indexOf("safari")>-1&&navigator.userAgent.toLowerCase().indexOf("chrome")===-1,hasScrollBar:function(a,b){return b?a.get(0).scrollWidth>a.width():a.get(0).scrollHeight>a.height()},setWidth:function(a,b){a.css({width:b,"min-width":b,"max-width":b})},getBarWidth:function(){var b=a("<div>").css({position:"absolute",top:"-9999px",left:0,width:"100px",height:"100px",overflow:"scroll",visibility:"hidden"}).appendTo("body"),c=b[0],d=c.offsetWidth-c.clientWidth;return b.remove(),d},setup:function(e,f){var g,h,i,j,k,l,m,n,o,p=a(b),q=c.scroller,r=e.namespace+"tsscroller",s=a(),t=e.namespace.slice(1)+"tsscroller",u=e.$table;e.widthFixed=!0,f.scroller_calcWidths=[],f.scroller_saved=[0,0],f.scroller_isBusy=!0,null!==f.scroller_barWidth?f.scroller_barSetWidth=f.scroller_barWidth:(o=q.getBarWidth(),f.scroller_barSetWidth=null!==o?o:15),n=u.children("caption"),h=a('<table class="'+u.attr("class")+'" cellpadding=0 cellspacing=0>'+(n.length?n[0].outerHTML:"")+u.children("thead")[0].outerHTML+"</table>"),f.scroller_$header=h.addClass(e.namespace.slice(1)+"_extra_table"),i=u.children("tfoot"),i.length&&(s=a('<table class="'+u.attr("class")+'" cellpadding=0 cellspacing=0 style="margin-top:0"></table>').addClass(e.namespace.slice(1)+"_extra_table").append(i.clone(!0)).wrap('<div class="'+d.scrollerFooter+'"/>'),k=s.children("tfoot").eq(0).children("tr").children()),f.scroller_$footer=s,u.wrap('<div id="'+t+'" class="'+d.scrollerWrap+'" />').before(h).find("."+d.filterRow).addClass(d.filterRowHide),f.scroller_$container=u.parent(),s.length&&u.after(s.parent()),j=h.wrap('<div class="'+d.scrollerHeader+'" />').find("."+d.header),u.wrap('<div class="'+d.scrollerTable+(f.scroller_height>0?'" style="max-height:'+f.scroller_height+'px;">':'">')),l=u.parent(),c.bindEvents(e.table,j),u.hasClass("hasFilters")&&c.filter.bindSearch(u,h.find("."+d.filter)),u.children("thead, caption").addClass(d.scrollerHideElement),g=l.parent().height(),l.off("scroll"+r).on("scroll"+r,function(){if(f.scroller_jumpToHeader){var b=p.scrollTop()-h.offset().top;0!==a(this).scrollTop()&&b<g&&b>0&&p.scrollTop(h.offset().top)}h.parent().add(s.parent()).scrollLeft(a(this).scrollLeft())}),m=((c.hasWidget(e.table,"filter")?"filterEnd":"tablesorter-initialized updateComplete")+" sortEnd pagerComplete columnUpdate ").split(" ").join(r+" "),u.off(r).on("sortEnd filterEnd".split(" ").join(r+" "),function(a){"sortEnd"===a.type&&f.scroller_upAfterSort?l.animate({scrollTop:0},"fast"):f.scroller_fixedColumns&&setTimeout(function(){l.scrollTop(f.scroller_saved[1]).scrollLeft(f.scroller_saved[0]),q.updateFixed(e,f)},0)}).on("setFixedColumnSize"+r,function(a,b){var c=f.scroller_$container;"undefined"==typeof b||isNaN(b)||(f.scroller_fixedColumns=parseInt(b,10)),q.removeFixed(e,f),b=f.scroller_fixedColumns,b>0&&b<e.columns-1?q.updateFixed(e,f):c.hasClass(d.scrollerHasFix)&&(c.removeClass(d.scrollerHasFix),q.resize(e,f))}).on(m,function(a){c.hasWidget("pager")&&"updateComplete"===a.type||(f.scroller_fixedColumns>0&&q.updateFixed(e,f),q.resize(e,f))}),p.off("resize resizeEnd ".split(" ").join(r+" ")).on("resize"+r,c.window_resize).on("resizeEnd"+r,function(){p.off("resize"+r,c.window_resize),q.resize(e,f),p.on("resize"+r,c.window_resize),l.trigger("scroll"+r)}),e.isScrolling=!0,q.updateFixed(e,f),e.table.hasInitialized&&e.isScrolling&&setTimeout(function(){c.scroller.resize(e,f)},50)},resize:function(e,f){if(!f.scroller_isBusy){var g,h,i,j,k,l,m=c.scroller,n=f.scroller_$container,o=e.$table,p=o.parent(),q=f.scroller_$header,r=f.scroller_$footer,s=a(b),t=[s.scrollLeft(),s.scrollTop()],u=e.namespace.slice(1)+"tsscroller",v=a("div."+d.scrollerWrap+'[id!="'+u+'"]').addClass(d.scrollerHideElement),w='<tr class="'+d.scrollerSpacerRow+" "+e.selectorRemove.slice(1)+'">';for(f.scroller_calcWidths=[],m.removeFixed(e,f),n.find("."+d.scrollerSpacerRow).remove(),n.find("."+c.css.colgroup).remove(),o.find("."+d.scrollerHideElement).removeClass(d.scrollerHideElement),h=parseInt(o.css("border-left-width"),10),j=e.$headerIndexed,g=0;g<e.columns;g++)k=j[g],i="border-box"===k.css("box-sizing")?k.outerWidth():"collapse"===k.css("border-collapse")?k.length&&b.getComputedStyle?parseFloat(b.getComputedStyle(k[0],null).width):k.outerWidth()-parseFloat(k.css("padding-left"))-parseFloat(k.css("padding-right"))-(parseFloat(k.css("border-width"))||0):k.width(),w+='<td data-column="'+g+'" style="padding:0;margin:0;border:0;height:0;max-height:0;min-height:0;width:'+i+"px;min-width:"+i+"px;max-width:"+i+'px"></td>',f.scroller_calcWidths[g]=i;w+="</tr>",e.$tbodies.eq(0).prepend(w),q.children("thead").append(w),r.children("tfoot").append(w),c.fixColumnWidth(e.table),w=e.$table.children("colgroup")[0].outerHTML,q.prepend(w),r.prepend(w),l=p.parent().innerWidth()-(m.hasScrollBar(p)?f.scroller_barSetWidth:0),p.width(l),l=(m.hasScrollBar(p)?f.scroller_barSetWidth:0)+h,i=p.innerWidth()-l,q.parent().add(r.parent()).width(i),p.width(i+l),o.children("thead, caption").addClass(d.scrollerHideElement),m.updateFixed(e,f),v.removeClass(d.scrollerHideElement),p.scrollTop(f.scroller_saved[1]),f.scroller_$container.find("."+d.scrollerFixed).find("."+d.scrollerTable).scrollTop(f.scroller_saved[1]),s.scrollLeft(t[0]),s.scrollTop(t[1]),setTimeout(function(){e.$table.triggerHandler("resizableUpdate")},100)}},setupFixed:function(a,b){var e,f,g,h,i,j,k,l=a.$table,m=b.scroller_$container,n=b.scroller_fixedColumns;for(j=m.addClass(d.scrollerHasFix).clone().addClass(d.scrollerFixed).removeClass(d.scrollerWrap).attr("id",""),j.find("caption").html("&nbsp;"),b.scroller_addFixedOverlay&&j.append('<div class="'+d.scrollerFixedPanel+'">'),k=j.find("."+d.scrollerTable),k.children("table").addClass(a.namespace.slice(1)+"_extra_table").attr("id","").children("thead, tfoot").remove(),b.scroller_$fixedColumns=j,l.hasClass(d.scrollerRtl)&&j.addClass(d.scrollerRtl),g=j.find("tr"),h=g.length,e=0;e<h;e++)g.eq(e).children(":gt("+(n-1)+")").remove();if(j.addClass(d.scrollerHideElement).prependTo(m),a.$table.hasClass("hasFilters"))for(g=j.find("."+d.filter).not("."+d.filterDisabled).prop("disabled",!1),c.filter.bindSearch(l,j.find("."+d.filter)),g=m.children("."+d.scrollerHeader).find("."+d.filter),h=g.length,e=0;e<h;e++)g.eq(e).hasClass(d.filterDisabled||"disabled")||g.eq(e).prop("disabled",e<n);for(a.$table.add("."+d.scrollerFooter+" table").children("thead").children("tr."+d.headerRow).children().attr("tabindex",-1),g=b.scroller_$header.add(j.find("."+d.scrollerTable+" table")).children("thead").children("tr."+d.headerRow),h=g.length,e=0;e<h;e++)for(i=g.eq(e).children(),f=0;f<i.length;f++)i.eq(f).attr("tabindex",f<n?-1:0);c.bindEvents(a.table,j.find("."+d.header)),c.scroller.bindFixedColumnEvents(a,b),(c.scroller.isFirefox||c.scroller.isOldIE)&&k.wrap('<div class="'+d.scrollerHack+'" style="overflow:hidden;">')},throttle:function(a,b,c){b=b||50;var d,e;return function(){var f=c||this,g=+new Date,h=arguments;d&&g<d+b?(clearTimeout(e),e=setTimeout(function(){d=g,a.apply(f,h)},b)):(d=g,a.apply(f,h))}},bindFixedColumnEvents:function(b,e){var f=c.scroller,g=b.namespace+"tsscrollerFixed",h="scroll"+g,i=e.scroller_$fixedColumns.find("."+d.scrollerTable),j=!0,k=!0;b.$table.parent().off(h).on(h,f.throttle(function(){if(!e.scroller_isBusy&&j){k=!1;var b=a(this);i[0].scrollTop=e.scroller_saved[1]=b.scrollTop(),e.scroller_saved[0]=b.scrollLeft(),setTimeout(function(){k=!0},20)}})),i.off(h).on(h,f.throttle(function(){!e.scroller_isBusy&&k&&(j=!1,b.$table.parent()[0].scrollTop=e.scroller_saved[1]=a(this).scrollTop(),setTimeout(function(){j=!0},20))})).scroll(),""!==e.scroller_rowHighlight&&(h="mouseover mouseleave ".split(" ").join(g+" "),b.$table.off(h,"tbody > tr").on(h,"tbody > tr",function(a){var c=b.$table.children("tbody").children("tr").index(this);i.children("table").children("tbody").children("tr").eq(c).add(this).toggleClass(e.scroller_rowHighlight,"mouseover"===a.type)}),i.find("table").off(h,"tbody > tr").on(h,"tbody > tr",function(a){var c=i.children("table").children("tbody").children("tr"),d=c.index(this);b.$table.children("tbody").children("tr").eq(d).add(this).toggleClass(e.scroller_rowHighlight,"mouseover"===a.type)}))},adjustWidth:function(a,b,e,f,g){var h=b.scroller_$container;h.children("."+d.scrollerTable).css(g?"right":"left",e),h.children("."+d.scrollerHeader+", ."+d.scrollerFooter).css(g?"right":"left",e+(g&&c.scroller.isSafari?f:0))},updateFixed:function(b,e){var f,g,h=e.scroller_$container,i=e.scroller_$header,j=e.scroller_$footer,k=b.$table,l=k.parent(),m=e.scroller_barSetWidth,n=k.hasClass(d.scrollerRtl);if(0===e.scroller_fixedColumns)return e.scroller_isBusy=!1,c.scroller.removeFixed(b,e),f=h.width(),l.width(f),g=c.scroller.hasScrollBar(l)?m:0,void i.parent().add(j.parent()).width(f-g);if(b.isScrolling){e.scroller_isBusy=!0,h.find("."+d.scrollerFixed).length||c.scroller.setupFixed(b,e);var o,p,q,r,s,t,u,v=e.scroller_$container.children("."+d.scrollerTable).children("table").children("tbody"),w=e.scroller_$header.children("thead").children("."+d.headerRow),x=e.scroller_$fixedColumns.addClass(d.scrollerHideElement),y=x.find("."+d.scrollerTable).children("table"),z=y.children("tbody"),A=c.scroller,B=e.scroller_fixedColumns,C=k.find("tbody td"),D=parseInt(C.css("border-right-width"),10)||1,E=parseInt((C.css("border-spacing")||"").split(/\s/)[0],10)/2||0,F=parseInt(k.css("padding-left"),10)+parseInt(k.css("padding-right"),10)-D,G=e.scroller_calcWidths;for(c.scroller.removeFixed(b,e,!1),o=0;o<B;o++)F+=G[o]+E;for(F=F+2*D-E,A.setWidth(x.add(x.children()),F),A.setWidth(x.children().children("table"),F),p=0;p<b.$tbodies.length;p++)if(r=v.eq(p),r.length){for(w=r.children(),u=w.length,t=c.processTbody(y,z.eq(p),!0),t.empty(),q=0;q<u;q++)s=a(w[q].outerHTML),s.children("td, th").slice(B).remove(),t.append(s);c.processTbody(y,t,!1)}for(g=c.scroller.hasScrollBar(l)?m:0,(A.isFirefox||A.isOldIE)&&y.css("width",F).parent().css("width",F+g),x.removeClass(d.scrollerHideElement),o=0;o<B;o++)f=":nth-child("+(o+1)+")",h.children("div").children("table").find("th"+f+", td"+f+", col"+f).addClass(d.scrollerHideColumn);F-=D,f=l.parent().innerWidth()-F,l.width(f),h.children("."+d.scrollerTable).css(n?"right":"left",F),h.children("."+d.scrollerHeader+", ."+d.scrollerFooter).css(n?"right":"left",F+(n&&c.scroller.isSafari?g:0)),i.parent().add(j.parent()).width(f-g),f=c.scroller.hasScrollBar(l,!0),g=f?m:0,!x.find("."+d.scrollerBarSpacer).length&&f?(C=a('<div class="'+d.scrollerBarSpacer+'">').css("height",g+"px"),x.find("."+d.scrollerTable).append(C)):f||x.find("."+d.scrollerBarSpacer).remove(),c.scroller.updateRowHeight(b,e),x.height(h.height()),x.removeClass(d.scrollerHideElement),x.find("caption").height(e.scroller_$header.find("caption").height()),e.scroller_isBusy=!1}},fixHeight:function(a,b){var c,e,f,g,h,i=d.scrollerAddedHeight,j=a.length;for(c=0;c<j;c++)g=a.eq(c),h=b.eq(c),e=g.height(),f=h.height(),e>f?h.addClass(i).height(e):e<f&&g.addClass(i).height(f)},updateRowHeight:function(a,b){var e,f,g=b.scroller_$fixedColumns;b.scroller_$container.find("."+d.scrollerAddedHeight).removeClass(d.scrollerAddedHeight).height(""),e=b.scroller_$header.children("thead").children("tr"),f=g.children("."+d.scrollerHeader).children("table").children("thead").children("tr"),c.scroller.fixHeight(e,f),e=b.scroller_$footer.children("tfoot").children("tr"),f=g.children("."+d.scrollerFooter).children("table").children("tfoot").children("tr"),c.scroller.fixHeight(e,f),(c.scroller.isFirefox||c.scroller.isOldIE)&&(g=g.find("."+d.scrollerHack)),e=a.$table.children("tbody").children("tr"),f=g.children("."+d.scrollerTable).children("table").children("tbody").children("tr"),c.scroller.fixHeight(e,f)},removeFixed:function(a,b,c){var e=a.$table,f=b.scroller_$container,g=e.hasClass(d.scrollerRtl);(c||"undefined"==typeof c)&&f.find("."+d.scrollerFixed).remove(),f.find("."+d.scrollerHideColumn).removeClass(d.scrollerHideColumn),f.children(":not(."+d.scrollerFixed+")").css(g?"right":"left",0)},remove:function(c,e){var f=e.scroller_$container,g=c.namespace+"tsscroller";c.$table.off(g),a(b).off(g),f&&(c.$table.insertBefore(f).find("thead").removeClass(d.scrollerHideElement).children("tr."+d.headerRow).children().attr("tabindex",0).end().find("."+d.filterRow).removeClass(d.scrollerHideElement+" "+d.filterRowHide),c.$table.find("."+d.filter).not("."+d.filterDisabled).prop("disabled",!1),f.remove(),c.isScrolling=!1)}}}(jQuery,window);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-sort2Hash.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-sort2Hash.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..ef35447f0ec4fc8aeb74b8e02d27dbdd9796ebfa
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-sort2Hash.min.js
@@ -0,0 +1,2 @@
+/*! Widget: sort2Hash (BETA) - updated 11/10/2015 (v2.24.4) */
+!function(a){"use strict";var b=a.tablesorter||{},c=b.sort2Hash={init:function(d,e){var f,g,h,i,j=d.table,k=d.pager,l=b.hasWidget(j,"saveSort"),m=c.decodeHash(d,e,"sort");(m&&!l||m&&l&&e.sort2Hash_overrideSaveSort)&&c.convertString2Sort(d,e,m),b.hasWidget(d.table,"pager")&&(g=parseInt(c.decodeHash(d,e,"page"),10),h=k.page=g<0?0:g>k.totalPages?k.totalPages-1:g,i=k.size=parseInt(c.decodeHash(d,e,"size"),10)),b.hasWidget(j,"filter")&&(f=c.decodeHash(d,e,"filter"),f&&(f=f.split(e.sort2Hash_separator),d.$table.one("tablesorter-ready",function(){setTimeout(function(){d.$table.one("filterEnd",function(){a(this).triggerHandler("pageAndSize",[h,i])}),a.tablesorter.setFilters(j,f,!0)},100)}))),f||d.$table.one("tablesorter-ready",function(){d.$table.triggerHandler("pageAndSize",[h,i])}),d.$table.on("sortEnd.sort2hash filterEnd.sort2hash pagerComplete.sort2Hash",function(){this.hasInitialized&&c.setHash(this.config,this.config.widgetOptions)})},getTableId:function(b,c){return c.sort2Hash_tableId||b.table.id||"table"+a("table").index(b.$table)},regexEscape:function(a){return a.replace(/([\.\^\$\*\+\-\?\(\)\[\]\{\}\\\|])/g,"\\$1")},convertString2Sort:function(a,b,d){for(var e,f,g,h,i,j,k=d.split(b.sort2Hash_separator),l=0,m=k.length,n=[];l<m;){if(f=k[l++],h=parseInt(f,10),isNaN(h)||h>a.columns)for(e=new RegExp("("+c.regexEscape(f)+")","i"),i=0;i<a.columns;i++)j=a.$headerIndexed[i],e.test(j.attr(b.sort2Hash_headerTextAttr))&&(f=i,i=a.columns);g=k[l++],"undefined"!=typeof f&&"undefined"!=typeof g&&(isNaN(g)&&(g=g.indexOf(b.sort2Hash_directionText[1])>-1?1:0),n.push([f,g]))}n.length&&(a.sortList=n)},convertSort2String:function(b,c){var d,e,f,g,h=[],i=b.sortList||[],j=i.length;for(d=0;d<j;d++)f=i[d][0],e=a.trim(b.$headerIndexed[f].attr(c.sort2Hash_headerTextAttr)),h.push(""!==e?encodeURIComponent(e):f),g=c.sort2Hash_directionText[i[d][1]],h.push(g);return h.join(c.sort2Hash_separator)},convertFilter2String:function(b,c){var d,e,f,g,h=[],i=b.sortList||[],j=i.length;for(d=0;d<j;d++)f=i[d][0],e=a.trim(b.$headerIndexed[f].attr(c.sort2Hash_headerTextAttr)),f="undefined"!=typeof e?encodeURIComponent(e):f,h.push(f),g=c.sort2Hash_directionText[i[d][1]],h.push(g);return h.join(c.sort2Hash_separator)},getParam:function(a,b,d){b||(b=window.location.hash);var e=new RegExp("[\\?&]"+c.regexEscape(a)+"=([^&#]*)"),f=e.exec(b);return d?e:null===f?"":decodeURIComponent(f[1])},removeParam:function(a,b){b||(b=window.location.hash);var d,e=c.getParam(a,b,!0),f=[],g=b.split("&"),h=g.length;for(d=0;d<h;d++)e.test("&"+g[d])||f.push(g[d]);return f.length?f.join("&"):""},encodeHash:function(a,b,d,e,f){var g=!1,h=c.getTableId(a,b);return"function"==typeof b.sort2Hash_encodeHash&&(g=b.sort2Hash_encodeHash(a,h,d,e,f||e)),g===!1&&(g="&"+d+"["+h+"]="+e),g},decodeHash:function(a,b,d){var e=!1,f=c.getTableId(a,b);return"function"==typeof b.sort2Hash_decodeHash&&(e=b.sort2Hash_decodeHash(a,f,d)),e===!1&&(e=c.getParam(d+"["+f+"]")),e||""},cleanHash:function(a,b,d,e){var f=!1,g=c.getTableId(a,b);return"function"==typeof b.sort2Hash_cleanHash&&(f=b.sort2Hash_cleanHash(a,g,d,e)),f===!1&&(f=c.removeParam(d+"["+g+"]",e)),f||""},setHash:function(d,e){var f="",g=window.location.hash,h=b.hasWidget(d.table,"pager"),i=b.hasWidget(d.table,"filter"),j=c.convertSort2String(d,e),k=i&&""!==d.lastSearch.join("")?d.lastSearch:[],l=encodeURIComponent(k.join(d.widgetOptions.sort2Hash_separator)),m={sort:j?c.encodeHash(d,e,"sort",j,d.sortList):"",page:h?c.encodeHash(d,e,"page",d.pager.page+1):"",size:h?c.encodeHash(d,e,"size",d.pager.size):"",filter:l?c.encodeHash(d,e,"filter",l,k):""};a.each(m,function(a,b){g=c.cleanHash(d,e,a,g),f+=b}),window.location.hash=((window.location.hash||"").replace("#","").length?g:e.sort2Hash_hash)+f}};b.addWidget({id:"sort2Hash",priority:60,options:{sort2Hash_hash:"#",sort2Hash_separator:"-",sort2Hash_headerTextAttr:"data-header",sort2Hash_directionText:[0,1],sort2Hash_overrideSaveSort:!1},init:function(a,b,d,e){c.init(d,e)},remove:function(a,b){b.$table.off(".sort2hash")}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-sortTbodies.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-sortTbodies.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..a48f1c3669a2b859aed1740c8c2dad8dd2d93cbe
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-sortTbodies.min.js
@@ -0,0 +1,6 @@
+/*! tablesorter tbody sorting widget (BETA) - 11/26/2016 (v2.28.0)
+ * Requires tablesorter v2.22.2+ and jQuery 1.4+
+ * by Rob Garrison
+ * Contributors: Chris Rogers
+ */
+!function(a){"use strict";var b=a.tablesorter;b.sortTbodies={init:function(c,d){var e,f,g,h,i,j=c.namespace+"sortTbody",k=c.$table.children("tbody"),l=k.length;for(d.sortTbody_original_serverSideSorting=c.serverSideSorting,d.sortTbody_original_cssInfoBlock=c.cssInfoBlock,c.cssInfoBlock=d.sortTbody_noSort,b.sortTbodies.setTbodies(c,d),e=0;e<l;e++)k.eq(e).attr("data-ts-original-order",e);for(c.$table.unbind("sortBegin updateComplete ".split(" ").join(j+" ")).bind("sortBegin"+j,function(){b.sortTbodies.sorter(c)}).bind("updateComplete"+j,function(){b.sortTbodies.setTbodies(c,d),b.updateCache(c,null,c.$tbodies)}).bind("sortEnd",function(){var b=d.sortTbody_primaryRow;d.sortTbody_lockHead&&b&&c.$table.find(b).each(function(){a(this).parents("tbody").prepend(this)})}),(a.isEmptyObject(c.parsers)||c.$tbodies.length!==k.length)&&(b.sortTbodies.setTbodies(c,d),b.updateCache(c,null,c.$tbodies)),i=k.children("tr"),l=i.length,e=0;e<c.columns;e++){if(h=0,"numeric"===c.parsers[e].type)for(f=0;f<l;f++)g=b.getParsedText(c,i.eq(f).children()[e],e),h=Math.max(Math.abs(g)||0,h);c.$headerIndexed[e].attr("data-ts-col-max-value",h)}},setTbodies:function(a,b){a.$tbodies=a.$table.children("tbody").not("."+b.sortTbody_noSort)},sorter:function(c){var d=c.$table,e=c.widgetOptions;if(e.sortTbody_busy!==!0){e.sortTbody_busy=!0;var f=d.children("tbody").not("."+e.sortTbody_noSort),g=e.sortTbody_primaryRow||"tr:eq(0)",h=c.sortList||[],i=h.length;i&&(c.serverSideSorting=!e.sortTbody_sortRows,f.sort(function(d,e){var f,j,k,l,m,n,o,p,q,r,s,t,u=c.table,v=c.parsers,w=c.textSorter||"",x=a(d),y=a(e),z=x.find(g).children("td, th"),A=y.find(g).children("td, th");for(f=0;f<i;f++){if(o=h[f][0],p=h[f][1],k=0===p,j=b.getElementText(c,z.eq(o),o),q=v[o].format(j,u,z[o],o),j=b.getElementText(c,A.eq(o),o),r=v[o].format(j,u,A[o],o),c.sortStable&&q===r&&1===i)return x.attr("data-ts-original-order")-y.attr("data-ts-original-order");if(l=/n/i.test(v&&v[o]?v[o].type||"":""),l&&c.strings[o]?(m=c.$headerIndexed[o].attr("data-ts-col-max-value")||1.79e308,l="boolean"==typeof b.string[c.strings[o]]?(k?1:-1)*(b.string[c.strings[o]]?-1:1):c.strings[o]?b.string[c.strings[o]]||0:0,n=c.numberSorter?c.numberSorter(q,r,k,m,u):b["sortNumeric"+(k?"Asc":"Desc")](q,r,l,m,o,c)):(s=k?q:r,t=k?r:q,n="function"==typeof w?w(s,t,k,o,u):"object"==typeof w&&w.hasOwnProperty(o)?w[o](s,t,k,o,u):b["sortNatural"+(k?"Asc":"Desc")](q,r,o,c)),n)return n}return x.attr("data-ts-original-order")-y.attr("data-ts-original-order")}),b.sortTbodies.restoreTbodies(c,e,f),e.sortTbody_busy=!1)}},restoreTbodies:function(a,b,c){var d,e,f,g,h,i,j,k=a.$table,l=!0,m=0;if(k.hide(),c.appendTo(k),e=k.children("tbody"),g=e.length,d=e.filter("."+b.sortTbody_noSort).appendTo(k),h=d.length)for(;l&&m<h;){for(l=!1,i=0;i<h;i++)j=parseInt(d.eq(i).attr("data-ts-original-order"),10),j=j>=g?g:j<0?0:j,j!==d.eq(i).index()&&(l=!0,f=d.eq(i).detach(),j>=g?f.appendTo(k):0===j?f.prependTo(k):f.insertBefore(k.children("tbody:eq("+j+")")));m++}k.show()}},b.addWidget({id:"sortTbody",priority:40,options:{sortTbody_lockHead:!1,sortTbody_primaryRow:null,sortTbody_sortRows:!1,sortTbody_noSort:"tablesorter-no-sort-tbody"},init:function(a,c,d,e){b.sortTbodies.init(d,e)},remove:function(a,b,c,d){b.$table.unbind("sortBegin updateComplete ".split(" ").join(b.namespace+"sortTbody ")),b.serverSideSorting=c.sortTbody_original_serverSideSorting,b.cssInfoBlock=c.sortTbody_original_cssInfoBlock}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-staticRow.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-staticRow.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..c95472f6e38cb78408a420666602db53aa531913
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-staticRow.min.js
@@ -0,0 +1,2 @@
+/*! widget: staticRow - updated 10/31/2015 (v2.24.0) */
+!function(a){"use strict";var b=a.tablesorter,c=function(b){var c,d,e,f,g,h=b.config;h&&(d=h.widgetOptions,h.$tbodies.each(function(){c=a(this).children(),g=c.length,c.filter(d.staticRow_class).each(function(){c=a(this),f=c.data(d.staticRow_index),"undefined"!=typeof f?(e=parseFloat(f),f=/%/.test(f)?Math.round(e/100*g):e):f=c.index(),c.data(d.staticRow_data,f)})}))};b.addWidget({id:"staticRow",options:{staticRow_class:".static",staticRow_data:"static-index",staticRow_index:"row-index",staticRow_event:"staticRowsRefresh"},init:function(a,d,e,f){c(a),e.$table.unbind(("updateComplete.tsstaticrows "+f.staticRow_event).replace(/\s+/g," ")).bind("updateComplete.tsstaticrows "+f.staticRow_event,function(){c(a),b.applyWidget(a)})},format:function(b,c,d){var e,f,g,h,i,j,k,l;c.$tbodies.each(function(){for(i=a.tablesorter.processTbody(b,a(this),!0),j=!0,g=0,k=i.children(d.staticRow_class),h=i.children("tr").length-1,l=k.length;j&&g<l;)j=!1,k.each(function(){e=a(this).data(d.staticRow_data),e=e>=h?h:e<0?0:e,e!==a(this).index()&&(j=!0,f=a(this).detach(),e>=h?f.appendTo(i):0===e?f.prependTo(i):f.insertBefore(i.find("tr:eq("+e+")")))}),g++;a.tablesorter.processTbody(b,i,!1)}),c.$table.triggerHandler("staticRowsComplete",b)},remove:function(a,b,c){b.$table.unbind(("updateComplete.tsstaticrows "+c.staticRow_event).replace(/\s+/g," "))}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-stickyHeaders.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-stickyHeaders.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..1e17e02e0cbd48e72d949204052e8057a7d3fb90
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-stickyHeaders.min.js
@@ -0,0 +1,2 @@
+/*! Widget: stickyHeaders - updated 1/6/2017 (v2.28.4) */
+!function(a,b){"use strict";var c=a.tablesorter||{};a.extend(c.css,{sticky:"tablesorter-stickyHeader",stickyVis:"tablesorter-sticky-visible",stickyHide:"tablesorter-sticky-hidden",stickyWrap:"tablesorter-sticky-wrapper"}),c.addHeaderResizeEvent=function(b,c,d){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;b<j;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.triggerHandler("resize",[c]),h.resize_flag=!1};if(clearInterval(h.resize_timer),c)return h.resize_flag=!1,!1;i(!1),h.resize_timer=setInterval(function(){h.resize_flag||i()},f.timer)}},c.addWidget({id:"stickyHeaders",priority:54,options:{stickyHeaders:"",stickyHeaders_appendTo:null,stickyHeaders_attachTo:null,stickyHeaders_xScroll:null,stickyHeaders_yScroll:null,stickyHeaders_offset:0,stickyHeaders_filteredToTop:!0,stickyHeaders_cloneId:"-sticky",stickyHeaders_addResizeEvent:!0,stickyHeaders_includeCaption:!0,stickyHeaders_zIndex:2},format:function(d,e,f){if(!(e.$table.hasClass("hasStickyHeaders")||a.inArray("filter",e.widgets)>=0&&!e.$table.hasClass("hasFilters"))){var g,h,i,j,k=e.$table,l=a(f.stickyHeaders_attachTo),m=e.namespace+"stickyheaders ",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,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,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;d<j;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")){v=u.length?u.offset().top-n.scrollTop()+u.height():0;var d=k.offset(),e=a.isWindow(n[0]),g=a.isWindow(o[0]),h=l.length?e?n.scrollTop():n.offset().top:n.scrollTop(),i=f.stickyHeaders_includeCaption?0:k.children("caption").height()||0,j=h+t+v-i,m=k.height()-(x.height()+(r.height()||0))-i,p=j>d.top&&j<d.top+m?"visible":"hidden",q={visibility:p};l.length&&(q.top=e?j-l.offset().top:l.scrollTop()),g&&(q.left=k.offset().left-parseInt(k.css("margin-left"),10)-o.scrollLeft()-A),u.length&&(q.top=(q.top||0)+t+v),x.removeClass(c.css.stickyVis+" "+c.css.stickyHide).addClass("visible"===p?c.css.stickyVis:c.css.stickyHide).css(q),(p!==z||b)&&(C(),z=p)}};if(l.length&&!l.css("position")&&l.css("position","relative"),w.attr("id")&&(w[0].id+=f.stickyHeaders_cloneId),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)),f.stickyHeaders_appendTo?a(f.stickyHeaders_appendTo).append(x):k.after(x),e.onRenderHeader)for(i=y.children("tr").children(),h=i.length,g=0;g<h;g++)e.onRenderHeader.apply(i.eq(g),[g,e,w]);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),k.hasClass("hasFilters")&&f.filter_columnFilters&&(k.bind("filterEnd"+m,function(){var d=a(document.activeElement).closest("td"),g=d.parent().children().index(d);x.hasClass(c.css.stickyVis)&&f.stickyHeaders_filteredToTop&&(b.scrollTo(0,k.position().top),g>=0&&e.$filters&&e.$filters.eq(g).find("a, select, input").filter(":visible").focus())}),c.filter.bindSearch(k,j.find("."+c.css.filter)),f.filter_hideFilters&&c.filter.hideFilters(e,w)),f.stickyHeaders_addResizeEvent&&k.bind("resize"+e.namespace+"stickyheaders",function(){C()}),k.triggerHandler("stickyHeadersInit")}},remove:function(d,e,f){var g=e.namespace+"stickyheaders ";e.$table.removeClass("hasStickyHeaders").unbind("pagerComplete resize filterEnd stickyHeadersUpdate ".split(" ").join(g).replace(/\s+/g," ")).next("."+c.css.stickyWrap).remove(),f.$sticky&&f.$sticky.length&&f.$sticky.remove(),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,!0)}})}(jQuery,window);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-storage.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-storage.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..88416bd8eb6c4a62d6a2f2dccd65e2ec05a18243
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-storage.min.js
@@ -0,0 +1,2 @@
+/*! Widget: storage - updated 11/26/2016 (v2.28.0) */
+!function(a,b,c){"use strict";var d=a.tablesorter||{};d.storage=function(e,f,g,h){e=a(e)[0];var i,j,k,l=!1,m={},n=e.config,o=n&&n.widgetOptions,p=h&&h.useSessionStorage||o&&o.storage_useSessionStorage?"sessionStorage":"localStorage",q=a(e),r=h&&h.id||q.attr(h&&h.group||o&&o.storage_group||"data-table-group")||o&&o.storage_tableId||e.id||a(".tablesorter").index(q),s=h&&h.url||q.attr(h&&h.page||o&&o.storage_page||"data-table-page")||o&&o.storage_fixedUrl||n&&n.fixedUrl||b.location.pathname;if(a.extend(!0,d.defaults,{fixedUrl:"",widgetOptions:{storage_fixedUrl:"",storage_group:"",storage_page:"",storage_tableId:"",storage_useSessionStorage:""}}),p in b)try{b[p].setItem("_tmptest","temp"),l=!0,b[p].removeItem("_tmptest")}catch(a){n&&n.debug&&console.warn(p+" is not supported in this browser")}return a.parseJSON&&(l?m=a.parseJSON(b[p][f]||"null")||{}:(j=c.cookie.split(/[;\s|=]/),i=a.inArray(f,j)+1,m=0!==i?a.parseJSON(j[i]||"null")||{}:{})),"undefined"!=typeof g&&b.JSON&&JSON.hasOwnProperty("stringify")?(m[s]||(m[s]={}),m[s][r]=g,l?b[p][f]=JSON.stringify(m):(k=new Date,k.setTime(k.getTime()+31536e6),c.cookie=f+"="+JSON.stringify(m).replace(/\"/g,'"')+"; expires="+k.toGMTString()+"; path=/"),void 0):m&&m[s]?m[s][r]:""}}(jQuery,window,document);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-toggle.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-toggle.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..f9aefc95c9c2fc9962192d8b996ee70d4454823b
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-toggle.min.js
@@ -0,0 +1,5 @@
+/*! tablesorter enable/disable sort & filter (BETA) - 11/10/2015 (v2.24.4)
+ * Requires tablesorter v2.24.4+ & jQuery 1.7+
+ * by Rob Garrison
+ */
+!function(a){"use strict";var b=a.tablesorter,c=b.toggleTS={init:function(a,b){b.toggleTS_isEnabled=!0,b.toggleTS_areDisabled={headers:[],filters:[]},a.$table.on("enable.toggleTS disable.toggleTS",function(a){c.toggle(this.config,this.config.widgetOptions,"enable"===a.type)})},toggle:function(a,c,d){if(c.toggleTS_isEnabled!==d){c.toggleTS_isEnabled=d;var e,f,g=a.$headers.length;for(e=0;e<g;e++)f=a.$headers.eq(e),b.setColumnSort(a,f,!d),b.setColumnAriaLabel(a,f,d);if(c.toggleTS_hideFilterRow)a.$table.find("."+b.css.filterRow).toggle(d);else if(b.hasWidget(a.$table,"filter"))for(g=a.$filters.length,e=0;e<g;e++)d&&!c.toggleTS_areDisabled.filters[e]?a.$filters.eq(e).find("input, select").removeClass(b.css.filterDisabled).prop("disabled",!1):d||(f=a.$filters.eq(e).find("input, select"),f.hasClass(b.css.filterDisabled)&&(c.toggleTS_areDisabled.filters[e]=!0),f.addClass(b.css.filterDisabled).prop("disabled",!0));c.filter_$externalFilters.toggleClass(b.css.filterDisabled,d).prop("disabled",!d)}"function"==typeof c.toggleTS_callback&&c.toggleTS_callback(a,d)}};b.addWidget({id:"toggle-ts",options:{toggleTS_hideFilterRow:!1,toggleTS_callback:null},init:function(a,b,d,e){c.init(d,e)},remove:function(a,b){b.$table.off("enable.toggleTS disable.toggleTS")}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-uitheme.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-uitheme.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..7b6bd338bfadd8565cee05e788c4b10d5e686355
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-uitheme.min.js
@@ -0,0 +1,2 @@
+/*! Widget: uitheme - updated 12/8/2016 (v2.28.1) */
+!function(a){"use strict";var b=a.tablesorter||{};b.themes={bootstrap:{table:"table table-bordered table-striped",caption:"caption",header:"bootstrap-header",sortNone:"",sortAsc:"",sortDesc:"",active:"",hover:"",icons:"",iconSortNone:"bootstrap-icon-unsorted",iconSortAsc:"icon-chevron-up glyphicon glyphicon-chevron-up",iconSortDesc:"icon-chevron-down glyphicon glyphicon-chevron-down",filterRow:"",footerRow:"",footerCells:"",even:"",odd:""},jui:{table:"ui-widget ui-widget-content ui-corner-all",caption:"ui-widget-content",header:"ui-widget-header ui-corner-all ui-state-default",sortNone:"",sortAsc:"",sortDesc:"",active:"ui-state-active",hover:"ui-state-hover",icons:"ui-icon",iconSortNone:"ui-icon-carat-2-n-s ui-icon-caret-2-n-s",iconSortAsc:"ui-icon-carat-1-n ui-icon-caret-1-n",iconSortDesc:"ui-icon-carat-1-s ui-icon-caret-1-s",filterRow:"",footerRow:"",footerCells:"",even:"ui-widget-content",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,s=b.themes,t=d.$table.add(a(d.namespace+"_extra_table")),u=d.$headers.add(a(d.namespace+"_extra_headers")),v=d.theme||"jui",w=s[v]||{},x=a.trim([w.sortNone,w.sortDesc,w.sortAsc,w.active].join(" ")),y=a.trim([w.iconSortNone,w.iconSortDesc,w.iconSortAsc].join(" "));for(d.debug&&(j=new Date),t.hasClass("tablesorter-"+v)&&d.theme===d.appliedTheme&&e.uitheme_applied||(e.uitheme_applied=!0,o=s[d.appliedTheme]||{},r=!a.isEmptyObject(o),p=r?[o.sortNone,o.sortDesc,o.sortAsc,o.active].join(" "):"",q=r?[o.iconSortNone,o.iconSortDesc,o.iconSortAsc].join(" "):"",r&&(e.zebra[0]=a.trim(" "+e.zebra[0].replace(" "+o.even,"")),e.zebra[1]=a.trim(" "+e.zebra[1].replace(" "+o.odd,"")),d.$tbodies.children().removeClass([o.even,o.odd].join(" "))),w.even&&(e.zebra[0]+=" "+w.even),w.odd&&(e.zebra[1]+=" "+w.odd),t.children("caption").removeClass(o.caption||"").addClass(w.caption),m=t.removeClass((d.appliedTheme?"tablesorter-"+(d.appliedTheme||""):"")+" "+(o.table||"")).addClass("tablesorter-"+v+" "+(w.table||"")).children("tfoot"),d.appliedTheme=d.theme,m.length&&m.children("tr").removeClass(o.footerRow||"").addClass(w.footerRow).children("th, td").removeClass(o.footerCells||"").addClass(w.footerCells),u.removeClass((r?[o.header,o.hover,p].join(" "):"")||"").addClass(w.header).not(".sorter-false").unbind("mouseenter.tsuitheme mouseleave.tsuitheme").bind("mouseenter.tsuitheme mouseleave.tsuitheme",function(b){a(this)["mouseenter"===b.type?"addClass":"removeClass"](w.hover||"")}),u.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&&u.find("."+b.css.icon).removeClass(r?[o.icons,q].join(" "):"").addClass(w.icons||""),b.hasWidget(d.table,"filter")&&(g=function(){t.children("thead").children("."+b.css.filterRow).removeClass(r?o.filterRow||"":"").addClass(w.filterRow||"")},e.filter_initialized?g():t.one("filterInit",function(){g()}))),f=0;f<d.columns;f++)k=d.$headers.add(a(d.namespace+"_extra_headers")).not(".sorter-false").filter('[data-column="'+f+'"]'),l=b.css.icon?k.find("."+b.css.icon):a(),n=u.not(".sorter-false").filter('[data-column="'+f+'"]:last'),n.length&&(k.removeClass(x),l.removeClass(y),n[0].sortDisabled?l.removeClass(w.icons||""):(h=w.sortNone,i=w.iconSortNone,n.hasClass(b.css.sortAsc)?(h=[w.sortAsc,w.active].join(" "),i=w.iconSortAsc):n.hasClass(b.css.sortDesc)&&(h=[w.sortDesc,w.active].join(" "),i=w.iconSortDesc),k.addClass(h),l.addClass(i||"")));d.debug&&console.log("Applying "+v+" theme"+b.benchmark(j))},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);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-view.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-view.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..462bfe15e5fdf2bd49bf84f9b34b7d8dc32d75f7
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/js/widgets/widget-view.min.js
@@ -0,0 +1 @@
+!function(a){"use strict";var b,c,d,e=a.tablesorter,f=!1,g=e.view={copyCaption:function(b,c){g.removeCaption(b,c),b.$table.find("caption").length>0&&a(c.view_caption).text(b.$table.find("caption").text())},removeCaption:function(b,c){a(c.view_caption).empty()},buildToolBar:function(b,c){g.removeToolBar(b,c),g.copyCaption(b,c);var d=a(c.view_toolbar);a.each(c.view_layouts,function(b,e){var f=c.view_switcher_class;b==c.view_layout&&(f+=" active");var g=a("<a>",{href:"#",class:f,"data-view-type":b,title:e.title});g.append(a("<i>",{class:e.icon})),d.append(g)}),d.find("."+c.view_switcher_class).on("click",function(e){return e.preventDefault(),!a(this).hasClass("active")&&(d.find("."+c.view_switcher_class).removeClass("active"),a(this).addClass("active"),c.view_layout=a(this).attr("data-view-type"),c.view_layouts[c.view_layout].raw===!0?(g.remove(b,c),g.buildToolBar(b,c)):(f===!1&&g.hideTable(b,c),g.buildView(b,c)),void 0)})},removeToolBar:function(b,c){a(c.view_toolbar).empty(),g.removeCaption(b,c)},buildView:function(b,c){g.removeView(b,c);var d=c.view_layouts[c.view_layout],f=a(d.container,{class:c.view_layout});e.getColumnText(b.$table,0,function(b){var c=d.tmpl;a.each(a(b.$row).find("td"),function(b,d){var e={},f="{col"+b+"}";a.each(d.attributes,function(a,b){e[b.nodeName]=b.nodeValue});var g=a(d).html(),h=a("<span />").append(a("<span/>",e).append(g));c=c.replace(new RegExp(f,"g"),h.html()),f="{col"+b+":raw}",c=c.replace(new RegExp(f,"g"),a(d).text())});var e=a(c);a.each(b.$row[0].attributes,function(a,b){"class"==b.nodeName?e.attr(b.nodeName,e.attr(b.nodeName)+" "+b.nodeValue):e.attr(b.nodeName,b.nodeValue)}),f.append(e)}),a(c.view_container).append(f),b.$table.triggerHandler("viewComplete")},removeView:function(b,c){a(c.view_container).empty()},hideTable:function(a,e){b=a.$table.css("position"),c=a.$table.css("bottom"),d=a.$table.css("left"),a.$table.css({position:"absolute",top:"-10000px",left:"-10000px"}),f=!0},init:function(a,b){b.view_layout!==!1&&"undefined"!=typeof b.view_layouts[b.view_layout]&&(f===!1&&g.hideTable(a,b),a.$table.on("tablesorter-ready",function(){g.buildToolBar(a,b),g.buildView(a,b)}))},remove:function(a,e){g.removeToolBar(a,e),g.removeView(a,e),a.$table.css({position:b,top:c,left:d}),f=!1}};e.addWidget({id:"view",options:{view_toolbar:"#ts-view-toolbar",view_container:"#ts-view",view_caption:"#ts-view-caption",view_switcher_class:"ts-view-switcher",view_layout:!1,view_layouts:{}},init:function(a,b,c,d){g.init(c,d)},remove:function(a,b,c){g.remove(b,c)}})}(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/old/asc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/old/asc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..74157867f25acbc146704d43399d6c3605ba7724
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/old/asc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/old/bg.gif b/smash/web/static/AdminLTE/plugins/tablesorter/old/bg.gif
new file mode 100644
index 0000000000000000000000000000000000000000..fac668fcf42af844a3af0a239fa638ddbc08443c
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/old/bg.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/old/desc.gif b/smash/web/static/AdminLTE/plugins/tablesorter/old/desc.gif
new file mode 100644
index 0000000000000000000000000000000000000000..3b30b3c58eabdb47a1c420ad03c8e30b966cc858
Binary files /dev/null and b/smash/web/static/AdminLTE/plugins/tablesorter/old/desc.gif differ
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.min.js b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.min.js
new file mode 100644
index 0000000000000000000000000000000000000000..b8605df1e7277e2f88237eb7bee7c7e38d80a232
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.min.js
@@ -0,0 +1,4 @@
+
+(function($){$.extend({tablesorter:new
+function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,rows,-1,i);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,rows,rowIndex,cellIndex){var l=parsers.length,node=false,nodeValue=false,keepLooking=true;while(nodeValue==''&&keepLooking){rowIndex++;if(rows[rowIndex]){node=getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex);nodeValue=trimAndGetNodeText(table.config,node);if(table.config.debug){log('Checking if value was empty on row:'+rowIndex);}}else{keepLooking=false;}}for(var i=1;i<l;i++){if(parsers[i].is(nodeValue,table,node)){return parsers[i];}}return parsers[0];}function getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex){return rows[rowIndex].cells[cellIndex];}function trimAndGetNodeText(config,node){return $.trim(getElementText(config,node));}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=$(table.tBodies[0].rows[i]),cols=[];if(c.hasClass(table.config.cssChildRow)){cache.row[cache.row.length-1]=cache.row[cache.row.length-1].add(c);continue;}cache.row.push(c);for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c[0].cells[j]),table,c[0].cells[j]));}cols.push(cache.normalized.length);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){var text="";if(!node)return"";if(!config.supportsTextContent)config.supportsTextContent=node.textContent||false;if(config.textExtraction=="simple"){if(config.supportsTextContent){text=node.textContent;}else{if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){text=node.childNodes[0].innerHTML;}else{text=node.innerHTML;}}}else{if(typeof(config.textExtraction)=="function"){text=config.textExtraction(node);}else{text=$(node).text();}}return text;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){var pos=n[i][checkCell];rows.push(r[pos]);if(!table.config.appender){var l=r[pos].length;for(var j=0;j<l;j++){tableBody[0].appendChild(r[pos][j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false;var header_index=computeTableHeaderCellIndexes(table);$tableHeaders=$(table.config.selectorHeaders,table).each(function(index){this.column=header_index[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=formatSortingOrder(table.config.sortInitialOrder);this.count=this.order;if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(checkHeaderOptionsSortingLocked(table,index))this.order=this.lockedOrder=checkHeaderOptionsSortingLocked(table,index);if(!this.sortDisabled){var $th=$(this).addClass(table.config.cssHeader);if(table.config.onRenderHeader)table.config.onRenderHeader.apply($th);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function computeTableHeaderCellIndexes(t){var matrix=[];var lookup={};var thead=t.getElementsByTagName('THEAD')[0];var trs=thead.getElementsByTagName('TR');for(var i=0;i<trs.length;i++){var cells=trs[i].cells;for(var j=0;j<cells.length;j++){var c=cells[j];var rowIndex=c.parentNode.rowIndex;var cellId=rowIndex+"-"+c.cellIndex;var rowSpan=c.rowSpan||1;var colSpan=c.colSpan||1
+var firstAvailCol;if(typeof(matrix[rowIndex])=="undefined"){matrix[rowIndex]=[];}for(var k=0;k<matrix[rowIndex].length+1;k++){if(typeof(matrix[rowIndex][k])=="undefined"){firstAvailCol=k;break;}}lookup[cellId]=firstAvailCol;for(var k=rowIndex;k<rowIndex+rowSpan;k++){if(typeof(matrix[k])=="undefined"){matrix[k]=[];}var matrixrow=matrix[k];for(var l=firstAvailCol;l<firstAvailCol+colSpan;l++){matrixrow[l]="x";}}}}return lookup;}function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){return(v.toLowerCase()=="desc")?1:0;}else{return(v==1)?1:0;}}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(table.config.parsers[c].type=="text")?((order==0)?makeSortFunction("text","asc",c):makeSortFunction("text","desc",c)):((order==0)?makeSortFunction("numeric","asc",c):makeSortFunction("numeric","desc",c));var e="e"+i;dynamicExp+="var "+e+" = "+s;dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";if(table.config.debug){benchmark("Evaling expression:"+dynamicExp,new Date());}eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function makeSortFunction(type,direction,index){var a="a["+index+"]",b="b["+index+"]";if(type=='text'&&direction=='asc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+a+" < "+b+") ? -1 : 1 )));";}else if(type=='text'&&direction=='desc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+b+" < "+a+") ? -1 : 1 )));";}else if(type=='numeric'&&direction=='asc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+a+" - "+b+"));";}else if(type=='numeric'&&direction=='desc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+b+" - "+a+"));";}};function makeSortText(i){return"((a["+i+"] < b["+i+"]) ? -1 : ((a["+i+"] > b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){var me=this;setTimeout(function(){me.config.parsers=buildParserCache(me,$headers);cache=buildCache(me);},1);}).bind("updateCell",function(e,cell){var config=this.config;var pos=[(cell.parentNode.rowIndex-1),cell.cellIndex];cache.normalized[pos[0]][pos[1]]=config.parsers[pos[1]].format(getElementText(config,cell),cell);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){return/^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g,'')));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLocaleLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}var $tr,row=-1,odd;$("tr:visible",table.tBodies[0]).each(function(i){$tr=$(this);if(!$tr.hasClass(table.config.cssChildRow))row++;odd=(row%2==0);$tr.removeClass(table.config.widgetZebra.css[odd?0:1]).addClass(table.config.widgetZebra.css[odd?1:0])});if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.pager.css b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.pager.css
new file mode 100644
index 0000000000000000000000000000000000000000..8c8e9fca4b0424c5658a82fa3107d86bc497131f
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.pager.css
@@ -0,0 +1,25 @@
+div.tablesorterPager {
+	padding: 10px 0 10px 0;
+	background-color: #D6D2C2;
+	text-align: center;
+}
+div.tablesorterPager span {
+	padding: 0 5px 0 5px;
+}
+div.tablesorterPager input.prev {
+	width: auto;
+	margin-right: 10px;
+}
+div.tablesorterPager input.next {
+	width: auto;
+	margin-left: 10px;
+}
+div.tablesorterPager input {
+	font-size: 8px;
+	width: 50px;
+	border: 1px solid #330000;
+	text-align: center;
+}
+
+
+  
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.pager.js b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.pager.js
new file mode 100644
index 0000000000000000000000000000000000000000..cce6ea26460f35376f630e6b8f6a523da196aec8
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.pager.js
@@ -0,0 +1,184 @@
+(function($) {
+	$.extend({
+		tablesorterPager: new function() {
+			
+			function updatePageDisplay(c) {
+				var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages);	
+			}
+			
+			function setPageSize(table,size) {
+				var c = table.config;
+				c.size = size;
+				c.totalPages = Math.ceil(c.totalRows / c.size);
+				c.pagerPositionSet = false;
+				moveToPage(table);
+				fixPosition(table);
+			}
+			
+			function fixPosition(table) {
+				var c = table.config;
+				if(!c.pagerPositionSet && c.positionFixed) {
+					var c = table.config, o = $(table);
+					if(o.offset) {
+						c.container.css({
+							top: o.offset().top + o.height() + 'px',
+							position: 'absolute'
+						});
+					}
+					c.pagerPositionSet = true;
+				}
+			}
+			
+			function moveToFirstPage(table) {
+				var c = table.config;
+				c.page = 0;
+				moveToPage(table);
+			}
+			
+			function moveToLastPage(table) {
+				var c = table.config;
+				c.page = (c.totalPages-1);
+				moveToPage(table);
+			}
+			
+			function moveToNextPage(table) {
+				var c = table.config;
+				c.page++;
+				if(c.page >= (c.totalPages-1)) {
+					c.page = (c.totalPages-1);
+				}
+				moveToPage(table);
+			}
+			
+			function moveToPrevPage(table) {
+				var c = table.config;
+				c.page--;
+				if(c.page <= 0) {
+					c.page = 0;
+				}
+				moveToPage(table);
+			}
+						
+			
+			function moveToPage(table) {
+				var c = table.config;
+				if(c.page < 0 || c.page > (c.totalPages-1)) {
+					c.page = 0;
+				}
+				
+				renderTable(table,c.rowsCopy);
+			}
+			
+			function renderTable(table,rows) {
+				
+				var c = table.config;
+				var l = rows.length;
+				var s = (c.page * c.size);
+				var e = (s + c.size);
+				if(e > rows.length ) {
+					e = rows.length;
+				}
+				
+				
+				var tableBody = $(table.tBodies[0]);
+				
+				// clear the table body
+				
+				$.tablesorter.clearTableBody(table);
+				
+				for(var i = s; i < e; i++) {
+					
+					//tableBody.append(rows[i]);
+					
+					var o = rows[i];
+					var l = o.length;
+					for(var j=0; j < l; j++) {
+						
+						tableBody[0].appendChild(o[j]);
+
+					}
+				}
+				
+				fixPosition(table,tableBody);
+				
+				$(table).trigger("applyWidgets");
+				
+				if( c.page >= c.totalPages ) {
+        			moveToLastPage(table);
+				}
+				
+				updatePageDisplay(c);
+			}
+			
+			this.appender = function(table,rows) {
+				
+				var c = table.config;
+				
+				c.rowsCopy = rows;
+				c.totalRows = rows.length;
+				c.totalPages = Math.ceil(c.totalRows / c.size);
+				
+				renderTable(table,rows);
+			};
+			
+			this.defaults = {
+				size: 10,
+				offset: 0,
+				page: 0,
+				totalRows: 0,
+				totalPages: 0,
+				container: null,
+				cssNext: '.next',
+				cssPrev: '.prev',
+				cssFirst: '.first',
+				cssLast: '.last',
+				cssPageDisplay: '.pagedisplay',
+				cssPageSize: '.pagesize',
+				seperator: "/",
+				positionFixed: true,
+				appender: this.appender
+			};
+			
+			this.construct = function(settings) {
+				
+				return this.each(function() {	
+					
+					config = $.extend(this.config, $.tablesorterPager.defaults, settings);
+					
+					var table = this, pager = config.container;
+				
+					$(this).trigger("appendCache");
+					
+					config.size = parseInt($(".pagesize",pager).val());
+					
+					$(config.cssFirst,pager).click(function() {
+						moveToFirstPage(table);
+						return false;
+					});
+					$(config.cssNext,pager).click(function() {
+						moveToNextPage(table);
+						return false;
+					});
+					$(config.cssPrev,pager).click(function() {
+						moveToPrevPage(table);
+						return false;
+					});
+					$(config.cssLast,pager).click(function() {
+						moveToLastPage(table);
+						return false;
+					});
+					$(config.cssPageSize,pager).change(function() {
+						setPageSize(table,parseInt($(this).val()));
+						return false;
+					});
+				});
+			};
+			
+		}
+	});
+	// extend plugin scope
+	$.fn.extend({
+        tablesorterPager: $.tablesorterPager.construct
+	});
+	
+})(jQuery);				
\ No newline at end of file
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.style.css b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.style.css
new file mode 100644
index 0000000000000000000000000000000000000000..eb41f70c0f896f5367bf6a08da8f0579f101abe1
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.style.css
@@ -0,0 +1,39 @@
+/* tables */
+table.tablesorter {
+	font-family:arial;
+	background-color: #CDCDCD;
+	margin:10px 0pt 15px;
+	font-size: 8pt;
+	width: 100%;
+	text-align: left;
+}
+table.tablesorter thead tr th, table.tablesorter tfoot tr th {
+	background-color: #e6EEEE;
+	border: 1px solid #FFF;
+	font-size: 8pt;
+	padding: 4px;
+}
+table.tablesorter thead tr .header {
+	background-image: url(bg.gif);
+	background-repeat: no-repeat;
+	background-position: center right;
+	cursor: pointer;
+}
+table.tablesorter tbody td {
+	color: #3D3D3D;
+	padding: 4px;
+	background-color: #FFF;
+	vertical-align: top;
+}
+table.tablesorter tbody tr.odd td {
+	background-color:#F0F0F6;
+}
+table.tablesorter thead tr .headerSortUp {
+	background-image: url(asc.gif);
+}
+table.tablesorter thead tr .headerSortDown {
+	background-image: url(desc.gif);
+}
+table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp {
+background-color: #8dbdd8;
+}
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.widgets.js b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.widgets.js
new file mode 100644
index 0000000000000000000000000000000000000000..44305471b348c4da21e196ac8e8c09c7c8cfcdd5
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/old/jquery.tablesorter.widgets.js
@@ -0,0 +1,3049 @@
+/*** This file is dynamically generated ***
+█████▄ ▄████▄   █████▄ ▄████▄ ██████   ███████▄ ▄████▄ █████▄ ██ ██████ ██  ██
+██  ██ ██  ██   ██  ██ ██  ██   ██     ██ ██ ██ ██  ██ ██  ██ ██ ██▄▄   ██▄▄██
+██  ██ ██  ██   ██  ██ ██  ██   ██     ██ ██ ██ ██  ██ ██  ██ ██ ██▀▀    ▀▀▀██
+█████▀ ▀████▀   ██  ██ ▀████▀   ██     ██ ██ ██ ▀████▀ █████▀ ██ ██     █████▀
+*/
+/*! tablesorter (FORK) - updated 01-06-2017 (v2.28.4)*/
+/* Includes widgets ( storage,uitheme,columns,filter,stickyHeaders,resizable,saveSort ) */
+(function(factory) {
+	if (typeof define === 'function' && define.amd) {
+		define(['jquery'], factory);
+	} else if (typeof module === 'object' && typeof module.exports === 'object') {
+		module.exports = factory(require('jquery'));
+	} else {
+		factory(jQuery);
+	}
+}(function(jQuery) {
+
+/*! Widget: storage - updated 11/26/2016 (v2.28.0) */
+/*global JSON:false */
+;(function ($, window, document) {
+	'use strict';
+
+	var ts = $.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
+	*/
+	ts.storage = function(table, key, value, options) {
+		table = $(table)[0];
+		var cookieIndex, cookies, date,
+			hasStorage = false,
+			values = {},
+			c = table.config,
+			wo = c && c.widgetOptions,
+			storageType = ( options && options.useSessionStorage ) || ( wo && wo.storage_useSessionStorage ) ?
+				'sessionStorage' : 'localStorage',
+			$table = $(table),
+			// id from (1) options ID, (2) table 'data-table-group' attribute, (3) widgetOptions.storage_tableId,
+			// (4) table ID, then (5) table index
+			id = options && options.id ||
+				$table.attr( options && options.group || wo && wo.storage_group || 'data-table-group') ||
+				wo && wo.storage_tableId || table.id || $('.tablesorter').index( $table ),
+			// 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
+			url = options && options.url ||
+				$table.attr(options && options.page || wo && wo.storage_page || 'data-table-page') ||
+				wo && wo.storage_fixedUrl || c && c.fixedUrl || window.location.pathname;
+		// update defaults for validator; these values must be falsy!
+		$.extend(true, ts.defaults, {
+			fixedUrl: '',
+			widgetOptions: {
+				storage_fixedUrl: '',
+				storage_group: '',
+				storage_page: '',
+				storage_tableId: '',
+				storage_useSessionStorage: ''
+			}
+		});
+		// https://gist.github.com/paulirish/5558557
+		if (storageType in window) {
+			try {
+				window[storageType].setItem('_tmptest', 'temp');
+				hasStorage = true;
+				window[storageType].removeItem('_tmptest');
+			} catch (error) {
+				if (c && c.debug) {
+					console.warn( storageType + ' is not supported in this browser' );
+				}
+			}
+		}
+		// *** get value ***
+		if ($.parseJSON) {
+			if (hasStorage) {
+				values = $.parseJSON( window[storageType][key] || 'null' ) || {};
+			} else {
+				// old browser, using cookies
+				cookies = document.cookie.split(/[;\s|=]/);
+				// add one to get from the key to the value
+				cookieIndex = $.inArray(key, cookies) + 1;
+				values = (cookieIndex !== 0) ? $.parseJSON(cookies[cookieIndex] || 'null') || {} : {};
+			}
+		}
+		// allow value to be an empty string too
+		if (typeof value !== 'undefined' && window.JSON && JSON.hasOwnProperty('stringify')) {
+			// add unique identifiers = url pathname > table ID/index on page > data
+			if (!values[url]) {
+				values[url] = {};
+			}
+			values[url][id] = value;
+			// *** set value ***
+			if (hasStorage) {
+				window[storageType][key] = JSON.stringify(values);
+			} else {
+				date = new Date();
+				date.setTime(date.getTime() + (31536e+6)); // 365 days
+				document.cookie = key + '=' + (JSON.stringify(values)).replace(/\"/g, '\"') + '; expires=' + date.toGMTString() + '; path=/';
+			}
+		} else {
+			return values && values[url] ? values[url][id] : '';
+		}
+	};
+
+})(jQuery, window, document);
+
+/*! Widget: uitheme - updated 12/8/2016 (v2.28.1) */
+;(function ($) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	ts.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          : ''  // odd row zebra striping
+		},
+		'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 ui-icon-caret-2-n-s', // class name added to icon when column is not sorted
+			iconSortAsc  : 'ui-icon-carat-1-n ui-icon-caret-1-n', // class name added to icon when column has ascending sort
+			iconSortDesc : 'ui-icon-carat-1-s ui-icon-caret-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'   // odd row zebra striping
+		}
+	};
+
+	$.extend(ts.css, {
+		wrapper : 'tablesorter-wrapper' // ui theme & resizable
+	});
+
+	ts.addWidget({
+		id: 'uitheme',
+		priority: 10,
+		format: function(table, c, wo) {
+			var i, tmp, hdr, icon, time, $header, $icon, $tfoot, $h, oldtheme, oldremove, oldIconRmv, hasOldTheme,
+				themesAll = ts.themes,
+				$table = c.$table.add( $( c.namespace + '_extra_table' ) ),
+				$headers = c.$headers.add( $( c.namespace + '_extra_headers' ) ),
+				theme = c.theme || 'jui',
+				themes = themesAll[theme] || {},
+				remove = $.trim( [ themes.sortNone, themes.sortDesc, themes.sortAsc, themes.active ].join( ' ' ) ),
+				iconRmv = $.trim( [ themes.iconSortNone, themes.iconSortDesc, themes.iconSortAsc ].join( ' ' ) );
+			if (c.debug) { time = new Date(); }
+			// initialization code - run once
+			if (!$table.hasClass('tablesorter-' + theme) || c.theme !== c.appliedTheme || !wo.uitheme_applied) {
+				wo.uitheme_applied = true;
+				oldtheme = themesAll[c.appliedTheme] || {};
+				hasOldTheme = !$.isEmptyObject(oldtheme);
+				oldremove =  hasOldTheme ? [ oldtheme.sortNone, oldtheme.sortDesc, oldtheme.sortAsc, oldtheme.active ].join( ' ' ) : '';
+				oldIconRmv = hasOldTheme ? [ oldtheme.iconSortNone, oldtheme.iconSortDesc, oldtheme.iconSortAsc ].join( ' ' ) : '';
+				if (hasOldTheme) {
+					wo.zebra[0] = $.trim( ' ' + wo.zebra[0].replace(' ' + oldtheme.even, '') );
+					wo.zebra[1] = $.trim( ' ' + wo.zebra[1].replace(' ' + oldtheme.odd, '') );
+					c.$tbodies.children().removeClass( [ oldtheme.even, oldtheme.odd ].join(' ') );
+				}
+				// update zebra stripes
+				if (themes.even) { wo.zebra[0] += ' ' + themes.even; }
+				if (themes.odd) { wo.zebra[1] += ' ' + themes.odd; }
+				// add caption style
+				$table.children('caption')
+					.removeClass(oldtheme.caption || '')
+					.addClass(themes.caption);
+				// add table/footer class names
+				$tfoot = $table
+					// remove other selected themes
+					.removeClass( (c.appliedTheme ? 'tablesorter-' + (c.appliedTheme || '') : '') + ' ' + (oldtheme.table || '') )
+					.addClass('tablesorter-' + theme + ' ' + (themes.table || '')) // add theme widget class name
+					.children('tfoot');
+				c.appliedTheme = c.theme;
+
+				if ($tfoot.length) {
+					$tfoot
+						// if oldtheme.footerRow or oldtheme.footerCells are undefined, all class names are removed
+						.children('tr').removeClass(oldtheme.footerRow || '').addClass(themes.footerRow)
+						.children('th, td').removeClass(oldtheme.footerCells || '').addClass(themes.footerCells);
+				}
+				// update header classes
+				$headers
+					.removeClass( (hasOldTheme ? [ oldtheme.header, oldtheme.hover, oldremove ].join(' ') : '') || '' )
+					.addClass(themes.header)
+					.not('.sorter-false')
+					.unbind('mouseenter.tsuitheme mouseleave.tsuitheme')
+					.bind('mouseenter.tsuitheme mouseleave.tsuitheme', function(event) {
+						// toggleClass with switch added in jQuery 1.3
+						$(this)[ event.type === 'mouseenter' ? 'addClass' : 'removeClass' ](themes.hover || '');
+					});
+
+				$headers.each(function(){
+					var $this = $(this);
+					if (!$this.find('.' + ts.css.wrapper).length) {
+						// Firefox needs this inner div to position the icon & resizer correctly
+						$this.wrapInner('<div class="' + ts.css.wrapper + '" style="position:relative;height:100%;width:100%"></div>');
+					}
+				});
+				if (c.cssIcon) {
+					// if c.cssIcon is '', then no <i> is added to the header
+					$headers
+						.find('.' + ts.css.icon)
+						.removeClass(hasOldTheme ? [ oldtheme.icons, oldIconRmv ].join(' ') : '')
+						.addClass(themes.icons || '');
+				}
+				// filter widget initializes after uitheme
+				if (ts.hasWidget( c.table, 'filter' )) {
+					tmp = function() {
+						$table.children('thead').children('.' + ts.css.filterRow)
+							.removeClass(hasOldTheme ? oldtheme.filterRow || '' : '')
+							.addClass(themes.filterRow || '');
+					};
+					if (wo.filter_initialized) {
+						tmp();
+					} else {
+						$table.one('filterInit', function() {
+							tmp();
+						});
+					}
+				}
+			}
+			for (i = 0; i < c.columns; i++) {
+				$header = c.$headers
+					.add($(c.namespace + '_extra_headers'))
+					.not('.sorter-false')
+					.filter('[data-column="' + i + '"]');
+				$icon = (ts.css.icon) ? $header.find('.' + ts.css.icon) : $();
+				$h = $headers.not('.sorter-false').filter('[data-column="' + i + '"]:last');
+				if ($h.length) {
+					$header.removeClass(remove);
+					$icon.removeClass(iconRmv);
+					if ($h[0].sortDisabled) {
+						// no sort arrows for disabled columns!
+						$icon.removeClass(themes.icons || '');
+					} else {
+						hdr = themes.sortNone;
+						icon = themes.iconSortNone;
+						if ($h.hasClass(ts.css.sortAsc)) {
+							hdr = [ themes.sortAsc, themes.active ].join(' ');
+							icon = themes.iconSortAsc;
+						} else if ($h.hasClass(ts.css.sortDesc)) {
+							hdr = [ themes.sortDesc, themes.active ].join(' ');
+							icon = themes.iconSortDesc;
+						}
+						$header.addClass(hdr);
+						$icon.addClass(icon || '');
+					}
+				}
+			}
+			if (c.debug) {
+				console.log('Applying ' + theme + ' theme' + ts.benchmark(time));
+			}
+		},
+		remove: function(table, c, wo, refreshing) {
+			if (!wo.uitheme_applied) { return; }
+			var $table = c.$table,
+				theme = c.appliedTheme || 'jui',
+				themes = ts.themes[ theme ] || ts.themes.jui,
+				$headers = $table.children('thead').children(),
+				remove = themes.sortNone + ' ' + themes.sortDesc + ' ' + themes.sortAsc,
+				iconRmv = themes.iconSortNone + ' ' + themes.iconSortDesc + ' ' + themes.iconSortAsc;
+			$table.removeClass('tablesorter-' + theme + ' ' + themes.table);
+			wo.uitheme_applied = false;
+			if (refreshing) { return; }
+			$table.find(ts.css.header).removeClass(themes.header);
+			$headers
+				.unbind('mouseenter.tsuitheme mouseleave.tsuitheme') // remove hover
+				.removeClass(themes.hover + ' ' + remove + ' ' + themes.active)
+				.filter('.' + ts.css.filterRow)
+				.removeClass(themes.filterRow);
+			$headers.find('.' + ts.css.icon).removeClass(themes.icons + ' ' + iconRmv);
+		}
+	});
+
+})(jQuery);
+
+/*! Widget: columns */
+;(function ($) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	ts.addWidget({
+		id: 'columns',
+		priority: 30,
+		options : {
+			columns : [ 'primary', 'secondary', 'tertiary' ]
+		},
+		format: function(table, c, wo) {
+			var $tbody, tbodyIndex, $rows, rows, $row, $cells, remove, indx,
+			$table = c.$table,
+			$tbodies = c.$tbodies,
+			sortList = c.sortList,
+			len = sortList.length,
+			// removed c.widgetColumns support
+			css = wo && wo.columns || [ 'primary', 'secondary', 'tertiary' ],
+			last = css.length - 1;
+			remove = css.join(' ');
+			// check if there is a sort (on initialization there may not be one)
+			for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // detach tbody
+				$rows = $tbody.children('tr');
+				// loop through the visible rows
+				$rows.each(function() {
+					$row = $(this);
+					if (this.style.display !== 'none') {
+						// remove all columns class names
+						$cells = $row.children().removeClass(remove);
+						// add appropriate column class names
+						if (sortList && sortList[0]) {
+							// primary sort column class
+							$cells.eq(sortList[0][0]).addClass(css[0]);
+							if (len > 1) {
+								for (indx = 1; indx < len; indx++) {
+									// secondary, tertiary, etc sort column classes
+									$cells.eq(sortList[indx][0]).addClass( css[indx] || css[last] );
+								}
+							}
+						}
+					}
+				});
+				ts.processTbody(table, $tbody, false);
+			}
+			// add classes to thead and tfoot
+			rows = wo.columns_thead !== false ? [ 'thead tr' ] : [];
+			if (wo.columns_tfoot !== false) {
+				rows.push('tfoot tr');
+			}
+			if (rows.length) {
+				$rows = $table.find( rows.join(',') ).children().removeClass(remove);
+				if (len) {
+					for (indx = 0; indx < len; indx++) {
+						// add primary. secondary, tertiary, etc sort column classes
+						$rows.filter('[data-column="' + sortList[indx][0] + '"]').addClass(css[indx] || css[last]);
+					}
+				}
+			}
+		},
+		remove: function(table, c, wo) {
+			var tbodyIndex, $tbody,
+				$tbodies = c.$tbodies,
+				remove = (wo.columns || [ 'primary', 'secondary', 'tertiary' ]).join(' ');
+			c.$headers.removeClass(remove);
+			c.$table.children('tfoot').children('tr').children('th, td').removeClass(remove);
+			for (tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody(table, $tbodies.eq(tbodyIndex), true); // remove tbody
+				$tbody.children('tr').each(function() {
+					$(this).children().removeClass(remove);
+				});
+				ts.processTbody(table, $tbody, false); // restore tbody
+			}
+		}
+	});
+
+})(jQuery);
+
+/*! Widget: filter - updated 12/8/2016 (v2.28.1) *//*
+ * Requires tablesorter v2.8+ and jQuery 1.7+
+ * by Rob Garrison
+ */
+;( function ( $ ) {
+	'use strict';
+	var tsf, tsfRegex,
+		ts = $.tablesorter || {},
+		tscss = ts.css,
+		tskeyCodes = ts.keyCodes;
+
+	$.extend( tscss, {
+		filterRow      : 'tablesorter-filter-row',
+		filter         : 'tablesorter-filter',
+		filterDisabled : 'disabled',
+		filterRowHide  : 'hideme'
+	});
+
+	$.extend( tskeyCodes, {
+		backSpace : 8,
+		escape : 27,
+		space : 32,
+		left : 37,
+		down : 40
+	});
+
+	ts.addWidget({
+		id: 'filter',
+		priority: 50,
+		options : {
+			filter_cellFilter    : '',    // css class name added to the filter cell ( string or array )
+			filter_childRows     : false, // if true, filter includes child row content in the search
+			filter_childByColumn : false, // ( filter_childRows must be true ) if true = search child rows by column; false = search all child row text grouped
+			filter_childWithSibs : true,  // if true, include matching child row siblings
+			filter_columnAnyMatch: true,  // if true, allows using '#:{query}' in AnyMatch searches ( column:query )
+			filter_columnFilters : true,  // if true, a filter will be added to the top of each table column
+			filter_cssFilter     : '',    // css class name added to the filter row & each input in the row ( tablesorter-filter is ALWAYS added )
+			filter_defaultAttrib : 'data-value', // data attribute in the header cell that contains the default filter value
+			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; define in css with "display:none" to hide the filtered-out rows
+			filter_formatter     : null,  // add custom filter elements to the filter row
+			filter_functions     : null,  // add custom filter functions using this option
+			filter_hideEmpty     : true,  // hide filter row when table is empty
+			filter_hideFilters   : false, // collapse filter row when mouse leaves the area
+			filter_ignoreCase    : true,  // if true, make all searches case-insensitive
+			filter_liveSearch    : true,  // if true, search column content while the user types ( with a delay )
+			filter_matchType     : { 'input': 'exact', 'select': 'exact' }, // global query settings ('exact' or 'match'); overridden by "filter-match" or "filter-exact" class
+			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_resetOnEsc    : true,  // Reset filter input when the user presses escape - normalized across browsers
+			filter_saveFilters   : false, // Use the $.tablesorter.storage utility to save the most recent filters
+			filter_searchDelay   : 300,   // typing delay in milliseconds before starting a search
+			filter_searchFiltered: true,  // 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_selectSourceSeparator : '|', // filter_selectSource array text left of the separator is added to the option value, right into the option text
+			filter_serversideFiltering : false, // if true, must perform server-side filtering b/c client-side filtering is disabled, but the ui and events will still be used.
+			filter_startsWith    : false, // if true, filter start from the beginning of the cell contents
+			filter_useParsedData : false  // filter all data using parsed content
+		},
+		format: function( table, c, wo ) {
+			if ( !c.$table.hasClass( 'hasFilters' ) ) {
+				tsf.init( table, c, wo );
+			}
+		},
+		remove: function( table, c, wo, refreshing ) {
+			var tbodyIndex, $tbody,
+				$table = c.$table,
+				$tbodies = c.$tbodies,
+				events = 'addRows updateCell update updateRows updateComplete appendCache filterReset filterEnd search '
+					.split( ' ' ).join( c.namespace + 'filter ' );
+			$table
+				.removeClass( 'hasFilters' )
+				// add filter namespace to all BUT search
+				.unbind( events.replace( ts.regex.spaces, ' ' ) )
+				// remove the filter row even if refreshing, because the column might have been moved
+				.find( '.' + tscss.filterRow ).remove();
+			wo.filter_initialized = false;
+			if ( refreshing ) { return; }
+			for ( tbodyIndex = 0; tbodyIndex < $tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody( table, $tbodies.eq( tbodyIndex ), true ); // remove tbody
+				$tbody.children().removeClass( wo.filter_filteredRow ).show();
+				ts.processTbody( table, $tbody, false ); // restore tbody
+			}
+			if ( wo.filter_reset ) {
+				$( document ).undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' );
+			}
+		}
+	});
+
+	tsf = ts.filter = {
+
+		// regex used in filter 'check' functions - not for general use and not documented
+		regex: {
+			regex     : /^\/((?:\\\/|[^\/])+)\/([migyu]{0,5})?$/, // 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, data, vars ) {
+				// look for "|", but not if it is inside of a regular expression
+				if ( ( tsfRegex.orTest.test( data.iFilter ) || tsfRegex.orSplit.test( data.filter ) ) &&
+					// this test for regex has potential to slow down the overall search
+					!tsfRegex.regex.test( data.filter ) ) {
+					var indx, filterMatched, query, regex,
+						// duplicate data but split filter
+						data2 = $.extend( {}, data ),
+						filter = data.filter.split( tsfRegex.orSplit ),
+						iFilter = data.iFilter.split( tsfRegex.orSplit ),
+						len = filter.length;
+					for ( indx = 0; indx < len; indx++ ) {
+						data2.nestedFilters = true;
+						data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
+						data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
+						query = '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')';
+						try {
+							// use try/catch, because query may not be a valid regex if "|" is contained within a partial regex search,
+							// e.g "/(Alex|Aar" -> Uncaught SyntaxError: Invalid regular expression: /(/(Alex)/: Unterminated group
+							regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
+							// filterMatched = data2.filter === '' && indx > 0 ? true
+							// look for an exact match with the 'or' unless the 'filter-match' class is found
+							filterMatched = regex.test( data2.exact ) || tsf.processTypes( c, data2, vars );
+							if ( filterMatched ) {
+								return filterMatched;
+							}
+						} catch ( error ) {
+							return null;
+						}
+					}
+					// may be null from processing types
+					return filterMatched || false;
+				}
+				return null;
+			},
+			// Look for an AND or && operator ( logical and )
+			and : function( c, data, vars ) {
+				if ( tsfRegex.andTest.test( data.filter ) ) {
+					var indx, filterMatched, result, query, regex,
+						// duplicate data but split filter
+						data2 = $.extend( {}, data ),
+						filter = data.filter.split( tsfRegex.andSplit ),
+						iFilter = data.iFilter.split( tsfRegex.andSplit ),
+						len = filter.length;
+					for ( indx = 0; indx < len; indx++ ) {
+						data2.nestedFilters = true;
+						data2.filter = '' + ( tsf.parseFilter( c, filter[ indx ], data ) || '' );
+						data2.iFilter = '' + ( tsf.parseFilter( c, iFilter[ indx ], data ) || '' );
+						query = ( '(' + ( tsf.parseFilter( c, data2.filter, data ) || '' ) + ')' )
+							// replace wild cards since /(a*)/i will match anything
+							.replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' );
+						try {
+							// use try/catch just in case RegExp is invalid
+							regex = new RegExp( data.isMatch ? query : '^' + query + '$', c.widgetOptions.filter_ignoreCase ? 'i' : '' );
+							// look for an exact match with the 'and' unless the 'filter-match' class is found
+							result = ( regex.test( data2.exact ) || tsf.processTypes( c, data2, vars ) );
+							if ( indx === 0 ) {
+								filterMatched = result;
+							} else {
+								filterMatched = filterMatched && result;
+							}
+						} catch ( error ) {
+							return null;
+						}
+					}
+					// may be null from processing types
+					return filterMatched || false;
+				}
+				return null;
+			},
+			// Look for regex
+			regex: function( c, data ) {
+				if ( tsfRegex.regex.test( data.filter ) ) {
+					var matches,
+						// cache regex per column for optimal speed
+						regex = data.filter_regexCache[ data.index ] || tsfRegex.regex.exec( data.filter ),
+						isRegex = regex instanceof RegExp;
+					try {
+						if ( !isRegex ) {
+							// force case insensitive search if ignoreCase option set?
+							// if ( c.ignoreCase && !regex[2] ) { regex[2] = 'i'; }
+							data.filter_regexCache[ data.index ] = regex = new RegExp( regex[1], regex[2] );
+						}
+						matches = regex.test( data.exact );
+					} catch ( error ) {
+						matches = false;
+					}
+					return matches;
+				}
+				return null;
+			},
+			// Look for operators >, >=, < or <=
+			operators: function( c, data ) {
+				// ignore empty strings... because '' < 10 is true
+				if ( tsfRegex.operTest.test( data.iFilter ) && data.iExact !== '' ) {
+					var cachedValue, result, txt,
+						table = c.table,
+						parsed = data.parsed[ data.index ],
+						query = ts.formatFloat( data.iFilter.replace( tsfRegex.operators, '' ), table ),
+						parser = c.parsers[ data.index ] || {},
+						savedSearch = query;
+					// parse filter value in case we're comparing numbers ( dates )
+					if ( parsed || parser.type === 'numeric' ) {
+						txt = $.trim( '' + data.iFilter.replace( tsfRegex.operators, '' ) );
+						result = tsf.parseFilter( c, txt, data, true );
+						query = ( typeof result === 'number' && result !== '' && !isNaN( result ) ) ? result : query;
+					}
+					// iExact may be numeric - see issue #149;
+					// check if cached is defined, because sometimes j goes out of range? ( numeric columns )
+					if ( ( parsed || parser.type === 'numeric' ) && !isNaN( query ) &&
+						typeof data.cache !== 'undefined' ) {
+						cachedValue = data.cache;
+					} else {
+						txt = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
+						cachedValue = ts.formatFloat( txt, table );
+					}
+					if ( tsfRegex.gtTest.test( data.iFilter ) ) {
+						result = tsfRegex.gteTest.test( data.iFilter ) ? cachedValue >= query : cachedValue > query;
+					} else if ( tsfRegex.ltTest.test( data.iFilter ) ) {
+						result = tsfRegex.lteTest.test( data.iFilter ) ? cachedValue <= query : cachedValue < query;
+					}
+					// keep showing all rows if nothing follows the operator
+					if ( !result && savedSearch === '' ) {
+						result = true;
+					}
+					return result;
+				}
+				return null;
+			},
+			// Look for a not match
+			notMatch: function( c, data ) {
+				if ( tsfRegex.notTest.test( data.iFilter ) ) {
+					var indx,
+						txt = data.iFilter.replace( '!', '' ),
+						filter = tsf.parseFilter( c, txt, data ) || '';
+					if ( tsfRegex.exact.test( filter ) ) {
+						// look for exact not matches - see #628
+						filter = filter.replace( tsfRegex.exact, '' );
+						return filter === '' ? true : $.trim( filter ) !== data.iExact;
+					} else {
+						indx = data.iExact.search( $.trim( filter ) );
+						return filter === '' ? true :
+							// return true if not found
+							data.anyMatch ? indx < 0 :
+							// return false if found
+							!( c.widgetOptions.filter_startsWith ? indx === 0 : indx >= 0 );
+					}
+				}
+				return null;
+			},
+			// Look for quotes or equals to get an exact match; ignore type since iExact could be numeric
+			exact: function( c, data ) {
+				/*jshint eqeqeq:false */
+				if ( tsfRegex.exact.test( data.iFilter ) ) {
+					var txt = data.iFilter.replace( tsfRegex.exact, '' ),
+						filter = tsf.parseFilter( c, txt, data ) || '';
+					return data.anyMatch ? $.inArray( filter, data.rowArray ) >= 0 : filter == data.iExact;
+				}
+				return null;
+			},
+			// Look for a range ( using ' to ' or ' - ' ) - see issue #166; thanks matzhu!
+			range : function( c, data ) {
+				if ( tsfRegex.toTest.test( data.iFilter ) ) {
+					var result, tmp, range1, range2,
+						table = c.table,
+						index = data.index,
+						parsed = data.parsed[index],
+						// make sure the dash is for a range and not indicating a negative number
+						query = data.iFilter.split( tsfRegex.toSplit );
+
+					tmp = query[0].replace( ts.regex.nondigit, '' ) || '';
+					range1 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
+					tmp = query[1].replace( ts.regex.nondigit, '' ) || '';
+					range2 = ts.formatFloat( tsf.parseFilter( c, tmp, data ), table );
+					// parse filter value in case we're comparing numbers ( dates )
+					if ( parsed || c.parsers[ index ].type === 'numeric' ) {
+						result = c.parsers[ index ].format( '' + query[0], table, c.$headers.eq( index ), index );
+						range1 = ( result !== '' && !isNaN( result ) ) ? result : range1;
+						result = c.parsers[ index ].format( '' + query[1], table, c.$headers.eq( index ), index );
+						range2 = ( result !== '' && !isNaN( result ) ) ? result : range2;
+					}
+					if ( ( parsed || c.parsers[ index ].type === 'numeric' ) && !isNaN( range1 ) && !isNaN( range2 ) ) {
+						result = data.cache;
+					} else {
+						tmp = isNaN( data.iExact ) ? data.iExact.replace( ts.regex.nondigit, '' ) : data.iExact;
+						result = ts.formatFloat( tmp, table );
+					}
+					if ( range1 > range2 ) {
+						tmp = range1; range1 = range2; range2 = tmp; // swap
+					}
+					return ( result >= range1 && result <= range2 ) || ( range1 === '' || range2 === '' );
+				}
+				return null;
+			},
+			// Look for wild card: ? = single, * = multiple, or | = logical OR
+			wild : function( c, data ) {
+				if ( tsfRegex.wildOrTest.test( data.iFilter ) ) {
+					var query = '' + ( tsf.parseFilter( c, data.iFilter, data ) || '' );
+					// look for an exact match with the 'or' unless the 'filter-match' class is found
+					if ( !tsfRegex.wildTest.test( query ) && data.nestedFilters ) {
+						query = data.isMatch ? query : '^(' + query + ')$';
+					}
+					// parsing the filter may not work properly when using wildcards =/
+					try {
+						return new RegExp(
+							query.replace( tsfRegex.wild01, '\\S{1}' ).replace( tsfRegex.wild0More, '\\S*' ),
+							c.widgetOptions.filter_ignoreCase ? 'i' : ''
+						)
+						.test( data.exact );
+					} catch ( error ) {
+						return null;
+					}
+				}
+				return null;
+			},
+			// fuzzy text search; modified from https://github.com/mattyork/fuzzy ( MIT license )
+			fuzzy: function( c, data ) {
+				if ( tsfRegex.fuzzyTest.test( data.iFilter ) ) {
+					var indx,
+						patternIndx = 0,
+						len = data.iExact.length,
+						txt = data.iFilter.slice( 1 ),
+						pattern = tsf.parseFilter( c, txt, data ) || '';
+					for ( indx = 0; indx < len; indx++ ) {
+						if ( data.iExact[ indx ] === pattern[ patternIndx ] ) {
+							patternIndx += 1;
+						}
+					}
+					return patternIndx === pattern.length;
+				}
+				return null;
+			}
+		},
+		init: function( table ) {
+			// filter language options
+			ts.language = $.extend( true, {}, {
+				to  : 'to',
+				or  : 'or',
+				and : 'and'
+			}, ts.language );
+
+			var options, string, txt, $header, column, val, fxn, noSelect,
+				c = table.config,
+				wo = c.widgetOptions;
+			c.$table.addClass( 'hasFilters' );
+			c.lastSearch = [];
+
+			// define timers so using clearTimeout won't cause an undefined error
+			wo.filter_searchTimer = null;
+			wo.filter_initTimer = null;
+			wo.filter_formatterCount = 0;
+			wo.filter_formatterInit = [];
+			wo.filter_anyColumnSelector = '[data-column="all"],[data-column="any"]';
+			wo.filter_multipleColumnSelector = '[data-column*="-"],[data-column*=","]';
+
+			val = '\\{' + tsfRegex.query + '\\}';
+			$.extend( tsfRegex, {
+				child : new RegExp( c.cssChildRow ),
+				filtered : new RegExp( wo.filter_filteredRow ),
+				alreadyFiltered : new RegExp( '(\\s+(' + ts.language.or + '|-|' + ts.language.to + ')\\s+)', 'i' ),
+				toTest : new RegExp( '\\s+(-|' + ts.language.to + ')\\s+', 'i' ),
+				toSplit : new RegExp( '(?:\\s+(?:-|' + ts.language.to + ')\\s+)', 'gi' ),
+				andTest : new RegExp( '\\s+(' + ts.language.and + '|&&)\\s+', 'i' ),
+				andSplit : new RegExp( '(?:\\s+(?:' + ts.language.and + '|&&)\\s+)', 'gi' ),
+				orTest : new RegExp( '(\\||\\s+' + ts.language.or + '\\s+)', 'i' ),
+				orSplit : new RegExp( '(?:\\s+(?:' + ts.language.or + ')\\s+|\\|)', 'gi' ),
+				iQuery : new RegExp( val, 'i' ),
+				igQuery : new RegExp( val, 'ig' ),
+				operTest : /^[<>]=?/,
+				gtTest  : />/,
+				gteTest : />=/,
+				ltTest  : /</,
+				lteTest : /<=/,
+				notTest : /^\!/,
+				wildOrTest : /[\?\*\|]/,
+				wildTest : /\?\*/,
+				fuzzyTest : /^~/,
+				exactTest : /[=\"\|!]/
+			});
+
+			// don't build filter row if columnFilters is false or all columns are set to 'filter-false'
+			// see issue #156
+			val = c.$headers.filter( '.filter-false, .parser-false' ).length;
+			if ( wo.filter_columnFilters !== false && val !== c.$headers.length ) {
+				// build filter row
+				tsf.buildRow( table, c, wo );
+			}
+
+			txt = 'addRows updateCell update updateRows updateComplete appendCache filterReset ' +
+				'filterResetSaved filterEnd search '.split( ' ' ).join( c.namespace + 'filter ' );
+			c.$table.bind( txt, function( event, filter ) {
+				val = wo.filter_hideEmpty &&
+					$.isEmptyObject( c.cache ) &&
+					!( c.delayInit && event.type === 'appendCache' );
+				// hide filter row using the 'filtered' class name
+				c.$table.find( '.' + tscss.filterRow ).toggleClass( wo.filter_filteredRow, val ); // fixes #450
+				if ( !/(search|filter)/.test( event.type ) ) {
+					event.stopPropagation();
+					tsf.buildDefault( table, true );
+				}
+				if ( event.type === 'filterReset' ) {
+					c.$table.find( '.' + tscss.filter ).add( wo.filter_$externalFilters ).val( '' );
+					tsf.searching( table, [] );
+				} else if ( event.type === 'filterResetSaved' ) {
+					ts.storage( table, 'tablesorter-filters', '' );
+				} else if ( event.type === 'filterEnd' ) {
+					tsf.buildDefault( table, true );
+				} else {
+					// send false argument to force a new search; otherwise if the filter hasn't changed,
+					// it will return
+					filter = event.type === 'search' ? filter :
+						event.type === 'updateComplete' ? c.$table.data( 'lastSearch' ) : '';
+					if ( /(update|add)/.test( event.type ) && event.type !== 'updateComplete' ) {
+						// force a new search since content has changed
+						c.lastCombinedFilter = null;
+						c.lastSearch = [];
+						// update filterFormatters after update (& small delay) - Fixes #1237
+						setTimeout(function(){
+							c.$table.triggerHandler( 'filterFomatterUpdate' );
+						}, 100);
+					}
+					// pass true ( skipFirst ) to prevent the tablesorter.setFilters function from skipping the first
+					// input ensures all inputs are updated when a search is triggered on the table
+					// $( 'table' ).trigger( 'search', [...] );
+					tsf.searching( table, filter, true );
+				}
+				return false;
+			});
+
+			// reset button/link
+			if ( wo.filter_reset ) {
+				if ( wo.filter_reset instanceof $ ) {
+					// reset contains a jQuery object, bind to it
+					wo.filter_reset.click( function() {
+						c.$table.triggerHandler( 'filterReset' );
+					});
+				} else if ( $( wo.filter_reset ).length ) {
+					// reset is a jQuery selector, use event delegation
+					$( document )
+						.undelegate( wo.filter_reset, 'click' + c.namespace + 'filter' )
+						.delegate( wo.filter_reset, 'click' + c.namespace + 'filter', function() {
+							// trigger a reset event, so other functions ( filter_formatter ) know when to reset
+							c.$table.triggerHandler( 'filterReset' );
+						});
+				}
+			}
+			if ( wo.filter_functions ) {
+				for ( column = 0; column < c.columns; column++ ) {
+					fxn = ts.getColumnData( table, wo.filter_functions, column );
+					if ( fxn ) {
+						// remove 'filter-select' from header otherwise the options added here are replaced with
+						// all options
+						$header = c.$headerIndexed[ column ].removeClass( 'filter-select' );
+						// don't build select if 'filter-false' or 'parser-false' set
+						noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
+						options = '';
+						if ( fxn === true && noSelect ) {
+							tsf.buildSelect( table, column );
+						} else if ( typeof fxn === 'object' && noSelect ) {
+							// add custom drop down list
+							for ( string in fxn ) {
+								if ( typeof string === 'string' ) {
+									options += options === '' ?
+										'<option value="">' +
+											( $header.data( 'placeholder' ) ||
+												$header.attr( 'data-placeholder' ) ||
+												wo.filter_placeholder.select ||
+												''
+											) +
+										'</option>' : '';
+									val = string;
+									txt = string;
+									if ( string.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
+										val = string.split( wo.filter_selectSourceSeparator );
+										txt = val[1];
+										val = val[0];
+									}
+									options += '<option ' +
+										( txt === val ? '' : 'data-function-name="' + string + '" ' ) +
+										'value="' + val + '">' + txt + '</option>';
+								}
+							}
+							c.$table
+								.find( 'thead' )
+								.find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
+								.append( options );
+							txt = wo.filter_selectSource;
+							fxn = typeof txt === 'function' ? true : ts.getColumnData( table, txt, column );
+							if ( fxn ) {
+								// updating so the extra options are appended
+								tsf.buildSelect( c.table, column, '', true, $header.hasClass( wo.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.
+			tsf.buildDefault( table, true );
+
+			tsf.bindSearch( table, c.$table.find( '.' + tscss.filter ), true );
+			if ( wo.filter_external ) {
+				tsf.bindSearch( table, wo.filter_external );
+			}
+
+			if ( wo.filter_hideFilters ) {
+				tsf.hideFilters( c );
+			}
+
+			// show processing icon
+			if ( c.showProcessing ) {
+				txt = 'filterStart filterEnd '.split( ' ' ).join( c.namespace + 'filter ' );
+				c.$table
+					.unbind( txt.replace( ts.regex.spaces, ' ' ) )
+					.bind( txt, function( event, columns ) {
+					// only add processing to certain columns to all columns
+					$header = ( columns ) ?
+						c.$table
+							.find( '.' + tscss.header )
+							.filter( '[data-column]' )
+							.filter( function() {
+								return columns[ $( this ).data( 'column' ) ] !== '';
+							}) : '';
+					ts.isProcessing( table, event.type === 'filterStart', columns ? $header : '' );
+				});
+			}
+
+			// set filtered rows count ( intially unfiltered )
+			c.filteredRows = c.totalRows;
+
+			// add default values
+			txt = 'tablesorter-initialized pagerBeforeInitialized '.split( ' ' ).join( c.namespace + 'filter ' );
+			c.$table
+			.unbind( txt.replace( ts.regex.spaces, ' ' ) )
+			.bind( txt, function() {
+				tsf.completeInit( this );
+			});
+			// if filter widget is added after pager has initialized; then set filter init flag
+			if ( c.pager && c.pager.initialized && !wo.filter_initialized ) {
+				c.$table.triggerHandler( 'filterFomatterUpdate' );
+				setTimeout( function() {
+					tsf.filterInitComplete( c );
+				}, 100 );
+			} else if ( !wo.filter_initialized ) {
+				tsf.completeInit( table );
+			}
+		},
+		completeInit: function( table ) {
+			// redefine 'c' & 'wo' so they update properly inside this callback
+			var c = table.config,
+				wo = c.widgetOptions,
+				filters = tsf.setDefaults( table, c, wo ) || [];
+			if ( filters.length ) {
+				// prevent delayInit from triggering a cache build if filters are empty
+				if ( !( c.delayInit && filters.join( '' ) === '' ) ) {
+					ts.setFilters( table, filters, true );
+				}
+			}
+			c.$table.triggerHandler( 'filterFomatterUpdate' );
+			// trigger init after setTimeout to prevent multiple filterStart/End/Init triggers
+			setTimeout( function() {
+				if ( !wo.filter_initialized ) {
+					tsf.filterInitComplete( c );
+				}
+			}, 100 );
+		},
+
+		// $cell parameter, but not the config, is passed to the filter_formatters,
+		// so we have to work with it instead
+		formatterUpdated: function( $cell, column ) {
+			// prevent error if $cell is undefined - see #1056
+			var wo = $cell && $cell.closest( 'table' )[0].config.widgetOptions;
+			if ( wo && !wo.filter_initialized ) {
+				// add updates by column since this function
+				// may be called numerous times before initialization
+				wo.filter_formatterInit[ column ] = 1;
+			}
+		},
+		filterInitComplete: function( c ) {
+			var indx, len,
+				wo = c.widgetOptions,
+				count = 0,
+				completed = function() {
+					wo.filter_initialized = true;
+					// update lastSearch - it gets cleared often
+					c.lastSearch = c.$table.data( 'lastSearch' );
+					c.$table.triggerHandler( 'filterInit', c );
+					tsf.findRows( c.table, c.lastSearch || [] );
+				};
+			if ( $.isEmptyObject( wo.filter_formatter ) ) {
+				completed();
+			} else {
+				len = wo.filter_formatterInit.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					if ( wo.filter_formatterInit[ indx ] === 1 ) {
+						count++;
+					}
+				}
+				clearTimeout( wo.filter_initTimer );
+				if ( !wo.filter_initialized && count === wo.filter_formatterCount ) {
+					// filter widget initialized
+					completed();
+				} else if ( !wo.filter_initialized ) {
+					// fall back in case a filter_formatter doesn't call
+					// $.tablesorter.filter.formatterUpdated( $cell, column ), and the count is off
+					wo.filter_initTimer = setTimeout( function() {
+						completed();
+					}, 500 );
+				}
+			}
+		},
+		// encode or decode filters for storage; see #1026
+		processFilters: function( filters, encode ) {
+			var indx,
+				// fixes #1237; previously returning an encoded "filters" value
+				result = [],
+				mode = encode ? encodeURIComponent : decodeURIComponent,
+				len = filters.length;
+			for ( indx = 0; indx < len; indx++ ) {
+				if ( filters[ indx ] ) {
+					result[ indx ] = mode( filters[ indx ] );
+				}
+			}
+			return result;
+		},
+		setDefaults: function( table, c, wo ) {
+			var isArray, saved, indx, col, $filters,
+				// get current ( default ) filters
+				filters = ts.getFilters( table ) || [];
+			if ( wo.filter_saveFilters && ts.storage ) {
+				saved = ts.storage( table, 'tablesorter-filters' ) || [];
+				isArray = $.isArray( saved );
+				// make sure we're not just getting an empty array
+				if ( !( isArray && saved.join( '' ) === '' || !isArray ) ) {
+					filters = tsf.processFilters( saved );
+				}
+			}
+			// if no filters saved, then check default settings
+			if ( filters.join( '' ) === '' ) {
+				// allow adding default setting to external filters
+				$filters = c.$headers.add( wo.filter_$externalFilters )
+					.filter( '[' + wo.filter_defaultAttrib + ']' );
+				for ( indx = 0; indx <= c.columns; indx++ ) {
+					// include data-column='all' external filters
+					col = indx === c.columns ? 'all' : indx;
+					filters[ indx ] = $filters
+						.filter( '[data-column="' + col + '"]' )
+						.attr( wo.filter_defaultAttrib ) || filters[indx] || '';
+				}
+			}
+			c.$table.data( 'lastSearch', filters );
+			return filters;
+		},
+		parseFilter: function( c, filter, data, parsed ) {
+			return parsed || data.parsed[ data.index ] ?
+				c.parsers[ data.index ].format( filter, c.table, [], data.index ) :
+				filter;
+		},
+		buildRow: function( table, c, wo ) {
+			var $filter, col, column, $header, makeSelect, disabled, name, ffxn, tmp,
+				// c.columns defined in computeThIndexes()
+				cellFilter = wo.filter_cellFilter,
+				columns = c.columns,
+				arry = $.isArray( cellFilter ),
+				buildFilter = '<tr role="row" class="' + tscss.filterRow + ' ' + c.cssIgnoreRow + '">';
+			for ( column = 0; column < columns; column++ ) {
+				if ( c.$headerIndexed[ column ].length ) {
+					// account for entire column set with colspan. See #1047
+					tmp = c.$headerIndexed[ column ] && c.$headerIndexed[ column ][0].colSpan || 0;
+					if ( tmp > 1 ) {
+						buildFilter += '<td data-column="' + column + '-' + ( column + tmp - 1 ) + '" colspan="' + tmp + '"';
+					} else {
+						buildFilter += '<td data-column="' + column + '"';
+					}
+					if ( arry ) {
+						buildFilter += ( cellFilter[ column ] ? ' class="' + cellFilter[ column ] + '"' : '' );
+					} else {
+						buildFilter += ( cellFilter !== '' ? ' class="' + cellFilter + '"' : '' );
+					}
+					buildFilter += '></td>';
+				}
+			}
+			c.$filters = $( buildFilter += '</tr>' )
+				.appendTo( c.$table.children( 'thead' ).eq( 0 ) )
+				.children( 'td' );
+			// build each filter input
+			for ( column = 0; column < columns; column++ ) {
+				disabled = false;
+				// assuming last cell of a column is the main column
+				$header = c.$headerIndexed[ column ];
+				if ( $header && $header.length ) {
+					// $filter = c.$filters.filter( '[data-column="' + column + '"]' );
+					$filter = tsf.getColumnElm( c, c.$filters, column );
+					ffxn = ts.getColumnData( table, wo.filter_functions, column );
+					makeSelect = ( wo.filter_functions && ffxn && typeof ffxn !== 'function' ) ||
+						$header.hasClass( 'filter-select' );
+					// get data from jQuery data, metadata, headers option or header class name
+					col = ts.getColumnData( table, c.headers, column );
+					disabled = ts.getData( $header[0], col, 'filter' ) === 'false' ||
+						ts.getData( $header[0], col, 'parser' ) === 'false';
+
+					if ( makeSelect ) {
+						buildFilter = $( '<select>' ).appendTo( $filter );
+					} else {
+						ffxn = ts.getColumnData( table, wo.filter_formatter, column );
+						if ( ffxn ) {
+							wo.filter_formatterCount++;
+							buildFilter = ffxn( $filter, column );
+							// no element returned, so lets go find it
+							if ( buildFilter && buildFilter.length === 0 ) {
+								buildFilter = $filter.children( 'input' );
+							}
+							// element not in DOM, so lets attach it
+							if ( buildFilter && ( buildFilter.parent().length === 0 ||
+								( buildFilter.parent().length && buildFilter.parent()[0] !== $filter[0] ) ) ) {
+								$filter.append( buildFilter );
+							}
+						} else {
+							buildFilter = $( '<input type="search">' ).appendTo( $filter );
+						}
+						if ( buildFilter ) {
+							tmp = $header.data( 'placeholder' ) ||
+								$header.attr( 'data-placeholder' ) ||
+								wo.filter_placeholder.search || '';
+							buildFilter.attr( 'placeholder', tmp );
+						}
+					}
+					if ( buildFilter ) {
+						// add filter class name
+						name = ( $.isArray( wo.filter_cssFilter ) ?
+							( typeof wo.filter_cssFilter[column] !== 'undefined' ? wo.filter_cssFilter[column] || '' : '' ) :
+							wo.filter_cssFilter ) || '';
+						// copy data-column from table cell (it will include colspan)
+						buildFilter.addClass( tscss.filter + ' ' + name ).attr( 'data-column', $filter.attr( 'data-column' ) );
+						if ( disabled ) {
+							buildFilter.attr( 'placeholder', '' ).addClass( tscss.filterDisabled )[0].disabled = true;
+						}
+					}
+				}
+			}
+		},
+		bindSearch: function( table, $el, internal ) {
+			table = $( table )[0];
+			$el = $( $el ); // allow passing a selector string
+			if ( !$el.length ) { return; }
+			var tmp,
+				c = table.config,
+				wo = c.widgetOptions,
+				namespace = c.namespace + 'filter',
+				$ext = wo.filter_$externalFilters;
+			if ( internal !== true ) {
+				// save anyMatch element
+				tmp = wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector;
+				wo.filter_$anyMatch = $el.filter( tmp );
+				if ( $ext && $ext.length ) {
+					wo.filter_$externalFilters = wo.filter_$externalFilters.add( $el );
+				} else {
+					wo.filter_$externalFilters = $el;
+				}
+				// update values ( external filters added after table initialization )
+				ts.setFilters( table, c.$table.data( 'lastSearch' ) || [], internal === false );
+			}
+			// unbind events
+			tmp = ( 'keypress keyup keydown search change input '.split( ' ' ).join( namespace + ' ' ) );
+			$el
+			// use data attribute instead of jQuery data since the head is cloned without including
+			// the data/binding
+			.attr( 'data-lastSearchTime', new Date().getTime() )
+			.unbind( tmp.replace( ts.regex.spaces, ' ' ) )
+			.bind( 'keydown' + namespace, function( event ) {
+				if ( event.which === tskeyCodes.escape && !table.config.widgetOptions.filter_resetOnEsc ) {
+					// prevent keypress event
+					return false;
+				}
+			})
+			.bind( 'keyup' + namespace, function( event ) {
+				wo = table.config.widgetOptions; // make sure "wo" isn't cached
+				var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
+					liveSearch = typeof wo.filter_liveSearch === 'boolean' ? wo.filter_liveSearch :
+						ts.getColumnData( table, wo.filter_liveSearch, column );
+				if ( typeof liveSearch === 'undefined' ) {
+					liveSearch = wo.filter_liveSearch.fallback || false;
+				}
+				$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
+				// emulate what webkit does.... escape clears the filter
+				if ( event.which === tskeyCodes.escape ) {
+					// make sure to restore the last value on escape
+					this.value = wo.filter_resetOnEsc ? '' : c.lastSearch[column];
+				// live search
+				} else if ( liveSearch === false ) {
+					return;
+					// don't return if the search value is empty ( all rows need to be revealed )
+				} else if ( this.value !== '' && (
+					// liveSearch can contain a min value length; ignore arrow and meta keys, but allow backspace
+					( typeof liveSearch === 'number' && this.value.length < liveSearch ) ||
+					// let return & backspace continue on, but ignore arrows & non-valid characters
+					( event.which !== tskeyCodes.enter && event.which !== tskeyCodes.backSpace &&
+						( event.which < tskeyCodes.space || ( event.which >= tskeyCodes.left && event.which <= tskeyCodes.down ) ) ) ) ) {
+					return;
+				}
+				// change event = no delay; last true flag tells getFilters to skip newest timed input
+				tsf.searching( table, true, true, column );
+			})
+			// include change for select - fixes #473
+			.bind( 'search change keypress input '.split( ' ' ).join( namespace + ' ' ), function( event ) {
+				// don't get cached data, in case data-column changes dynamically
+				var column = parseInt( $( this ).attr( 'data-column' ), 10 ),
+					liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
+						wo.filter_liveSearch :
+						ts.getColumnData( table, wo.filter_liveSearch, column );
+				if ( table.config.widgetOptions.filter_initialized &&
+					// immediate search if user presses enter
+					( event.which === tskeyCodes.enter ||
+						// immediate search if a "search" is triggered on the input
+						event.type === 'search' ||
+						// change & input events must be ignored if liveSearch !== true
+						( event.type === 'change' || event.type === 'input' ) &&
+						// prevent search if liveSearch is a number
+						liveSearch === true &&
+						// don't allow 'change' or 'input' event to process if the input value
+						// is the same - fixes #685
+						this.value !== c.lastSearch[column]
+					)
+				) {
+					event.preventDefault();
+					// init search with no delay
+					$( this ).attr( 'data-lastSearchTime', new Date().getTime() );
+					tsf.searching( table, event.type !== 'keypress', true, column );
+				}
+			});
+		},
+		searching: function( table, filter, skipFirst, column ) {
+			var liveSearch,
+				wo = table.config.widgetOptions;
+			if (typeof column === 'undefined') {
+				// no delay
+				liveSearch = false;
+			} else {
+				liveSearch = typeof wo.filter_liveSearch === 'boolean' ?
+					wo.filter_liveSearch :
+					// get column setting, or set to fallback value, or default to false
+					ts.getColumnData( table, wo.filter_liveSearch, column );
+				if ( typeof liveSearch === 'undefined' ) {
+					liveSearch = wo.filter_liveSearch.fallback || false;
+				}
+			}
+			clearTimeout( wo.filter_searchTimer );
+			if ( typeof filter === 'undefined' || filter === true ) {
+				// delay filtering
+				wo.filter_searchTimer = setTimeout( function() {
+					tsf.checkFilters( table, filter, skipFirst );
+				}, liveSearch ? wo.filter_searchDelay : 10 );
+			} else {
+				// skip delay
+				tsf.checkFilters( table, filter, skipFirst );
+			}
+		},
+		checkFilters: function( table, filter, skipFirst ) {
+			var c = table.config,
+				wo = c.widgetOptions,
+				filterArray = $.isArray( filter ),
+				filters = ( filterArray ) ? filter : ts.getFilters( table, true ),
+				combinedFilters = ( filters || [] ).join( '' ); // combined filter values
+			// prevent errors if delay init is set
+			if ( $.isEmptyObject( c.cache ) ) {
+				// update cache if delayInit set & pager has initialized ( after user initiates a search )
+				if ( c.delayInit && ( !c.pager || c.pager && c.pager.initialized ) ) {
+					ts.updateCache( c, function() {
+						tsf.checkFilters( table, false, skipFirst );
+					});
+				}
+				return;
+			}
+			// add filter array back into inputs
+			if ( filterArray ) {
+				ts.setFilters( table, filters, false, skipFirst !== true );
+				if ( !wo.filter_initialized ) { c.lastCombinedFilter = ''; }
+			}
+			if ( wo.filter_hideFilters ) {
+				// show/hide filter row as needed
+				c.$table
+					.find( '.' + tscss.filterRow )
+					.triggerHandler( tsf.hideFiltersCheck( c ) ? 'mouseleave' : 'mouseenter' );
+			}
+			// return if the last search is the same; but filter === false when updating the search
+			// see example-widget-filter.html filter toggle buttons
+			if ( c.lastCombinedFilter === combinedFilters && filter !== false ) {
+				return;
+			} else if ( filter === false ) {
+				// force filter refresh
+				c.lastCombinedFilter = null;
+				c.lastSearch = [];
+			}
+			// define filter inside it is false
+			filters = filters || [];
+			// convert filters to strings - see #1070
+			filters = Array.prototype.map ?
+				filters.map( String ) :
+				// for IE8 & older browsers - maybe not the best method
+				filters.join( '\ufffd' ).split( '\ufffd' );
+
+			if ( wo.filter_initialized ) {
+				c.$table.triggerHandler( 'filterStart', [ filters ] );
+			}
+			if ( c.showProcessing ) {
+				// give it time for the processing icon to kick in
+				setTimeout( function() {
+					tsf.findRows( table, filters, combinedFilters );
+					return false;
+				}, 30 );
+			} else {
+				tsf.findRows( table, filters, combinedFilters );
+				return false;
+			}
+		},
+		hideFiltersCheck: function( c ) {
+			if (typeof c.widgetOptions.filter_hideFilters === 'function') {
+				var val = c.widgetOptions.filter_hideFilters( c );
+				if (typeof val === 'boolean') {
+					return val;
+				}
+			}
+			return ts.getFilters( c.$table ).join( '' ) === '';
+		},
+		hideFilters: function( c, $table ) {
+			var timer;
+			( $table || c.$table )
+				.find( '.' + tscss.filterRow )
+				.addClass( tscss.filterRowHide )
+				.bind( 'mouseenter mouseleave', function( e ) {
+					// save event object - http://bugs.jquery.com/ticket/12140
+					var event = e,
+						$row = $( this );
+					clearTimeout( timer );
+					timer = setTimeout( function() {
+						if ( /enter|over/.test( event.type ) ) {
+							$row.removeClass( tscss.filterRowHide );
+						} else {
+							// don't hide if input has focus
+							// $( ':focus' ) needs jQuery 1.6+
+							if ( $( document.activeElement ).closest( 'tr' )[0] !== $row[0] ) {
+								// don't hide row if any filter has a value
+								$row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) );
+							}
+						}
+					}, 200 );
+				})
+				.find( 'input, select' ).bind( 'focus blur', function( e ) {
+					var event = e,
+						$row = $( this ).closest( 'tr' );
+					clearTimeout( timer );
+					timer = setTimeout( function() {
+						clearTimeout( timer );
+						// don't hide row if any filter has a value
+						$row.toggleClass( tscss.filterRowHide, tsf.hideFiltersCheck( c ) && event.type !== 'focus' );
+					}, 200 );
+				});
+		},
+		defaultFilter: function( filter, mask ) {
+			if ( filter === '' ) { return filter; }
+			var regex = tsfRegex.iQuery,
+				maskLen = mask.match( tsfRegex.igQuery ).length,
+				query = maskLen > 1 ? $.trim( filter ).split( /\s/ ) : [ $.trim( filter ) ],
+				len = query.length - 1,
+				indx = 0,
+				val = mask;
+			if ( len < 1 && maskLen > 1 ) {
+				// only one 'word' in query but mask has >1 slots
+				query[1] = query[0];
+			}
+			// 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'
+			while ( regex.test( val ) ) {
+				val = val.replace( regex, query[indx++] || '' );
+				if ( regex.test( val ) && indx < len && ( query[indx] || '' ) !== '' ) {
+					val = mask.replace( regex, val );
+				}
+			}
+			return val;
+		},
+		getLatestSearch: function( $input ) {
+			if ( $input ) {
+				return $input.sort( function( a, b ) {
+					return $( b ).attr( 'data-lastSearchTime' ) - $( a ).attr( 'data-lastSearchTime' );
+				});
+			}
+			return $input || $();
+		},
+		findRange: function( c, val, ignoreRanges ) {
+			// look for multiple columns '1-3,4-6,8' in data-column
+			var temp, ranges, range, start, end, singles, i, indx, len,
+				columns = [];
+			if ( /^[0-9]+$/.test( val ) ) {
+				// always return an array
+				return [ parseInt( val, 10 ) ];
+			}
+			// process column range
+			if ( !ignoreRanges && /-/.test( val ) ) {
+				ranges = val.match( /(\d+)\s*-\s*(\d+)/g );
+				len = ranges ? ranges.length : 0;
+				for ( indx = 0; indx < len; indx++ ) {
+					range = ranges[indx].split( /\s*-\s*/ );
+					start = parseInt( range[0], 10 ) || 0;
+					end = parseInt( range[1], 10 ) || ( c.columns - 1 );
+					if ( start > end ) {
+						temp = start; start = end; end = temp; // swap
+					}
+					if ( end >= c.columns ) {
+						end = c.columns - 1;
+					}
+					for ( ; start <= end; start++ ) {
+						columns[ columns.length ] = start;
+					}
+					// remove processed range from val
+					val = val.replace( ranges[ indx ], '' );
+				}
+			}
+			// process single columns
+			if ( !ignoreRanges && /,/.test( val ) ) {
+				singles = val.split( /\s*,\s*/ );
+				len = singles.length;
+				for ( i = 0; i < len; i++ ) {
+					if ( singles[ i ] !== '' ) {
+						indx = parseInt( singles[ i ], 10 );
+						if ( indx < c.columns ) {
+							columns[ columns.length ] = indx;
+						}
+					}
+				}
+			}
+			// return all columns
+			if ( !columns.length ) {
+				for ( indx = 0; indx < c.columns; indx++ ) {
+					columns[ columns.length ] = indx;
+				}
+			}
+			return columns;
+		},
+		getColumnElm: function( c, $elements, column ) {
+			// data-column may contain multiple columns '1-3,5-6,8'
+			// replaces: c.$filters.filter( '[data-column="' + column + '"]' );
+			return $elements.filter( function() {
+				var cols = tsf.findRange( c, $( this ).attr( 'data-column' ) );
+				return $.inArray( column, cols ) > -1;
+			});
+		},
+		multipleColumns: function( c, $input ) {
+			// look for multiple columns '1-3,4-6,8' in data-column
+			var wo = c.widgetOptions,
+				// only target 'all' column inputs on initialization
+				// & don't target 'all' column inputs if they don't exist
+				targets = wo.filter_initialized || !$input.filter( wo.filter_anyColumnSelector ).length,
+				val = $.trim( tsf.getLatestSearch( $input ).attr( 'data-column' ) || '' );
+			return tsf.findRange( c, val, !targets );
+		},
+		processTypes: function( c, data, vars ) {
+			var ffxn,
+				filterMatched = null,
+				matches = null;
+			for ( ffxn in tsf.types ) {
+				if ( $.inArray( ffxn, vars.excludeMatch ) < 0 && matches === null ) {
+					matches = tsf.types[ffxn]( c, data, vars );
+					if ( matches !== null ) {
+						filterMatched = matches;
+					}
+				}
+			}
+			return filterMatched;
+		},
+		matchType: function( c, columnIndex ) {
+			var isMatch,
+				wo = c.widgetOptions,
+				$el = c.$headerIndexed[ columnIndex ];
+			// filter-exact > filter-match > filter_matchType for type
+			if ( $el.hasClass( 'filter-exact' ) ) {
+				isMatch = false;
+			} else if ( $el.hasClass( 'filter-match' ) ) {
+				isMatch = true;
+			} else {
+				// filter-select is not applied when filter_functions are used, so look for a select
+				if ( wo.filter_columnFilters ) {
+					$el = c.$filters
+						.find( '.' + tscss.filter )
+						.add( wo.filter_$externalFilters )
+						.filter( '[data-column="' + columnIndex + '"]' );
+				} else if ( wo.filter_$externalFilters ) {
+					$el = wo.filter_$externalFilters.filter( '[data-column="' + columnIndex + '"]' );
+				}
+				isMatch = $el.length ?
+					c.widgetOptions.filter_matchType[ ( $el[ 0 ].nodeName || '' ).toLowerCase() ] === 'match' :
+					// default to exact, if no inputs found
+					false;
+			}
+			return isMatch;
+		},
+		processRow: function( c, data, vars ) {
+			var result, filterMatched,
+				fxn, ffxn, txt,
+				wo = c.widgetOptions,
+				showRow = true,
+				hasAnyMatchInput = wo.filter_$anyMatch && wo.filter_$anyMatch.length,
+
+				// 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
+				columnIndex = wo.filter_$anyMatch && wo.filter_$anyMatch.length ?
+					// look for multiple columns '1-3,4-6,8'
+					tsf.multipleColumns( c, wo.filter_$anyMatch ) :
+					[];
+			data.$cells = data.$row.children();
+			if ( data.anyMatchFlag && columnIndex.length > 1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
+				data.anyMatch = true;
+				data.isMatch = true;
+				data.rowArray = data.$cells.map( function( i ) {
+					if ( $.inArray( i, columnIndex ) > -1 || ( data.anyMatchFilter && !hasAnyMatchInput ) ) {
+						if ( data.parsed[ i ] ) {
+							txt = data.cacheArray[ i ];
+						} else {
+							txt = data.rawArray[ i ];
+							txt = $.trim( wo.filter_ignoreCase ? txt.toLowerCase() : txt );
+							if ( c.sortLocaleCompare ) {
+								txt = ts.replaceAccents( txt );
+							}
+						}
+						return txt;
+					}
+				}).get();
+				data.filter = data.anyMatchFilter;
+				data.iFilter = data.iAnyMatchFilter;
+				data.exact = data.rowArray.join( ' ' );
+				data.iExact = wo.filter_ignoreCase ? data.exact.toLowerCase() : data.exact;
+				data.cache = data.cacheArray.slice( 0, -1 ).join( ' ' );
+				vars.excludeMatch = vars.noAnyMatch;
+				filterMatched = tsf.processTypes( c, data, vars );
+				if ( filterMatched !== null ) {
+					showRow = filterMatched;
+				} else {
+					if ( wo.filter_startsWith ) {
+						showRow = false;
+						// data.rowArray may not contain all columns
+						columnIndex = Math.min( c.columns, data.rowArray.length );
+						while ( !showRow && columnIndex > 0 ) {
+							columnIndex--;
+							showRow = showRow || data.rowArray[ columnIndex ].indexOf( data.iFilter ) === 0;
+						}
+					} else {
+						showRow = ( data.iExact + data.childRowText ).indexOf( data.iFilter ) >= 0;
+					}
+				}
+				data.anyMatch = false;
+				// no other filters to process
+				if ( data.filters.join( '' ) === data.filter ) {
+					return showRow;
+				}
+			}
+
+			for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
+				data.filter = data.filters[ columnIndex ];
+				data.index = columnIndex;
+
+				// filter types to exclude, per column
+				vars.excludeMatch = vars.excludeFilter[ columnIndex ];
+
+				// ignore if filter is empty or disabled
+				if ( data.filter ) {
+					data.cache = data.cacheArray[ columnIndex ];
+					result = data.parsed[ columnIndex ] ? data.cache : data.rawArray[ columnIndex ] || '';
+					data.exact = c.sortLocaleCompare ? ts.replaceAccents( result ) : result; // issue #405
+					data.iExact = !tsfRegex.type.test( typeof data.exact ) && wo.filter_ignoreCase ?
+						data.exact.toLowerCase() : data.exact;
+					data.isMatch = tsf.matchType( c, columnIndex );
+
+					result = showRow; // if showRow is true, show that row
+
+					// in case select filter option has a different value vs text 'a - z|A through Z'
+					ffxn = wo.filter_columnFilters ?
+						c.$filters.add( wo.filter_$externalFilters )
+							.filter( '[data-column="' + columnIndex + '"]' )
+							.find( 'select option:selected' )
+							.attr( 'data-function-name' ) || '' : '';
+					// replace accents - see #357
+					if ( c.sortLocaleCompare ) {
+						data.filter = ts.replaceAccents( data.filter );
+					}
+
+					// replace column specific default filters - see #1088
+					if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultColFilter[ columnIndex ] ) ) {
+						data.filter = tsf.defaultFilter( data.filter, vars.defaultColFilter[ columnIndex ] );
+					}
+
+					// data.iFilter = case insensitive ( if wo.filter_ignoreCase is true ),
+					// data.filter = case sensitive
+					data.iFilter = wo.filter_ignoreCase ? ( data.filter || '' ).toLowerCase() : data.filter;
+					fxn = vars.functions[ columnIndex ];
+					filterMatched = null;
+					if ( fxn ) {
+						if ( fxn === true ) {
+							// default selector uses exact match unless 'filter-match' class is found
+							filterMatched = data.isMatch ?
+								// data.iExact may be a number
+								( '' + data.iExact ).search( data.iFilter ) >= 0 :
+								data.filter === data.exact;
+						} else if ( typeof fxn === 'function' ) {
+							// filter callback( exact cell content, parser normalized content,
+							// filter input value, column index, jQuery row object )
+							filterMatched = fxn( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
+						} else if ( typeof fxn[ ffxn || data.filter ] === 'function' ) {
+							// selector option function
+							txt = ffxn || data.filter;
+							filterMatched =
+								fxn[ txt ]( data.exact, data.cache, data.filter, columnIndex, data.$row, c, data );
+						}
+					}
+					if ( filterMatched === null ) {
+						// cycle through the different filters
+						// filters return a boolean or null if nothing matches
+						filterMatched = tsf.processTypes( c, data, vars );
+						if ( filterMatched !== null ) {
+							result = filterMatched;
+						// Look for match, and add child row data for matching
+						} else {
+							txt = ( data.iExact + data.childRowText ).indexOf( tsf.parseFilter( c, data.iFilter, data ) );
+							result = ( ( !wo.filter_startsWith && txt >= 0 ) || ( wo.filter_startsWith && txt === 0 ) );
+						}
+					} else {
+						result = filterMatched;
+					}
+					showRow = ( result ) ? showRow : false;
+				}
+			}
+			return showRow;
+		},
+		findRows: function( table, filters, combinedFilters ) {
+			if ( table.config.lastCombinedFilter === combinedFilters ||
+				!table.config.widgetOptions.filter_initialized ) {
+				return;
+			}
+			var len, norm_rows, rowData, $rows, $row, rowIndex, tbodyIndex, $tbody, columnIndex,
+				isChild, childRow, lastSearch, showRow, showParent, time, val, indx,
+				notFiltered, searchFiltered, query, injected, res, id, txt,
+				storedFilters = $.extend( [], filters ),
+				c = table.config,
+				wo = c.widgetOptions,
+				// data object passed to filters; anyMatch is a flag for the filters
+				data = {
+					anyMatch: false,
+					filters: filters,
+					// regex filter type cache
+					filter_regexCache : []
+				},
+				vars = {
+					// anyMatch really screws up with these types of filters
+					noAnyMatch: [ 'range',  'operators' ],
+					// cache filter variables that use ts.getColumnData in the main loop
+					functions : [],
+					excludeFilter : [],
+					defaultColFilter : [],
+					defaultAnyFilter : ts.getColumnData( table, wo.filter_defaultFilter, c.columns, true ) || ''
+				};
+
+			// parse columns after formatter, in case the class is added at that point
+			data.parsed = [];
+			for ( columnIndex = 0; columnIndex < c.columns; columnIndex++ ) {
+				data.parsed[ columnIndex ] = wo.filter_useParsedData ||
+					// parser has a "parsed" parameter
+					( c.parsers && c.parsers[ columnIndex ] && c.parsers[ columnIndex ].parsed ||
+					// getData may not return 'parsed' if other 'filter-' class names exist
+					// ( e.g. <th class="filter-select filter-parsed"> )
+					ts.getData && ts.getData( c.$headerIndexed[ columnIndex ],
+						ts.getColumnData( table, c.headers, columnIndex ), 'filter' ) === 'parsed' ||
+					c.$headerIndexed[ columnIndex ].hasClass( 'filter-parsed' ) );
+
+				vars.functions[ columnIndex ] =
+					ts.getColumnData( table, wo.filter_functions, columnIndex ) ||
+					c.$headerIndexed[ columnIndex ].hasClass( 'filter-select' );
+				vars.defaultColFilter[ columnIndex ] =
+					ts.getColumnData( table, wo.filter_defaultFilter, columnIndex ) || '';
+				vars.excludeFilter[ columnIndex ] =
+					( ts.getColumnData( table, wo.filter_excludeFilter, columnIndex, true ) || '' ).split( /\s+/ );
+			}
+
+			if ( c.debug ) {
+				console.log( 'Filter: Starting filter widget search', filters );
+				time = new Date();
+			}
+			// filtered rows count
+			c.filteredRows = 0;
+			c.totalRows = 0;
+			// combindedFilters are undefined on init
+			combinedFilters = ( storedFilters || [] ).join( '' );
+
+			for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
+				$tbody = ts.processTbody( table, c.$tbodies.eq( tbodyIndex ), true );
+				// skip child rows & widget added ( removable ) rows - fixes #448 thanks to @hempel!
+				// $rows = $tbody.children( 'tr' ).not( c.selectorRemove );
+				columnIndex = c.columns;
+				// convert stored rows into a jQuery object
+				norm_rows = c.cache[ tbodyIndex ].normalized;
+				$rows = $( $.map( norm_rows, function( el ) {
+					return el[ columnIndex ].$row.get();
+				}) );
+
+				if ( combinedFilters === '' || wo.filter_serversideFiltering ) {
+					$rows
+						.removeClass( wo.filter_filteredRow )
+						.not( '.' + c.cssChildRow )
+						.css( 'display', '' );
+				} else {
+					// filter out child rows
+					$rows = $rows.not( '.' + c.cssChildRow );
+					len = $rows.length;
+
+					if ( ( wo.filter_$anyMatch && wo.filter_$anyMatch.length ) ||
+						typeof filters[c.columns] !== 'undefined' ) {
+						data.anyMatchFlag = true;
+						data.anyMatchFilter = '' + (
+							filters[ c.columns ] ||
+							wo.filter_$anyMatch && tsf.getLatestSearch( wo.filter_$anyMatch ).val() ||
+							''
+						);
+						if ( wo.filter_columnAnyMatch ) {
+							// specific columns search
+							query = data.anyMatchFilter.split( tsfRegex.andSplit );
+							injected = false;
+							for ( indx = 0; indx < query.length; indx++ ) {
+								res = query[ indx ].split( ':' );
+								if ( res.length > 1 ) {
+									// make the column a one-based index ( non-developers start counting from one :P )
+									if ( isNaN( res[0] ) ) {
+										$.each( c.headerContent, function( i, txt ) {
+											// multiple matches are possible
+											if ( txt.toLowerCase().indexOf( res[0] ) > -1 ) {
+												id = i;
+												filters[ id ] = res[1];
+											}
+										});
+									} else {
+										id = parseInt( res[0], 10 ) - 1;
+									}
+									if ( id >= 0 && id < c.columns ) { // if id is an integer
+										filters[ id ] = res[1];
+										query.splice( indx, 1 );
+										indx--;
+										injected = true;
+									}
+								}
+							}
+							if ( injected ) {
+								data.anyMatchFilter = query.join( ' && ' );
+							}
+						}
+					}
+
+					// optimize searching only through already filtered rows - see #313
+					searchFiltered = wo.filter_searchFiltered;
+					lastSearch = c.lastSearch || c.$table.data( 'lastSearch' ) || [];
+					if ( searchFiltered ) {
+						// cycle through all filters; include last ( columnIndex + 1 = match any column ). Fixes #669
+						for ( indx = 0; indx < columnIndex + 1; indx++ ) {
+							val = filters[indx] || '';
+							// break out of loop if we've already determined not to search filtered rows
+							if ( !searchFiltered ) { indx = columnIndex; }
+							// search already filtered rows if...
+							searchFiltered = searchFiltered && lastSearch.length &&
+								// there are no changes from beginning of filter
+								val.indexOf( lastSearch[indx] || '' ) === 0 &&
+								// if there is NOT a logical 'or', or range ( 'to' or '-' ) in the string
+								!tsfRegex.alreadyFiltered.test( val ) &&
+								// if we are not doing exact matches, using '|' ( logical or ) or not '!'
+								!tsfRegex.exactTest.test( val ) &&
+								// don't search only filtered if the value is negative
+								// ( '> -10' => '> -100' will ignore hidden rows )
+								!( tsfRegex.isNeg1.test( val ) || tsfRegex.isNeg2.test( val ) ) &&
+								// if filtering using a select without a 'filter-match' class ( exact match ) - fixes #593
+								!( val !== '' && c.$filters && c.$filters.filter( '[data-column="' + indx + '"]' ).find( 'select' ).length &&
+									!tsf.matchType( c, indx ) );
+						}
+					}
+					notFiltered = $rows.not( '.' + wo.filter_filteredRow ).length;
+					// can't search when all rows are hidden - this happens when looking for exact matches
+					if ( searchFiltered && notFiltered === 0 ) { searchFiltered = false; }
+					if ( c.debug ) {
+						console.log( 'Filter: Searching through ' +
+							( searchFiltered && notFiltered < len ? notFiltered : 'all' ) + ' rows' );
+					}
+					if ( data.anyMatchFlag ) {
+						if ( c.sortLocaleCompare ) {
+							// replace accents
+							data.anyMatchFilter = ts.replaceAccents( data.anyMatchFilter );
+						}
+						if ( wo.filter_defaultFilter && tsfRegex.iQuery.test( vars.defaultAnyFilter ) ) {
+							data.anyMatchFilter = tsf.defaultFilter( data.anyMatchFilter, vars.defaultAnyFilter );
+							// clear search filtered flag because default filters are not saved to the last search
+							searchFiltered = false;
+						}
+						// make iAnyMatchFilter lowercase unless both filter widget & core ignoreCase options are true
+						// when c.ignoreCase is true, the cache contains all lower case data
+						data.iAnyMatchFilter = !( wo.filter_ignoreCase && c.ignoreCase ) ?
+							data.anyMatchFilter :
+							data.anyMatchFilter.toLowerCase();
+					}
+
+					// loop through the rows
+					for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
+
+						txt = $rows[ rowIndex ].className;
+						// the first row can never be a child row
+						isChild = rowIndex && tsfRegex.child.test( txt );
+						// skip child rows & already filtered rows
+						if ( isChild || ( searchFiltered && tsfRegex.filtered.test( txt ) ) ) {
+							continue;
+						}
+
+						data.$row = $rows.eq( rowIndex );
+						data.rowIndex = rowIndex;
+						data.cacheArray = norm_rows[ rowIndex ];
+						rowData = data.cacheArray[ c.columns ];
+						data.rawArray = rowData.raw;
+						data.childRowText = '';
+
+						if ( !wo.filter_childByColumn ) {
+							txt = '';
+							// child row cached text
+							childRow = rowData.child;
+							// 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 ( indx = 0; indx < childRow.length; indx++ ) {
+								txt += ' ' + childRow[indx].join( ' ' ) || '';
+							}
+							data.childRowText = wo.filter_childRows ?
+								( wo.filter_ignoreCase ? txt.toLowerCase() : txt ) :
+								'';
+						}
+
+						showRow = false;
+						showParent = tsf.processRow( c, data, vars );
+						$row = rowData.$row;
+
+						// don't pass reference to val
+						val = showParent ? true : false;
+						childRow = rowData.$row.filter( ':gt(0)' );
+						if ( wo.filter_childRows && childRow.length ) {
+							if ( wo.filter_childByColumn ) {
+								if ( !wo.filter_childWithSibs ) {
+									// hide all child rows
+									childRow.addClass( wo.filter_filteredRow );
+									// if only showing resulting child row, only include parent
+									$row = $row.eq( 0 );
+								}
+								// cycle through each child row
+								for ( indx = 0; indx < childRow.length; indx++ ) {
+									data.$row = childRow.eq( indx );
+									data.cacheArray = rowData.child[ indx ];
+									data.rawArray = data.cacheArray;
+									val = tsf.processRow( c, data, vars );
+									// use OR comparison on child rows
+									showRow = showRow || val;
+									if ( !wo.filter_childWithSibs && val ) {
+										childRow.eq( indx ).removeClass( wo.filter_filteredRow );
+									}
+								}
+							}
+							// keep parent row match even if no child matches... see #1020
+							showRow = showRow || showParent;
+						} else {
+							showRow = val;
+						}
+						$row
+							.toggleClass( wo.filter_filteredRow, !showRow )[0]
+							.display = showRow ? '' : 'none';
+					}
+				}
+				c.filteredRows += $rows.not( '.' + wo.filter_filteredRow ).length;
+				c.totalRows += $rows.length;
+				ts.processTbody( table, $tbody, false );
+			}
+			c.lastCombinedFilter = combinedFilters; // save last search
+			// don't save 'filters' directly since it may have altered ( AnyMatch column searches )
+			c.lastSearch = storedFilters;
+			c.$table.data( 'lastSearch', storedFilters );
+			if ( wo.filter_saveFilters && ts.storage ) {
+				ts.storage( table, 'tablesorter-filters', tsf.processFilters( storedFilters, true ) );
+			}
+			if ( c.debug ) {
+				console.log( 'Completed filter widget search' + ts.benchmark(time) );
+			}
+			if ( wo.filter_initialized ) {
+				c.$table.triggerHandler( 'filterBeforeEnd', c );
+				c.$table.triggerHandler( 'filterEnd', c );
+			}
+			setTimeout( function() {
+				ts.applyWidget( c.table ); // make sure zebra widget is applied
+			}, 0 );
+		},
+		getOptionSource: function( table, column, onlyAvail ) {
+			table = $( table )[0];
+			var c = table.config,
+				wo = c.widgetOptions,
+				arry = false,
+				source = wo.filter_selectSource,
+				last = c.$table.data( 'lastSearch' ) || [],
+				fxn = typeof source === 'function' ? true : ts.getColumnData( table, source, column );
+
+			if ( onlyAvail && last[column] !== '' ) {
+				onlyAvail = false;
+			}
+
+			// filter select source option
+			if ( fxn === true ) {
+				// OVERALL source
+				arry = source( table, column, onlyAvail );
+			} else if ( fxn instanceof $ || ( $.type( fxn ) === 'string' && fxn.indexOf( '</option>' ) >= 0 ) ) {
+				// selectSource is a jQuery object or string of options
+				return fxn;
+			} else if ( $.isArray( fxn ) ) {
+				arry = fxn;
+			} else if ( $.type( source ) === 'object' && fxn ) {
+				// custom select source function for a SPECIFIC COLUMN
+				arry = fxn( table, column, onlyAvail );
+			}
+			if ( arry === false ) {
+				// fall back to original method
+				arry = tsf.getOptions( table, column, onlyAvail );
+			}
+
+			return tsf.processOptions( table, column, arry );
+
+		},
+		processOptions: function( table, column, arry ) {
+			if ( !$.isArray( arry ) ) {
+				return false;
+			}
+			table = $( table )[0];
+			var cts, txt, indx, len, parsedTxt, str,
+				c = table.config,
+				validColumn = typeof column !== 'undefined' && column !== null && column >= 0 && column < c.columns,
+				direction = validColumn ? c.$headerIndexed[ column ].hasClass( 'filter-select-sort-desc' ) : false,
+				parsed = [];
+			// get unique elements and sort the list
+			// if $.tablesorter.sortText exists ( not in the original tablesorter ),
+			// then natural sort the list otherwise use a basic sort
+			arry = $.grep( arry, function( value, indx ) {
+				if ( value.text ) {
+					return true;
+				}
+				return $.inArray( value, arry ) === indx;
+			});
+			if ( validColumn && c.$headerIndexed[ column ].hasClass( 'filter-select-nosort' ) ) {
+				// unsorted select options
+				return arry;
+			} else {
+				len = arry.length;
+				// parse select option values
+				for ( indx = 0; indx < len; indx++ ) {
+					txt = arry[ indx ];
+					// check for object
+					str = txt.text ? txt.text : txt;
+					// sortNatural breaks if you don't pass it strings
+					parsedTxt = ( validColumn && c.parsers && c.parsers.length &&
+						c.parsers[ column ].format( str, table, [], column ) || str ).toString();
+					parsedTxt = c.widgetOptions.filter_ignoreCase ? parsedTxt.toLowerCase() : parsedTxt;
+					// parse array data using set column parser; this DOES NOT pass the original
+					// table cell to the parser format function
+					if ( txt.text ) {
+						txt.parsed = parsedTxt;
+						parsed[ parsed.length ] = txt;
+					} else {
+						parsed[ parsed.length ] = {
+							text : txt,
+							// check parser length - fixes #934
+							parsed : parsedTxt
+						};
+					}
+				}
+				// sort parsed select options
+				cts = c.textSorter || '';
+				parsed.sort( function( a, b ) {
+					var x = direction ? b.parsed : a.parsed,
+						y = direction ? a.parsed : b.parsed;
+					if ( validColumn && typeof cts === 'function' ) {
+						// custom OVERALL text sorter
+						return cts( x, y, true, column, table );
+					} else if ( validColumn && typeof cts === 'object' && cts.hasOwnProperty( column ) ) {
+						// custom text sorter for a SPECIFIC COLUMN
+						return cts[column]( x, y, true, column, table );
+					} else if ( ts.sortNatural ) {
+						// fall back to natural sort
+						return ts.sortNatural( x, y );
+					}
+					// using an older version! do a basic sort
+					return true;
+				});
+				// rebuild arry from sorted parsed data
+				arry = [];
+				len = parsed.length;
+				for ( indx = 0; indx < len; indx++ ) {
+					arry[ arry.length ] = parsed[indx];
+				}
+				return arry;
+			}
+		},
+		getOptions: function( table, column, onlyAvail ) {
+			table = $( table )[0];
+			var rowIndex, tbodyIndex, len, row, cache, indx, child, childLen,
+				c = table.config,
+				wo = c.widgetOptions,
+				arry = [];
+			for ( tbodyIndex = 0; tbodyIndex < c.$tbodies.length; tbodyIndex++ ) {
+				cache = c.cache[tbodyIndex];
+				len = c.cache[tbodyIndex].normalized.length;
+				// loop through the rows
+				for ( rowIndex = 0; rowIndex < len; rowIndex++ ) {
+					// get cached row from cache.row ( old ) or row data object
+					// ( new; last item in normalized array )
+					row = cache.row ?
+						cache.row[ rowIndex ] :
+						cache.normalized[ rowIndex ][ c.columns ].$row[0];
+					// check if has class filtered
+					if ( onlyAvail && row.className.match( wo.filter_filteredRow ) ) {
+						continue;
+					}
+					// get non-normalized cell content
+					if ( wo.filter_useParsedData ||
+						c.parsers[column].parsed ||
+						c.$headerIndexed[column].hasClass( 'filter-parsed' ) ) {
+						arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ column ];
+						// child row parsed data
+						if ( wo.filter_childRows && wo.filter_childByColumn ) {
+							childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length - 1;
+							for ( indx = 0; indx < childLen; indx++ ) {
+								arry[ arry.length ] = '' + cache.normalized[ rowIndex ][ c.columns ].child[ indx ][ column ];
+							}
+						}
+					} else {
+						// get raw cached data instead of content directly from the cells
+						arry[ arry.length ] = cache.normalized[ rowIndex ][ c.columns ].raw[ column ];
+						// child row unparsed data
+						if ( wo.filter_childRows && wo.filter_childByColumn ) {
+							childLen = cache.normalized[ rowIndex ][ c.columns ].$row.length;
+							for ( indx = 1; indx < childLen; indx++ ) {
+								child =  cache.normalized[ rowIndex ][ c.columns ].$row.eq( indx ).children().eq( column );
+								arry[ arry.length ] = '' + ts.getElementText( c, child, column );
+							}
+						}
+					}
+				}
+			}
+			return arry;
+		},
+		buildSelect: function( table, column, arry, updating, onlyAvail ) {
+			table = $( table )[0];
+			column = parseInt( column, 10 );
+			if ( !table.config.cache || $.isEmptyObject( table.config.cache ) ) {
+				return;
+			}
+
+			var indx, val, txt, t, $filters, $filter, option,
+				c = table.config,
+				wo = c.widgetOptions,
+				node = c.$headerIndexed[ column ],
+				// t.data( 'placeholder' ) won't work in jQuery older than 1.4.3
+				options = '<option value="">' +
+					( node.data( 'placeholder' ) ||
+						node.attr( 'data-placeholder' ) ||
+						wo.filter_placeholder.select || ''
+					) + '</option>',
+				// Get curent filter value
+				currentValue = c.$table
+					.find( 'thead' )
+					.find( 'select.' + tscss.filter + '[data-column="' + column + '"]' )
+					.val();
+
+			// nothing included in arry ( external source ), so get the options from
+			// filter_selectSource or column data
+			if ( typeof arry === 'undefined' || arry === '' ) {
+				arry = tsf.getOptionSource( table, column, onlyAvail );
+			}
+
+			if ( $.isArray( arry ) ) {
+				// build option list
+				for ( indx = 0; indx < arry.length; indx++ ) {
+					option = arry[ indx ];
+					if ( option.text ) {
+						// OBJECT!! add data-function-name in case the value is set in filter_functions
+						option['data-function-name'] = typeof option.value === 'undefined' ? option.text : option.value;
+
+						// support jQuery < v1.8, otherwise the below code could be shortened to
+						// options += $( '<option>', option )[ 0 ].outerHTML;
+						options += '<option';
+						for ( val in option ) {
+							if ( option.hasOwnProperty( val ) && val !== 'text' ) {
+								options += ' ' + val + '="' + option[ val ] + '"';
+							}
+						}
+						if ( !option.value ) {
+							options += ' value="' + option.text + '"';
+						}
+						options += '>' + option.text + '</option>';
+						// above code is needed in jQuery < v1.8
+
+						// make sure we don't turn an object into a string (objects without a "text" property)
+					} else if ( '' + option !== '[object Object]' ) {
+						txt = option = ( '' + option ).replace( tsfRegex.quote, '&quot;' );
+						val = txt;
+						// allow including a symbol in the selectSource array
+						// 'a-z|A through Z' so that 'a-z' becomes the option value
+						// and 'A through Z' becomes the option text
+						if ( txt.indexOf( wo.filter_selectSourceSeparator ) >= 0 ) {
+							t = txt.split( wo.filter_selectSourceSeparator );
+							val = t[0];
+							txt = t[1];
+						}
+						// replace quotes - fixes #242 & ignore empty strings
+						// see http://stackoverflow.com/q/14990971/145346
+						options += option !== '' ?
+							'<option ' +
+								( val === txt ? '' : 'data-function-name="' + option + '" ' ) +
+								'value="' + val + '">' + txt +
+							'</option>' : '';
+					}
+				}
+				// clear arry so it doesn't get appended twice
+				arry = [];
+			}
+
+			// update all selects in the same column ( clone thead in sticky headers &
+			// any external selects ) - fixes 473
+			$filters = ( c.$filters ? c.$filters : c.$table.children( 'thead' ) )
+				.find( '.' + tscss.filter );
+			if ( wo.filter_$externalFilters ) {
+				$filters = $filters && $filters.length ?
+					$filters.add( wo.filter_$externalFilters ) :
+					wo.filter_$externalFilters;
+			}
+			$filter = $filters.filter( 'select[data-column="' + column + '"]' );
+
+			// make sure there is a select there!
+			if ( $filter.length ) {
+				$filter[ updating ? 'html' : 'append' ]( options );
+				if ( !$.isArray( arry ) ) {
+					// append options if arry is provided externally as a string or jQuery object
+					// options ( default value ) was already added
+					$filter.append( arry ).val( currentValue );
+				}
+				$filter.val( currentValue );
+			}
+		},
+		buildDefault: function( table, updating ) {
+			var columnIndex, $header, noSelect,
+				c = table.config,
+				wo = c.widgetOptions,
+				columns = c.columns;
+			// build default select dropdown
+			for ( columnIndex = 0; columnIndex < columns; columnIndex++ ) {
+				$header = c.$headerIndexed[columnIndex];
+				noSelect = !( $header.hasClass( 'filter-false' ) || $header.hasClass( 'parser-false' ) );
+				// look for the filter-select class; build/update it if found
+				if ( ( $header.hasClass( 'filter-select' ) ||
+					ts.getColumnData( table, wo.filter_functions, columnIndex ) === true ) && noSelect ) {
+					tsf.buildSelect( table, columnIndex, '', updating, $header.hasClass( wo.filter_onlyAvail ) );
+				}
+			}
+		}
+	};
+
+	// filter regex variable
+	tsfRegex = tsf.regex;
+
+	ts.getFilters = function( table, getRaw, setFilters, skipFirst ) {
+		var i, $filters, $column, cols,
+			filters = [],
+			c = table ? $( table )[0].config : '',
+			wo = c ? c.widgetOptions : '';
+		if ( ( getRaw !== true && wo && !wo.filter_columnFilters ) ||
+			// setFilters called, but last search is exactly the same as the current
+			// fixes issue #733 & #903 where calling update causes the input values to reset
+			( $.isArray(setFilters) && setFilters.join('') === c.lastCombinedFilter ) ) {
+			return $( table ).data( 'lastSearch' );
+		}
+		if ( c ) {
+			if ( c.$filters ) {
+				$filters = c.$filters.find( '.' + tscss.filter );
+			}
+			if ( wo.filter_$externalFilters ) {
+				$filters = $filters && $filters.length ?
+					$filters.add( wo.filter_$externalFilters ) :
+					wo.filter_$externalFilters;
+			}
+			if ( $filters && $filters.length ) {
+				filters = setFilters || [];
+				for ( i = 0; i < c.columns + 1; i++ ) {
+					cols = ( i === c.columns ?
+						// 'all' columns can now include a range or set of columms ( data-column='0-2,4,6-7' )
+						wo.filter_anyColumnSelector + ',' + wo.filter_multipleColumnSelector :
+						'[data-column="' + i + '"]' );
+					$column = $filters.filter( cols );
+					if ( $column.length ) {
+						// move the latest search to the first slot in the array
+						$column = tsf.getLatestSearch( $column );
+						if ( $.isArray( setFilters ) ) {
+							// skip first ( latest input ) to maintain cursor position while typing
+							if ( skipFirst && $column.length > 1 ) {
+								$column = $column.slice( 1 );
+							}
+							if ( i === c.columns ) {
+								// prevent data-column='all' from filling data-column='0,1' ( etc )
+								cols = $column.filter( wo.filter_anyColumnSelector );
+								$column = cols.length ? cols : $column;
+							}
+							$column
+								.val( setFilters[ i ] )
+								// must include a namespace here; but not c.namespace + 'filter'?
+								.trigger( 'change' + c.namespace );
+						} else {
+							filters[i] = $column.val() || '';
+							// don't change the first... it will move the cursor
+							if ( i === c.columns ) {
+								// don't update range columns from 'all' setting
+								$column
+									.slice( 1 )
+									.filter( '[data-column*="' + $column.attr( 'data-column' ) + '"]' )
+									.val( filters[ i ] );
+							} else {
+								$column
+									.slice( 1 )
+									.val( filters[ i ] );
+							}
+						}
+						// save any match input dynamically
+						if ( i === c.columns && $column.length ) {
+							wo.filter_$anyMatch = $column;
+						}
+					}
+				}
+			}
+		}
+		return filters;
+	};
+
+	ts.setFilters = function( table, filter, apply, skipFirst ) {
+		var c = table ? $( table )[0].config : '',
+			valid = ts.getFilters( table, true, filter, skipFirst );
+		// default apply to "true"
+		if ( typeof apply === 'undefined' ) {
+			apply = true;
+		}
+		if ( c && apply ) {
+			// ensure new set filters are applied, even if the search is the same
+			c.lastCombinedFilter = null;
+			c.lastSearch = [];
+			tsf.searching( c.table, filter, skipFirst );
+			c.$table.triggerHandler( 'filterFomatterUpdate' );
+		}
+		return valid.length !== 0;
+	};
+
+})( jQuery );
+
+/*! Widget: stickyHeaders - updated 1/6/2017 (v2.28.4) *//*
+ * Requires tablesorter v2.8+ and jQuery 1.4.3+
+ * by Rob Garrison
+ */
+;(function ($, window) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	$.extend(ts.css, {
+		sticky    : 'tablesorter-stickyHeader', // stickyHeader
+		stickyVis : 'tablesorter-sticky-visible',
+		stickyHide: 'tablesorter-sticky-hidden',
+		stickyWrap: 'tablesorter-sticky-wrapper'
+	});
+
+	// Add a resize event to table headers
+	ts.addHeaderResizeEvent = function(table, disable, settings) {
+		table = $(table)[0]; // make sure we're using a dom element
+		if ( !table.config ) { return; }
+		var defaults = {
+				timer : 250
+			},
+			options = $.extend({}, defaults, settings),
+			c = table.config,
+			wo = c.widgetOptions,
+			checkSizes = function( triggerEvent ) {
+				var index, headers, $header, sizes, width, height,
+					len = c.$headers.length;
+				wo.resize_flag = true;
+				headers = [];
+				for ( index = 0; index < len; index++ ) {
+					$header = c.$headers.eq( index );
+					sizes = $header.data( 'savedSizes' ) || [ 0, 0 ]; // fixes #394
+					width = $header[0].offsetWidth;
+					height = $header[0].offsetHeight;
+					if ( width !== sizes[0] || height !== sizes[1] ) {
+						$header.data( 'savedSizes', [ width, height ] );
+						headers.push( $header[0] );
+					}
+				}
+				if ( headers.length && triggerEvent !== false ) {
+					c.$table.triggerHandler( 'resize', [ headers ] );
+				}
+				wo.resize_flag = false;
+			};
+		clearInterval(wo.resize_timer);
+		if (disable) {
+			wo.resize_flag = false;
+			return false;
+		}
+		checkSizes( false );
+		wo.resize_timer = setInterval(function() {
+			if (wo.resize_flag) { return; }
+			checkSizes();
+		}, options.timer);
+	};
+
+	// Sticky headers based on this awesome article:
+	// http://css-tricks.com/13465-persistent-headers/
+	// and https://github.com/jmosbech/StickyTableHeaders by Jonas Mosbech
+	// **************************
+	ts.addWidget({
+		id: 'stickyHeaders',
+		priority: 54, // sticky widget must be initialized after the filter & before pager widget!
+		options: {
+			stickyHeaders : '',       // extra class name added to the sticky header row
+			stickyHeaders_appendTo : null, // jQuery selector or object to phycially attach the sticky headers
+			stickyHeaders_attachTo : null, // jQuery selector or object to attach scroll listener to (overridden by xScroll & yScroll settings)
+			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: true, // scroll table top into view after filtering
+			stickyHeaders_cloneId : '-sticky', // added to table ID, if it exists
+			stickyHeaders_addResizeEvent : true, // trigger 'resize' event on headers
+			stickyHeaders_includeCaption : true, // if false and a caption exist, it won't be included in the sticky header
+			stickyHeaders_zIndex : 2 // The zIndex of the stickyHeaders, allows the user to adjust this to their needs
+		},
+		format: function(table, c, wo) {
+			// filter widget doesn't initialize on an empty table. Fixes #449
+			if ( c.$table.hasClass('hasStickyHeaders') || ($.inArray('filter', c.widgets) >= 0 && !c.$table.hasClass('hasFilters')) ) {
+				return;
+			}
+			var index, len, $t,
+				$table = c.$table,
+				// add position: relative to attach element, hopefully it won't cause trouble.
+				$attach = $(wo.stickyHeaders_attachTo),
+				namespace = c.namespace + 'stickyheaders ',
+				// element to watch for the scroll event
+				$yScroll = $(wo.stickyHeaders_yScroll || wo.stickyHeaders_attachTo || window),
+				$xScroll = $(wo.stickyHeaders_xScroll || wo.stickyHeaders_attachTo || window),
+				$thead = $table.children('thead:first'),
+				$header = $thead.children('tr').not('.sticky-false').children(),
+				$tfoot = $table.children('tfoot'),
+				$stickyOffset = isNaN(wo.stickyHeaders_offset) ? $(wo.stickyHeaders_offset) : '',
+				stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0,
+				// is this table nested? If so, find parent sticky header wrapper (div, not table)
+				$nestedSticky = $table.parent().closest('.' + ts.css.table).hasClass('hasStickyHeaders') ?
+					$table.parent().closest('table.tablesorter')[0].config.widgetOptions.$sticky.parent() : [],
+				nestedStickyTop = $nestedSticky.length ? $nestedSticky.height() : 0,
+				// clone table, then wrap to make sticky header
+				$stickyTable = wo.$sticky = $table.clone()
+					.addClass('containsStickyHeaders ' + ts.css.sticky + ' ' + wo.stickyHeaders + ' ' + c.namespace.slice(1) + '_extra_table' )
+					.wrap('<div class="' + ts.css.stickyWrap + '">'),
+				$stickyWrap = $stickyTable.parent()
+					.addClass(ts.css.stickyHide)
+					.css({
+						position   : $attach.length ? 'absolute' : 'fixed',
+						padding    : parseInt( $stickyTable.parent().parent().css('padding-left'), 10 ),
+						top        : stickyOffset + nestedStickyTop,
+						left       : 0,
+						visibility : 'hidden',
+						zIndex     : wo.stickyHeaders_zIndex || 2
+					}),
+				$stickyThead = $stickyTable.children('thead:first'),
+				$stickyCells,
+				laststate = '',
+				spacing = 0,
+				setWidth = function($orig, $clone){
+					var index, width, border, $cell, $this,
+						$cells = $orig.filter(':visible'),
+						len = $cells.length;
+					for ( index = 0; index < len; index++ ) {
+						$cell = $clone.filter(':visible').eq(index);
+						$this = $cells.eq(index);
+						// code from https://github.com/jmosbech/StickyTableHeaders
+						if ($this.css('box-sizing') === 'border-box') {
+							width = $this.outerWidth();
+						} else {
+							if ($cell.css('border-collapse') === 'collapse') {
+								if (window.getComputedStyle) {
+									width = parseFloat( window.getComputedStyle($this[0], null).width );
+								} else {
+									// ie8 only
+									border = parseFloat( $this.css('border-width') );
+									width = $this.outerWidth() - parseFloat( $this.css('padding-left') ) - parseFloat( $this.css('padding-right') ) - border;
+								}
+							} else {
+								width = $this.width();
+							}
+						}
+						$cell.css({
+							'width': width,
+							'min-width': width,
+							'max-width': width
+						});
+					}
+				},
+				resizeHeader = function() {
+					stickyOffset = $stickyOffset.length ? $stickyOffset.height() || 0 : parseInt(wo.stickyHeaders_offset, 10) || 0;
+					spacing = 0;
+					$stickyWrap.css({
+						left : $attach.length ? parseInt($attach.css('padding-left'), 10) || 0 :
+								$table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing,
+						width: $table.outerWidth()
+					});
+					setWidth( $table, $stickyTable );
+					setWidth( $header, $stickyCells );
+				},
+				scrollSticky = function( resizing ) {
+					if (!$table.is(':visible')) { return; } // fixes #278
+					// Detect nested tables - fixes #724
+					nestedStickyTop = $nestedSticky.length ? $nestedSticky.offset().top - $yScroll.scrollTop() + $nestedSticky.height() : 0;
+					var offset = $table.offset(),
+						yWindow = $.isWindow( $yScroll[0] ), // $.isWindow needs jQuery 1.4.3
+						xWindow = $.isWindow( $xScroll[0] ),
+						attachTop = $attach.length ?
+							( yWindow ? $yScroll.scrollTop() : $yScroll.offset().top ) :
+							$yScroll.scrollTop(),
+						captionHeight = wo.stickyHeaders_includeCaption ? 0 : $table.children( 'caption' ).height() || 0,
+						scrollTop = attachTop + stickyOffset + nestedStickyTop - captionHeight,
+						tableHeight = $table.height() - ($stickyWrap.height() + ($tfoot.height() || 0)) - captionHeight,
+						isVisible = ( scrollTop > offset.top ) && ( scrollTop < offset.top + tableHeight ) ? 'visible' : 'hidden',
+						cssSettings = { visibility : isVisible };
+					if ($attach.length) {
+						cssSettings.top = yWindow ? scrollTop - $attach.offset().top : $attach.scrollTop();
+					}
+					if (xWindow) {
+						// adjust when scrolling horizontally - fixes issue #143
+						cssSettings.left = $table.offset().left - parseInt($table.css('margin-left'), 10) - $xScroll.scrollLeft() - spacing;
+					}
+					if ($nestedSticky.length) {
+						cssSettings.top = ( cssSettings.top || 0 ) + stickyOffset + nestedStickyTop;
+					}
+					$stickyWrap
+						.removeClass( ts.css.stickyVis + ' ' + ts.css.stickyHide )
+						.addClass( isVisible === 'visible' ? ts.css.stickyVis : ts.css.stickyHide )
+						.css(cssSettings);
+					if (isVisible !== laststate || resizing) {
+						// make sure the column widths match
+						resizeHeader();
+						laststate = isVisible;
+					}
+				};
+			// only add a position relative if a position isn't already defined
+			if ($attach.length && !$attach.css('position')) {
+				$attach.css('position', 'relative');
+			}
+			// fix clone ID, if it exists - fixes #271
+			if ($stickyTable.attr('id')) { $stickyTable[0].id += wo.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
+			$stickyTable.find('thead:gt(0), tr.sticky-false').hide();
+			$stickyTable.find('tbody, tfoot').remove();
+			$stickyTable.find('caption').toggle(wo.stickyHeaders_includeCaption);
+			// issue #172 - find td/th in sticky header
+			$stickyCells = $stickyThead.children().children();
+			$stickyTable.css({ height:0, width:0, margin: 0 });
+			// remove resizable block
+			$stickyCells.find('.' + ts.css.resizer).remove();
+			// update sticky header class names to match real header after sorting
+			$table
+				.addClass('hasStickyHeaders')
+				.bind('pagerComplete' + namespace, function() {
+					resizeHeader();
+				});
+
+			ts.bindEvents(table, $stickyThead.children().children('.' + ts.css.header));
+
+			if (wo.stickyHeaders_appendTo) {
+				$(wo.stickyHeaders_appendTo).append( $stickyWrap );
+			} else {
+				// add stickyheaders AFTER the table. If the table is selected by ID, the original one (first) will be returned.
+				$table.after( $stickyWrap );
+			}
+
+			// onRenderHeader is defined, we need to do something about it (fixes #641)
+			if (c.onRenderHeader) {
+				$t = $stickyThead.children('tr').children();
+				len = $t.length;
+				for ( index = 0; index < len; index++ ) {
+					// send second parameter
+					c.onRenderHeader.apply( $t.eq( index ), [ index, c, $stickyTable ] );
+				}
+			}
+
+			// make it sticky!
+			$xScroll.add($yScroll)
+				.unbind( ('scroll resize '.split(' ').join( namespace )).replace(/\s+/g, ' ') )
+				.bind('scroll resize '.split(' ').join( namespace ), function( event ) {
+					scrollSticky( event.type === 'resize' );
+				});
+			c.$table
+				.unbind('stickyHeadersUpdate' + namespace)
+				.bind('stickyHeadersUpdate' + namespace, function(){
+					scrollSticky( true );
+				});
+
+			if (wo.stickyHeaders_addResizeEvent) {
+				ts.addHeaderResizeEvent(table);
+			}
+
+			// look for filter widget
+			if ($table.hasClass('hasFilters') && wo.filter_columnFilters) {
+				// scroll table into view after filtering, if sticky header is active - #482
+				$table.bind('filterEnd' + namespace, function() {
+					// $(':focus') needs jQuery 1.6+
+					var $td = $(document.activeElement).closest('td'),
+						column = $td.parent().children().index($td);
+					// only scroll if sticky header is active
+					if ($stickyWrap.hasClass(ts.css.stickyVis) && wo.stickyHeaders_filteredToTop) {
+						// scroll to original table (not sticky clone)
+						window.scrollTo(0, $table.position().top);
+						// give same input/select focus; check if c.$filters exists; fixes #594
+						if (column >= 0 && c.$filters) {
+							c.$filters.eq(column).find('a, select, input').filter(':visible').focus();
+						}
+					}
+				});
+				ts.filter.bindSearch( $table, $stickyCells.find('.' + ts.css.filter) );
+				// support hideFilters
+				if (wo.filter_hideFilters) {
+					ts.filter.hideFilters(c, $stickyTable);
+				}
+			}
+
+			// resize table (Firefox)
+			if (wo.stickyHeaders_addResizeEvent) {
+				$table.bind('resize' + c.namespace + 'stickyheaders', function() {
+					resizeHeader();
+				});
+			}
+
+			$table.triggerHandler('stickyHeadersInit');
+
+		},
+		remove: function(table, c, wo) {
+			var namespace = c.namespace + 'stickyheaders ';
+			c.$table
+				.removeClass('hasStickyHeaders')
+				.unbind( ('pagerComplete resize filterEnd stickyHeadersUpdate '.split(' ').join(namespace)).replace(/\s+/g, ' ') )
+				.next('.' + ts.css.stickyWrap).remove();
+			if (wo.$sticky && wo.$sticky.length) { wo.$sticky.remove(); } // remove cloned table
+			$(window)
+				.add(wo.stickyHeaders_xScroll)
+				.add(wo.stickyHeaders_yScroll)
+				.add(wo.stickyHeaders_attachTo)
+				.unbind( ('scroll resize '.split(' ').join(namespace)).replace(/\s+/g, ' ') );
+			ts.addHeaderResizeEvent(table, true);
+		}
+	});
+
+})(jQuery, window);
+
+/*! Widget: resizable - updated 12/15/2016 (v2.28.2) */
+/*jshint browser:true, jquery:true, unused:false */
+;(function ($, window) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	$.extend(ts.css, {
+		resizableContainer : 'tablesorter-resizable-container',
+		resizableHandle    : 'tablesorter-resizable-handle',
+		resizableNoSelect  : 'tablesorter-disableSelection',
+		resizableStorage   : 'tablesorter-resizable'
+	});
+
+	// Add extra scroller css
+	$(function(){
+		var s = '<style>' +
+			'body.' + ts.css.resizableNoSelect + ' { -ms-user-select: none; -moz-user-select: -moz-none;' +
+				'-khtml-user-select: none; -webkit-user-select: none; user-select: none; }' +
+			'.' + ts.css.resizableContainer + ' { position: relative; height: 1px; }' +
+			// make handle z-index > than stickyHeader z-index, so the handle stays above sticky header
+			'.' + ts.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>';
+		$('head').append(s);
+	});
+
+	ts.resizable = {
+		init : function( c, wo ) {
+			if ( c.$table.hasClass( 'hasResizable' ) ) { return; }
+			c.$table.addClass( 'hasResizable' );
+
+			var noResize, $header, column, storedSizes, tmp,
+				$table = c.$table,
+				$parent = $table.parent(),
+				marginTop = parseInt( $table.css( 'margin-top' ), 10 ),
+
+			// internal variables
+			vars = wo.resizable_vars = {
+				useStorage : ts.storage && wo.resizable !== false,
+				$wrap : $parent,
+				mouseXPosition : 0,
+				$target : null,
+				$next : null,
+				overflow : $parent.css('overflow') === 'auto' ||
+					$parent.css('overflow') === 'scroll' ||
+					$parent.css('overflow-x') === 'auto' ||
+					$parent.css('overflow-x') === 'scroll',
+				storedSizes : []
+			};
+
+			// set default widths
+			ts.resizableReset( c.table, true );
+
+			// now get measurements!
+			vars.tableWidth = $table.width();
+			// attempt to autodetect
+			vars.fullWidth = Math.abs( $parent.width() - vars.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>');
+			}
+			*/
+
+			if ( vars.useStorage && vars.overflow ) {
+				// save table width
+				ts.storage( c.table, 'tablesorter-table-original-css-width', vars.tableWidth );
+				tmp = ts.storage( c.table, 'tablesorter-table-resized-width' ) || 'auto';
+				ts.resizable.setWidth( $table, tmp, true );
+			}
+			wo.resizable_vars.storedSizes = storedSizes = ( vars.useStorage ?
+				ts.storage( c.table, ts.css.resizableStorage ) :
+				[] ) || [];
+			ts.resizable.setWidths( c, wo, storedSizes );
+			ts.resizable.updateStoredSizes( c, wo );
+
+			wo.$resizable_container = $( '<div class="' + ts.css.resizableContainer + '">' )
+				.css({ top : marginTop })
+				.insertBefore( $table );
+			// add container
+			for ( column = 0; column < c.columns; column++ ) {
+				$header = c.$headerIndexed[ column ];
+				tmp = ts.getColumnData( c.table, c.headers, column );
+				noResize = ts.getData( $header, tmp, 'resizable' ) === 'false';
+				if ( !noResize ) {
+					$( '<div class="' + ts.css.resizableHandle + '">' )
+						.appendTo( wo.$resizable_container )
+						.attr({
+							'data-column' : column,
+							'unselectable' : 'on'
+						})
+						.data( 'header', $header )
+						.bind( 'selectstart', false );
+				}
+			}
+			ts.resizable.bindings( c, wo );
+		},
+
+		updateStoredSizes : function( c, wo ) {
+			var column, $header,
+				len = c.columns,
+				vars = wo.resizable_vars;
+			vars.storedSizes = [];
+			for ( column = 0; column < len; column++ ) {
+				$header = c.$headerIndexed[ column ];
+				vars.storedSizes[ column ] = $header.is(':visible') ? $header.width() : 0;
+			}
+		},
+
+		setWidth : function( $el, width, overflow ) {
+			// overflow tables need min & max width set as well
+			$el.css({
+				'width' : width,
+				'min-width' : overflow ? width : '',
+				'max-width' : overflow ? width : ''
+			});
+		},
+
+		setWidths : function( c, wo, storedSizes ) {
+			var column, $temp,
+				vars = wo.resizable_vars,
+				$extra = $( c.namespace + '_extra_headers' ),
+				$col = c.$table.children( 'colgroup' ).children( 'col' );
+			storedSizes = storedSizes || vars.storedSizes || [];
+			// process only if table ID or url match
+			if ( storedSizes.length ) {
+				for ( column = 0; column < c.columns; column++ ) {
+					// set saved resizable widths
+					ts.resizable.setWidth( c.$headerIndexed[ column ], storedSizes[ column ], vars.overflow );
+					if ( $extra.length ) {
+						// stickyHeaders needs to modify min & max width as well
+						$temp = $extra.eq( column ).add( $col.eq( column ) );
+						ts.resizable.setWidth( $temp, storedSizes[ column ], vars.overflow );
+					}
+				}
+				$temp = $( c.namespace + '_extra_table' );
+				if ( $temp.length && !ts.hasWidget( c.table, 'scroller' ) ) {
+					ts.resizable.setWidth( $temp, c.$table.outerWidth(), vars.overflow );
+				}
+			}
+		},
+
+		setHandlePosition : function( c, wo ) {
+			var startPosition,
+				tableHeight = c.$table.height(),
+				$handles = wo.$resizable_container.children(),
+				handleCenter = Math.floor( $handles.width() / 2 );
+
+			if ( ts.hasWidget( c.table, 'scroller' ) ) {
+				tableHeight = 0;
+				c.$table.closest( '.' + ts.css.scrollerWrap ).children().each(function(){
+					var $this = $(this);
+					// center table has a max-height set
+					tableHeight += $this.filter('[style*="height"]').length ? $this.height() : $this.children('table').height();
+				});
+			}
+			// subtract out table left position from resizable handles. Fixes #864
+			startPosition = c.$table.position().left;
+			$handles.each( function() {
+				var $this = $(this),
+					column = parseInt( $this.attr( 'data-column' ), 10 ),
+					columns = c.columns - 1,
+					$header = $this.data( 'header' );
+				if ( !$header ) { return; } // see #859
+				if ( !$header.is(':visible') ) {
+					$this.hide();
+				} else if ( column < columns || column === columns && wo.resizable_addLastColumn ) {
+					$this.css({
+						display: 'inline-block',
+						height : tableHeight,
+						left : $header.position().left - startPosition + $header.outerWidth() - handleCenter
+					});
+				}
+			});
+		},
+
+		// prevent text selection while dragging resize bar
+		toggleTextSelection : function( c, wo, toggle ) {
+			var namespace = c.namespace + 'tsresize';
+			wo.resizable_vars.disabled = toggle;
+			$( 'body' ).toggleClass( ts.css.resizableNoSelect, toggle );
+			if ( toggle ) {
+				$( 'body' )
+					.attr( 'unselectable', 'on' )
+					.bind( 'selectstart' + namespace, false );
+			} else {
+				$( 'body' )
+					.removeAttr( 'unselectable' )
+					.unbind( 'selectstart' + namespace );
+			}
+		},
+
+		bindings : function( c, wo ) {
+			var namespace = c.namespace + 'tsresize';
+			wo.$resizable_container.children().bind( 'mousedown', function( event ) {
+				// save header cell and mouse position
+				var column,
+					vars = wo.resizable_vars,
+					$extras = $( c.namespace + '_extra_headers' ),
+					$header = $( event.target ).data( 'header' );
+
+				column = parseInt( $header.attr( 'data-column' ), 10 );
+				vars.$target = $header = $header.add( $extras.filter('[data-column="' + column + '"]') );
+				vars.target = column;
+
+				// if table is not as wide as it's parent, then resize the table
+				vars.$next = event.shiftKey || wo.resizable_targetLast ?
+					$header.parent().children().not( '.resizable-false' ).filter( ':last' ) :
+					$header.nextAll( ':not(.resizable-false)' ).eq( 0 );
+
+				column = parseInt( vars.$next.attr( 'data-column' ), 10 );
+				vars.$next = vars.$next.add( $extras.filter('[data-column="' + column + '"]') );
+				vars.next = column;
+
+				vars.mouseXPosition = event.pageX;
+				ts.resizable.updateStoredSizes( c, wo );
+				ts.resizable.toggleTextSelection(c, wo, true );
+			});
+
+			$( document )
+				.bind( 'mousemove' + namespace, function( event ) {
+					var vars = wo.resizable_vars;
+					// ignore mousemove if no mousedown
+					if ( !vars.disabled || vars.mouseXPosition === 0 || !vars.$target ) { return; }
+					if ( wo.resizable_throttle ) {
+						clearTimeout( vars.timer );
+						vars.timer = setTimeout( function() {
+							ts.resizable.mouseMove( c, wo, event );
+						}, isNaN( wo.resizable_throttle ) ? 5 : wo.resizable_throttle );
+					} else {
+						ts.resizable.mouseMove( c, wo, event );
+					}
+				})
+				.bind( 'mouseup' + namespace, function() {
+					if (!wo.resizable_vars.disabled) { return; }
+					ts.resizable.toggleTextSelection( c, wo, false );
+					ts.resizable.stopResize( c, wo );
+					ts.resizable.setHandlePosition( c, wo );
+				});
+
+			// resizeEnd event triggered by scroller widget
+			$( window ).bind( 'resize' + namespace + ' resizeEnd' + namespace, function() {
+				ts.resizable.setHandlePosition( c, wo );
+			});
+
+			// right click to reset columns to default widths
+			c.$table
+				.bind( 'columnUpdate' + namespace + ' pagerComplete' + namespace, function() {
+					ts.resizable.setHandlePosition( c, wo );
+				})
+				.find( 'thead:first' )
+				.add( $( c.namespace + '_extra_table' ).find( 'thead:first' ) )
+				.bind( 'contextmenu' + namespace, function() {
+					// $.isEmptyObject() needs jQuery 1.4+; allow right click if already reset
+					var allowClick = wo.resizable_vars.storedSizes.length === 0;
+					ts.resizableReset( c.table );
+					ts.resizable.setHandlePosition( c, wo );
+					wo.resizable_vars.storedSizes = [];
+					return allowClick;
+				});
+
+		},
+
+		mouseMove : function( c, wo, event ) {
+			if ( wo.resizable_vars.mouseXPosition === 0 || !wo.resizable_vars.$target ) { return; }
+			// resize columns
+			var column,
+				total = 0,
+				vars = wo.resizable_vars,
+				$next = vars.$next,
+				tar = vars.storedSizes[ vars.target ],
+				leftEdge = event.pageX - vars.mouseXPosition;
+			if ( vars.overflow ) {
+				if ( tar + leftEdge > 0 ) {
+					vars.storedSizes[ vars.target ] += leftEdge;
+					ts.resizable.setWidth( vars.$target, vars.storedSizes[ vars.target ], true );
+					// update the entire table width
+					for ( column = 0; column < c.columns; column++ ) {
+						total += vars.storedSizes[ column ];
+					}
+					ts.resizable.setWidth( c.$table.add( $( c.namespace + '_extra_table' ) ), total );
+				}
+				if ( !$next.length ) {
+					// if expanding right-most column, scroll the wrapper
+					vars.$wrap[0].scrollLeft = c.$table.width();
+				}
+			} else if ( vars.fullWidth ) {
+				vars.storedSizes[ vars.target ] += leftEdge;
+				vars.storedSizes[ vars.next ] -= leftEdge;
+				ts.resizable.setWidths( c, wo );
+			} else {
+				vars.storedSizes[ vars.target ] += leftEdge;
+				ts.resizable.setWidths( c, wo );
+			}
+			vars.mouseXPosition = event.pageX;
+			// dynamically update sticky header widths
+			c.$table.triggerHandler('stickyHeadersUpdate');
+		},
+
+		stopResize : function( c, wo ) {
+			var vars = wo.resizable_vars;
+			ts.resizable.updateStoredSizes( c, wo );
+			if ( vars.useStorage ) {
+				// save all column widths
+				ts.storage( c.table, ts.css.resizableStorage, vars.storedSizes );
+				ts.storage( c.table, 'tablesorter-table-resized-width', c.$table.width() );
+			}
+			vars.mouseXPosition = 0;
+			vars.$target = vars.$next = null;
+			// will update stickyHeaders, just in case, see #912
+			c.$table.triggerHandler('stickyHeadersUpdate');
+		}
+	};
+
+	// this widget saves the column widths if
+	// $.tablesorter.storage function is included
+	// **************************
+	ts.addWidget({
+		id: 'resizable',
+		priority: 40,
+		options: {
+			resizable : true, // save column widths to storage
+			resizable_addLastColumn : false,
+			resizable_widths : [],
+			resizable_throttle : false, // set to true (5ms) or any number 0-10 range
+			resizable_targetLast : false,
+			resizable_fullWidth : null
+		},
+		init: function(table, thisWidget, c, wo) {
+			ts.resizable.init( c, wo );
+		},
+		format: function( table, c, wo ) {
+			ts.resizable.setHandlePosition( c, wo );
+		},
+		remove: function( table, c, wo, refreshing ) {
+			if (wo.$resizable_container) {
+				var namespace = c.namespace + 'tsresize';
+				c.$table.add( $( c.namespace + '_extra_table' ) )
+					.removeClass('hasResizable')
+					.children( 'thead' )
+					.unbind( 'contextmenu' + namespace );
+
+				wo.$resizable_container.remove();
+				ts.resizable.toggleTextSelection( c, wo, false );
+				ts.resizableReset( table, refreshing );
+				$( document ).unbind( 'mousemove' + namespace + ' mouseup' + namespace );
+			}
+		}
+	});
+
+	ts.resizableReset = function( table, refreshing ) {
+		$( table ).each(function(){
+			var index, $t,
+				c = this.config,
+				wo = c && c.widgetOptions,
+				vars = wo.resizable_vars;
+			if ( table && c && c.$headerIndexed.length ) {
+				// restore the initial table width
+				if ( vars.overflow && vars.tableWidth ) {
+					ts.resizable.setWidth( c.$table, vars.tableWidth, true );
+					if ( vars.useStorage ) {
+						ts.storage( table, 'tablesorter-table-resized-width', 'auto' );
+					}
+				}
+				for ( index = 0; index < c.columns; index++ ) {
+					$t = c.$headerIndexed[ index ];
+					if ( wo.resizable_widths && wo.resizable_widths[ index ] ) {
+						ts.resizable.setWidth( $t, wo.resizable_widths[ index ], vars.overflow );
+					} else if ( !$t.hasClass( 'resizable-false' ) ) {
+						// don't clear the width of any column that is not resizable
+						ts.resizable.setWidth( $t, '', vars.overflow );
+					}
+				}
+
+				// reset stickyHeader widths
+				c.$table.triggerHandler( 'stickyHeadersUpdate' );
+				if ( ts.storage && !refreshing ) {
+					ts.storage( this, ts.css.resizableStorage, {} );
+				}
+			}
+		});
+	};
+
+})( jQuery, window );
+
+/*! Widget: saveSort - updated 10/31/2015 (v2.24.0) *//*
+* Requires tablesorter v2.16+
+* by Rob Garrison
+*/
+;(function ($) {
+	'use strict';
+	var ts = $.tablesorter || {};
+
+	// this widget saves the last sort only if the
+	// saveSort widget option is true AND the
+	// $.tablesorter.storage function is included
+	// **************************
+	ts.addWidget({
+		id: 'saveSort',
+		priority: 20,
+		options: {
+			saveSort : true
+		},
+		init: function(table, thisWidget, c, wo) {
+			// run widget format before all other widgets are applied to the table
+			thisWidget.format(table, c, wo, true);
+		},
+		format: function(table, c, wo, init) {
+			var stored, time,
+				$table = c.$table,
+				saveSort = wo.saveSort !== false, // make saveSort active/inactive; default to true
+				sortList = { 'sortList' : c.sortList };
+			if (c.debug) {
+				time = new Date();
+			}
+			if ($table.hasClass('hasSaveSort')) {
+				if (saveSort && table.hasInitialized && ts.storage) {
+					ts.storage( table, 'tablesorter-savesort', sortList );
+					if (c.debug) {
+						console.log('saveSort widget: Saving last sort: ' + c.sortList + ts.benchmark(time));
+					}
+				}
+			} else {
+				// set table sort on initial run of the widget
+				$table.addClass('hasSaveSort');
+				sortList = '';
+				// get data
+				if (ts.storage) {
+					stored = ts.storage( table, 'tablesorter-savesort' );
+					sortList = (stored && stored.hasOwnProperty('sortList') && $.isArray(stored.sortList)) ? stored.sortList : '';
+					if (c.debug) {
+						console.log('saveSort: Last sort loaded: "' + sortList + '"' + ts.benchmark(time));
+					}
+					$table.bind('saveSortReset', function(event) {
+						event.stopPropagation();
+						ts.storage( table, 'tablesorter-savesort', '' );
+					});
+				}
+				// init is true when widget init is run, this will run this widget before all other widgets have initialized
+				// this method allows using this widget in the original tablesorter plugin; but then it will run all widgets twice.
+				if (init && sortList && sortList.length > 0) {
+					c.sortList = sortList;
+				} else if (table.hasInitialized && sortList && sortList.length > 0) {
+					// update sort change
+					ts.sortOn( c, sortList );
+				}
+			}
+		},
+		remove: function(table, c) {
+			c.$table.removeClass('hasSaveSort');
+			// clear storage
+			if (ts.storage) { ts.storage( table, 'tablesorter-savesort', '' ); }
+		}
+	});
+
+})(jQuery);
+
+return jQuery.tablesorter;
+}));
diff --git a/smash/web/static/AdminLTE/plugins/tablesorter/old/theme.bootstrap.css b/smash/web/static/AdminLTE/plugins/tablesorter/old/theme.bootstrap.css
new file mode 100644
index 0000000000000000000000000000000000000000..78bfc7d07da8b079ad7d5c7c4e6478f408bb1e7b
--- /dev/null
+++ b/smash/web/static/AdminLTE/plugins/tablesorter/old/theme.bootstrap.css
@@ -0,0 +1,193 @@
+/**
+ * Bootstrap theme v3.x
+ *
+ * WARNING!... once a stable Bootstrap v4.x is released,
+ * this file will be removed; use theme.bootstrap_3.css
+ */
+.tablesorter-bootstrap {
+	width: 100%;
+}
+.tablesorter-bootstrap thead th,
+.tablesorter-bootstrap thead td,
+.tablesorter-bootstrap tfoot th,
+.tablesorter-bootstrap tfoot td {
+	font: 14px/20px Arial, Sans-serif;
+	font-weight: bold;
+	padding: 4px;
+	margin: 0 0 18px;
+	background-color: #eee;
+}
+
+.tablesorter-bootstrap .tablesorter-header {
+	cursor: pointer;
+}
+.tablesorter-bootstrap .sorter-false {
+	cursor: default;
+}
+
+.tablesorter-bootstrap .tablesorter-header.sorter-false i.tablesorter-icon {
+	display: none;
+}
+
+.tablesorter-bootstrap .tablesorter-header-inner {
+	position: relative;
+	padding: 4px 18px 4px 4px;
+}
+.tablesorter-bootstrap .sorter-false .tablesorter-header-inner {
+	padding: 4px;
+}
+
+/* bootstrap uses <i> for icons */
+.tablesorter-bootstrap .tablesorter-header i.tablesorter-icon {
+	font-size: 11px;
+	position: absolute;
+	right: 2px;
+	top: 50%;
+	margin-top: -7px; /* half the icon height; older IE doesn't like this */
+	width: 14px;
+	height: 14px;
+	background-repeat: no-repeat;
+	line-height: 14px;
+	display: inline-block;
+}
+
+/* black unsorted icon */
+.tablesorter-bootstrap .bootstrap-icon-unsorted {
+	background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAA20lEQVR4AWJABpKSkoxALCstLb0aUAsZaCAMhVEY6B0amx8YZWDDEDSBa2AGe7XeIiAAClYwVGBvsAcIllsf/mvcC9DgOOd8h90fxWvngVEUbZIkuWRZZlE8eQjcisgZMM9zi+LJ6ZfwegmWZflZDugdHMfxTcGqql7TNBlUB/QObtv2VBSFrev6OY7jngzFk9OT/fn73fWYpqnlXNyXDMWT0zuYx/Bvel9ej+LJ6R08DMOu67q7DkTkrSA5vYPneV71fX/QASdTkJwezhs0TfMARn0wMDDGXEPgF4oijqwM5YjNAAAAAElFTkSuQmCC);
+}
+
+/* white unsorted icon */
+.tablesorter-bootstrap .icon-white.bootstrap-icon-unsorted {
+	background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAOCAYAAAD5YeaVAAAAe0lEQVR4AbXQoRWDMBiF0Sh2QLAAQ8SxJGugWSA6A2STW1PxTsnB9cnkfuYvv8OGC1t5G3Y0QMP+Bm857keAdQIzWBP3+Bw4MADQE18B6/etRnCV/w9nnGuLezfAmXhABGtAGIkruvk6auIFRwQJDywllsEAjCecB20GP59BQQ+gtlRLAAAAAElFTkSuQmCC);
+}
+
+/* since bootstrap (table-striped) uses nth-child(), we just use this to add a zebra stripe color */
+.tablesorter-bootstrap > tbody > tr.odd > td,
+.tablesorter-bootstrap > tbody > tr.tablesorter-hasChildRow.odd:hover ~ tr.tablesorter-hasChildRow.odd ~ .tablesorter-childRow.odd > td {
+	background-color: #f9f9f9;
+}
+.tablesorter-bootstrap > tbody > tr.hover > td,
+.tablesorter-bootstrap > tbody > tr.odd:hover > td,
+.tablesorter-bootstrap > tbody > tr.even:hover > td,
+.tablesorter-bootstrap > tbody > tr.tablesorter-hasChildRow.odd:hover ~ .tablesorter-childRow.odd > td,
+.tablesorter-bootstrap > tbody > tr.tablesorter-hasChildRow.even:hover ~ .tablesorter-childRow.even > td {
+	background-color: #f5f5f5;
+}
+.tablesorter-bootstrap > tbody > tr.even > td,
+.tablesorter-bootstrap > tbody > tr.tablesorter-hasChildRow.even:hover ~ tr.tablesorter-hasChildRow.even ~ .tablesorter-childRow.even > td {
+	background-color: #fff;
+}
+
+/* processing icon */
+.tablesorter-bootstrap .tablesorter-processing {
+	background-image: url('data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=');
+	background-position: center center !important;
+	background-repeat: no-repeat !important;
+}
+
+/* Column Widget - column sort colors */
+.tablesorter-bootstrap > tbody > tr.odd td.primary {
+	background-color: #bfbfbf;
+}
+.tablesorter-bootstrap > tbody > tr td.primary,
+.tablesorter-bootstrap > tbody > tr.even td.primary {
+	background-color: #d9d9d9;
+}
+.tablesorter-bootstrap > tbody > tr.odd td.secondary {
+	background-color: #d9d9d9;
+}
+.tablesorter-bootstrap > tbody > tr td.secondary,
+.tablesorter-bootstrap > tbody > tr.even td.secondary {
+	background-color: #e6e6e6;
+}
+.tablesorter-bootstrap > tbody > tr.odd td.tertiary {
+	background-color: #e6e6e6;
+}
+.tablesorter-bootstrap > tbody > tr td.tertiary,
+.tablesorter-bootstrap > tbody > tr.even td.tertiary {
+	background-color: #f2f2f2;
+}
+
+/* caption */
+.caption {
+	background-color: #fff;
+}
+
+/* filter widget */
+.tablesorter-bootstrap .tablesorter-filter-row input.tablesorter-filter,
+.tablesorter-bootstrap .tablesorter-filter-row select.tablesorter-filter {
+	width: 98%;
+	margin: 0;
+	padding: 4px 6px;
+	color: #333;
+	-webkit-box-sizing: border-box;
+	-moz-box-sizing: border-box;
+	box-sizing: border-box;
+	-webkit-transition: height 0.1s ease;
+	-moz-transition: height 0.1s ease;
+	-o-transition: height 0.1s ease;
+	transition: height 0.1s ease;
+}
+.tablesorter-bootstrap .tablesorter-filter-row .tablesorter-filter.disabled {
+	background-color: #eee;
+	color: #555;
+	cursor: not-allowed;
+	border: 1px solid #ccc;
+	border-radius: 4px;
+	box-shadow: 0px 1px 1px rgba(0, 0, 0, 0.075) inset;
+	box-sizing: border-box;
+	transition: height 0.1s ease;
+}
+.tablesorter-bootstrap .tablesorter-filter-row {
+	background-color: #efefef;
+}
+.tablesorter-bootstrap .tablesorter-filter-row td {
+	background-color: #efefef;
+	line-height: normal;
+	text-align: center;
+	padding: 4px 6px;
+	vertical-align: middle;
+	-webkit-transition: line-height 0.1s ease;
+	-moz-transition: line-height 0.1s ease;
+	-o-transition: line-height 0.1s ease;
+	transition: line-height 0.1s ease;
+}
+/* hidden filter row */
+.tablesorter-bootstrap .tablesorter-filter-row.hideme td {
+	padding: 2px; /* change this to modify the thickness of the closed border row */
+	margin: 0;
+	line-height: 0;
+}
+.tablesorter-bootstrap .tablesorter-filter-row.hideme * {
+	height: 1px;
+	min-height: 0;
+	border: 0;
+	padding: 0;
+	margin: 0;
+	/* don't use visibility: hidden because it disables tabbing */
+	opacity: 0;
+	filter: alpha(opacity=0);
+}
+/* rows hidden by filtering */
+.tablesorter .filtered {
+	display: none;
+}
+
+/* pager plugin */
+.tablesorter-bootstrap .tablesorter-pager select {
+  padding: 4px 6px;
+}
+.tablesorter-bootstrap .tablesorter-pager .pagedisplay {
+	border: 0;
+}
+/* tfoot i for pager controls */
+.tablesorter-bootstrap tfoot i {
+	font-size: 11px;
+}
+
+/* ajax error row */
+.tablesorter .tablesorter-errorRow td {
+	text-align: center;
+	cursor: pointer;
+	background-color: #e6bf99;
+}
diff --git a/smash/web/templates/doctors/add.html b/smash/web/templates/doctors/add.html
index d04bef461f9e16cc1fbd1fa04bd6f322e0eb5911..e51dee186986eca04248acc41d93c1f4f26eaa4a 100644
--- a/smash/web/templates/doctors/add.html
+++ b/smash/web/templates/doctors/add.html
@@ -11,7 +11,7 @@
 {% block page_header %}New worker{% endblock page_header %}
 {% block page_description %}{% endblock page_description %}
 
-{% block title %} - Add new worker{% endblock %}
+{% block title %}{{ block.super }} - Add new worker{% endblock %}
 
 {% block breadcrumb %}
 {% include "doctors/breadcrumb.html" %}
diff --git a/smash/web/templates/includes/tablesorter.css.html b/smash/web/templates/includes/tablesorter.css.html
new file mode 100644
index 0000000000000000000000000000000000000000..77a5d1310986ee746b7de6dd4fdf536e31cc7b77
--- /dev/null
+++ b/smash/web/templates/includes/tablesorter.css.html
@@ -0,0 +1,6 @@
+{% load static %}
+
+<!-- Tablesorter -->
+<link rel="stylesheet" href="{% static 'AdminLTE/plugins/tablesorter/css/theme.bootstrap_3.min.css' %}">
+<link rel="stylesheet" href="{% static 'AdminLTE/plugins/tablesorter/css/jquery.tablesorter.pager.min.css' %}">
+<link rel="stylesheet" href="{% static 'AdminLTE/plugins/tablesorter/css/filter.formatter.min.css' %}">
\ No newline at end of file
diff --git a/smash/web/templates/includes/tablesorter.js.html b/smash/web/templates/includes/tablesorter.js.html
new file mode 100644
index 0000000000000000000000000000000000000000..7ad3edf86663aa026280d34e2f88eda000b0d88c
--- /dev/null
+++ b/smash/web/templates/includes/tablesorter.js.html
@@ -0,0 +1,4 @@
+{% load static %}
+<script src="{% static 'AdminLTE/plugins/tablesorter/js/jquery.tablesorter.min.js' %}"></script>
+<script src="{% static 'AdminLTE/plugins/tablesorter/js/jquery.tablesorter.widgets.min.js' %}"></script>
+<script src="{% static 'AdminLTE/plugins/tablesorter/js/jquery.tablesorter.pager.js' %}"></script>
\ No newline at end of file
diff --git a/smash/web/templates/includes/tablesorter.tfoot.html b/smash/web/templates/includes/tablesorter.tfoot.html
new file mode 100644
index 0000000000000000000000000000000000000000..d345ac6c9fce001a6ff774b90df66510581cdd28
--- /dev/null
+++ b/smash/web/templates/includes/tablesorter.tfoot.html
@@ -0,0 +1,22 @@
+<tfoot>
+<tr>
+  <th colspan="7" class="ts-pager form-inline">
+    <div class="btn-group btn-group-sm" role="group">
+      <button type="button" class="btn btn-default first"><span class="glyphicon glyphicon-step-backward"></span></button>
+      <button type="button" class="btn btn-default prev"><span class="glyphicon glyphicon-backward"></span></button>
+    </div>
+    <span class="pagedisplay"></span>
+    <div class="btn-group btn-group-sm" role="group">
+      <button type="button" class="btn btn-default next"><span class="glyphicon glyphicon-forward"></span></button>
+      <button type="button" class="btn btn-default last"><span class="glyphicon glyphicon-step-forward"></span></button>
+    </div>
+    <select class="form-control input-sm pagesize" title="Select page size">
+      <option selected="selected" value="10">10</option>
+      <option value="20">20</option>
+      <option value="30">30</option>
+      <option value="all">All Rows</option>
+    </select>
+    <select class="form-control input-sm pagenum" title="Select page number"></select>
+  </th>
+</tr>
+</tfoot>
\ No newline at end of file
diff --git a/smash/web/templates/subjects/add.html b/smash/web/templates/subjects/add.html
index 7add549ed61d37023f27bb9accaaa92f7a40247e..4f8c93e9702d47de2de272162e6c8ae9357e20a4 100644
--- a/smash/web/templates/subjects/add.html
+++ b/smash/web/templates/subjects/add.html
@@ -11,7 +11,7 @@
 {% block page_header %}New subject{% endblock page_header %}
 {% block page_description %}{% endblock page_description %}
 
-{% block title %} - Add new subject{% endblock %}
+{% block title %}{{ block.super }} - Add new subject{% endblock %}
 
 {% block breadcrumb %}
 {% include "subjects/breadcrumb.html" %}
diff --git a/smash/web/templates/subjects/index.html b/smash/web/templates/subjects/index.html
index fc6346743cae53c43bc2d38e6c59e9e282e1afcd..f27fe6127a0733aeca6fc5bc4fcb8f2344846a29 100644
--- a/smash/web/templates/subjects/index.html
+++ b/smash/web/templates/subjects/index.html
@@ -3,8 +3,7 @@
 
 {% block styles %}
 {{ block.super }}
-	<!-- DataTables -->
-  <link rel="stylesheet" href="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.css' %}">
+	{% include "includes/tablesorter.css.html" %}
 {% endblock styles %}
 
 {% block page_title %}'subjects'{% endblock page_title %}
@@ -28,21 +27,24 @@
 
 <div class="box-body">
   {% if subjects_list %}
-  <table id="table" class="table table-bordered table-striped">
+  <table id="table" class="table table-bordered table-striped tablesorter">
 		<thead>
 			<tr>
 				<th>No.</th>
 				<th>First name</th>
 				<th>Last name</th>
 				<th>Country</th>
-				<th>Languages</th>
-				<th>Type</th>
+				<th></th>
+				<th class="filter-select filter-exact" data-placeholder="Select type">Type</th>
 				<th>Last visit</th>
 				<th>Details</th>
 				<th>Edit</th>
         <th>Delete</th>
 			</tr>
 		</thead>
+
+		{% include "includes/tablesorter.tfoot.html" %}
+
 	<tbody>
     {% for subject in subjects_list %}
 		<tr>
@@ -64,6 +66,7 @@
       <td><a href="{% url 'web.views.subjectdelete' subject.id %}" type="button" class="btn btn-block btn-default">Delete</a></td>
 		</tr>
     {% endfor %}
+
 	</tbody>
 	</table>
   {% else %}
@@ -75,19 +78,38 @@
 {% block scripts %}
 	{{ block.super }}
 
-	<script src="{% static 'AdminLTE/plugins/datatables/jquery.dataTables.min.js' %}"></script>
-	<script src="{% static 'AdminLTE/plugins/datatables/dataTables.bootstrap.min.js' %}"></script>
+	{% include "includes/tablesorter.js.html" %}
 
 	<script>
 		$(function () {
-			$('#table').DataTable({
-			  "paging": true,
-			  "lengthChange": false,
-			  "searching": true,
-			  "ordering": true,
-			  "info": true,
-			  "autoWidth": false
+			$('#table').tablesorter({
+				theme : "bootstrap",
+				widthFixed: true,
+				headerTemplate : '{content} {icon}',
+				widgets : [ "uitheme", "filter", "columns", "zebra" ],
+				widgetOptions : {
+					zebra : ["even", "odd"],
+					columns: [ "primary", "secondary", "tertiary" ],
+					filter_reset : ".reset",
+					filter_cssFilter: "form-control",
+				},
+				headers: {
+					4: { sorter: false},
+					7: { sorter: false},
+					8: { sorter: false},
+					9: { sorter: false}
+				}
+			}).tablesorterPager({
+			    container: $(".ts-pager"),
+			    cssGoto  : ".pagenum",
+			    // remove rows from the table to speed up the sort of large tables.
+			    // setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled.
+			    removeRows: false,
+			    // output string - default is '{page}/{totalPages}';
+			    // possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows}
+			    output: '{startRow} - {endRow} / {filteredRows} ({totalRows})'
 			});
-		});
+  		});
 	</script>
+
 {% endblock scripts %}
diff --git a/todos.txt b/todos.txt
index 3422b043784594866ca34fbce0a5f6f5e41fadb7..40eb2ae7ce90165721281b16765eae2687f66fa6 100644
--- a/todos.txt
+++ b/todos.txt
@@ -8,7 +8,7 @@
 
 ** Visual
  - all html forms - make them more "bootstrap'y"
- - make fields in details not editable
+ - make fields in details not editable	
 
 ** Possible improvements
 - breadcrumbs - make them stack (multiple template inheritance?)