]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
check in raw verto js files and directory structure for development
authorAnthony Minessale <anthm@freeswitch.org>
Sat, 21 Jun 2014 00:26:06 +0000 (05:26 +0500)
committerAnthony Minessale <anthm@freeswitch.org>
Sat, 21 Jun 2014 00:26:06 +0000 (05:26 +0500)
40 files changed:
html5/verto/README [new file with mode: 0644]
html5/verto/demo/css/images/ajax-loader.gif [new file with mode: 0644]
html5/verto/demo/css/images/icons-18-black.png [new file with mode: 0644]
html5/verto/demo/css/images/icons-18-white.png [new file with mode: 0644]
html5/verto/demo/css/images/icons-36-black.png [new file with mode: 0644]
html5/verto/demo/css/images/icons-36-white.png [new file with mode: 0644]
html5/verto/demo/css/images/loading.gif [new file with mode: 0644]
html5/verto/demo/css/images/login.gif [new file with mode: 0644]
html5/verto/demo/css/jquery.mobile-1.3.2.min.css [new file with mode: 0644]
html5/verto/demo/css/jsontable.css [new file with mode: 0644]
html5/verto/demo/favicon.ico [new file with mode: 0644]
html5/verto/demo/images/ajax-loader.gif [new file with mode: 0644]
html5/verto/demo/images/icons-18-black.png [new file with mode: 0644]
html5/verto/demo/images/icons-18-white.png [new file with mode: 0644]
html5/verto/demo/images/icons-36-black.png [new file with mode: 0644]
html5/verto/demo/images/icons-36-white.png [new file with mode: 0644]
html5/verto/demo/images/loading.gif [new file with mode: 0644]
html5/verto/demo/images/login.gif [new file with mode: 0644]
html5/verto/demo/img/cc_banner2014.gif [new file with mode: 0644]
html5/verto/demo/img/cc_banner2014.jpg [new file with mode: 0644]
html5/verto/demo/img/logo.png [new file with mode: 0644]
html5/verto/demo/img/logo_big.png [new file with mode: 0644]
html5/verto/demo/img/logo_med.png [new file with mode: 0644]
html5/verto/demo/index.html [new file with mode: 0644]
html5/verto/demo/js/jquery-2.0.3.min.js [new file with mode: 0644]
html5/verto/demo/js/jquery.cookie.js [new file with mode: 0644]
html5/verto/demo/js/jquery.dataTables.js [new file with mode: 0644]
html5/verto/demo/js/jquery.json-2.4.min.js [new file with mode: 0644]
html5/verto/demo/js/jquery.mobile-1.3.2.min.js [new file with mode: 0644]
html5/verto/demo/js/verto-min.js [new file with mode: 0644]
html5/verto/demo/sounds/bell_ring2.mp3 [new file with mode: 0644]
html5/verto/demo/sounds/bell_ring2.wav [new file with mode: 0644]
html5/verto/demo/verto.html [new file with mode: 0644]
html5/verto/demo/verto.js [new file with mode: 0644]
html5/verto/js/Makefile [new file with mode: 0644]
html5/verto/js/README [new file with mode: 0644]
html5/verto/js/jsmin.c [new file with mode: 0644]
html5/verto/js/src/jquery.FSRTC.js [new file with mode: 0644]
html5/verto/js/src/jquery.jsonrpcclient.js [new file with mode: 0644]
html5/verto/js/src/jquery.verto.js [new file with mode: 0644]

diff --git a/html5/verto/README b/html5/verto/README
new file mode 100644 (file)
index 0000000..c3d8142
--- /dev/null
@@ -0,0 +1,3 @@
+This needs to be fleshed out more.
+It would be nice to develop a web app here that implements a web phone.
+Do not base it on the demo because it was just tossed together.
diff --git a/html5/verto/demo/css/images/ajax-loader.gif b/html5/verto/demo/css/images/ajax-loader.gif
new file mode 100644 (file)
index 0000000..fd1a189
Binary files /dev/null and b/html5/verto/demo/css/images/ajax-loader.gif differ
diff --git a/html5/verto/demo/css/images/icons-18-black.png b/html5/verto/demo/css/images/icons-18-black.png
new file mode 100644 (file)
index 0000000..7916463
Binary files /dev/null and b/html5/verto/demo/css/images/icons-18-black.png differ
diff --git a/html5/verto/demo/css/images/icons-18-white.png b/html5/verto/demo/css/images/icons-18-white.png
new file mode 100644 (file)
index 0000000..3419b81
Binary files /dev/null and b/html5/verto/demo/css/images/icons-18-white.png differ
diff --git a/html5/verto/demo/css/images/icons-36-black.png b/html5/verto/demo/css/images/icons-36-black.png
new file mode 100644 (file)
index 0000000..043bfcd
Binary files /dev/null and b/html5/verto/demo/css/images/icons-36-black.png differ
diff --git a/html5/verto/demo/css/images/icons-36-white.png b/html5/verto/demo/css/images/icons-36-white.png
new file mode 100644 (file)
index 0000000..12455c9
Binary files /dev/null and b/html5/verto/demo/css/images/icons-36-white.png differ
diff --git a/html5/verto/demo/css/images/loading.gif b/html5/verto/demo/css/images/loading.gif
new file mode 100644 (file)
index 0000000..fe378da
Binary files /dev/null and b/html5/verto/demo/css/images/loading.gif differ
diff --git a/html5/verto/demo/css/images/login.gif b/html5/verto/demo/css/images/login.gif
new file mode 100644 (file)
index 0000000..9f4f36b
Binary files /dev/null and b/html5/verto/demo/css/images/login.gif differ
diff --git a/html5/verto/demo/css/jquery.mobile-1.3.2.min.css b/html5/verto/demo/css/jquery.mobile-1.3.2.min.css
new file mode 100644 (file)
index 0000000..0975cbc
--- /dev/null
@@ -0,0 +1,12 @@
+/*! jQuery Mobile 1.3.2 | Git HEAD hash: 528cf0e <> 2013-07-19T22:17:57Z | (c) 2010, 2013 jQuery Foundation, Inc. | jquery.org/license */
+
+/*!
+* jQuery Mobile 1.3.2
+* Git HEAD hash: 528cf0e96940644ea644096bfeb913ed920ffaef <> Date: Fri Jul 19 2013 22:17:57 UTC
+* http://jquerymobile.com
+*
+* Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
+* Released under the MIT license.
+* http://jquery.org/license
+*
+*/.ui-bar-a{border:1px solid #333;background:#111;color:#fff;font-weight:700;text-shadow:0 -1px 0 #000;background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#111));background-image:-webkit-linear-gradient(#3c3c3c,#111);background-image:-moz-linear-gradient(#3c3c3c,#111);background-image:-ms-linear-gradient(#3c3c3c,#111);background-image:-o-linear-gradient(#3c3c3c,#111);background-image:linear-gradient(#3c3c3c,#111)}.ui-bar-a,.ui-bar-a input,.ui-bar-a select,.ui-bar-a textarea,.ui-bar-a button{font-family:Helvetica,Arial,sans-serif}.ui-bar-a .ui-link-inherit{color:#fff}.ui-bar-a a.ui-link{color:#7cc4e7;font-weight:700}.ui-bar-a a.ui-link:visited{color:#2489ce}.ui-bar-a a.ui-link:hover{color:#2489ce}.ui-bar-a a.ui-link:active{color:#2489ce}.ui-body-a,.ui-overlay-a{border:1px solid #444;background:#222;color:#fff;text-shadow:0 1px 0 #111;font-weight:400;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#222));background-image:-webkit-linear-gradient(#444,#222);background-image:-moz-linear-gradient(#444,#222);background-image:-ms-linear-gradient(#444,#222);background-image:-o-linear-gradient(#444,#222);background-image:linear-gradient(#444,#222)}.ui-overlay-a{background-image:none;border-width:0}.ui-body-a,.ui-body-a input,.ui-body-a select,.ui-body-a textarea,.ui-body-a button{font-family:Helvetica,Arial,sans-serif}.ui-body-a .ui-link-inherit{color:#fff}.ui-body-a .ui-link{color:#2489ce;font-weight:700}.ui-body-a .ui-link:visited{color:#2489ce}.ui-body-a .ui-link:hover{color:#2489ce}.ui-body-a .ui-link:active{color:#2489ce}.ui-btn-up-a{border:1px solid #111;background:#333;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#444),to(#2d2d2d));background-image:-webkit-linear-gradient(#444,#2d2d2d);background-image:-moz-linear-gradient(#444,#2d2d2d);background-image:-ms-linear-gradient(#444,#2d2d2d);background-image:-o-linear-gradient(#444,#2d2d2d);background-image:linear-gradient(#444,#2d2d2d)}.ui-btn-up-a:visited,.ui-btn-up-a a.ui-link-inherit{color:#fff}.ui-btn-hover-a{border:1px solid #000;background:#444;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#555),to(#383838));background-image:-webkit-linear-gradient(#555,#383838);background-image:-moz-linear-gradient(#555,#383838);background-image:-ms-linear-gradient(#555,#383838);background-image:-o-linear-gradient(#555,#383838);background-image:linear-gradient(#555,#383838)}.ui-btn-hover-a:visited,.ui-btn-hover-a:hover,.ui-btn-hover-a a.ui-link-inherit{color:#fff}.ui-btn-down-a{border:1px solid #000;background:#222;font-weight:700;color:#fff;text-shadow:0 1px 0 #111;background-image:-webkit-gradient(linear,left top,left bottom,from(#202020),to(#2c2c2c));background-image:-webkit-linear-gradient(#202020,#2c2c2c);background-image:-moz-linear-gradient(#202020,#2c2c2c);background-image:-ms-linear-gradient(#202020,#2c2c2c);background-image:-o-linear-gradient(#202020,#2c2c2c);background-image:linear-gradient(#202020,#2c2c2c)}.ui-btn-down-a:visited,.ui-btn-down-a:hover,.ui-btn-down-a a.ui-link-inherit{color:#fff}.ui-btn-up-a,.ui-btn-hover-a,.ui-btn-down-a{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-b{border:1px solid #456f9a;background:#5e87b0;color:#fff;font-weight:700;text-shadow:0 1px 0 #3e6790;background-image:-webkit-gradient(linear,left top,left bottom,from(#6facd5),to(#497bae));background-image:-webkit-linear-gradient(#6facd5,#497bae);background-image:-moz-linear-gradient(#6facd5,#497bae);background-image:-ms-linear-gradient(#6facd5,#497bae);background-image:-o-linear-gradient(#6facd5,#497bae);background-image:linear-gradient(#6facd5,#497bae)}.ui-bar-b,.ui-bar-b input,.ui-bar-b select,.ui-bar-b textarea,.ui-bar-b button{font-family:Helvetica,Arial,sans-serif}.ui-bar-b .ui-link-inherit{color:#fff}.ui-bar-b a.ui-link{color:#ddf0f8;font-weight:700}.ui-bar-b a.ui-link:visited{color:#ddf0f8}.ui-bar-b a.ui-link:hover{color:#ddf0f8}.ui-bar-b a.ui-link:active{color:#ddf0f8}.ui-body-b,.ui-overlay-b{border:1px solid #999;background:#f3f3f3;color:#222;text-shadow:0 1px 0 #fff;font-weight:400;background-image:-webkit-gradient(linear,left top,left bottom,from(#ddd),to(#ccc));background-image:-webkit-linear-gradient(#ddd,#ccc);background-image:-moz-linear-gradient(#ddd,#ccc);background-image:-ms-linear-gradient(#ddd,#ccc);background-image:-o-linear-gradient(#ddd,#ccc);background-image:linear-gradient(#ddd,#ccc)}.ui-overlay-b{background-image:none;border-width:0}.ui-body-b,.ui-body-b input,.ui-body-b select,.ui-body-b textarea,.ui-body-b button{font-family:Helvetica,Arial,sans-serif}.ui-body-b .ui-link-inherit{color:#333}.ui-body-b .ui-link{color:#2489ce;font-weight:700}.ui-body-b .ui-link:visited{color:#2489ce}.ui-body-b .ui-link:hover{color:#2489ce}.ui-body-b .ui-link:active{color:#2489ce}.ui-btn-up-b{border:1px solid #044062;background:#396b9e;font-weight:700;color:#fff;text-shadow:0 1px 0 #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from(#5f9cc5),to(#396b9e));background-image:-webkit-linear-gradient(#5f9cc5,#396b9e);background-image:-moz-linear-gradient(#5f9cc5,#396b9e);background-image:-ms-linear-gradient(#5f9cc5,#396b9e);background-image:-o-linear-gradient(#5f9cc5,#396b9e);background-image:linear-gradient(#5f9cc5,#396b9e)}.ui-btn-up-b:visited,.ui-btn-up-b a.ui-link-inherit{color:#fff}.ui-btn-hover-b{border:1px solid #00415e;background:#4b88b6;font-weight:700;color:#fff;text-shadow:0 1px 0 #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from(#6facd5),to(#4272a4));background-image:-webkit-linear-gradient(#6facd5,#4272a4);background-image:-moz-linear-gradient(#6facd5,#4272a4);background-image:-ms-linear-gradient(#6facd5,#4272a4);background-image:-o-linear-gradient(#6facd5,#4272a4);background-image:linear-gradient(#6facd5,#4272a4)}.ui-btn-hover-b:visited,.ui-btn-hover-b:hover,.ui-btn-hover-b a.ui-link-inherit{color:#fff}.ui-btn-down-b{border:1px solid #225377;background:#4e89c5;font-weight:700;color:#fff;text-shadow:0 1px 0 #194b7e;background-image:-webkit-gradient(linear,left top,left bottom,from(#295b8e),to(#3e79b5));background-image:-webkit-linear-gradient(#295b8e,#3e79b5);background-image:-moz-linear-gradient(#295b8e,#3e79b5);background-image:-ms-linear-gradient(#295b8e,#3e79b5);background-image:-o-linear-gradient(#295b8e,#3e79b5);background-image:linear-gradient(#295b8e,#3e79b5)}.ui-btn-down-b:visited,.ui-btn-down-b:hover,.ui-btn-down-b a.ui-link-inherit{color:#fff}.ui-btn-up-b,.ui-btn-hover-b,.ui-btn-down-b{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-c{border:1px solid #b3b3b3;background:#eee;color:#3e3e3e;font-weight:700;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#f0f0f0),to(#ddd));background-image:-webkit-linear-gradient(#f0f0f0,#ddd);background-image:-moz-linear-gradient(#f0f0f0,#ddd);background-image:-ms-linear-gradient(#f0f0f0,#ddd);background-image:-o-linear-gradient(#f0f0f0,#ddd);background-image:linear-gradient(#f0f0f0,#ddd)}.ui-bar-c .ui-link-inherit{color:#3e3e3e}.ui-bar-c a.ui-link{color:#7cc4e7;font-weight:700}.ui-bar-c a.ui-link:visited{color:#2489ce}.ui-bar-c a.ui-link:hover{color:#2489ce}.ui-bar-c a.ui-link:active{color:#2489ce}.ui-bar-c,.ui-bar-c input,.ui-bar-c select,.ui-bar-c textarea,.ui-bar-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c,.ui-overlay-c{border:1px solid #aaa;color:#333;text-shadow:0 1px 0 #fff;background:#f9f9f9;background-image:-webkit-gradient(linear,left top,left bottom,from(#f9f9f9),to(#eee));background-image:-webkit-linear-gradient(#f9f9f9,#eee);background-image:-moz-linear-gradient(#f9f9f9,#eee);background-image:-ms-linear-gradient(#f9f9f9,#eee);background-image:-o-linear-gradient(#f9f9f9,#eee);background-image:linear-gradient(#f9f9f9,#eee)}.ui-overlay-c{background-image:none;border-width:0}.ui-body-c,.ui-body-c input,.ui-body-c select,.ui-body-c textarea,.ui-body-c button{font-family:Helvetica,Arial,sans-serif}.ui-body-c .ui-link-inherit{color:#333}.ui-body-c .ui-link{color:#2489ce;font-weight:700}.ui-body-c .ui-link:visited{color:#2489ce}.ui-body-c .ui-link:hover{color:#2489ce}.ui-body-c .ui-link:active{color:#2489ce}.ui-btn-up-c{border:1px solid #ccc;background:#eee;font-weight:700;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f1f1f1));background-image:-webkit-linear-gradient(#fff,#f1f1f1);background-image:-moz-linear-gradient(#fff,#f1f1f1);background-image:-ms-linear-gradient(#fff,#f1f1f1);background-image:-o-linear-gradient(#fff,#f1f1f1);background-image:linear-gradient(#fff,#f1f1f1)}.ui-btn-up-c:visited,.ui-btn-up-c a.ui-link-inherit{color:#2f3e46}.ui-btn-hover-c{border:1px solid #bbb;background:#dfdfdf;font-weight:700;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#f6f6f6),to(#e0e0e0));background-image:-webkit-linear-gradient(#f6f6f6,#e0e0e0);background-image:-moz-linear-gradient(#f6f6f6,#e0e0e0);background-image:-ms-linear-gradient(#f6f6f6,#e0e0e0);background-image:-o-linear-gradient(#f6f6f6,#e0e0e0);background-image:linear-gradient(#f6f6f6,#e0e0e0)}.ui-btn-hover-c:visited,.ui-btn-hover-c:hover,.ui-btn-hover-c a.ui-link-inherit{color:#2f3e46}.ui-btn-down-c{border:1px solid #bbb;background:#d6d6d6;font-weight:700;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#d0d0d0),to(#dfdfdf));background-image:-webkit-linear-gradient(#d0d0d0,#dfdfdf);background-image:-moz-linear-gradient(#d0d0d0,#dfdfdf);background-image:-ms-linear-gradient(#d0d0d0,#dfdfdf);background-image:-o-linear-gradient(#d0d0d0,#dfdfdf);background-image:linear-gradient(#d0d0d0,#dfdfdf)}.ui-btn-down-c:visited,.ui-btn-down-c:hover,.ui-btn-down-c a.ui-link-inherit{color:#2f3e46}.ui-btn-up-c,.ui-btn-hover-c,.ui-btn-down-c{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-d{border:1px solid #bbb;background:#bbb;color:#333;font-weight:700;text-shadow:0 1px 0 #eee;background-image:-webkit-gradient(linear,left top,left bottom,from(#ddd),to(#bbb));background-image:-webkit-linear-gradient(#ddd,#bbb);background-image:-moz-linear-gradient(#ddd,#bbb);background-image:-ms-linear-gradient(#ddd,#bbb);background-image:-o-linear-gradient(#ddd,#bbb);background-image:linear-gradient(#ddd,#bbb)}.ui-bar-d,.ui-bar-d input,.ui-bar-d select,.ui-bar-d textarea,.ui-bar-d button{font-family:Helvetica,Arial,sans-serif}.ui-bar-d .ui-link-inherit{color:#333}.ui-bar-d a.ui-link{color:#2489ce;font-weight:700}.ui-bar-d a.ui-link:visited{color:#2489ce}.ui-bar-d a.ui-link:hover{color:#2489ce}.ui-bar-d a.ui-link:active{color:#2489ce}.ui-body-d,.ui-overlay-d{border:1px solid #bbb;color:#333;text-shadow:0 1px 0 #fff;background:#fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#fff));background-image:-webkit-linear-gradient(#fff,#fff);background-image:-moz-linear-gradient(#fff,#fff);background-image:-ms-linear-gradient(#fff,#fff);background-image:-o-linear-gradient(#fff,#fff);background-image:linear-gradient(#fff,#fff)}.ui-overlay-d{background-image:none;border-width:0}.ui-body-d,.ui-body-d input,.ui-body-d select,.ui-body-d textarea,.ui-body-d button{font-family:Helvetica,Arial,sans-serif}.ui-body-d .ui-link-inherit{color:#333}.ui-body-d .ui-link{color:#2489ce;font-weight:700}.ui-body-d .ui-link:visited{color:#2489ce}.ui-body-d .ui-link:hover{color:#2489ce}.ui-body-d .ui-link:active{color:#2489ce}.ui-btn-up-d{border:1px solid #bbb;background:#fff;font-weight:700;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fafafa),to(#f6f6f6));background-image:-webkit-linear-gradient(#fafafa,#f6f6f6);background-image:-moz-linear-gradient(#fafafa,#f6f6f6);background-image:-ms-linear-gradient(#fafafa,#f6f6f6);background-image:-o-linear-gradient(#fafafa,#f6f6f6);background-image:linear-gradient(#fafafa,#f6f6f6)}.ui-btn-up-d:visited,.ui-btn-up-d a.ui-link-inherit{color:#333}.ui-btn-hover-d{border:1px solid #aaa;background:#eee;font-weight:700;color:#333;cursor:pointer;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#eee),to(#fff));background-image:-webkit-linear-gradient(#eee,#fff);background-image:-moz-linear-gradient(#eee,#fff);background-image:-ms-linear-gradient(#eee,#fff);background-image:-o-linear-gradient(#eee,#fff);background-image:linear-gradient(#eee,#fff)}.ui-btn-hover-d:visited,.ui-btn-hover-d:hover,.ui-btn-hover-d a.ui-link-inherit{color:#333}.ui-btn-down-d{border:1px solid #aaa;background:#eee;font-weight:700;color:#333;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#e5e5e5),to(#f2f2f2));background-image:-webkit-linear-gradient(#e5e5e5,#f2f2f2);background-image:-moz-linear-gradient(#e5e5e5,#f2f2f2);background-image:-ms-linear-gradient(#e5e5e5,#f2f2f2);background-image:-o-linear-gradient(#e5e5e5,#f2f2f2);background-image:linear-gradient(#e5e5e5,#f2f2f2)}.ui-btn-down-d:visited,.ui-btn-down-d:hover,.ui-btn-down-d a.ui-link-inherit{color:#333}.ui-btn-up-d,.ui-btn-hover-d,.ui-btn-down-d{font-family:Helvetica,Arial,sans-serif;text-decoration:none}.ui-bar-e{border:1px solid #f7c942;background:#fadb4e;color:#333;font-weight:700;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fceda7),to(#fbef7e));background-image:-webkit-linear-gradient(#fceda7,#fbef7e);background-image:-moz-linear-gradient(#fceda7,#fbef7e);background-image:-ms-linear-gradient(#fceda7,#fbef7e);background-image:-o-linear-gradient(#fceda7,#fbef7e);background-image:linear-gradient(#fceda7,#fbef7e)}.ui-bar-e,.ui-bar-e input,.ui-bar-e select,.ui-bar-e textarea,.ui-bar-e button{font-family:Helvetica,Arial,sans-serif}.ui-bar-e .ui-link-inherit{color:#333}.ui-bar-e a.ui-link{color:#2489ce;font-weight:700}.ui-bar-e a.ui-link:visited{color:#2489ce}.ui-bar-e a.ui-link:hover{color:#2489ce}.ui-bar-e a.ui-link:active{color:#2489ce}.ui-body-e,.ui-overlay-e{border:1px solid #f7c942;color:#222;text-shadow:0 1px 0 #fff;background:#fff9df;background-image:-webkit-gradient(linear,left top,left bottom,from(#fffadf),to(#fff3a5));background-image:-webkit-linear-gradient(#fffadf,#fff3a5);background-image:-moz-linear-gradient(#fffadf,#fff3a5);background-image:-ms-linear-gradient(#fffadf,#fff3a5);background-image:-o-linear-gradient(#fffadf,#fff3a5);background-image:linear-gradient(#fffadf,#fff3a5)}.ui-overlay-e{background-image:none;border-width:0}.ui-body-e,.ui-body-e input,.ui-body-e select,.ui-body-e textarea,.ui-body-e button{font-family:Helvetica,Arial,sans-serif}.ui-body-e .ui-link-inherit{color:#222}.ui-body-e .ui-link{color:#2489ce;font-weight:700}.ui-body-e .ui-link:visited{color:#2489ce}.ui-body-e .ui-link:hover{color:#2489ce}.ui-body-e .ui-link:active{color:#2489ce}.ui-btn-up-e{border:1px solid #f4c63f;background:#fadb4e;font-weight:700;color:#222;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#ffefaa),to(#ffe155));background-image:-webkit-linear-gradient(#ffefaa,#ffe155);background-image:-moz-linear-gradient(#ffefaa,#ffe155);background-image:-ms-linear-gradient(#ffefaa,#ffe155);background-image:-o-linear-gradient(#ffefaa,#ffe155);background-image:linear-gradient(#ffefaa,#ffe155)}.ui-btn-up-e:visited,.ui-btn-up-e a.ui-link-inherit{color:#222}.ui-btn-hover-e{border:1px solid #f2c43d;background:#fbe26f;font-weight:700;color:#111;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#fff5ba),to(#fbdd52));background-image:-webkit-linear-gradient(#fff5ba,#fbdd52);background-image:-moz-linear-gradient(#fff5ba,#fbdd52);background-image:-ms-linear-gradient(#fff5ba,#fbdd52);background-image:-o-linear-gradient(#fff5ba,#fbdd52);background-image:linear-gradient(#fff5ba,#fbdd52)}.ui-btn-hover-e:visited,.ui-btn-hover-e:hover,.ui-btn-hover-e a.ui-link-inherit{color:#333}.ui-btn-down-e{border:1px solid #f2c43d;background:#fceda7;font-weight:700;color:#111;text-shadow:0 1px 0 #fff;background-image:-webkit-gradient(linear,left top,left bottom,from(#f8d94c),to(#fadb4e));background-image:-webkit-linear-gradient(#f8d94c,#fadb4e);background-image:-moz-linear-gradient(#f8d94c,#fadb4e);background-image:-ms-linear-gradient(#f8d94c,#fadb4e);background-image:-o-linear-gradient(#f8d94c,#fadb4e);background-image:linear-gradient(#f8d94c,#fadb4e)}.ui-btn-down-e:visited,.ui-btn-down-e:hover,.ui-btn-down-e a.ui-link-inherit{color:#333}.ui-btn-up-e,.ui-btn-hover-e,.ui-btn-down-e{font-family:Helvetica,Arial,sans-serif;text-decoration:none}a.ui-link-inherit{text-decoration:none!important}.ui-btn-active{border:1px solid #2373a5;background:#5393c5;font-weight:700;color:#fff;cursor:pointer;text-shadow:0 1px 0 #3373a5;text-decoration:none;background-image:-webkit-gradient(linear,left top,left bottom,from(#5393c5),to(#6facd5));background-image:-webkit-linear-gradient(#5393c5,#6facd5);background-image:-moz-linear-gradient(#5393c5,#6facd5);background-image:-ms-linear-gradient(#5393c5,#6facd5);background-image:-o-linear-gradient(#5393c5,#6facd5);background-image:linear-gradient(#5393c5,#6facd5);font-family:Helvetica,Arial,sans-serif}.ui-btn-active:visited,.ui-btn-active:hover,.ui-btn-active a.ui-link-inherit{color:#fff}.ui-btn-inner{border-top:1px solid #fff;border-color:rgba(255,255,255,.3)}.ui-corner-all{-webkit-border-radius:.6em;border-radius:.6em}.ui-br{border-color:#828282;border-color:rgba(130,130,130,.3);border-style:solid}.ui-disabled{filter:Alpha(Opacity=30);opacity:.3;zoom:1}.ui-disabled,.ui-disabled a{cursor:default!important;pointer-events:none}.ui-icon,.ui-icon-searchfield:after{background:#666;background:rgba(0,0,0,.4);background-image:url(images/icons-18-white.png);background-repeat:no-repeat;-webkit-border-radius:9px;border-radius:9px}.ui-icon-alt .ui-icon,.ui-icon-alt .ui-icon-searchfield:after{background-color:#fff;background-color:rgba(255,255,255,.3);background-image:url(images/icons-18-black.png);background-repeat:no-repeat}.ui-icon-nodisc .ui-icon,.ui-icon-nodisc .ui-icon-searchfield:after,.ui-icon-nodisc .ui-icon-alt .ui-icon,.ui-icon-nodisc .ui-icon-alt .ui-icon-searchfield:after{background-color:transparent}.ui-icon-plus{background-position:-1px -1px}.ui-icon-minus{background-position:-37px -1px}.ui-icon-delete{background-position:-73px -1px}.ui-icon-arrow-r{background-position:-108px -1px}.ui-icon-arrow-l{background-position:-144px -1px}.ui-icon-arrow-u{background-position:-180px -1px}.ui-icon-arrow-d{background-position:-216px -1px}.ui-icon-check{background-position:-252px -1px}.ui-icon-gear{background-position:-288px -1px}.ui-icon-refresh{background-position:-323px -1px}.ui-icon-forward{background-position:-360px -1px}.ui-icon-back{background-position:-396px -1px}.ui-icon-grid{background-position:-432px -1px}.ui-icon-star{background-position:-467px -1px}.ui-icon-alert{background-position:-503px -1px}.ui-icon-info{background-position:-539px -1px}.ui-icon-home{background-position:-575px -1px}.ui-icon-search,.ui-icon-searchfield:after{background-position:-611px -1px}.ui-icon-checkbox-on{background-position:-647px -1px}.ui-icon-checkbox-off{background-position:-683px -1px}.ui-icon-radio-on{background-position:-718px -1px}.ui-icon-radio-off{background-position:-754px -1px}.ui-icon-bars{background-position:-788px -1px}.ui-icon-edit{background-position:-824px -1px}@media only screen and (-webkit-min-device-pixel-ratio:1.3),only screen and (min--moz-device-pixel-ratio:1.3),only screen and (min-resolution:200dpi){.ui-icon-plus,.ui-icon-minus,.ui-icon-delete,.ui-icon-arrow-r,.ui-icon-arrow-l,.ui-icon-arrow-u,.ui-icon-arrow-d,.ui-icon-check,.ui-icon-gear,.ui-icon-refresh,.ui-icon-forward,.ui-icon-back,.ui-icon-grid,.ui-icon-star,.ui-icon-alert,.ui-icon-info,.ui-icon-home,.ui-icon-bars,.ui-icon-edit,.ui-icon-search,.ui-icon-searchfield:after,.ui-icon-checkbox-off,.ui-icon-checkbox-on,.ui-icon-radio-off,.ui-icon-radio-on{background-image:url(images/icons-36-white.png);-moz-background-size:864px 18px;-o-background-size:864px 18px;-webkit-background-size:864px 18px;background-size:864px 18px}.ui-icon-alt .ui-icon{background-image:url(images/icons-36-black.png)}.ui-icon-plus{background-position:0 50%}.ui-icon-minus{background-position:-36px 50%}.ui-icon-delete{background-position:-72px 50%}.ui-icon-arrow-r{background-position:-108px 50%}.ui-icon-arrow-l{background-position:-144px 50%}.ui-icon-arrow-u{background-position:-179px 50%}.ui-icon-arrow-d{background-position:-215px 50%}.ui-icon-check{background-position:-252px 50%}.ui-icon-gear{background-position:-287px 50%}.ui-icon-refresh{background-position:-323px 50%}.ui-icon-forward{background-position:-360px 50%}.ui-icon-back{background-position:-395px 50%}.ui-icon-grid{background-position:-431px 50%}.ui-icon-star{background-position:-467px 50%}.ui-icon-alert{background-position:-503px 50%}.ui-icon-info{background-position:-538px 50%}.ui-icon-home{background-position:-575px 50%}.ui-icon-search,.ui-icon-searchfield:after{background-position:-611px 50%}.ui-icon-checkbox-on{background-position:-647px 50%}.ui-icon-checkbox-off{background-position:-683px 50%}.ui-icon-radio-on{background-position:-718px 50%}.ui-icon-radio-off{background-position:-754px 50%}.ui-icon-bars{background-position:-788px 50%}.ui-icon-edit{background-position:-824px 50%}}.ui-checkbox .ui-icon,.ui-selectmenu-list .ui-icon{-webkit-border-radius:3px;border-radius:3px}.ui-icon-checkbox-off,.ui-icon-radio-off{background-color:transparent}.ui-checkbox-on .ui-icon,.ui-radio-on .ui-icon{background-color:#4596ce}.ui-icon-loading{background:url(images/ajax-loader.gif);background-size:46px 46px}.ui-btn-corner-all{-webkit-border-radius:1em;border-radius:1em}.ui-corner-all,.ui-btn-corner-all{-webkit-background-clip:padding;background-clip:padding-box}.ui-overlay{background:#666;filter:Alpha(Opacity=50);opacity:.5;position:absolute;width:100%;height:100%}.ui-overlay-shadow{-moz-box-shadow:0 0 12px rgba(0,0,0,.6);-webkit-box-shadow:0 0 12px rgba(0,0,0,.6);box-shadow:0 0 12px rgba(0,0,0,.6)}.ui-shadow{-moz-box-shadow:0 1px 3px rgba(0,0,0,.2);-webkit-box-shadow:0 1px 3px rgba(0,0,0,.2);box-shadow:0 1px 3px rgba(0,0,0,.2)}.ui-bar-a .ui-shadow,.ui-bar-b .ui-shadow,.ui-bar-c .ui-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.3);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.3);box-shadow:0 1px 0 rgba(255,255,255,.3)}.ui-shadow-inset{-moz-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 4px rgba(0,0,0,.2);box-shadow:inset 0 1px 4px rgba(0,0,0,.2)}.ui-icon-shadow{-moz-box-shadow:0 1px 0 rgba(255,255,255,.4);-webkit-box-shadow:0 1px 0 rgba(255,255,255,.4);box-shadow:0 1px 0 rgba(255,255,255,.4)}.ui-btn:focus,.ui-link-inherit:focus{outline:0}.ui-btn.ui-focus{z-index:1}.ui-focus,.ui-btn:focus{-moz-box-shadow:inset 0 0 3px #387bbe,0 0 9px #387bbe;-webkit-box-shadow:inset 0 0 3px #387bbe,0 0 9px #387bbe;box-shadow:inset 0 0 3px #387bbe,0 0 9px #387bbe}.ui-input-text.ui-focus,.ui-input-search.ui-focus{-moz-box-shadow:0 0 12px #387bbe;-webkit-box-shadow:0 0 12px #387bbe;box-shadow:0 0 12px #387bbe}.ui-mobile-nosupport-boxshadow *{-moz-box-shadow:none!important;-webkit-box-shadow:none!important;box-shadow:none!important}.ui-mobile-nosupport-boxshadow .ui-focus,.ui-mobile-nosupport-boxshadow .ui-btn:focus,.ui-mobile-nosupport-boxshadow .ui-link-inherit:focus{outline-width:1px;outline-style:auto}.ui-mobile,.ui-mobile body{height:99.9%}.ui-mobile fieldset,.ui-page{padding:0;margin:0}.ui-mobile a img,.ui-mobile fieldset{border-width:0}.ui-mobile fieldset{min-width:0}.ui-mobile-viewport{margin:0;overflow-x:visible;-webkit-text-size-adjust:100%;-ms-text-size-adjust:none;-webkit-tap-highlight-color:rgba(0,0,0,0)}body.ui-mobile-viewport,div.ui-mobile-viewport{overflow-x:hidden}.ui-mobile [data-role=page],.ui-mobile [data-role=dialog],.ui-page{top:0;left:0;width:100%;min-height:100%;position:absolute;display:none;border:0}.ui-mobile .ui-page-active{display:block;overflow:visible}.ui-page{outline:0}@media screen and (orientation:portrait){.ui-mobile .ui-page{min-height:420px}}@media screen and (orientation:landscape){.ui-mobile .ui-page{min-height:300px}}.ui-loading .ui-loader{display:block}.ui-loader{display:none;z-index:9999999;position:fixed;top:50%;left:50%;border:0}.ui-loader-default{background:0;filter:Alpha(Opacity=18);opacity:.18;width:46px;height:46px;margin-left:-23px;margin-top:-23px}.ui-loader-verbose{width:200px;filter:Alpha(Opacity=88);opacity:.88;box-shadow:0 1px 1px -1px #fff;height:auto;margin-left:-110px;margin-top:-43px;padding:10px}.ui-loader-default h1{font-size:0;width:0;height:0;overflow:hidden}.ui-loader-verbose h1{font-size:16px;margin:0;text-align:center}.ui-loader .ui-icon{background-color:#000;display:block;margin:0;width:44px;height:44px;padding:1px;-webkit-border-radius:36px;border-radius:36px}.ui-loader-verbose .ui-icon{margin:0 auto 10px;filter:Alpha(Opacity=75);opacity:.75}.ui-loader-textonly{padding:15px;margin-left:-115px}.ui-loader-textonly .ui-icon{display:none}.ui-loader-fakefix{position:absolute}.ui-mobile-rendering>*{visibility:hidden}.ui-bar,.ui-body{position:relative;padding:.4em 15px;overflow:hidden;display:block;clear:both}.ui-bar{font-size:16px;margin:0}.ui-bar h1,.ui-bar h2,.ui-bar h3,.ui-bar h4,.ui-bar h5,.ui-bar h6{margin:0;padding:0;font-size:16px;display:inline-block}.ui-header,.ui-footer{position:relative;zoom:1}.ui-mobile .ui-header,.ui-mobile .ui-footer{border-left-width:0;border-right-width:0}.ui-header .ui-btn-left,.ui-header .ui-btn-right,.ui-footer .ui-btn-left,.ui-footer .ui-btn-right,.ui-header-fixed.ui-fixed-hidden .ui-btn-left,.ui-header-fixed.ui-fixed-hidden .ui-btn-right{position:absolute;top:3px}.ui-header-fixed .ui-btn-left,.ui-header-fixed .ui-btn-right{top:4px}.ui-header .ui-btn-left,.ui-footer .ui-btn-left{left:5px}.ui-header .ui-btn-right,.ui-footer .ui-btn-right{right:5px}.ui-footer>.ui-btn-icon-notext,.ui-header>.ui-btn-icon-notext,.ui-header-fixed.ui-fixed-hidden>.ui-btn-icon-notext{top:6px}.ui-header-fixed>.ui-btn-icon-notext{top:7px}.ui-header .ui-title,.ui-footer .ui-title{min-height:1.1em;text-align:center;font-size:16px;display:block;margin:.6em 30% .8em;padding:0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;outline:0!important}.ui-footer .ui-title{margin:.6em 15px .8em}.ui-content{border-width:0;overflow:visible;overflow-x:hidden;padding:15px}.ui-corner-all>.ui-header:first-child,.ui-corner-all>.ui-content:first-child,.ui-corner-all>.ui-footer:first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-corner-all>.ui-header:last-child,.ui-corner-all>.ui-content:last-child,.ui-corner-all>.ui-footer:last-child{-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-icon{width:18px;height:18px}.ui-nojs{position:absolute;left:-9999px}.ui-hide-label label.ui-input-text,.ui-hide-label label.ui-select,.ui-hide-label label.ui-slider,.ui-hide-label label.ui-submit,.ui-hide-label .ui-controlgroup-label,.ui-hidden-accessible{position:absolute!important;left:-9999px;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ui-mobile-viewport-transitioning,.ui-mobile-viewport-transitioning .ui-page{width:100%;height:100%;overflow:hidden;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.ui-page-pre-in{opacity:0}.in{-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms;animation-timing-function:ease-out;animation-duration:350ms}.out{-webkit-animation-timing-function:ease-in;-webkit-animation-duration:225ms;-moz-animation-timing-function:ease-in;-moz-animation-duration:225ms;animation-timing-function:ease-in;animation-duration:225ms}@-webkit-keyframes fadein{from{opacity:0}to{opacity:1}}@-moz-keyframes fadein{from{opacity:0}to{opacity:1}}@keyframes fadein{from{opacity:0}to{opacity:1}}@-webkit-keyframes fadeout{from{opacity:1}to{opacity:0}}@-moz-keyframes fadeout{from{opacity:1}to{opacity:0}}@keyframes fadeout{from{opacity:1}to{opacity:0}}.fade.out{opacity:0;-webkit-animation-duration:125ms;-webkit-animation-name:fadeout;-moz-animation-duration:125ms;-moz-animation-name:fadeout;animation-duration:125ms;animation-name:fadeout}.fade.in{opacity:1;-webkit-animation-duration:225ms;-webkit-animation-name:fadein;-moz-animation-duration:225ms;-moz-animation-name:fadein;animation-duration:225ms;animation-name:fadein}.pop{-webkit-transform-origin:50% 50%;-moz-transform-origin:50% 50%;transform-origin:50% 50%}.pop.in{-webkit-transform:scale(1);-webkit-animation-name:popin;-webkit-animation-duration:350ms;-moz-transform:scale(1);-moz-animation-name:popin;-moz-animation-duration:350ms;transform:scale(1);animation-name:popin;animation-duration:350ms;opacity:1}.pop.out{-webkit-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-name:fadeout;-moz-animation-duration:100ms;animation-name:fadeout;animation-duration:100ms;opacity:0}.pop.in.reverse{-webkit-animation-name:fadein;-moz-animation-name:fadein;animation-name:fadein}.pop.out.reverse{-webkit-transform:scale(.8);-webkit-animation-name:popout;-moz-transform:scale(.8);-moz-animation-name:popout;transform:scale(.8);animation-name:popout}@-webkit-keyframes popin{from{-webkit-transform:scale(.8);opacity:0}to{-webkit-transform:scale(1);opacity:1}}@-moz-keyframes popin{from{-moz-transform:scale(.8);opacity:0}to{-moz-transform:scale(1);opacity:1}}@keyframes popin{from{transform:scale(.8);opacity:0}to{transform:scale(1);opacity:1}}@-webkit-keyframes popout{from{-webkit-transform:scale(1);opacity:1}to{-webkit-transform:scale(.8);opacity:0}}@-moz-keyframes popout{from{-moz-transform:scale(1);opacity:1}to{-moz-transform:scale(.8);opacity:0}}@keyframes popout{from{transform:scale(1);opacity:1}to{transform:scale(.8);opacity:0}}@-webkit-keyframes slideinfromright{from{-webkit-transform:translate3d(100%,0,0)}to{-webkit-transform:translate3d(0,0,0)}}@-moz-keyframes slideinfromright{from{-moz-transform:translateX(100%)}to{-moz-transform:translateX(0)}}@keyframes slideinfromright{from{transform:translateX(100%)}to{transform:translateX(0)}}@-webkit-keyframes slideinfromleft{from{-webkit-transform:translate3d(-100%,0,0)}to{-webkit-transform:translate3d(0,0,0)}}@-moz-keyframes slideinfromleft{from{-moz-transform:translateX(-100%)}to{-moz-transform:translateX(0)}}@keyframes slideinfromleft{from{transform:translateX(-100%)}to{transform:translateX(0)}}@-webkit-keyframes slideouttoleft{from{-webkit-transform:translate3d(0,0,0)}to{-webkit-transform:translate3d(-100%,0,0)}}@-moz-keyframes slideouttoleft{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(-100%)}}@keyframes slideouttoleft{from{transform:translateX(0)}to{transform:translateX(-100%)}}@-webkit-keyframes slideouttoright{from{-webkit-transform:translate3d(0,0,0)}to{-webkit-transform:translate3d(100%,0,0)}}@-moz-keyframes slideouttoright{from{-moz-transform:translateX(0)}to{-moz-transform:translateX(100%)}}@keyframes slideouttoright{from{transform:translateX(0)}to{transform:translateX(100%)}}.slide.out,.slide.in{-webkit-animation-timing-function:ease-out;-webkit-animation-duration:350ms;-moz-animation-timing-function:ease-out;-moz-animation-duration:350ms;animation-timing-function:ease-out;animation-duration:350ms}.slide.out{-webkit-transform:translate3d(-100%,0,0);-webkit-animation-name:slideouttoleft;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft;transform:translateX(-100%);animation-name:slideouttoleft}.slide.in{-webkit-transform:translate3d(0,0,0);-webkit-animation-name:slideinfromright;-moz-transform:translateX(0);-moz-animation-name:slideinfromright;transform:translateX(0);animation-name:slideinfromright}.slide.out.reverse{-webkit-transform:translate3d(100%,0,0);-webkit-animation-name:slideouttoright;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright;transform:translateX(100%);animation-name:slideouttoright}.slide.in.reverse{-webkit-transform:translate3d(0,0,0);-webkit-animation-name:slideinfromleft;-moz-transform:translateX(0);-moz-animation-name:slideinfromleft;transform:translateX(0);animation-name:slideinfromleft}.slidefade.out{-webkit-transform:translateX(-100%);-webkit-animation-name:slideouttoleft;-webkit-animation-duration:225ms;-moz-transform:translateX(-100%);-moz-animation-name:slideouttoleft;-moz-animation-duration:225ms;transform:translateX(-100%);animation-name:slideouttoleft;animation-duration:225ms}.slidefade.in{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-webkit-animation-duration:200ms;-moz-transform:translateX(0);-moz-animation-name:fadein;-moz-animation-duration:200ms;transform:translateX(0);animation-name:fadein;animation-duration:200ms}.slidefade.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:slideouttoright;-webkit-animation-duration:200ms;-moz-transform:translateX(100%);-moz-animation-name:slideouttoright;-moz-animation-duration:200ms;transform:translateX(100%);animation-name:slideouttoright;animation-duration:200ms}.slidefade.in.reverse{-webkit-transform:translateX(0);-webkit-animation-name:fadein;-webkit-animation-duration:200ms;-moz-transform:translateX(0);-moz-animation-name:fadein;-moz-animation-duration:200ms;transform:translateX(0);animation-name:fadein;animation-duration:200ms}.slidedown.out{-webkit-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-name:fadeout;-moz-animation-duration:100ms;animation-name:fadeout;animation-duration:100ms}.slidedown.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfromtop;-webkit-animation-duration:250ms;-moz-transform:translateY(0);-moz-animation-name:slideinfromtop;-moz-animation-duration:250ms;transform:translateY(0);animation-name:slideinfromtop;animation-duration:250ms}.slidedown.in.reverse{-webkit-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-name:fadein;-moz-animation-duration:150ms;animation-name:fadein;animation-duration:150ms}.slidedown.out.reverse{-webkit-transform:translateY(-100%);-webkit-animation-name:slideouttotop;-webkit-animation-duration:200ms;-moz-transform:translateY(-100%);-moz-animation-name:slideouttotop;-moz-animation-duration:200ms;transform:translateY(-100%);animation-name:slideouttotop;animation-duration:200ms}@-webkit-keyframes slideinfromtop{from{-webkit-transform:translateY(-100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfromtop{from{-moz-transform:translateY(-100%)}to{-moz-transform:translateY(0)}}@keyframes slideinfromtop{from{transform:translateY(-100%)}to{transform:translateY(0)}}@-webkit-keyframes slideouttotop{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(-100%)}}@-moz-keyframes slideouttotop{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(-100%)}}@keyframes slideouttotop{from{transform:translateY(0)}to{transform:translateY(-100%)}}.slideup.out{-webkit-animation-name:fadeout;-webkit-animation-duration:100ms;-moz-animation-name:fadeout;-moz-animation-duration:100ms;animation-name:fadeout;animation-duration:100ms}.slideup.in{-webkit-transform:translateY(0);-webkit-animation-name:slideinfrombottom;-webkit-animation-duration:250ms;-moz-transform:translateY(0);-moz-animation-name:slideinfrombottom;-moz-animation-duration:250ms;transform:translateY(0);animation-name:slideinfrombottom;animation-duration:250ms}.slideup.in.reverse{-webkit-animation-name:fadein;-webkit-animation-duration:150ms;-moz-animation-name:fadein;-moz-animation-duration:150ms;animation-name:fadein;animation-duration:150ms}.slideup.out.reverse{-webkit-transform:translateY(100%);-webkit-animation-name:slideouttobottom;-webkit-animation-duration:200ms;-moz-transform:translateY(100%);-moz-animation-name:slideouttobottom;-moz-animation-duration:200ms;transform:translateY(100%);animation-name:slideouttobottom;animation-duration:200ms}@-webkit-keyframes slideinfrombottom{from{-webkit-transform:translateY(100%)}to{-webkit-transform:translateY(0)}}@-moz-keyframes slideinfrombottom{from{-moz-transform:translateY(100%)}to{-moz-transform:translateY(0)}}@keyframes slideinfrombottom{from{transform:translateY(100%)}to{transform:translateY(0)}}@-webkit-keyframes slideouttobottom{from{-webkit-transform:translateY(0)}to{-webkit-transform:translateY(100%)}}@-moz-keyframes slideouttobottom{from{-moz-transform:translateY(0)}to{-moz-transform:translateY(100%)}}@keyframes slideouttobottom{from{transform:translateY(0)}to{transform:translateY(100%)}}.viewport-flip{-webkit-perspective:1000;-moz-perspective:1000;perspective:1000;position:absolute}.flip{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-moz-backface-visibility:hidden;-moz-transform:translateX(0);backface-visibility:hidden;transform:translateX(0)}.flip.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-webkit-animation-duration:175ms;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-moz-animation-duration:175ms;transform:rotateY(-90deg) scale(.9);animation-name:flipouttoleft;animation-duration:175ms}.flip.in{-webkit-animation-name:flipintoright;-webkit-animation-duration:225ms;-moz-animation-name:flipintoright;-moz-animation-duration:225ms;animation-name:flipintoright;animation-duration:225ms}.flip.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright;transform:rotateY(90deg) scale(.9);animation-name:flipouttoright}.flip.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft;animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@keyframes flipouttoleft{from{transform:rotateY(0)}to{transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@keyframes flipouttoright{from{transform:rotateY(0)}to{transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoleft{from{transform:rotateY(-90deg) scale(.9)}to{transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoright{from{transform:rotateY(90deg) scale(.9)}to{transform:rotateY(0)}}.viewport-turn{-webkit-perspective:200px;-moz-perspective:200px;-ms-perspective:200px;perspective:200px;position:absolute}.turn{-webkit-backface-visibility:hidden;-webkit-transform:translateX(0);-webkit-transform-origin:0;-moz-backface-visibility:hidden;-moz-transform:translateX(0);-moz-transform-origin:0;backface-visibility :hidden;transform:translateX(0);transform-origin:0}.turn.out{-webkit-transform:rotateY(-90deg) scale(.9);-webkit-animation-name:flipouttoleft;-webkit-animation-duration:125ms;-moz-transform:rotateY(-90deg) scale(.9);-moz-animation-name:flipouttoleft;-moz-animation-duration:125ms;transform:rotateY(-90deg) scale(.9);animation-name:flipouttoleft;animation-duration:125ms}.turn.in{-webkit-animation-name:flipintoright;-webkit-animation-duration:250ms;-moz-animation-name:flipintoright;-moz-animation-duration:250ms;animation-name:flipintoright;animation-duration:250ms}.turn.out.reverse{-webkit-transform:rotateY(90deg) scale(.9);-webkit-animation-name:flipouttoright;-moz-transform:rotateY(90deg) scale(.9);-moz-animation-name:flipouttoright;transform:rotateY(90deg) scale(.9);animation-name:flipouttoright}.turn.in.reverse{-webkit-animation-name:flipintoleft;-moz-animation-name:flipintoleft;animation-name:flipintoleft}@-webkit-keyframes flipouttoleft{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(-90deg) scale(.9)}}@-moz-keyframes flipouttoleft{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(-90deg) scale(.9)}}@keyframes flipouttoleft{from{transform:rotateY(0)}to{transform:rotateY(-90deg) scale(.9)}}@-webkit-keyframes flipouttoright{from{-webkit-transform:rotateY(0)}to{-webkit-transform:rotateY(90deg) scale(.9)}}@-moz-keyframes flipouttoright{from{-moz-transform:rotateY(0)}to{-moz-transform:rotateY(90deg) scale(.9)}}@keyframes flipouttoright{from{transform:rotateY(0)}to{transform:rotateY(90deg) scale(.9)}}@-webkit-keyframes flipintoleft{from{-webkit-transform:rotateY(-90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoleft{from{-moz-transform:rotateY(-90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoleft{from{transform:rotateY(-90deg) scale(.9)}to{transform:rotateY(0)}}@-webkit-keyframes flipintoright{from{-webkit-transform:rotateY(90deg) scale(.9)}to{-webkit-transform:rotateY(0)}}@-moz-keyframes flipintoright{from{-moz-transform:rotateY(90deg) scale(.9)}to{-moz-transform:rotateY(0)}}@keyframes flipintoright{from{transform:rotateY(90deg) scale(.9)}to{transform:rotateY(0)}}.flow{-webkit-transform-origin:50% 30%;-webkit-box-shadow:0 0 20px rgba(0,0,0,.4);-moz-transform-origin:50% 30%;-moz-box-shadow:0 0 20px rgba(0,0,0,.4);transform-origin:50% 30%;box-shadow:0 0 20px rgba(0,0,0,.4)}.ui-dialog.flow{-webkit-transform-origin:none;-webkit-box-shadow:none;-moz-transform-origin:none;-moz-box-shadow:none;transform-origin:none;box-shadow:none}.flow.out{-webkit-transform:translateX(-100%) scale(.7);-webkit-animation-name:flowouttoleft;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(-100%) scale(.7);-moz-animation-name:flowouttoleft;-moz-animation-timing-function:ease;-moz-animation-duration:350ms;transform:translateX(-100%) scale(.7);animation-name:flowouttoleft;animation-timing-function:ease;animation-duration:350ms}.flow.in{-webkit-transform:translateX(0) scale(1);-webkit-animation-name:flowinfromright;-webkit-animation-timing-function:ease;-webkit-animation-duration:350ms;-moz-transform:translateX(0) scale(1);-moz-animation-name:flowinfromright;-moz-animation-timing-function:ease;-moz-animation-duration:350ms;transform:translateX(0) scale(1);animation-name:flowinfromright;animation-timing-function:ease;animation-duration:350ms}.flow.out.reverse{-webkit-transform:translateX(100%);-webkit-animation-name:flowouttoright;-moz-transform:translateX(100%);-moz-animation-name:flowouttoright;transform:translateX(100%);animation-name:flowouttoright}.flow.in.reverse{-webkit-animation-name:flowinfromleft;-moz-animation-name:flowinfromleft;animation-name:flowinfromleft}@-webkit-keyframes flowouttoleft{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(-100%) scale(.7)}}@-moz-keyframes flowouttoleft{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(-100%) scale(.7)}}@keyframes flowouttoleft{0%{transform:translateX(0) scale(1)}60%,70%{transform:translateX(0) scale(.7)}100%{transform:translateX(-100%) scale(.7)}}@-webkit-keyframes flowouttoright{0%{-webkit-transform:translateX(0) scale(1)}60%,70%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(100%) scale(.7)}}@-moz-keyframes flowouttoright{0%{-moz-transform:translateX(0) scale(1)}60%,70%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(100%) scale(.7)}}@keyframes flowouttoright{0%{transform:translateX(0) scale(1)}60%,70%{transform:translateX(0) scale(.7)}100%{transform:translateX(100%) scale(.7)}}@-webkit-keyframes flowinfromleft{0%{-webkit-transform:translateX(-100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromleft{0%{-moz-transform:translateX(-100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}@keyframes flowinfromleft{0%{transform:translateX(-100%) scale(.7)}30%,40%{transform:translateX(0) scale(.7)}100%{transform:translateX(0) scale(1)}}@-webkit-keyframes flowinfromright{0%{-webkit-transform:translateX(100%) scale(.7)}30%,40%{-webkit-transform:translateX(0) scale(.7)}100%{-webkit-transform:translateX(0) scale(1)}}@-moz-keyframes flowinfromright{0%{-moz-transform:translateX(100%) scale(.7)}30%,40%{-moz-transform:translateX(0) scale(.7)}100%{-moz-transform:translateX(0) scale(1)}}@keyframes flowinfromright{0%{transform:translateX(100%) scale(.7)}30%,40%{transform:translateX(0) scale(.7)}100%{transform:translateX(0) scale(1)}}.ui-grid-a,.ui-grid-b,.ui-grid-c,.ui-grid-d{overflow:hidden}.ui-block-a,.ui-block-b,.ui-block-c,.ui-block-d,.ui-block-e{margin:0;padding:0;border:0;float:left;min-height:1px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.ui-grid-solo .ui-block-a{display:block;float:none}.ui-grid-a .ui-block-a,.ui-grid-a .ui-block-b{width:49.95%}.ui-grid-a>:nth-child(n){width:50%;margin-right:-.5px}.ui-grid-a .ui-block-a{clear:left}.ui-grid-b .ui-block-a,.ui-grid-b .ui-block-b,.ui-grid-b .ui-block-c{width:33.25%}.ui-grid-b>:nth-child(n){width:33.333%;margin-right:-.5px}.ui-grid-b .ui-block-a{clear:left}.ui-grid-c .ui-block-a,.ui-grid-c .ui-block-b,.ui-grid-c .ui-block-c,.ui-grid-c .ui-block-d{width:24.925%}.ui-grid-c>:nth-child(n){width:25%;margin-right:-.5px}.ui-grid-c .ui-block-a{clear:left}.ui-grid-d .ui-block-a,.ui-grid-d .ui-block-b,.ui-grid-d .ui-block-c,.ui-grid-d .ui-block-d,.ui-grid-d .ui-block-e{width:19.925%}.ui-grid-d>:nth-child(n){width:20%}.ui-grid-d .ui-block-a{clear:left}@media all and (max-width:35em){.ui-responsive .ui-block-a,.ui-responsive .ui-block-b,.ui-responsive .ui-block-c,.ui-responsive .ui-block-d,.ui-responsive .ui-block-e{width:100%;float:none}}.ui-header-fixed,.ui-footer-fixed{left:0;right:0;width:100%;position:fixed;z-index:1000}.ui-header-fixed{top:-1px;padding-top:1px}.ui-header-fixed.ui-fixed-hidden{top:0;padding-top:0}.ui-footer-fixed{bottom:-1px;padding-bottom:1px}.ui-footer-fixed.ui-fixed-hidden{bottom:0;padding-bottom:0}.ui-header-fullscreen,.ui-footer-fullscreen{filter:Alpha(Opacity=90);opacity:.9}.ui-page-header-fixed{padding-top:2.6875em}.ui-page-footer-fixed{padding-bottom:2.6875em}.ui-page-header-fullscreen>.ui-content,.ui-page-footer-fullscreen>.ui-content{padding:0}.ui-fixed-hidden{position:absolute}.ui-page-header-fullscreen .ui-fixed-hidden,.ui-page-footer-fullscreen .ui-fixed-hidden{left:-9999px}.ui-header-fixed .ui-btn,.ui-footer-fixed .ui-btn{z-index:10}.ui-android-2x-fixed .ui-li-has-thumb{-webkit-transform:translate3d(0,0,0)}.ui-navbar{max-width:100%}.ui-navbar.ui-mini{margin:0}.ui-navbar ul:before,.ui-navbar ul:after{content:" ";display:table}.ui-navbar ul:after{clear:both}.ui-navbar ul{list-style:none;margin:0;padding:0;position:relative;display:block;border:0;max-width:100%;overflow:visible;zoom:1}.ui-navbar li .ui-btn{display:block;text-align:center;margin:0 -1px 0 0;border-right-width:0}.ui-navbar li .ui-btn-icon-right .ui-icon{right:6px}.ui-navbar li:last-child .ui-btn,.ui-navbar .ui-grid-duo .ui-block-b .ui-btn{margin-right:0;border-right-width:1px}.ui-header .ui-navbar li:last-child .ui-btn,.ui-footer .ui-navbar li:last-child .ui-btn,.ui-header .ui-navbar .ui-grid-duo .ui-block-b .ui-btn,.ui-footer .ui-navbar .ui-grid-duo .ui-block-b .ui-btn{margin-right:-1px;border-right-width:0}.ui-navbar .ui-grid-duo li.ui-block-a:last-child .ui-btn{margin-right:-1px;border-right-width:1px}.ui-header .ui-navbar li .ui-btn,.ui-footer .ui-navbar li .ui-btn{border-top-width:0;border-bottom-width:0}.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn,.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn{margin-right:-5px}.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn,.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn,.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn{margin-right:-4px}.ui-header .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,.ui-footer .ui-navbar .ui-grid-b li.ui-block-c .ui-btn-icon-right .ui-icon,.ui-header .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,.ui-footer .ui-navbar .ui-grid-c li.ui-block-d .ui-btn-icon-right .ui-icon,.ui-header .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon,.ui-footer .ui-navbar .ui-grid-d li.ui-block-e .ui-btn-icon-right .ui-icon{right:8px}.ui-navbar li .ui-btn .ui-btn-inner{padding-top:.7em;padding-bottom:.8em}.ui-navbar li .ui-btn-icon-top .ui-btn-inner{padding-top:30px}.ui-navbar li .ui-btn-icon-bottom .ui-btn-inner{padding-bottom:30px}.ui-btn{display:block;text-align:center;cursor:pointer;position:relative;margin:.5em 0;padding:0}.ui-mini{margin-top:.25em;margin-bottom:.25em}.ui-btn-left,.ui-btn-right,.ui-input-clear,.ui-btn-inline,.ui-grid-a .ui-btn,.ui-grid-b .ui-btn,.ui-grid-c .ui-btn,.ui-grid-d .ui-btn,.ui-grid-e .ui-btn,.ui-grid-solo .ui-btn{margin-right:5px;margin-left:5px}.ui-btn-inner{font-size:16px;padding:.6em 20px;min-width:.75em;display:block;position:relative;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;zoom:1}.ui-btn input,.ui-btn button{z-index:2}.ui-btn-left,.ui-btn-right,.ui-btn-inline{display:inline-block;vertical-align:middle}.ui-mobile .ui-btn-left,.ui-mobile .ui-btn-right,.ui-btn-left>.ui-btn,.ui-btn-right>.ui-btn{margin:0}.ui-btn-block{display:block}.ui-header>.ui-btn,.ui-footer>.ui-btn{display:inline-block;margin:0}.ui-header .ui-btn-block,.ui-footer .ui-btn-block{display:block}.ui-header .ui-btn-inner,.ui-footer .ui-btn-inner,.ui-mini .ui-btn-inner{font-size:12.5px;padding:.55em 11px .5em}.ui-fullsize .ui-btn-inner,.ui-fullsize .ui-btn-inner{font-size:16px;padding:.6em 20px}.ui-btn-icon-notext{width:24px;height:24px}.ui-btn-icon-notext .ui-btn-inner{padding:0;height:100%}.ui-btn-icon-notext .ui-btn-inner .ui-icon{margin:2px 1px 2px 3px;float:left}.ui-btn-text{position:relative;z-index:1;width:100%;-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}div.ui-btn-text{width:auto}.ui-btn-icon-notext .ui-btn-text{position:absolute;left:-9999px}.ui-btn-icon-left .ui-btn-inner{padding-left:40px}.ui-btn-icon-right .ui-btn-inner{padding-right:40px}.ui-btn-icon-top .ui-btn-inner{padding-top:40px}.ui-btn-icon-bottom .ui-btn-inner{padding-bottom:40px}.ui-header .ui-btn-icon-left .ui-btn-inner,.ui-footer .ui-btn-icon-left .ui-btn-inner,.ui-mini.ui-btn-icon-left .ui-btn-inner,.ui-mini .ui-btn-icon-left .ui-btn-inner{padding-left:30px}.ui-header .ui-btn-icon-right .ui-btn-inner,.ui-footer .ui-btn-icon-right .ui-btn-inner,.ui-mini.ui-btn-icon-right .ui-btn-inner,.ui-mini .ui-btn-icon-right .ui-btn-inner{padding-right:30px}.ui-header .ui-btn-icon-top .ui-btn-inner,.ui-footer .ui-btn-icon-top .ui-btn-inner{padding:30px 3px .5em}.ui-mini.ui-btn-icon-top .ui-btn-inner,.ui-mini .ui-btn-icon-top .ui-btn-inner{padding-top:30px}.ui-header .ui-btn-icon-bottom .ui-btn-inner,.ui-footer .ui-btn-icon-bottom .ui-btn-inner{padding:.55em 3px 30px}.ui-mini.ui-btn-icon-bottom .ui-btn-inner,.ui-mini .ui-btn-icon-bottom .ui-btn-inner{padding-bottom:30px}.ui-btn-inner{-webkit-border-radius:inherit;border-radius:inherit}.ui-btn-icon-notext .ui-icon{display:block;z-index:0}.ui-btn-icon-left>.ui-btn-inner>.ui-icon,.ui-btn-icon-right>.ui-btn-inner>.ui-icon{position:absolute;top:50%;margin-top:-9px}.ui-btn-icon-top .ui-btn-inner .ui-icon,.ui-btn-icon-bottom .ui-btn-inner .ui-icon{position:absolute;left:50%;margin-left:-9px}.ui-btn-icon-left .ui-icon{left:10px}.ui-btn-icon-right .ui-icon{right:10px}.ui-btn-icon-top .ui-icon{top:10px}.ui-btn-icon-bottom .ui-icon{top:auto;bottom:10px}.ui-header .ui-btn-icon-left .ui-icon,.ui-footer .ui-btn-icon-left .ui-icon,.ui-mini.ui-btn-icon-left .ui-icon,.ui-mini .ui-btn-icon-left .ui-icon{left:5px}.ui-header .ui-btn-icon-right .ui-icon,.ui-footer .ui-btn-icon-right .ui-icon,.ui-mini.ui-btn-icon-right .ui-icon,.ui-mini .ui-btn-icon-right .ui-icon{right:5px}.ui-header .ui-btn-icon-top .ui-icon,.ui-footer .ui-btn-icon-top .ui-icon,.ui-mini.ui-btn-icon-top .ui-icon,.ui-mini .ui-btn-icon-top .ui-icon{top:5px}.ui-header .ui-btn-icon-bottom .ui-icon,.ui-footer .ui-btn-icon-bottom .ui-icon,.ui-mini.ui-btn-icon-bottom .ui-icon,.ui-mini .ui-btn-icon-bottom .ui-icon{bottom:5px}.ui-btn-hidden{position:absolute;top:0;left:0;width:100%;height:100%;-webkit-appearance:none;cursor:pointer;background:#fff;background:rgba(255,255,255,0);filter:Alpha(Opacity=0);opacity:.1;font-size:1px;border:0;text-indent:-9999px}.ui-disabled .ui-btn-hidden{display:none}.ui-disabled{z-index:1}.ui-field-contain .ui-btn.ui-submit{margin:0}label.ui-submit{font-size:16px;line-height:1.4;font-weight:400;margin:0 0 .3em;display:block}@media all and (min-width:28em){.ui-field-contain label.ui-submit{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-btn.ui-submit{width:78%;display:inline-block;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.ui-hide-label .ui-btn.ui-submit{width:auto;display:block}}.ui-collapsible-inset{margin:.5em 0}.ui-collapsible-heading{font-size:16px;display:block;margin:0 -15px;padding:0;position:relative}.ui-collapsible-inset .ui-collapsible-heading{margin:0}.ui-collapsible-heading .ui-btn{text-align:left;margin:0;border-left-width:0;border-right-width:0}.ui-collapsible-inset .ui-collapsible-heading .ui-btn{border-right-width:1px;border-left-width:1px}.ui-collapsible-collapsed+.ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn{border-top-width:0}.ui-collapsible-set .ui-collapsible:not(.ui-collapsible-inset) .ui-collapsible-heading .ui-btn{border-top-width:1px}.ui-collapsible-heading .ui-btn-inner{padding-left:12px;padding-right:12px}.ui-collapsible-heading .ui-btn-icon-left .ui-btn-inner{padding-left:40px}.ui-collapsible-heading .ui-btn-icon-right .ui-btn-inner{padding-right:40px}.ui-collapsible-heading .ui-btn-icon-top .ui-btn-inner,.ui-collapsible-heading .ui-btn-icon-bottom .ui-btn-inner{text-align:center}.ui-collapsible-heading .ui-btn-icon-left.ui-mini .ui-btn-inner{padding-left:30px}.ui-collapsible-heading .ui-btn-icon-right.ui-mini .ui-btn-inner{padding-right:30px}.ui-collapsible-heading .ui-btn span.ui-btn{position:absolute;left:6px;top:50%;margin:-12px 0 0 0;width:20px;height:20px;padding:1px 0 1px 2px;text-indent:-9999px}.ui-collapsible-heading .ui-btn span.ui-btn .ui-btn-inner{padding:10px 0}.ui-collapsible-heading .ui-btn span.ui-btn .ui-icon{left:0;margin-top:-10px}.ui-collapsible-heading-status{position:absolute;top:-9999px;left:0}.ui-collapsible-content{display:block;margin:0 -15px;padding:10px 15px;border-left-width:0;border-right-width:0;border-top:0;background-image:none}.ui-collapsible-inset .ui-collapsible-content{margin:0;border-right-width:1px;border-left-width:1px}.ui-collapsible-content-collapsed{display:none}.ui-collapsible-set>.ui-collapsible.ui-corner-all{-webkit-border-radius:0;border-radius:0}.ui-collapsible-heading,.ui-collapsible-heading>.ui-btn{-webkit-border-radius:inherit;border-radius:inherit}.ui-collapsible-set .ui-collapsible.ui-first-child{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit;-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit}.ui-collapsible-content,.ui-collapsible-set .ui-collapsible.ui-last-child{-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit;-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-collapsible-themed-content:not(.ui-collapsible-collapsed)>.ui-collapsible-heading{-webkit-border-bottom-right-radius:0;border-bottom-right-radius:0;-webkit-border-bottom-left-radius:0;border-bottom-left-radius:0}.ui-collapsible-set{margin:.5em 0}.ui-collapsible-set .ui-collapsible{margin:-1px 0 0}.ui-collapsible-set .ui-collapsible.ui-first-child{margin-top:0}.ui-controlgroup,fieldset.ui-controlgroup{padding:0;margin:.5em 0;zoom:1}.ui-controlgroup.ui-mini,fieldset.ui-controlgroup.ui-mini{margin:.25em 0}.ui-field-contain .ui-controlgroup,.ui-field-contain fieldset.ui-controlgroup{margin:0}.ui-bar .ui-controlgroup{margin:0 5px}.ui-controlgroup-label{font-size:16px;line-height:1.4;font-weight:400;margin:0 0 .4em}.ui-controlgroup-label legend{max-width:100%}.ui-controlgroup-controls label.ui-select,.ui-controlgroup-controls label.ui-submit{position:absolute;left:-9999px}.ui-controlgroup li{list-style:none}.ui-controlgroup .ui-btn{margin:0}.ui-controlgroup .ui-btn-icon-notext{width:auto;height:auto;top:auto}.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner{height:20px;padding:.6em 20px}.ui-controlgroup-horizontal .ui-btn-icon-notext .ui-btn-inner{width:18px}.ui-controlgroup.ui-mini .ui-btn-icon-notext .ui-btn-inner,.ui-header .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner,.ui-footer .ui-controlgroup .ui-btn-icon-notext .ui-btn-inner{height:16px;padding:.55em 11px .5em}.ui-controlgroup .ui-btn-icon-notext .ui-btn-inner .ui-icon{position:absolute;top:50%;right:50%;margin:-9px -9px 0 0}.ui-controlgroup-horizontal .ui-btn-inner{text-align:center}.ui-controlgroup-horizontal.ui-mini .ui-btn-inner{height:16px;line-height:16px}.ui-controlgroup .ui-checkbox label,.ui-controlgroup .ui-radio label{font-size:16px}.ui-controlgroup-horizontal .ui-controlgroup-controls:before,.ui-controlgroup-horizontal .ui-controlgroup-controls:after{content:"";display:table}.ui-controlgroup-horizontal .ui-controlgroup-controls:after{clear:both}.ui-controlgroup-horizontal .ui-controlgroup-controls{display:inline-block;vertical-align:middle;zoom:1}.ui-controlgroup-horizontal .ui-controlgroup-controls>.ui-btn,.ui-controlgroup-horizontal .ui-controlgroup-controls li>.ui-btn,.ui-controlgroup-horizontal .ui-checkbox,.ui-controlgroup-horizontal .ui-radio,.ui-controlgroup-horizontal .ui-select{float:left;clear:none;margin:0}.ui-controlgroup-horizontal .ui-select .ui-btn-text{width:auto}.ui-controlgroup-vertical .ui-btn{border-bottom-width:0}.ui-controlgroup-vertical .ui-btn.ui-last-child{border-bottom-width:1px}.ui-controlgroup-horizontal .ui-btn{border-right-width:0}.ui-controlgroup-horizontal .ui-btn.ui-last-child{border-right-width:1px}.ui-controlgroup .ui-btn-corner-all{-webkit-border-radius:0;border-radius:0}.ui-controlgroup .ui-controlgroup-controls,.ui-controlgroup .ui-radio,.ui-controlgroup .ui-checkbox,.ui-controlgroup .ui-select,.ui-controlgroup li{-webkit-border-radius:inherit;border-radius:inherit}.ui-controlgroup-vertical .ui-btn.ui-first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-controlgroup-vertical .ui-btn.ui-last-child{-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-controlgroup-horizontal .ui-btn.ui-first-child{-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit;-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-controlgroup-horizontal .ui-btn.ui-last-child{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit;-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-controlgroup .ui-shadow:not(.ui-focus){-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none}@media all and (min-width:28em){.ui-field-contain .ui-controlgroup-label{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-controlgroup-controls{width:78%;display:inline-block}.ui-field-contain .ui-controlgroup .ui-select{width:100%;display:block}.ui-field-contain .ui-controlgroup-horizontal .ui-select{width:auto}.ui-hide-label .ui-controlgroup-controls{width:100%}}.ui-dialog{background:none!important}.ui-dialog-contain{width:92.5%;max-width:500px;margin:10% auto 15px;padding:0;position:relative;top:-15px}.ui-dialog-contain>.ui-header,.ui-dialog-contain>.ui-content,.ui-dialog-contain>.ui-footer{display:block;position:relative;width:auto;margin:0}.ui-dialog-contain>.ui-header{border:0;overflow:hidden;z-index:10;padding:0}.ui-dialog-contain>.ui-content{padding:15px}.ui-dialog-contain>.ui-footer{z-index:10;padding:0 15px}.ui-popup-open .ui-header-fixed,.ui-popup-open .ui-footer-fixed{position:absolute!important}.ui-popup-screen{background-image:url(data:image/gif;base64,R0lGODlhAQABAID/AMDAwAAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==);top:0;left:0;right:0;bottom:1px;position:absolute;filter:Alpha(Opacity=0);opacity:0;z-index:1099}.ui-popup-screen.in{opacity:.5;filter:Alpha(Opacity=50)}.ui-popup-screen.out{opacity:0;filter:Alpha(Opacity=0)}.ui-popup-container{z-index:1100;display:inline-block;position:absolute;padding:0;outline:0}.ui-popup{position:relative}.ui-popup.ui-content,.ui-popup .ui-content{overflow:visible}.ui-popup>p,.ui-popup>h1,.ui-popup>h2,.ui-popup>h3,.ui-popup>h4,.ui-popup>h5,.ui-popup>h6{margin:.5em 7px}.ui-popup>span{display:block;margin:.5em 7px}.ui-popup .ui-title{font-size:16px;font-weight:700;margin-top:.5em;margin-bottom:.5em}.ui-popup-container .ui-content>p,.ui-popup-container .ui-content>h1,.ui-popup-container .ui-content>h2,.ui-popup-container .ui-content>h3,.ui-popup-container .ui-content>h4,.ui-popup-container .ui-content>h5,.ui-popup-container .ui-content>h6{margin:.5em 0}.ui-popup-container .ui-content>span{margin:0}.ui-popup-container .ui-content>p:first-child,.ui-popup-container .ui-content>h1:first-child,.ui-popup-container .ui-content>h2:first-child,.ui-popup-container .ui-content>h3:first-child,.ui-popup-container .ui-content>h4:first-child,.ui-popup-container .ui-content>h5:first-child,.ui-popup-container .ui-content>h6:first-child{margin-top:0}.ui-popup-container .ui-content>p:last-child,.ui-popup-container .ui-content>h1:last-child,.ui-popup-container .ui-content>h2:last-child,.ui-popup-container .ui-content>h3:last-child,.ui-popup-container .ui-content>h4:last-child,.ui-popup-container .ui-content>h5:last-child,.ui-popup-container .ui-content>h6:last-child{margin-bottom:0}.ui-popup>img{width:auto;height:auto;max-width:100%;max-height:100%;vertical-align:middle}.ui-popup:not(.ui-content)>img:only-child,.ui-popup:not(.ui-content)>.ui-btn-left:first-child+img:last-child,.ui-popup:not(.ui-content)>.ui-btn-right:first-child+img:last-child{-webkit-border-radius:inherit;border-radius:inherit}.ui-popup iframe{vertical-align:middle}@media all and (min-width:28em){.ui-popup .ui-field-contain label.ui-submit,.ui-popup .ui-field-contain .ui-controlgroup-label,.ui-popup .ui-field-contain label.ui-select,.ui-popup .ui-field-contain label.ui-input-text{font-size:16px;line-height:1.4;display:block;font-weight:400;margin:0 0 .3em}.ui-popup .ui-field-contain .ui-btn.ui-submit,.ui-popup .ui-field-contain .ui-controlgroup-controls,.ui-popup .ui-field-contain .ui-select,.ui-popup .ui-field-contain input.ui-input-text,.ui-popup .ui-field-contain textarea.ui-input-text,.ui-popup .ui-field-contain .ui-input-search{width:100%;display:block}}.ui-popup>.ui-btn-left,.ui-popup>.ui-btn-right{position:absolute;top:-9px;margin:0;z-index:1101}.ui-popup>.ui-btn-left{left:-9px}.ui-popup>.ui-btn-right{right:-9px}.ui-popup-hidden{top:-99999px;left:-9999px;visibility:hidden}.ui-checkbox,.ui-radio{position:relative;clear:both;margin:0;z-index:1}.ui-checkbox .ui-btn,.ui-radio .ui-btn{text-align:left;z-index:2}.ui-controlgroup .ui-checkbox .ui-btn,.ui-controlgroup .ui-radio .ui-btn{margin:0}.ui-checkbox .ui-btn-inner,.ui-radio .ui-btn-inner{white-space:normal}.ui-checkbox .ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-btn-icon-left .ui-btn-inner{padding-left:45px}.ui-checkbox .ui-mini.ui-btn-icon-left .ui-btn-inner,.ui-radio .ui-mini.ui-btn-icon-left .ui-btn-inner{padding-left:36px}.ui-checkbox .ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-btn-icon-right .ui-btn-inner{padding-right:45px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-btn-inner,.ui-radio .ui-mini.ui-btn-icon-right .ui-btn-inner{padding-right:36px}.ui-checkbox .ui-btn-icon-top .ui-btn-inner,.ui-radio .ui-btn-icon-top .ui-btn-inner{padding-right:0;padding-left:0;text-align:center}.ui-checkbox .ui-btn-icon-bottom .ui-btn-inner,.ui-radio .ui-btn-icon-bottom .ui-btn-inner{padding-right:0;padding-left:0;text-align:center}.ui-checkbox .ui-icon,.ui-radio .ui-icon{top:1.1em}.ui-checkbox .ui-btn-icon-left .ui-icon,.ui-radio .ui-btn-icon-left .ui-icon{left:15px}.ui-checkbox .ui-mini.ui-btn-icon-left .ui-icon,.ui-radio .ui-mini.ui-btn-icon-left .ui-icon{left:9px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon,.ui-radio .ui-mini.ui-btn-icon-right .ui-icon{right:9px}.ui-checkbox .ui-btn-icon-top .ui-icon,.ui-radio .ui-btn-icon-top .ui-icon{top:10px}.ui-checkbox .ui-btn-icon-bottom .ui-icon,.ui-radio .ui-btn-icon-bottom .ui-icon{top:auto;bottom:10px}.ui-checkbox .ui-btn-icon-right .ui-icon,.ui-radio .ui-btn-icon-right .ui-icon{right:15px}.ui-checkbox .ui-mini.ui-btn-icon-right .ui-icon,.ui-radio .ui-mini.ui-btn-icon-right .ui-icon{right:9px}.ui-controlgroup-horizontal .ui-checkbox .ui-icon,.ui-controlgroup-horizontal .ui-radio .ui-icon{display:none}.ui-controlgroup-horizontal .ui-checkbox .ui-btn-inner,.ui-controlgroup-horizontal .ui-radio .ui-btn-inner{padding:.6em 20px}.ui-controlgroup-horizontal .ui-checkbox .ui-mini .ui-btn-inner,.ui-controlgroup-horizontal .ui-radio .ui-mini .ui-btn-inner{padding:.55em 11px .5em}.ui-checkbox input,.ui-radio input{position:absolute;left:20px;top:50%;width:10px;height:10px;margin:-5px 0 0 0;outline:0!important;z-index:1}.ui-field-contain,fieldset.ui-field-contain{padding:.8em 0;margin:0;border-width:0 0 1px;overflow:visible}.ui-field-contain:last-child{border-bottom-width:0}.ui-field-contain{max-width:100%}@media all and (min-width:28em){.ui-field-contain,.ui-mobile fieldset.ui-field-contain{border-width:0;padding:0;margin:1em 0}}.ui-select{display:block;position:relative}.ui-select select{position:absolute;left:-9999px;top:-9999px}.ui-select .ui-btn{opacity:1}.ui-field-contain .ui-select .ui-btn{margin:0}.ui-select .ui-btn select{cursor:pointer;-webkit-appearance:none;left:0;top:0;width:100%;min-height:1.5em;min-height:100%;height:3em;max-height:100%;filter:Alpha(Opacity=0);opacity:0;z-index:2}.ui-select .ui-disabled{opacity:.3}.ui-select .ui-disabled select{display:none}@-moz-document url-prefix(){.ui-select .ui-btn select{opacity:.0001}}.ui-select .ui-btn.ui-select-nativeonly{border-radius:0;border:0}.ui-select .ui-btn.ui-select-nativeonly select{opacity:1;text-indent:0;display:block}.ui-select .ui-disabled.ui-select-nativeonly .ui-btn-inner{opacity:0}.ui-select .ui-btn-icon-right .ui-btn-inner,.ui-select .ui-li-has-count .ui-btn-inner{padding-right:45px}.ui-select .ui-mini.ui-btn-icon-right .ui-btn-inner{padding-right:32px}.ui-select .ui-btn-icon-right.ui-li-has-count .ui-btn-inner{padding-right:80px}.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-btn-inner{padding-right:67px}.ui-select .ui-btn-icon-right .ui-icon{right:15px}.ui-select .ui-mini.ui-btn-icon-right .ui-icon{right:7px}.ui-select .ui-btn-icon-right.ui-li-has-count .ui-li-count{right:45px}.ui-select .ui-mini.ui-btn-icon-right.ui-li-has-count .ui-li-count{right:32px}label.ui-select{font-size:16px;line-height:1.4;font-weight:400;margin:0 0 .3em;display:block}.ui-select .ui-btn-text,.ui-selectmenu .ui-btn-text{display:block;min-height:1em;overflow:hidden!important}.ui-select .ui-btn-text{text-overflow:ellipsis}.ui-selectmenu{padding:6px;min-width:160px}.ui-selectmenu .ui-listview{margin:0}.ui-selectmenu .ui-btn.ui-li-divider{cursor:default}.ui-screen-hidden,.ui-selectmenu-list .ui-li .ui-icon{display:none}.ui-selectmenu-list .ui-li .ui-icon{display:block}.ui-li.ui-selectmenu-placeholder{display:none}.ui-selectmenu .ui-header{margin:0;padding:0}.ui-selectmenu.ui-popup .ui-header{-webkit-border-top-left-radius:0;border-top-left-radius:0;-webkit-border-top-right-radius:0;border-top-right-radius:0}.ui-selectmenu .ui-header .ui-title{margin:.6em 46px .8em}@media all and (min-width:28em){.ui-field-contain label.ui-select{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain .ui-select{width:78%;display:inline-block}.ui-hide-label .ui-select{width:100%}}.ui-selectmenu .ui-header h1:after{content:'.';visibility:hidden}label.ui-input-text{font-size:16px;line-height:1.4;display:block;font-weight:400;margin:0 0 .3em}input.ui-input-text,textarea.ui-input-text{background-image:none;padding:.4em;margin:.5em 0;min-height:1.4em;line-height:1.4em;font-size:16px;display:block;width:100%;outline:0}input.ui-mini,.ui-mini input,textarea.ui-mini{font-size:14px}div.ui-input-text input.ui-input-text,div.ui-input-text textarea.ui-input-text,.ui-input-search input.ui-input-text{border:0;width:100%;padding:.4em 0;margin:0;display:block;background:transparent none;outline:0!important}.ui-input-search,div.ui-input-text{margin:.5em 0;background-image:none;position:relative}.ui-input-search{padding:0 30px}div.ui-input-text{padding:0 .4em}div.ui-input-has-clear{padding:0 30px 0 .4em}input.ui-input-text.ui-mini,textarea.ui-input-text.ui-mini,.ui-input-search.ui-mini,div.ui-input-text.ui-mini{margin:.25em 0}.ui-field-contain input.ui-input-text,.ui-field-contain textarea.ui-input-text,.ui-field-contain .ui-input-search,.ui-field-contain div.ui-input-text{margin:0}textarea.ui-input-text{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}input.ui-input-text{-webkit-appearance:none}textarea.ui-input-text{height:50px;-webkit-transition:height 200ms linear;-moz-transition:height 200ms linear;-o-transition:height 200ms linear;transition:height 200ms linear}textarea.ui-mini{height:45px}.ui-icon-searchfield:after{position:absolute;left:7px;top:50%;margin-top:-9px;content:"";width:18px;height:18px;opacity:.5}.ui-input-search .ui-input-clear,.ui-input-text .ui-input-clear{position:absolute;right:0;top:50%;margin-top:-13px}.ui-mini .ui-input-clear{right:-3px}.ui-input-search .ui-input-clear-hidden,.ui-input-text .ui-input-clear-hidden{display:none}input::-moz-placeholder,textarea::-moz-placeholder{color:#aaa}:-ms-input-placeholder{color:#aaa}input[type=number]::-webkit-outer-spin-button{margin:0}@media all and (min-width:28em){.ui-field-contain label.ui-input-text{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain input.ui-input-text,.ui-field-contain textarea.ui-input-text,.ui-field-contain .ui-input-search,.ui-field-contain div.ui-input-text{width:78%;display:inline-block}.ui-field-contain .ui-input-search,.ui-field-contain div.ui-input-text{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box}.ui-hide-label input.ui-input-text,.ui-hide-label textarea.ui-input-text,.ui-hide-label .ui-input-search,.ui-hide-label div.ui-input-text,.ui-input-search input.ui-input-text,div.ui-input-text input.ui-input-text{width:100%}}.ui-rangeslider{zoom:1;margin:0}.ui-rangeslider:before,.ui-rangeslider:after{content:"";display:table}.ui-rangeslider:after{clear:both}.ui-rangeslider input.ui-input-text.ui-slider-input{margin:.57143em 0}.ui-rangeslider.ui-mini input.ui-slider-input{margin:.28571em 0}.ui-rangeslider input.ui-slider-input.ui-rangeslider-last{float:right}.ui-rangeslider .ui-rangeslider-sliders{position:relative;overflow:visible;height:30px;margin:.5em 68px}.ui-rangeslider.ui-mini .ui-rangeslider-sliders{margin:.25em 68px}.ui-field-contain .ui-rangeslider input.ui-slider-input,.ui-field-contain .ui-rangeslider.ui-mini input.ui-slider-input,.ui-field-contain .ui-rangeslider .ui-rangeslider-sliders,.ui-field-contain .ui-rangeslider.ui-mini .ui-rangeslider-sliders{margin-top:0;margin-bottom:0}.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track{position:absolute;top:6px;right:0;left:0;margin:0}.ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track{top:8px}.ui-rangeslider .ui-slider-track:first-child .ui-slider-bg{display:none}.ui-rangeslider .ui-rangeslider-sliders .ui-slider-track:first-child{background-color:transparent;background:0;border-width:0;height:0}html >body .ui-rangeslider .ui-rangeslider-sliders .ui-slider-track:first-child{height:15px;border-width:1px}html >body .ui-rangeslider.ui-mini .ui-rangeslider-sliders .ui-slider-track:first-child{height:12px}@media all and (min-width:28em){.ui-field-contain .ui-rangeslider label.ui-slider{float:left}.ui-field-contain .ui-rangeslider input.ui-slider-input{position:relative;z-index:1}.ui-field-contain .ui-rangeslider input.ui-slider-input.ui-rangeslider-first,.ui-field-contain .ui-rangeslider.ui-mini input.ui-slider-input.ui-rangeslider-first{margin-right:17px}.ui-field-contain .ui-rangeslider .ui-rangeslider-sliders,.ui-field-contain .ui-rangeslider.ui-mini .ui-rangeslider-sliders{float:left;width:78%;margin:0 -68px}.ui-field-contain .ui-rangeslider .ui-slider-track,.ui-field-contain .ui-rangeslider.ui-mini .ui-slider-track{right:68px;left:68px}.ui-field-contain.ui-hide-label .ui-rangeslider input.ui-slider-input.ui-rangeslider-first{margin:0}.ui-field-contain.ui-hide-label .ui-rangeslider .ui-rangeslider-sliders,.ui-field-contain.ui-hide-label .ui-rangeslider.ui-mini .ui-rangeslider-sliders{width:auto;float:none;margin:0 68px}.ui-field-contain.ui-hide-label .ui-rangeslider .ui-slider-track,.ui-field-contain.ui-hide-label .ui-rangeslider.ui-mini .ui-slider-track{right:0;left:0}}.ui-listview{margin:0}ol.ui-listview,ol.ui-listview .ui-li-divider{counter-reset:listnumbering}.ui-content .ui-listview,.ui-panel-inner>.ui-listview{margin:-15px}.ui-collapsible-content>.ui-listview{margin:-10px -15px}.ui-content .ui-listview-inset,.ui-panel-inner .ui-listview-inset{margin:1em 0}.ui-collapsible-content .ui-listview-inset{margin:.5em 0}.ui-listview,.ui-li{list-style:none;padding:0}.ui-li,.ui-li.ui-field-contain{display:block;margin:0;position:relative;overflow:visible;text-align:left;border-width:0;border-top-width:1px}.ui-li.ui-btn,.ui-li.ui-field-contain,.ui-li-divider,.ui-li-static{margin:0}.ui-listview-inset .ui-li{border-right-width:1px;border-left-width:1px}.ui-li.ui-last-child,.ui-li.ui-field-contain.ui-last-child{border-bottom-width:1px}.ui-collapsible-content>.ui-listview:not(.ui-listview-inset)>.ui-li.ui-first-child{border-top-width:0}.ui-collapsible-themed-content .ui-listview:not(.ui-listview-inset)>.ui-li.ui-last-child{border-bottom-width:0}.ui-li .ui-btn-text a.ui-link-inherit{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-static{background-image:none}.ui-li-divider{padding:.5em 15px;font-size:14px;font-weight:700}ol.ui-listview .ui-link-inherit:before,ol.ui-listview .ui-li-static:before,.ui-li-dec{font-size:.8em;display:inline-block;padding-right:.3em;font-weight:400;counter-increment:listnumbering;content:counter(listnumbering) ". "}ol.ui-listview .ui-li-jsnumbering:before{content:""!important}.ui-listview .ui-li>.ui-btn-text{-webkit-border-radius:inherit;border-radius:inherit}.ui-listview>.ui-li.ui-first-child,.ui-listview .ui-btn.ui-first-child>.ui-li>.ui-btn-text>.ui-link-inherit{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit;-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit}.ui-listview>.ui-li.ui-last-child,.ui-listview .ui-btn.ui-last-child>.ui-li>.ui-btn-text>.ui-link-inherit,.ui-collapsible-content>.ui-listview:not(.ui-listview-inset),.ui-collapsible-content>.ui-listview:not(.ui-listview-inset) .ui-li.ui-last-child{-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit;-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-listview>.ui-li.ui-first-child .ui-li-link-alt{-webkit-border-top-right-radius:inherit;border-top-right-radius:inherit}.ui-listview>.ui-li.ui-last-child .ui-li-link-alt{-webkit-border-bottom-right-radius:inherit;border-bottom-right-radius:inherit}.ui-listview>.ui-li.ui-first-child .ui-li-thumb:not(.ui-li-icon){-webkit-border-top-left-radius:inherit;border-top-left-radius:inherit}.ui-listview>.ui-li.ui-last-child .ui-li-thumb:not(.ui-li-icon){-webkit-border-bottom-left-radius:inherit;border-bottom-left-radius:inherit}.ui-li>.ui-btn-inner{display:block;position:relative;padding:0}.ui-li .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li{padding:.7em 15px;display:block}.ui-li-has-thumb .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-thumb{min-height:59px;padding-left:100px}.ui-li-has-icon .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-icon{min-height:20px;padding-left:40px}.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-count,.ui-li-divider.ui-li-has-count{padding-right:45px}.ui-li-has-arrow .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow{padding-right:40px}.ui-li-has-arrow.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-arrow.ui-li-has-count{padding-right:75px}.ui-li-heading{font-size:16px;font-weight:700;display:block;margin:.6em 0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.ui-li-desc{font-size:12px;font-weight:400;display:block;margin:-.5em 0 .6em;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}ol.ui-listview>.ui-li .ui-li-heading{display:inline-block;width:100%;margin-left:-1.3em;text-indent:1.3em;vertical-align:middle}ol.ui-listview>.ui-li .ui-li-desc:not(.ui-li-aside){text-indent:1.55em}.ui-li-thumb,.ui-listview .ui-li-icon{position:absolute;left:1px;top:0;max-height:80px;max-width:80px}.ui-listview .ui-li-icon{max-height:16px;max-width:16px;left:10px;top:.9em}.ui-li-thumb,.ui-listview .ui-li-icon,.ui-li-content{float:left;margin-right:10px}.ui-li-aside{float:right;width:50%;text-align:right;margin:.3em 0}@media all and (min-width:480px){.ui-li-aside{width:45%}}.ui-li-divider{cursor:default}.ui-li-has-alt .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-alt{padding-right:53px}.ui-li-has-alt.ui-li-has-count .ui-btn-inner a.ui-link-inherit,.ui-li-static.ui-li-has-alt.ui-li-has-count{padding-right:88px}.ui-li-has-count .ui-li-count{position:absolute;font-size:11px;font-weight:700;padding:.2em .5em;top:50%;margin-top:-.9em;right:10px}.ui-li-has-count.ui-li-divider .ui-li-count,.ui-li-has-count .ui-link-inherit .ui-li-count{margin-top:-.95em}.ui-li-has-arrow.ui-li-has-count .ui-li-count{right:40px}.ui-li-has-alt.ui-li-has-count .ui-li-count{right:53px}.ui-li-link-alt{position:absolute;width:40px;height:100%;border-width:0;border-left-width:1px;top:0;right:0;margin:0;padding:0;z-index:2}.ui-li-link-alt .ui-btn{overflow:hidden;position:absolute;right:8px;top:50%;margin:-13px 0 0 0;border-bottom-width:1px;z-index:-1}.ui-li-link-alt .ui-btn-inner{padding:0;height:100%;position:absolute;width:100%;top:0;left:0}.ui-li-link-alt .ui-btn .ui-icon{right:50%;margin-right:-9px}.ui-li-link-alt .ui-btn-icon-notext .ui-btn-inner .ui-icon{position:absolute;top:50%;margin-top:-9px}.ui-listview * .ui-btn-inner>.ui-btn>.ui-btn-inner{border-top:0}.ui-listview-filter{border-width:0;overflow:hidden;margin:-15px -15px 15px -15px}.ui-collapsible-content .ui-listview-filter{margin:-10px -15px 10px -15px;border-bottom:inherit}.ui-listview-filter-inset{margin:-15px -5px;background:transparent}.ui-collapsible-content .ui-listview-filter-inset{margin:-5px;border-bottom-width:0}.ui-listview-filter .ui-input-search{margin:5px;width:auto;display:block}.ui-li.ui-screen-hidden{display:none}@media only screen and (min-device-width:768px) and (max-device-width:1024px){.ui-li .ui-btn-text{overflow:visible}}label.ui-slider{font-size:16px;line-height:1.4;font-weight:400;margin:0;display:block}.ui-field-contain label.ui-slider{margin-bottom:.4em}div.ui-slider{height:30px;margin:.5em 0;zoom:1}div.ui-slider.ui-mini{margin:.25em 0}.ui-field-contain div.ui-slider,.ui-field-contain div.ui-slider.ui-mini{margin:0}div.ui-slider:before,div.ui-slider:after{content:"";display:table}div.ui-slider:after{clear:both}input.ui-input-text.ui-slider-input{display:block;float:left;margin:0;padding:4px;width:40px;height:22px;line-height:22px;font-size:14px;border-width:0;background-image:none;font-weight:700;text-align:center;vertical-align:text-bottom;outline:0;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;-ms-box-sizing:content-box;box-sizing:content-box}.ui-slider-input::-webkit-outer-spin-button,.ui-slider-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}.ui-slider-track,.ui-slider-switch{position:relative;overflow:visible;height:15px;margin:0 15px 0 68px;top:6px}.ui-slider-track.ui-mini{height:12px;top:8px}.ui-slider-bg{border:0;height:100%}.ui-slider-track .ui-btn.ui-slider-handle,.ui-slider-switch .ui-btn.ui-slider-handle{position:absolute;z-index:1;top:50%;width:28px;height:28px;margin:-15px 0 0 -15px;outline:0}.ui-slider-track.ui-mini .ui-slider-handle{height:14px;width:14px;margin:-8px 0 0 -7px}.ui-slider-handle .ui-btn-inner{padding:0;height:100%}.ui-slider-track.ui-mini .ui-slider-handle .ui-btn-inner{height:30px;width:30px;padding:0;margin:-9px 0 0 -9px;border-top:0}select.ui-slider-switch{display:none}div.ui-slider-switch{display:inline-block;height:32px;width:5.8em;margin:.5em 0;top:0}div.ui-slider-switch:before,div.ui-slider-switch:after{display:none;clear:none}div.ui-slider-switch.ui-mini{width:5em;height:29px;margin:.25em 0;top:0}.ui-field-contain .ui-slider-switch,.ui-field-contain .ui-slider-switch.ui-mini{margin:0}.ui-slider-inneroffset{margin:0 16px;position:relative;z-index:1}.ui-slider-switch.ui-mini .ui-slider-inneroffset{margin:0 15px 0 14px}.ui-slider-switch .ui-btn.ui-slider-handle{margin:1px 0 0 -15px}.ui-slider-switch.ui-mini .ui-slider-handle{width:25px;height:25px;margin:1px 0 0 -13px;padding:0}.ui-slider-handle-snapping{-webkit-transition:left 70ms linear;-moz-transition:left 70ms linear}.ui-slider-switch.ui-mini .ui-slider-handle .ui-btn-inner{height:30px;width:30px;padding:0;margin:0;border-top:0}.ui-slider-switch .ui-slider-label{position:absolute;text-align:center;width:100%;overflow:hidden;font-size:16px;top:0;line-height:2;min-height:100%;border-width:0;white-space:nowrap;cursor:pointer}.ui-slider-switch.ui-mini .ui-slider-label{font-size:14px}.ui-slider-switch .ui-slider-label-a{z-index:1;left:0;text-indent:-1.5em}.ui-slider-switch .ui-slider-label-b{z-index:0;right:0;text-indent:1.5em}@media all and (min-width:28em){.ui-field-contain label.ui-slider{vertical-align:top;display:inline-block;width:20%;margin:0 2% 0 0}.ui-field-contain div.ui-slider{display:inline-block;width:78%}.ui-field-contain.ui-hide-label div.ui-slider{display:block;width:auto}.ui-field-contain div.ui-slider-switch,.ui-field-contain.ui-hide-label div.ui-slider-switch{display:inline-block;width:5.8em}.ui-field-contain div.ui-slider-switch.ui-mini{width:5em}}.ui-table{border:0;border-collapse:collapse;padding:0;width:100%}.ui-table th,.ui-table td{line-height:1.5em;text-align:left;padding:.4em .5em;vertical-align:top}.ui-table th .ui-btn,.ui-table td .ui-btn{line-height:normal}.ui-table th{font-weight:700}.ui-table caption{text-align:left;margin-bottom:1.4em;opacity:.5}.table-stroke thead th{border-bottom:1px solid #d6d6d6;border-bottom:1px solid rgba(0,0,0,.1)}.table-stroke tbody th,.table-stroke tbody td{border-bottom:1px solid #e6e6e6;border-bottom:1px solid rgba(0,0,0,.05)}.table-stripe tbody tr:nth-child(odd) td,.table-stripe tbody tr:nth-child(odd) th{background-color:#eee;background-color:rgba(0,0,0,.04)}.table-stripe thead th,.table-stripe tbody tr:last-child{border-bottom:1px solid #d6d6d6;border-bottom:1px solid rgba(0,0,0,.1)}.ui-table-columntoggle-btn{float:right;margin-bottom:.8em}.ui-table-columntoggle-popup fieldset{margin:0}@media only all{th.ui-table-priority-6,td.ui-table-priority-6,th.ui-table-priority-5,td.ui-table-priority-5,th.ui-table-priority-4,td.ui-table-priority-4,th.ui-table-priority-3,td.ui-table-priority-3,th.ui-table-priority-2,td.ui-table-priority-2,th.ui-table-priority-1,td.ui-table-priority-1{display:none}}@media screen and (min-width:20em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-1,.ui-table-columntoggle.ui-responsive td.ui-table-priority-1{display:table-cell}}@media screen and (min-width:30em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-2,.ui-table-columntoggle.ui-responsive td.ui-table-priority-2{display:table-cell}}@media screen and (min-width:40em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-3,.ui-table-columntoggle.ui-responsive td.ui-table-priority-3{display:table-cell}}@media screen and (min-width:50em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-4,.ui-table-columntoggle.ui-responsive td.ui-table-priority-4{display:table-cell}}@media screen and (min-width:60em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-5,.ui-table-columntoggle.ui-responsive td.ui-table-priority-5{display:table-cell}}@media screen and (min-width:70em){.ui-table-columntoggle.ui-responsive th.ui-table-priority-6,.ui-table-columntoggle.ui-responsive td.ui-table-priority-6{display:table-cell}}.ui-table-columntoggle th.ui-table-cell-hidden,.ui-table-columntoggle td.ui-table-cell-hidden,.ui-table-columntoggle.ui-responsive th.ui-table-cell-hidden,.ui-table-columntoggle.ui-responsive td.ui-table-cell-hidden{display:none}.ui-table-columntoggle th.ui-table-cell-visible,.ui-table-columntoggle td.ui-table-cell-visible,.ui-table-columntoggle.ui-responsive th.ui-table-cell-visible,.ui-table-columntoggle.ui-responsive td.ui-table-cell-visible{display:table-cell}.ui-table-reflow td .ui-table-cell-label,.ui-table-reflow th .ui-table-cell-label{display:none}@media only all{.ui-table-reflow thead td,.ui-table-reflow thead th{display:none}.ui-table-reflow td,.ui-table-reflow th{text-align:left;display:block}.ui-table-reflow tbody th{margin-top:3em}.ui-table-reflow td .ui-table-cell-label,.ui-table-reflow th .ui-table-cell-label{padding:.4em;min-width:30%;display:inline-block;margin:-.4em 1em -.4em -.4em}.ui-table-reflow th .ui-table-cell-label-top,.ui-table-reflow td .ui-table-cell-label-top{display:block;padding:.4em 0;margin:.4em 0;text-transform:uppercase;font-size:.9em;font-weight:400}}@media (min-width:35em){.ui-table-reflow.ui-responsive{display:table-row-group}.ui-table-reflow.ui-responsive td,.ui-table-reflow.ui-responsive th,.ui-table-reflow.ui-responsive tbody th,.ui-table-reflow.ui-responsive tbody td,.ui-table-reflow.ui-responsive thead td,.ui-table-reflow.ui-responsive thead th{display:table-cell;margin:0}.ui-table-reflow.ui-responsive td .ui-table-cell-label,.ui-table-reflow.ui-responsive th .ui-table-cell-label{display:none}}@media (max-width:35em){.ui-table-reflow.ui-responsive td,.ui-table-reflow.ui-responsive th{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;clear:left}}.ui-panel{width:17em;min-height:100%;max-height:none;border-width:0;position:absolute;top:0;display:block}.ui-panel-closed{width:0;max-height:100%;overflow:hidden;visibility:hidden}.ui-panel-fixed{position:fixed;bottom:-1px;padding-bottom:1px}.ui-panel-display-overlay{z-index:1001}.ui-panel-display-reveal{z-index:0}.ui-panel-display-push{z-index:999}.ui-panel-inner{padding:15px}.ui-panel-content-wrap{position:relative;left:0;min-height:inherit;border:0;z-index:999}.ui-panel-content-wrap-display-overlay,.ui-panel-animate.ui-panel-content-wrap>.ui-header,.ui-panel-content-wrap-closed{position:static}.ui-panel-dismiss{position:absolute;top:0;left:0;height:100%;width:100%;z-index:1002;display:none}.ui-panel-dismiss-open{display:block}.ui-panel-animate{-webkit-transition:-webkit-transform 350ms ease;-moz-transition:-moz-transform 350ms ease;transition:transform 350ms ease}.ui-panel-animate.ui-panel:not(.ui-panel-display-reveal),.ui-panel-animate.ui-panel:not(.ui-panel-display-reveal)>div,.ui-panel-animate.ui-panel-closed.ui-panel-display-reveal>div,.ui-panel-animate.ui-panel-content-wrap,.ui-panel-animate.ui-panel-content-fixed-toolbar{-webkit-backface-visibility:hidden;-webkit-transform:translate3d(0,0,0)}.ui-panel-position-left{left:-17em}.ui-panel-animate.ui-panel-position-left.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-left.ui-panel-display-push{left:0;-webkit-transform:translate3d(-17em,0,0);-moz-transform:translate3d(-17em,0,0);transform:translate3d(-17em,0,0)}.ui-panel-position-left.ui-panel-display-reveal,.ui-panel-position-left.ui-panel-open{left:0}.ui-panel-animate.ui-panel-position-left.ui-panel-open.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-left.ui-panel-open.ui-panel-display-push{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-moz-transform:none}.ui-panel-position-right{right:-17em}.ui-panel-animate.ui-panel-position-right.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-right.ui-panel-display-push{right:0;-webkit-transform:translate3d(17em,0,0);-moz-transform:translate3d(17em,0,0);transform:translate3d(17em,0,0)}.ui-panel-position-right.ui-panel-display-reveal,.ui-panel-position-right.ui-panel-open{right:0}.ui-panel-animate.ui-panel-position-right.ui-panel-open.ui-panel-display-overlay,.ui-panel-animate.ui-panel-position-right.ui-panel-open.ui-panel-display-push{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);-moz-transform:none}.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open,.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open,.ui-panel-dismiss-position-left.ui-panel-dismiss-open{left:17em;right:-17em}.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-reveal,.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push,.ui-panel-animate.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open.ui-panel-content-wrap-display-reveal,.ui-panel-animate.ui-panel-content-wrap-position-left.ui-panel-content-wrap-open.ui-panel-content-wrap-display-push{left:0;right:0;-webkit-transform:translate3d(17em,0,0);-moz-transform:translate3d(17em,0,0);transform:translate3d(17em,0,0)}.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open,.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open,.ui-panel-dismiss-position-right.ui-panel-dismiss-open{left:-17em;right:17em}.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-reveal,.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push,.ui-panel-animate.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open.ui-panel-content-wrap-display-reveal,.ui-panel-animate.ui-panel-content-wrap-position-right.ui-panel-content-wrap-open.ui-panel-content-wrap-display-push{left:0;right:0;-webkit-transform:translate3d(-17em,0,0);-moz-transform:translate3d(-17em,0,0);transform:translate3d(-17em,0,0)}.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-overlay,.ui-panel-content-wrap-open.ui-panel-content-wrap-display-overlay{left:0}.ui-page-active.ui-page-panel{overflow-x:hidden}.ui-panel-display-reveal{-webkit-box-shadow:inset -5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:inset -5px 0 5px rgba(0,0,0,.15);box-shadow:inset -5px 0 5px rgba(0,0,0,.15)}.ui-panel-position-right.ui-panel-display-reveal{-webkit-box-shadow:inset 5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:inset 5px 0 5px rgba(0,0,0,.15);box-shadow:inset 5px 0 5px rgba(0,0,0,.15)}.ui-panel-display-overlay{-webkit-box-shadow:5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:5px 0 5px rgba(0,0,0,.15);box-shadow:5px 0 5px rgba(0,0,0,.15)}.ui-panel-position-right.ui-panel-display-overlay{-webkit-box-shadow:-5px 0 5px rgba(0,0,0,.15);-moz-box-shadow:-5px 0 5px rgba(0,0,0,.15);box-shadow:-5px 0 5px rgba(0,0,0,.15)}.ui-panel-display-push.ui-panel-open.ui-panel-position-left{border-right-width:1px;margin-right:-1px}.ui-panel-animate.ui-panel-content-fixed-toolbar-position-left.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push{margin-left:1px}.ui-panel-display-push.ui-panel-open.ui-panel-position-right{border-left-width:1px;margin-left:-1px}.ui-panel-animate.ui-panel-content-fixed-toolbar-position-right.ui-panel-content-fixed-toolbar-open.ui-panel-content-fixed-toolbar-display-push{margin-right:1px}@media (min-width:55em){.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push.ui-panel-content-fixed-toolbar-position-left,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal.ui-panel-content-fixed-toolbar-position-left,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-push.ui-panel-content-wrap-position-left,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-reveal.ui-panel-content-wrap-position-left{margin-right:17em}.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push.ui-panel-content-fixed-toolbar-position-right,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal.ui-panel-content-fixed-toolbar-position-right,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-push.ui-panel-content-wrap-position-right,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-wrap-display-reveal.ui-panel-content-wrap-position-right{margin-left:17em}.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-push,.ui-responsive-panel.ui-page-panel-open .ui-panel-content-fixed-toolbar-display-reveal{width:auto}.ui-responsive-panel .ui-panel-dismiss-display-push{display:none}}
\ No newline at end of file
diff --git a/html5/verto/demo/css/jsontable.css b/html5/verto/demo/css/jsontable.css
new file mode 100644 (file)
index 0000000..1b6a23d
--- /dev/null
@@ -0,0 +1,64 @@
+.nthChildTest > div:nth-child(odd) {
+       display: none;
+}
+
+.jsDataTable > thead > tr > th {
+
+    border-width:4px;
+    padding: 2px;
+    font-size:10pt;
+    text-align: left;
+
+}
+
+.jsDataTable > thead > tr > th.notSortable {
+       padding: 5px;
+}
+
+.jsDataTable > tbody > tr > td {
+       border-bottom: 1px solid #ccc;
+       padding: 2px;
+       vertical-align: middle;
+}
+
+.jsDataTable {
+    font-family: verdana; 
+    font-size:10pt;  
+
+}
+
+.jsDataTable > tbody > tr:nth-child(odd),
+.jsDataTable > tbody > tr.odd {
+       background-color: #ffffee;
+}
+.jsDataTable > tbody > tr:nth-child(even),
+.jsDataTable > tbody > tr.even {
+       background-color: #ffffff;
+}
+
+.jsDataTable > thead th.sortAsc,
+.jsDataTable > thead th.sortDesc {
+    color:ffffff;
+
+    background-color: #7777ff;
+    background-position: right center;
+    background-repeat: no-repeat;
+}
+
+.jsDataTable > thead th.sortAsc {
+       background-image: url(/images/table/asc.png);
+}
+
+.jsDataTable > thead th.sortDesc {
+       background-image: url(/images/table/desc.png);
+}
+
+.jsDataTable.clickable > tbody > tr,
+.clickable > .jsDataTable > tbody > tr {
+       cursor: pointer;
+}
+
+.jsDataTable.clickable > tbody > tr.nonDataRow,
+.clickable > .jsDataTable > tbody > tr.nonDataRow {
+    cursor: auto;
+}
diff --git a/html5/verto/demo/favicon.ico b/html5/verto/demo/favicon.ico
new file mode 100644 (file)
index 0000000..c947ea2
Binary files /dev/null and b/html5/verto/demo/favicon.ico differ
diff --git a/html5/verto/demo/images/ajax-loader.gif b/html5/verto/demo/images/ajax-loader.gif
new file mode 100644 (file)
index 0000000..fd1a189
Binary files /dev/null and b/html5/verto/demo/images/ajax-loader.gif differ
diff --git a/html5/verto/demo/images/icons-18-black.png b/html5/verto/demo/images/icons-18-black.png
new file mode 100644 (file)
index 0000000..7916463
Binary files /dev/null and b/html5/verto/demo/images/icons-18-black.png differ
diff --git a/html5/verto/demo/images/icons-18-white.png b/html5/verto/demo/images/icons-18-white.png
new file mode 100644 (file)
index 0000000..3419b81
Binary files /dev/null and b/html5/verto/demo/images/icons-18-white.png differ
diff --git a/html5/verto/demo/images/icons-36-black.png b/html5/verto/demo/images/icons-36-black.png
new file mode 100644 (file)
index 0000000..043bfcd
Binary files /dev/null and b/html5/verto/demo/images/icons-36-black.png differ
diff --git a/html5/verto/demo/images/icons-36-white.png b/html5/verto/demo/images/icons-36-white.png
new file mode 100644 (file)
index 0000000..12455c9
Binary files /dev/null and b/html5/verto/demo/images/icons-36-white.png differ
diff --git a/html5/verto/demo/images/loading.gif b/html5/verto/demo/images/loading.gif
new file mode 100644 (file)
index 0000000..fe378da
Binary files /dev/null and b/html5/verto/demo/images/loading.gif differ
diff --git a/html5/verto/demo/images/login.gif b/html5/verto/demo/images/login.gif
new file mode 100644 (file)
index 0000000..9f4f36b
Binary files /dev/null and b/html5/verto/demo/images/login.gif differ
diff --git a/html5/verto/demo/img/cc_banner2014.gif b/html5/verto/demo/img/cc_banner2014.gif
new file mode 100644 (file)
index 0000000..3856211
Binary files /dev/null and b/html5/verto/demo/img/cc_banner2014.gif differ
diff --git a/html5/verto/demo/img/cc_banner2014.jpg b/html5/verto/demo/img/cc_banner2014.jpg
new file mode 100644 (file)
index 0000000..5eba3ff
Binary files /dev/null and b/html5/verto/demo/img/cc_banner2014.jpg differ
diff --git a/html5/verto/demo/img/logo.png b/html5/verto/demo/img/logo.png
new file mode 100644 (file)
index 0000000..04bce2b
Binary files /dev/null and b/html5/verto/demo/img/logo.png differ
diff --git a/html5/verto/demo/img/logo_big.png b/html5/verto/demo/img/logo_big.png
new file mode 100644 (file)
index 0000000..99184e9
Binary files /dev/null and b/html5/verto/demo/img/logo_big.png differ
diff --git a/html5/verto/demo/img/logo_med.png b/html5/verto/demo/img/logo_med.png
new file mode 100644 (file)
index 0000000..1b47ebf
Binary files /dev/null and b/html5/verto/demo/img/logo_med.png differ
diff --git a/html5/verto/demo/index.html b/html5/verto/demo/index.html
new file mode 100644 (file)
index 0000000..667920a
--- /dev/null
@@ -0,0 +1,5 @@
+<script>
+document.location = "https://" + window.location.hostname + "/verto/verto.html";
+</script>
+
+
diff --git a/html5/verto/demo/js/jquery-2.0.3.min.js b/html5/verto/demo/js/jquery-2.0.3.min.js
new file mode 100644 (file)
index 0000000..e1e3d3a
--- /dev/null
@@ -0,0 +1,6 @@
+/*! jQuery v2.0.3 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//# sourceMappingURL=jquery-2.0.3.min.map
+*/
+(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],p="2.0.3",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=st(),k=st(),N=st(),E=!1,S=function(e,t){return e===t?(E=!0,0):0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],q=L.pop,H=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){H.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+mt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,r,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function at(e){return e[v]=!0,e}function ut(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--)i.attrHandle[n[r]]=t}function ct(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return at(function(t){return t=+t,at(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.defaultView;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.attachEvent&&r!==r.top&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ut(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=ut(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=Q.test(t.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),ut(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=Q.test(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&ut(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=Q.test(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return ct(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?ct(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:at,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=gt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?at(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:at(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?at(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},i.pseudos.nth=i.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=ft(t);function dt(){}dt.prototype=i.filters=i.pseudos,i.setFilters=new dt;function gt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[v]&&(r=bt(r)),i&&!i[v]&&(i=bt(i,o)),at(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function wt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=yt(function(e){return e===t},a,!0),p=yt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[yt(vt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return bt(l>1&&vt(f),l>1&&mt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&wt(e.slice(l,r)),o>r&&wt(e=e.slice(r)),o>r&&mt(e))}f.push(n)}return vt(f)}function Tt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=q.call(f));y=xt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?at(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function kt(e,t,r,o){var s,u,l,c,p,f=gt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&mt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}n.sortStable=v.split("").sort(S).join("")===v,n.detectDuplicates=E,c(),n.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(p.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||lt("type|href|height|width",function(e,t,n){return n?undefined:e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||lt("value",function(e,t,n){return n||"input"!==e.nodeName.toLowerCase()?undefined:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||lt(R,function(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}),x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!a||n&&!u||(t=t||[],t=[e,t.slice?t.slice():t],r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){var r;return t===undefined||t&&"string"==typeof t&&n===undefined?(r=this.get(e,t),r!==undefined?r:this.get(e,x.camelCase(t))):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)
+};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ct={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1></$2>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1></$2>")+a[2],l=a[0];while(l--)o=o.lastChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[q.expando],o&&(t=q.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);q.cache[o]&&delete q.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=q.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function qt(t){return e.getComputedStyle(t,null)}function Ht(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=q.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=qt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return Ht(this,!0)},hide:function(){return Ht(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Lt(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||qt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=qt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(xt[0].contentWindow||xt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=Mt(e,t),xt.detach()),Nt[e]=n),n}function Mt(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,t){x.cssHooks[t]={get:function(e,n,r){return n?0===e.offsetWidth&&bt.test(x.css(e,"display"))?x.swap(e,Et,function(){return Pt(e,t,r)}):Pt(e,t,r):undefined},set:function(e,n,r){var i=r&&qt(e);return Ot(e,n,r?Ft(e,t,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,t){return t?x.swap(e,{display:"inline-block"},vt,[e,"marginRight"]):undefined}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,t){x.cssHooks[t]={get:function(e,n){return n?(n=vt(e,t),Ct.test(n)?x(e).position()[t]+"px":n):undefined}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+jt[r]+t]=o[r]||o[r-2]||o[0];return i}},wt.test(e)||(x.cssHooks[e+t].set=Ot)});var Wt=/%20/g,$t=/\[\]$/,Bt=/\r?\n/g,It=/^(?:submit|button|image|reset|file)$/i,zt=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&zt.test(this.nodeName)&&!It.test(e)&&(this.checked||!ot.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(Bt,"\r\n")}}):{name:t.name,value:n.replace(Bt,"\r\n")}}).get()}}),x.param=function(e,t){var n,r=[],i=function(e,t){t=x.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(t===undefined&&(t=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){i(this.name,this.value)});else for(n in e)_t(n,e[n],t,i);return r.join("&").replace(Wt,"+")};function _t(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||$t.test(e)?r(e,i):_t(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)_t(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)
+},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var Xt,Ut,Yt=x.now(),Vt=/\?/,Gt=/#.*$/,Jt=/([?&])_=[^&]*/,Qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Kt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Zt=/^(?:GET|HEAD)$/,en=/^\/\//,tn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,nn=x.fn.load,rn={},on={},sn="*/".concat("*");try{Ut=i.href}catch(an){Ut=o.createElement("a"),Ut.href="",Ut=Ut.href}Xt=tn.exec(Ut.toLowerCase())||[];function un(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function ln(e,t,n,r){var i={},o=e===on;function s(a){var u;return i[a]=!0,x.each(e[a]||[],function(e,a){var l=a(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):undefined:(t.dataTypes.unshift(l),s(l),!1)}),u}return s(t.dataTypes[0])||!i["*"]&&s("*")}function cn(e,t){var n,r,i=x.ajaxSettings.flatOptions||{};for(n in t)t[n]!==undefined&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,t,n){if("string"!=typeof e&&nn)return nn.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return a>=0&&(r=e.slice(a),e=e.slice(0,a)),x.isFunction(t)?(n=t,t=undefined):t&&"object"==typeof t&&(i="POST"),s.length>0&&x.ajax({url:e,type:i,dataType:"html",data:t}).done(function(e){o=arguments,s.html(r?x("<div>").append(x.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ut,type:"GET",isLocal:Kt.test(Xt[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":sn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?cn(cn(e,x.ajaxSettings),t):cn(x.ajaxSettings,e)},ajaxPrefilter:un(rn),ajaxTransport:un(on),ajax:function(e,t){"object"==typeof e&&(t=e,e=undefined),t=t||{};var n,r,i,o,s,a,u,l,c=x.ajaxSetup({},t),p=c.context||c,f=c.context&&(p.nodeType||p.jquery)?x(p):x.event,h=x.Deferred(),d=x.Callbacks("once memory"),g=c.statusCode||{},m={},y={},v=0,b="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!o){o={};while(t=Qt.exec(i))o[t[1].toLowerCase()]=t[2]}t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,m[e]=t),this},overrideMimeType:function(e){return v||(c.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>v)for(t in e)g[t]=[g[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||b;return n&&n.abort(t),k(0,t),this}};if(h.promise(T).complete=d.add,T.success=T.done,T.error=T.fail,c.url=((e||c.url||Ut)+"").replace(Gt,"").replace(en,Xt[1]+"//"),c.type=t.method||t.type||c.method||c.type,c.dataTypes=x.trim(c.dataType||"*").toLowerCase().match(w)||[""],null==c.crossDomain&&(a=tn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===Xt[1]&&a[2]===Xt[2]&&(a[3]||("http:"===a[1]?"80":"443"))===(Xt[3]||("http:"===Xt[1]?"80":"443")))),c.data&&c.processData&&"string"!=typeof c.data&&(c.data=x.param(c.data,c.traditional)),ln(rn,c,t,T),2===v)return T;u=c.global,u&&0===x.active++&&x.event.trigger("ajaxStart"),c.type=c.type.toUpperCase(),c.hasContent=!Zt.test(c.type),r=c.url,c.hasContent||(c.data&&(r=c.url+=(Vt.test(r)?"&":"?")+c.data,delete c.data),c.cache===!1&&(c.url=Jt.test(r)?r.replace(Jt,"$1_="+Yt++):r+(Vt.test(r)?"&":"?")+"_="+Yt++)),c.ifModified&&(x.lastModified[r]&&T.setRequestHeader("If-Modified-Since",x.lastModified[r]),x.etag[r]&&T.setRequestHeader("If-None-Match",x.etag[r])),(c.data&&c.hasContent&&c.contentType!==!1||t.contentType)&&T.setRequestHeader("Content-Type",c.contentType),T.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+("*"!==c.dataTypes[0]?", "+sn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)T.setRequestHeader(l,c.headers[l]);if(c.beforeSend&&(c.beforeSend.call(p,T,c)===!1||2===v))return T.abort();b="abort";for(l in{success:1,error:1,complete:1})T[l](c[l]);if(n=ln(on,c,t,T)){T.readyState=1,u&&f.trigger("ajaxSend",[T,c]),c.async&&c.timeout>0&&(s=setTimeout(function(){T.abort("timeout")},c.timeout));try{v=1,n.send(m,k)}catch(C){if(!(2>v))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,t,o,a){var l,m,y,b,w,C=t;2!==v&&(v=2,s&&clearTimeout(s),n=undefined,i=a||"",T.readyState=e>0?4:0,l=e>=200&&300>e||304===e,o&&(b=pn(c,T,o)),b=fn(c,b,T,l),l?(c.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(x.lastModified[r]=w),w=T.getResponseHeader("etag"),w&&(x.etag[r]=w)),204===e||"HEAD"===c.type?C="nocontent":304===e?C="notmodified":(C=b.state,m=b.data,y=b.error,l=!y)):(y=C,(e||!C)&&(C="error",0>e&&(e=0))),T.status=e,T.statusText=(t||C)+"",l?h.resolveWith(p,[m,C,T]):h.rejectWith(p,[T,C,y]),T.statusCode(g),g=undefined,u&&f.trigger(l?"ajaxSuccess":"ajaxError",[T,c,l?m:y]),d.fireWith(p,[T,C]),u&&(f.trigger("ajaxComplete",[T,c]),--x.active||x.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,t){return x.get(e,undefined,t,"script")}}),x.each(["get","post"],function(e,t){x[t]=function(e,n,r,i){return x.isFunction(n)&&(i=i||r,r=n,n=undefined),x.ajax({url:e,type:t,dataType:i,data:n,success:r})}});function pn(e,t,n){var r,i,o,s,a=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),r===undefined&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}s||(s=i)}o=o||s}return o?(o!==u[0]&&u.unshift(o),n[o]):undefined}function fn(e,t,n,r){var i,o,s,a,u,l={},c=e.dataTypes.slice();if(c[1])for(s in e.converters)l[s.toLowerCase()]=e.converters[s];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(s=l[u+" "+o]||l["* "+o],!s)for(i in l)if(a=i.split(" "),a[1]===o&&(s=l[u+" "+a[0]]||l["* "+a[0]])){s===!0?s=l[i]:l[i]!==!0&&(o=a[0],c.unshift(a[1]));break}if(s!==!0)if(s&&e["throws"])t=s(t);else try{t=s(t)}catch(p){return{state:"parsererror",error:s?p:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===undefined&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),x.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=x("<script>").prop({async:!0,charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&i("error"===e.type?404:200,e.type)}),o.head.appendChild(t[0])},abort:function(){n&&n()}}}});var hn=[],dn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=hn.pop()||x.expando+"_"+Yt++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,s,a=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&!(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");return a||"jsonp"===t.dataTypes[0]?(i=t.jsonpCallback=x.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,a?t[a]=t[a].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(Vt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return s||x.error(i+" was not called"),s[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){s=arguments},r.always(function(){e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,hn.push(i)),s&&x.isFunction(o)&&o(s[0]),s=o=undefined}),"script"):undefined}),x.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(e){}};var gn=x.ajaxSettings.xhr(),mn={0:200,1223:204},yn=0,vn={};e.ActiveXObject&&x(e).on("unload",function(){for(var e in vn)vn[e]();vn=undefined}),x.support.cors=!!gn&&"withCredentials"in gn,x.support.ajax=gn=!!gn,x.ajaxTransport(function(e){var t;return x.support.cors||gn&&!e.crossDomain?{send:function(n,r){var i,o,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(i in e.xhrFields)s[i]=e.xhrFields[i];e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(i in n)s.setRequestHeader(i,n[i]);t=function(e){return function(){t&&(delete vn[o],t=s.onload=s.onerror=null,"abort"===e?s.abort():"error"===e?r(s.status||404,s.statusText):r(mn[s.status]||s.status,s.statusText,"string"==typeof s.responseText?{text:s.responseText}:undefined,s.getAllResponseHeaders()))}},s.onload=t(),s.onerror=t("error"),t=vn[o=yn++]=t("abort"),s.send(e.hasContent&&e.data||null)},abort:function(){t&&t()}}:undefined});var xn,bn,wn=/^(?:toggle|show|hide)$/,Tn=RegExp("^(?:([+-])=|)("+b+")([a-z%]*)$","i"),Cn=/queueHooks$/,kn=[An],Nn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Tn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),s=(x.cssNumber[e]||"px"!==o&&+r)&&Tn.exec(x.css(n.elem,e)),a=1,u=20;if(s&&s[3]!==o){o=o||s[3],i=i||[],s=+r||1;do a=a||".5",s/=a,x.style(n.elem,e,s+o);while(a!==(a=n.cur()/r)&&1!==a&&--u)}return i&&(s=n.start=+s||+r||0,n.unit=o,n.end=i[1]?s+(i[1]+1)*i[2]:+i[2]),n}]};function En(){return setTimeout(function(){xn=undefined}),xn=x.now()}function Sn(e,t,n){var r,i=(Nn[t]||[]).concat(Nn["*"]),o=0,s=i.length;for(;s>o;o++)if(r=i[o].call(n,t,e))return r}function jn(e,t,n){var r,i,o=0,s=kn.length,a=x.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=xn||En(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,s=0,u=l.tweens.length;for(;u>s;s++)l.tweens[s].run(o);return a.notifyWith(e,[l,o,n]),1>o&&u?n:(a.resolveWith(e,[l]),!1)},l=a.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:xn||En(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?a.resolveWith(e,[l,t]):a.rejectWith(e,[l,t]),this}}),c=l.props;for(Dn(c,l.opts.specialEasing);s>o;o++)if(r=kn[o].call(l,e,c,l.opts))return r;return x.map(c,Sn,l),x.isFunction(l.opts.start)&&l.opts.start.call(e,l),x.fx.timer(x.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function Dn(e,t){var n,r,i,o,s;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),s=x.cssHooks[r],s&&"expand"in s){o=s.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(jn,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Nn[n]=Nn[n]||[],Nn[n].unshift(t)},prefilter:function(e,t){t?kn.unshift(e):kn.push(e)}});function An(e,t,n){var r,i,o,s,a,u,l=this,c={},p=e.style,f=e.nodeType&&Lt(e),h=q.get(e,"fxshow");n.queue||(a=x._queueHooks(e,"fx"),null==a.unqueued&&(a.unqueued=0,u=a.empty.fire,a.empty.fire=function(){a.unqueued||u()}),a.unqueued++,l.always(function(){l.always(function(){a.unqueued--,x.queue(e,"fx").length||a.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(p.display="inline-block")),n.overflow&&(p.overflow="hidden",l.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],wn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show")){if("show"!==i||!h||h[r]===undefined)continue;f=!0}c[r]=h&&h[r]||x.style(e,r)}if(!x.isEmptyObject(c)){h?"hidden"in h&&(f=h.hidden):h=q.access(e,"fxshow",{}),o&&(h.hidden=!f),f?x(e).show():l.done(function(){x(e).hide()}),l.done(function(){var t;q.remove(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)s=Sn(f?h[r]:0,r,l),r in h||(h[r]=s.start,f&&(s.end=s.start,s.start="width"===r||"height"===r?1:0))}}function Ln(e,t,n,r,i){return new Ln.prototype.init(e,t,n,r,i)}x.Tween=Ln,Ln.prototype={constructor:Ln,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=Ln.propHooks[this.prop];return e&&e.get?e.get(this):Ln.propHooks._default.get(this)},run:function(e){var t,n=Ln.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ln.propHooks._default.set(this),this}},Ln.prototype.init.prototype=Ln.prototype,Ln.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Ln.propHooks.scrollTop=Ln.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(qn(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Lt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),s=function(){var t=jn(this,x.extend({},e),o);(i||q.get(this,"finish"))&&t.stop(!0)};return s.finish=s,i||o.queue===!1?this.each(s):this.queue(o.queue,s)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=undefined),t&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=x.timers,s=q.get(this);if(i)s[i]&&s[i].stop&&r(s[i]);else for(i in s)s[i]&&s[i].stop&&Cn.test(i)&&r(s[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));(t||!n)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=q.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,s=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;s>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function qn(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=jt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:qn("show"),slideUp:qn("hide"),slideToggle:qn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=Ln.prototype.init,x.fx.tick=function(){var e,t=x.timers,n=0;for(xn=x.now();t.length>n;n++)e=t[n],e()||t[n]!==e||t.splice(n--,1);t.length||x.fx.stop(),xn=undefined},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){bn||(bn=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(bn),bn=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===undefined?this:this.each(function(t){x.offset.setOffset(this,e,t)});var t,n,i=this[0],o={top:0,left:0},s=i&&i.ownerDocument;if(s)return t=s.documentElement,x.contains(t,i)?(typeof i.getBoundingClientRect!==r&&(o=i.getBoundingClientRect()),n=Hn(s),{top:o.top+n.pageYOffset-t.clientTop,left:o.left+n.pageXOffset-t.clientLeft}):o},x.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l,c=x.css(e,"position"),p=x(e),f={};"static"===c&&(e.style.position="relative"),a=p.offset(),o=x.css(e,"top"),u=x.css(e,"left"),l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1,l?(r=p.position(),s=r.top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),x.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(f.top=t.top-a.top+s),null!=t.left&&(f.left=t.left-a.left+i),"using"in t?t.using.call(e,f):p.css(f)}},x.fn.extend({position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===x.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(r=e.offset()),r.top+=x.css(e[0],"borderTopWidth",!0),r.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-x.css(n,"marginTop",!0),left:t.left-r.left-x.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,n){var r="pageYOffset"===n;x.fn[t]=function(i){return x.access(this,function(t,i,o){var s=Hn(t);return o===undefined?s?s[n]:t[i]:(s?s.scrollTo(r?e.pageXOffset:o,r?o:e.pageYOffset):t[i]=o,undefined)},t,i,arguments.length,null)}});function Hn(e){return x.isWindow(e)?e:9===e.nodeType&&e.defaultView}x.each({Height:"height",Width:"width"},function(e,t){x.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){x.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),s=n||(r===!0||i===!0?"margin":"border");return x.access(this,function(t,n,r){var i;return x.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):r===undefined?x.css(t,n,s):x.style(t,n,r,s)},t,o?r:undefined,o,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}),"object"==typeof e&&"object"==typeof e.document&&(e.jQuery=e.$=x)})(window);
diff --git a/html5/verto/demo/js/jquery.cookie.js b/html5/verto/demo/js/jquery.cookie.js
new file mode 100644 (file)
index 0000000..3fb201c
--- /dev/null
@@ -0,0 +1,90 @@
+/*!
+ * jQuery Cookie Plugin v1.3.1
+ * https://github.com/carhartl/jquery-cookie
+ *
+ * Copyright 2013 Klaus Hartl
+ * Released under the MIT license
+ */
+(function ($, document, undefined) {
+
+       var pluses = /\+/g;
+
+       function raw(s) {
+               return s;
+       }
+
+       function decoded(s) {
+               return unRfc2068(decodeURIComponent(s.replace(pluses, ' ')));
+       }
+
+       function unRfc2068(value) {
+               if (value.indexOf('"') === 0) {
+                       // This is a quoted cookie as according to RFC2068, unescape
+                       value = value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
+               }
+               return value;
+       }
+
+       function fromJSON(value) {
+               return config.json ? JSON.parse(value) : value;
+       }
+
+       var config = $.cookie = function (key, value, options) {
+
+               // write
+               if (value !== undefined) {
+                       options = $.extend({}, config.defaults, options);
+
+                       if (value === null) {
+                               options.expires = -1;
+                       }
+
+                       if (typeof options.expires === 'number') {
+                               var days = options.expires, t = options.expires = new Date();
+                               t.setDate(t.getDate() + days);
+                       }
+
+                       value = config.json ? JSON.stringify(value) : String(value);
+
+                       return (document.cookie = [
+                               encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value),
+                               options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
+                               options.path    ? '; path=' + options.path : '',
+                               options.domain  ? '; domain=' + options.domain : '',
+                               options.secure  ? '; secure' : ''
+                       ].join(''));
+               }
+
+               // read
+               var decode = config.raw ? raw : decoded;
+               var cookies = document.cookie.split('; ');
+               var result = key ? null : {};
+               for (var i = 0, l = cookies.length; i < l; i++) {
+                       var parts = cookies[i].split('=');
+                       var name = decode(parts.shift());
+                       var cookie = decode(parts.join('='));
+
+                       if (key && key === name) {
+                               result = fromJSON(cookie);
+                               break;
+                       }
+
+                       if (!key) {
+                               result[name] = fromJSON(cookie);
+                       }
+               }
+
+               return result;
+       };
+
+       config.defaults = {};
+
+       $.removeCookie = function (key, options) {
+               if ($.cookie(key) !== null) {
+                       $.cookie(key, null, options);
+                       return true;
+               }
+               return false;
+       };
+
+})(jQuery, document);
diff --git a/html5/verto/demo/js/jquery.dataTables.js b/html5/verto/demo/js/jquery.dataTables.js
new file mode 100644 (file)
index 0000000..1d8a220
--- /dev/null
@@ -0,0 +1,12099 @@
+/**
+ * @summary     DataTables
+ * @description Paginate, search and sort HTML tables
+ * @version     1.9.4
+ * @file        jquery.dataTables.js
+ * @author      Allan Jardine (www.sprymedia.co.uk)
+ * @contact     www.sprymedia.co.uk/contact
+ *
+ * @copyright Copyright 2008-2012 Allan Jardine, all rights reserved.
+ *
+ * This source file is free software, under either the GPL v2 license or a
+ * BSD style license, available at:
+ *   http://datatables.net/license_gpl2
+ *   http://datatables.net/license_bsd
+ * 
+ * This source file is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ * 
+ * For details please refer to: http://www.datatables.net
+ */
+
+/*jslint evil: true, undef: true, browser: true */
+/*globals $, jQuery,define,_fnExternApiFunc,_fnInitialise,_fnInitComplete,_fnLanguageCompat,_fnAddColumn,_fnColumnOptions,_fnAddData,_fnCreateTr,_fnGatherData,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnServerParams,_fnAddOptionsHtml,_fnFeatureHtmlTable,_fnScrollDraw,_fnAdjustColumnSizing,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnBuildSearchArray,_fnBuildSearchRow,_fnFilterCreateSearch,_fnDataToSearch,_fnSort,_fnSortAttachListener,_fnSortingClasses,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnFeatureHtmlLength,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnNodeToDataIndex,_fnVisbleColumns,_fnCalculateEnd,_fnConvertToWidth,_fnCalculateColumnWidths,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnDetectType,_fnSettingsFromNode,_fnGetDataMaster,_fnGetTrNodes,_fnGetTdNodes,_fnEscapeRegex,_fnDeleteIndex,_fnReOrderIndex,_fnColumnOrdering,_fnLog,_fnClearTable,_fnSaveState,_fnLoadState,_fnCreateCookie,_fnReadCookie,_fnDetectHeader,_fnGetUniqueThs,_fnScrollBarWidth,_fnApplyToChildren,_fnMap,_fnGetRowData,_fnGetCellData,_fnSetCellData,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnApplyColumnDefs,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnJsonString,_fnRender,_fnNodeToColumnIndex,_fnInfoMacros,_fnBrowserDetect,_fnGetColumns*/
+
+(/** @lends <global> */function( window, document, undefined ) {
+
+(function( factory ) {
+       "use strict";
+
+       // Define as an AMD module if possible
+       if ( typeof define === 'function' && define.amd )
+       {
+               define( ['jquery'], factory );
+       }
+       /* Define using browser globals otherwise
+        * Prevent multiple instantiations if the script is loaded twice
+        */
+       else if ( jQuery && !jQuery.fn.dataTable )
+       {
+               factory( jQuery );
+       }
+}
+(/** @lends <global> */function( $ ) {
+       "use strict";
+       /** 
+        * DataTables is a plug-in for the jQuery Javascript library. It is a 
+        * highly flexible tool, based upon the foundations of progressive 
+        * enhancement, which will add advanced interaction controls to any 
+        * HTML table. For a full list of features please refer to
+        * <a href="http://datatables.net">DataTables.net</a>.
+        *
+        * Note that the <i>DataTable</i> object is not a global variable but is
+        * aliased to <i>jQuery.fn.DataTable</i> and <i>jQuery.fn.dataTable</i> through which 
+        * it may be  accessed.
+        *
+        *  @class
+        *  @param {object} [oInit={}] Configuration object for DataTables. Options
+        *    are defined by {@link DataTable.defaults}
+        *  @requires jQuery 1.3+
+        * 
+        *  @example
+        *    // Basic initialisation
+        *    $(document).ready( function {
+        *      $('#example').dataTable();
+        *    } );
+        *  
+        *  @example
+        *    // Initialisation with configuration options - in this case, disable
+        *    // pagination and sorting.
+        *    $(document).ready( function {
+        *      $('#example').dataTable( {
+        *        "bPaginate": false,
+        *        "bSort": false 
+        *      } );
+        *    } );
+        */
+       var DataTable = function( oInit )
+       {
+               
+               
+               /**
+                * Add a column to the list used for the table with default values
+                *  @param {object} oSettings dataTables settings object
+                *  @param {node} nTh The th element for this column
+                *  @memberof DataTable#oApi
+                */
+               function _fnAddColumn( oSettings, nTh )
+               {
+                       var oDefaults = DataTable.defaults.columns;
+                       var iCol = oSettings.aoColumns.length;
+                       var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
+                               "sSortingClass": oSettings.oClasses.sSortable,
+                               "sSortingClassJUI": oSettings.oClasses.sSortJUI,
+                               "nTh": nTh ? nTh : document.createElement('th'),
+                               "sTitle":    oDefaults.sTitle    ? oDefaults.sTitle    : nTh ? nTh.innerHTML : '',
+                               "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
+                               "mData": oDefaults.mData ? oDefaults.oDefaults : iCol
+                       } );
+                       oSettings.aoColumns.push( oCol );
+                       
+                       /* Add a column specific filter */
+                       if ( oSettings.aoPreSearchCols[ iCol ] === undefined || oSettings.aoPreSearchCols[ iCol ] === null )
+                       {
+                               oSettings.aoPreSearchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch );
+                       }
+                       else
+                       {
+                               var oPre = oSettings.aoPreSearchCols[ iCol ];
+                               
+                               /* Don't require that the user must specify bRegex, bSmart or bCaseInsensitive */
+                               if ( oPre.bRegex === undefined )
+                               {
+                                       oPre.bRegex = true;
+                               }
+                               
+                               if ( oPre.bSmart === undefined )
+                               {
+                                       oPre.bSmart = true;
+                               }
+                               
+                               if ( oPre.bCaseInsensitive === undefined )
+                               {
+                                       oPre.bCaseInsensitive = true;
+                               }
+                       }
+                       
+                       /* Use the column options function to initialise classes etc */
+                       _fnColumnOptions( oSettings, iCol, null );
+               }
+               
+               
+               /**
+                * Apply options for a column
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iCol column index to consider
+                *  @param {object} oOptions object with sType, bVisible and bSearchable etc
+                *  @memberof DataTable#oApi
+                */
+               function _fnColumnOptions( oSettings, iCol, oOptions )
+               {
+                       var oCol = oSettings.aoColumns[ iCol ];
+                       
+                       /* User specified column options */
+                       if ( oOptions !== undefined && oOptions !== null )
+                       {
+                               /* Backwards compatibility for mDataProp */
+                               if ( oOptions.mDataProp && !oOptions.mData )
+                               {
+                                       oOptions.mData = oOptions.mDataProp;
+                               }
+               
+                               if ( oOptions.sType !== undefined )
+                               {
+                                       oCol.sType = oOptions.sType;
+                                       oCol._bAutoType = false;
+                               }
+                               
+                               $.extend( oCol, oOptions );
+                               _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
+               
+                               /* iDataSort to be applied (backwards compatibility), but aDataSort will take
+                                * priority if defined
+                                */
+                               if ( oOptions.iDataSort !== undefined )
+                               {
+                                       oCol.aDataSort = [ oOptions.iDataSort ];
+                               }
+                               _fnMap( oCol, oOptions, "aDataSort" );
+                       }
+               
+                       /* Cache the data get and set functions for speed */
+                       var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
+                       var mData = _fnGetObjectDataFn( oCol.mData );
+               
+                       oCol.fnGetData = function (oData, sSpecific) {
+                               var innerData = mData( oData, sSpecific );
+               
+                               if ( oCol.mRender && (sSpecific && sSpecific !== '') )
+                               {
+                                       return mRender( innerData, sSpecific, oData );
+                               }
+                               return innerData;
+                       };
+                       oCol.fnSetData = _fnSetObjectDataFn( oCol.mData );
+                       
+                       /* Feature sorting overrides column specific when off */
+                       if ( !oSettings.oFeatures.bSort )
+                       {
+                               oCol.bSortable = false;
+                       }
+                       
+                       /* Check that the class assignment is correct for sorting */
+                       if ( !oCol.bSortable ||
+                                ($.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1) )
+                       {
+                               oCol.sSortingClass = oSettings.oClasses.sSortableNone;
+                               oCol.sSortingClassJUI = "";
+                       }
+                       else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) == -1 )
+                       {
+                               oCol.sSortingClass = oSettings.oClasses.sSortable;
+                               oCol.sSortingClassJUI = oSettings.oClasses.sSortJUI;
+                       }
+                       else if ( $.inArray('asc', oCol.asSorting) != -1 && $.inArray('desc', oCol.asSorting) == -1 )
+                       {
+                               oCol.sSortingClass = oSettings.oClasses.sSortableAsc;
+                               oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIAscAllowed;
+                       }
+                       else if ( $.inArray('asc', oCol.asSorting) == -1 && $.inArray('desc', oCol.asSorting) != -1 )
+                       {
+                               oCol.sSortingClass = oSettings.oClasses.sSortableDesc;
+                               oCol.sSortingClassJUI = oSettings.oClasses.sSortJUIDescAllowed;
+                       }
+               }
+               
+               
+               /**
+                * Adjust the table column widths for new data. Note: you would probably want to 
+                * do a redraw after calling this function!
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnAdjustColumnSizing ( oSettings )
+               {
+                       /* Not interested in doing column width calculation if auto-width is disabled */
+                       if ( oSettings.oFeatures.bAutoWidth === false )
+                       {
+                               return false;
+                       }
+                       
+                       _fnCalculateColumnWidths( oSettings );
+                       for ( var i=0 , iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                       {
+                               oSettings.aoColumns[i].nTh.style.width = oSettings.aoColumns[i].sWidth;
+                       }
+               }
+               
+               
+               /**
+                * Covert the index of a visible column to the index in the data array (take account
+                * of hidden columns)
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iMatch Visible column index to lookup
+                *  @returns {int} i the data index
+                *  @memberof DataTable#oApi
+                */
+               function _fnVisibleToColumnIndex( oSettings, iMatch )
+               {
+                       var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+               
+                       return typeof aiVis[iMatch] === 'number' ?
+                               aiVis[iMatch] :
+                               null;
+               }
+               
+               
+               /**
+                * Covert the index of an index in the data array and convert it to the visible
+                *   column index (take account of hidden columns)
+                *  @param {int} iMatch Column index to lookup
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {int} i the data index
+                *  @memberof DataTable#oApi
+                */
+               function _fnColumnIndexToVisible( oSettings, iMatch )
+               {
+                       var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+                       var iPos = $.inArray( iMatch, aiVis );
+               
+                       return iPos !== -1 ? iPos : null;
+               }
+               
+               
+               /**
+                * Get the number of visible columns
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {int} i the number of visible columns
+                *  @memberof DataTable#oApi
+                */
+               function _fnVisbleColumns( oSettings )
+               {
+                       return _fnGetColumns( oSettings, 'bVisible' ).length;
+               }
+               
+               
+               /**
+                * Get an array of column indexes that match a given property
+                *  @param {object} oSettings dataTables settings object
+                *  @param {string} sParam Parameter in aoColumns to look for - typically 
+                *    bVisible or bSearchable
+                *  @returns {array} Array of indexes with matched properties
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetColumns( oSettings, sParam )
+               {
+                       var a = [];
+               
+                       $.map( oSettings.aoColumns, function(val, i) {
+                               if ( val[sParam] ) {
+                                       a.push( i );
+                               }
+                       } );
+               
+                       return a;
+               }
+               
+               
+               /**
+                * Get the sort type based on an input string
+                *  @param {string} sData data we wish to know the type of
+                *  @returns {string} type (defaults to 'string' if no type can be detected)
+                *  @memberof DataTable#oApi
+                */
+               function _fnDetectType( sData )
+               {
+                       var aTypes = DataTable.ext.aTypes;
+                       var iLen = aTypes.length;
+                       
+                       for ( var i=0 ; i<iLen ; i++ )
+                       {
+                               var sType = aTypes[i]( sData );
+                               if ( sType !== null )
+                               {
+                                       return sType;
+                               }
+                       }
+                       
+                       return 'string';
+               }
+               
+               
+               /**
+                * Figure out how to reorder a display list
+                *  @param {object} oSettings dataTables settings object
+                *  @returns array {int} aiReturn index list for reordering
+                *  @memberof DataTable#oApi
+                */
+               function _fnReOrderIndex ( oSettings, sColumns )
+               {
+                       var aColumns = sColumns.split(',');
+                       var aiReturn = [];
+                       
+                       for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                       {
+                               for ( var j=0 ; j<iLen ; j++ )
+                               {
+                                       if ( oSettings.aoColumns[i].sName == aColumns[j] )
+                                       {
+                                               aiReturn.push( j );
+                                               break;
+                                       }
+                               }
+                       }
+                       
+                       return aiReturn;
+               }
+               
+               
+               /**
+                * Get the column ordering that DataTables expects
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {string} comma separated list of names
+                *  @memberof DataTable#oApi
+                */
+               function _fnColumnOrdering ( oSettings )
+               {
+                       var sNames = '';
+                       for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                       {
+                               sNames += oSettings.aoColumns[i].sName+',';
+                       }
+                       if ( sNames.length == iLen )
+                       {
+                               return "";
+                       }
+                       return sNames.slice(0, -1);
+               }
+               
+               
+               /**
+                * Take the column definitions and static columns arrays and calculate how
+                * they relate to column indexes. The callback function will then apply the
+                * definition found for a column to a suitable configuration object.
+                *  @param {object} oSettings dataTables settings object
+                *  @param {array} aoColDefs The aoColumnDefs array that is to be applied
+                *  @param {array} aoCols The aoColumns array that defines columns individually
+                *  @param {function} fn Callback function - takes two parameters, the calculated
+                *    column index and the definition for that column.
+                *  @memberof DataTable#oApi
+                */
+               function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
+               {
+                       var i, iLen, j, jLen, k, kLen;
+               
+                       // Column definitions with aTargets
+                       if ( aoColDefs )
+                       {
+                               /* Loop over the definitions array - loop in reverse so first instance has priority */
+                               for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
+                               {
+                                       /* Each definition can target multiple columns, as it is an array */
+                                       var aTargets = aoColDefs[i].aTargets;
+                                       if ( !$.isArray( aTargets ) )
+                                       {
+                                               _fnLog( oSettings, 1, 'aTargets must be an array of targets, not a '+(typeof aTargets) );
+                                       }
+               
+                                       for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
+                                       {
+                                               if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
+                                               {
+                                                       /* Add columns that we don't yet know about */
+                                                       while( oSettings.aoColumns.length <= aTargets[j] )
+                                                       {
+                                                               _fnAddColumn( oSettings );
+                                                       }
+               
+                                                       /* Integer, basic index */
+                                                       fn( aTargets[j], aoColDefs[i] );
+                                               }
+                                               else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
+                                               {
+                                                       /* Negative integer, right to left column counting */
+                                                       fn( oSettings.aoColumns.length+aTargets[j], aoColDefs[i] );
+                                               }
+                                               else if ( typeof aTargets[j] === 'string' )
+                                               {
+                                                       /* Class name matching on TH element */
+                                                       for ( k=0, kLen=oSettings.aoColumns.length ; k<kLen ; k++ )
+                                                       {
+                                                               if ( aTargets[j] == "_all" ||
+                                                                    $(oSettings.aoColumns[k].nTh).hasClass( aTargets[j] ) )
+                                                               {
+                                                                       fn( k, aoColDefs[i] );
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               
+                       // Statically defined columns array
+                       if ( aoCols )
+                       {
+                               for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
+                               {
+                                       fn( i, aoCols[i] );
+                               }
+                       }
+               }
+               
+               /**
+                * Add a data array to the table, creating DOM node etc. This is the parallel to 
+                * _fnGatherData, but for adding rows from a Javascript source, rather than a
+                * DOM source.
+                *  @param {object} oSettings dataTables settings object
+                *  @param {array} aData data array to be added
+                *  @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
+                *  @memberof DataTable#oApi
+                */
+               function _fnAddData ( oSettings, aDataSupplied )
+               {
+                       var oCol;
+                       
+                       /* Take an independent copy of the data source so we can bash it about as we wish */
+                       var aDataIn = ($.isArray(aDataSupplied)) ?
+                               aDataSupplied.slice() :
+                               $.extend( true, {}, aDataSupplied );
+                       
+                       /* Create the object for storing information about this new row */
+                       var iRow = oSettings.aoData.length;
+                       var oData = $.extend( true, {}, DataTable.models.oRow );
+                       oData._aData = aDataIn;
+                       oSettings.aoData.push( oData );
+               
+                       /* Create the cells */
+                       var nTd, sThisType;
+                       for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                       {
+                               oCol = oSettings.aoColumns[i];
+               
+                               /* Use rendered data for filtering / sorting */
+                               if ( typeof oCol.fnRender === 'function' && oCol.bUseRendered && oCol.mData !== null )
+                               {
+                                       _fnSetCellData( oSettings, iRow, i, _fnRender(oSettings, iRow, i) );
+                               }
+                               else
+                               {
+                                       _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
+                               }
+                               
+                               /* See if we should auto-detect the column type */
+                               if ( oCol._bAutoType && oCol.sType != 'string' )
+                               {
+                                       /* Attempt to auto detect the type - same as _fnGatherData() */
+                                       var sVarType = _fnGetCellData( oSettings, iRow, i, 'type' );
+                                       if ( sVarType !== null && sVarType !== '' )
+                                       {
+                                               sThisType = _fnDetectType( sVarType );
+                                               if ( oCol.sType === null )
+                                               {
+                                                       oCol.sType = sThisType;
+                                               }
+                                               else if ( oCol.sType != sThisType && oCol.sType != "html" )
+                                               {
+                                                       /* String is always the 'fallback' option */
+                                                       oCol.sType = 'string';
+                                               }
+                                       }
+                               }
+                       }
+                       
+                       /* Add to the display array */
+                       oSettings.aiDisplayMaster.push( iRow );
+               
+                       /* Create the DOM information */
+                       if ( !oSettings.oFeatures.bDeferRender )
+                       {
+                               _fnCreateTr( oSettings, iRow );
+                       }
+               
+                       return iRow;
+               }
+               
+               
+               /**
+                * Read in the data from the target table from the DOM
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnGatherData( oSettings )
+               {
+                       var iLoop, i, iLen, j, jLen, jInner,
+                               nTds, nTrs, nTd, nTr, aLocalData, iThisIndex,
+                               iRow, iRows, iColumn, iColumns, sNodeName,
+                               oCol, oData;
+                       
+                       /*
+                        * Process by row first
+                        * Add the data object for the whole table - storing the tr node. Note - no point in getting
+                        * DOM based data if we are going to go and replace it with Ajax source data.
+                        */
+                       if ( oSettings.bDeferLoading || oSettings.sAjaxSource === null )
+                       {
+                               nTr = oSettings.nTBody.firstChild;
+                               while ( nTr )
+                               {
+                                       if ( nTr.nodeName.toUpperCase() == "TR" )
+                                       {
+                                               iThisIndex = oSettings.aoData.length;
+                                               nTr._DT_RowIndex = iThisIndex;
+                                               oSettings.aoData.push( $.extend( true, {}, DataTable.models.oRow, {
+                                                       "nTr": nTr
+                                               } ) );
+               
+                                               oSettings.aiDisplayMaster.push( iThisIndex );
+                                               nTd = nTr.firstChild;
+                                               jInner = 0;
+                                               while ( nTd )
+                                               {
+                                                       sNodeName = nTd.nodeName.toUpperCase();
+                                                       if ( sNodeName == "TD" || sNodeName == "TH" )
+                                                       {
+                                                               _fnSetCellData( oSettings, iThisIndex, jInner, $.trim(nTd.innerHTML) );
+                                                               jInner++;
+                                                       }
+                                                       nTd = nTd.nextSibling;
+                                               }
+                                       }
+                                       nTr = nTr.nextSibling;
+                               }
+                       }
+                       
+                       /* Gather in the TD elements of the Table - note that this is basically the same as
+                        * fnGetTdNodes, but that function takes account of hidden columns, which we haven't yet
+                        * setup!
+                        */
+                       nTrs = _fnGetTrNodes( oSettings );
+                       nTds = [];
+                       for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+                       {
+                               nTd = nTrs[i].firstChild;
+                               while ( nTd )
+                               {
+                                       sNodeName = nTd.nodeName.toUpperCase();
+                                       if ( sNodeName == "TD" || sNodeName == "TH" )
+                                       {
+                                               nTds.push( nTd );
+                                       }
+                                       nTd = nTd.nextSibling;
+                               }
+                       }
+                       
+                       /* Now process by column */
+                       for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
+                       {
+                               oCol = oSettings.aoColumns[iColumn];
+               
+                               /* Get the title of the column - unless there is a user set one */
+                               if ( oCol.sTitle === null )
+                               {
+                                       oCol.sTitle = oCol.nTh.innerHTML;
+                               }
+                               
+                               var
+                                       bAutoType = oCol._bAutoType,
+                                       bRender = typeof oCol.fnRender === 'function',
+                                       bClass = oCol.sClass !== null,
+                                       bVisible = oCol.bVisible,
+                                       nCell, sThisType, sRendered, sValType;
+                               
+                               /* A single loop to rule them all (and be more efficient) */
+                               if ( bAutoType || bRender || bClass || !bVisible )
+                               {
+                                       for ( iRow=0, iRows=oSettings.aoData.length ; iRow<iRows ; iRow++ )
+                                       {
+                                               oData = oSettings.aoData[iRow];
+                                               nCell = nTds[ (iRow*iColumns) + iColumn ];
+                                               
+                                               /* Type detection */
+                                               if ( bAutoType && oCol.sType != 'string' )
+                                               {
+                                                       sValType = _fnGetCellData( oSettings, iRow, iColumn, 'type' );
+                                                       if ( sValType !== '' )
+                                                       {
+                                                               sThisType = _fnDetectType( sValType );
+                                                               if ( oCol.sType === null )
+                                                               {
+                                                                       oCol.sType = sThisType;
+                                                               }
+                                                               else if ( oCol.sType != sThisType && 
+                                                                         oCol.sType != "html" )
+                                                               {
+                                                                       /* String is always the 'fallback' option */
+                                                                       oCol.sType = 'string';
+                                                               }
+                                                       }
+                                               }
+               
+                                               if ( oCol.mRender )
+                                               {
+                                                       // mRender has been defined, so we need to get the value and set it
+                                                       nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
+                                               }
+                                               else if ( oCol.mData !== iColumn )
+                                               {
+                                                       // If mData is not the same as the column number, then we need to
+                                                       // get the dev set value. If it is the column, no point in wasting
+                                                       // time setting the value that is already there!
+                                                       nCell.innerHTML = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
+                                               }
+                                               
+                                               /* Rendering */
+                                               if ( bRender )
+                                               {
+                                                       sRendered = _fnRender( oSettings, iRow, iColumn );
+                                                       nCell.innerHTML = sRendered;
+                                                       if ( oCol.bUseRendered )
+                                                       {
+                                                               /* Use the rendered data for filtering / sorting */
+                                                               _fnSetCellData( oSettings, iRow, iColumn, sRendered );
+                                                       }
+                                               }
+                                               
+                                               /* Classes */
+                                               if ( bClass )
+                                               {
+                                                       nCell.className += ' '+oCol.sClass;
+                                               }
+                                               
+                                               /* Column visibility */
+                                               if ( !bVisible )
+                                               {
+                                                       oData._anHidden[iColumn] = nCell;
+                                                       nCell.parentNode.removeChild( nCell );
+                                               }
+                                               else
+                                               {
+                                                       oData._anHidden[iColumn] = null;
+                                               }
+               
+                                               if ( oCol.fnCreatedCell )
+                                               {
+                                                       oCol.fnCreatedCell.call( oSettings.oInstance,
+                                                               nCell, _fnGetCellData( oSettings, iRow, iColumn, 'display' ), oData._aData, iRow, iColumn
+                                                       );
+                                               }
+                                       }
+                               }
+                       }
+               
+                       /* Row created callbacks */
+                       if ( oSettings.aoRowCreatedCallback.length !== 0 )
+                       {
+                               for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+                               {
+                                       oData = oSettings.aoData[i];
+                                       _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, i] );
+                               }
+                       }
+               }
+               
+               
+               /**
+                * Take a TR element and convert it to an index in aoData
+                *  @param {object} oSettings dataTables settings object
+                *  @param {node} n the TR element to find
+                *  @returns {int} index if the node is found, null if not
+                *  @memberof DataTable#oApi
+                */
+               function _fnNodeToDataIndex( oSettings, n )
+               {
+                       return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
+               }
+               
+               
+               /**
+                * Take a TD element and convert it into a column data index (not the visible index)
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iRow The row number the TD/TH can be found in
+                *  @param {node} n The TD/TH element to find
+                *  @returns {int} index if the node is found, -1 if not
+                *  @memberof DataTable#oApi
+                */
+               function _fnNodeToColumnIndex( oSettings, iRow, n )
+               {
+                       var anCells = _fnGetTdNodes( oSettings, iRow );
+               
+                       for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                       {
+                               if ( anCells[i] === n )
+                               {
+                                       return i;
+                               }
+                       }
+                       return -1;
+               }
+               
+               
+               /**
+                * Get an array of data for a given row from the internal data cache
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iRow aoData row id
+                *  @param {string} sSpecific data get type ('type' 'filter' 'sort')
+                *  @param {array} aiColumns Array of column indexes to get data from
+                *  @returns {array} Data array
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetRowData( oSettings, iRow, sSpecific, aiColumns )
+               {
+                       var out = [];
+                       for ( var i=0, iLen=aiColumns.length ; i<iLen ; i++ )
+                       {
+                               out.push( _fnGetCellData( oSettings, iRow, aiColumns[i], sSpecific ) );
+                       }
+                       return out;
+               }
+               
+               
+               /**
+                * Get the data for a given cell from the internal cache, taking into account data mapping
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iRow aoData row id
+                *  @param {int} iCol Column index
+                *  @param {string} sSpecific data get type ('display', 'type' 'filter' 'sort')
+                *  @returns {*} Cell data
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetCellData( oSettings, iRow, iCol, sSpecific )
+               {
+                       var sData;
+                       var oCol = oSettings.aoColumns[iCol];
+                       var oData = oSettings.aoData[iRow]._aData;
+               
+                       if ( (sData=oCol.fnGetData( oData, sSpecific )) === undefined )
+                       {
+                               if ( oSettings.iDrawError != oSettings.iDraw && oCol.sDefaultContent === null )
+                               {
+                                       _fnLog( oSettings, 0, "Requested unknown parameter "+
+                                               (typeof oCol.mData=='function' ? '{mData function}' : "'"+oCol.mData+"'")+
+                                               " from the data source for row "+iRow );
+                                       oSettings.iDrawError = oSettings.iDraw;
+                               }
+                               return oCol.sDefaultContent;
+                       }
+               
+                       /* When the data source is null, we can use default column data */
+                       if ( sData === null && oCol.sDefaultContent !== null )
+                       {
+                               sData = oCol.sDefaultContent;
+                       }
+                       else if ( typeof sData === 'function' )
+                       {
+                               /* If the data source is a function, then we run it and use the return */
+                               return sData();
+                       }
+               
+                       if ( sSpecific == 'display' && sData === null )
+                       {
+                               return '';
+                       }
+                       return sData;
+               }
+               
+               
+               /**
+                * Set the value for a specific cell, into the internal data cache
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iRow aoData row id
+                *  @param {int} iCol Column index
+                *  @param {*} val Value to set
+                *  @memberof DataTable#oApi
+                */
+               function _fnSetCellData( oSettings, iRow, iCol, val )
+               {
+                       var oCol = oSettings.aoColumns[iCol];
+                       var oData = oSettings.aoData[iRow]._aData;
+               
+                       oCol.fnSetData( oData, val );
+               }
+               
+               
+               // Private variable that is used to match array syntax in the data property object
+               var __reArray = /\[.*?\]$/;
+               
+               /**
+                * Return a function that can be used to get data from a source object, taking
+                * into account the ability to use nested objects as a source
+                *  @param {string|int|function} mSource The data source for the object
+                *  @returns {function} Data get function
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetObjectDataFn( mSource )
+               {
+                       if ( mSource === null )
+                       {
+                               /* Give an empty string for rendering / sorting etc */
+                               return function (data, type) {
+                                       return null;
+                               };
+                       }
+                       else if ( typeof mSource === 'function' )
+                       {
+                               return function (data, type, extra) {
+                                       return mSource( data, type, extra );
+                               };
+                       }
+                       else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
+                       {
+                               /* If there is a . in the source string then the data source is in a 
+                                * nested object so we loop over the data for each level to get the next
+                                * level down. On each loop we test for undefined, and if found immediately
+                                * return. This allows entire objects to be missing and sDefaultContent to
+                                * be used if defined, rather than throwing an error
+                                */
+                               var fetchData = function (data, type, src) {
+                                       var a = src.split('.');
+                                       var arrayNotation, out, innerSrc;
+               
+                                       if ( src !== "" )
+                                       {
+                                               for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+                                               {
+                                                       // Check if we are dealing with an array notation request
+                                                       arrayNotation = a[i].match(__reArray);
+               
+                                                       if ( arrayNotation ) {
+                                                               a[i] = a[i].replace(__reArray, '');
+               
+                                                               // Condition allows simply [] to be passed in
+                                                               if ( a[i] !== "" ) {
+                                                                       data = data[ a[i] ];
+                                                               }
+                                                               out = [];
+                                                               
+                                                               // Get the remainder of the nested object to get
+                                                               a.splice( 0, i+1 );
+                                                               innerSrc = a.join('.');
+               
+                                                               // Traverse each entry in the array getting the properties requested
+                                                               for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
+                                                                       out.push( fetchData( data[j], type, innerSrc ) );
+                                                               }
+               
+                                                               // If a string is given in between the array notation indicators, that
+                                                               // is used to join the strings together, otherwise an array is returned
+                                                               var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
+                                                               data = (join==="") ? out : out.join(join);
+               
+                                                               // The inner call to fetchData has already traversed through the remainder
+                                                               // of the source requested, so we exit from the loop
+                                                               break;
+                                                       }
+               
+                                                       if ( data === null || data[ a[i] ] === undefined )
+                                                       {
+                                                               return undefined;
+                                                       }
+                                                       data = data[ a[i] ];
+                                               }
+                                       }
+               
+                                       return data;
+                               };
+               
+                               return function (data, type) {
+                                       return fetchData( data, type, mSource );
+                               };
+                       }
+                       else
+                       {
+                               /* Array or flat object mapping */
+                               return function (data, type) {
+                                       return data[mSource];   
+                               };
+                       }
+               }
+               
+               
+               /**
+                * Return a function that can be used to set data from a source object, taking
+                * into account the ability to use nested objects as a source
+                *  @param {string|int|function} mSource The data source for the object
+                *  @returns {function} Data set function
+                *  @memberof DataTable#oApi
+                */
+               function _fnSetObjectDataFn( mSource )
+               {
+                       if ( mSource === null )
+                       {
+                               /* Nothing to do when the data source is null */
+                               return function (data, val) {};
+                       }
+                       else if ( typeof mSource === 'function' )
+                       {
+                               return function (data, val) {
+                                       mSource( data, 'set', val );
+                               };
+                       }
+                       else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 || mSource.indexOf('[') !== -1) )
+                       {
+                               /* Like the get, we need to get data from a nested object */
+                               var setData = function (data, val, src) {
+                                       var a = src.split('.'), b;
+                                       var arrayNotation, o, innerSrc;
+               
+                                       for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
+                                       {
+                                               // Check if we are dealing with an array notation request
+                                               arrayNotation = a[i].match(__reArray);
+               
+                                               if ( arrayNotation )
+                                               {
+                                                       a[i] = a[i].replace(__reArray, '');
+                                                       data[ a[i] ] = [];
+                                                       
+                                                       // Get the remainder of the nested object to set so we can recurse
+                                                       b = a.slice();
+                                                       b.splice( 0, i+1 );
+                                                       innerSrc = b.join('.');
+               
+                                                       // Traverse each entry in the array setting the properties requested
+                                                       for ( var j=0, jLen=val.length ; j<jLen ; j++ )
+                                                       {
+                                                               o = {};
+                                                               setData( o, val[j], innerSrc );
+                                                               data[ a[i] ].push( o );
+                                                       }
+               
+                                                       // The inner call to setData has already traversed through the remainder
+                                                       // of the source and has set the data, thus we can exit here
+                                                       return;
+                                               }
+               
+                                               // If the nested object doesn't currently exist - since we are
+                                               // trying to set the value - create it
+                                               if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
+                                               {
+                                                       data[ a[i] ] = {};
+                                               }
+                                               data = data[ a[i] ];
+                                       }
+               
+                                       // If array notation is used, we just want to strip it and use the property name
+                                       // and assign the value. If it isn't used, then we get the result we want anyway
+                                       data[ a[a.length-1].replace(__reArray, '') ] = val;
+                               };
+               
+                               return function (data, val) {
+                                       return setData( data, val, mSource );
+                               };
+                       }
+                       else
+                       {
+                               /* Array or flat object mapping */
+                               return function (data, val) {
+                                       data[mSource] = val;    
+                               };
+                       }
+               }
+               
+               
+               /**
+                * Return an array with the full table data
+                *  @param {object} oSettings dataTables settings object
+                *  @returns array {array} aData Master data array
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetDataMaster ( oSettings )
+               {
+                       var aData = [];
+                       var iLen = oSettings.aoData.length;
+                       for ( var i=0 ; i<iLen; i++ )
+                       {
+                               aData.push( oSettings.aoData[i]._aData );
+                       }
+                       return aData;
+               }
+               
+               
+               /**
+                * Nuke the table
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnClearTable( oSettings )
+               {
+                       oSettings.aoData.splice( 0, oSettings.aoData.length );
+                       oSettings.aiDisplayMaster.splice( 0, oSettings.aiDisplayMaster.length );
+                       oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length );
+                       _fnCalculateEnd( oSettings );
+               }
+               
+               
+                /**
+                * Take an array of integers (index array) and remove a target integer (value - not 
+                * the key!)
+                *  @param {array} a Index array to target
+                *  @param {int} iTarget value to find
+                *  @memberof DataTable#oApi
+                */
+               function _fnDeleteIndex( a, iTarget )
+               {
+                       var iTargetIndex = -1;
+                       
+                       for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+                       {
+                               if ( a[i] == iTarget )
+                               {
+                                       iTargetIndex = i;
+                               }
+                               else if ( a[i] > iTarget )
+                               {
+                                       a[i]--;
+                               }
+                       }
+                       
+                       if ( iTargetIndex != -1 )
+                       {
+                               a.splice( iTargetIndex, 1 );
+                       }
+               }
+               
+               
+                /**
+                * Call the developer defined fnRender function for a given cell (row/column) with
+                * the required parameters and return the result.
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iRow aoData index for the row
+                *  @param {int} iCol aoColumns index for the column
+                *  @returns {*} Return of the developer's fnRender function
+                *  @memberof DataTable#oApi
+                */
+               function _fnRender( oSettings, iRow, iCol )
+               {
+                       var oCol = oSettings.aoColumns[iCol];
+               
+                       return oCol.fnRender( {
+                               "iDataRow":    iRow,
+                               "iDataColumn": iCol,
+                               "oSettings":   oSettings,
+                               "aData":       oSettings.aoData[iRow]._aData,
+                               "mDataProp":   oCol.mData
+                       }, _fnGetCellData(oSettings, iRow, iCol, 'display') );
+               }
+               /**
+                * Create a new TR element (and it's TD children) for a row
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iRow Row to consider
+                *  @memberof DataTable#oApi
+                */
+               function _fnCreateTr ( oSettings, iRow )
+               {
+                       var oData = oSettings.aoData[iRow];
+                       var nTd;
+               
+                       if ( oData.nTr === null )
+                       {
+                               oData.nTr = document.createElement('tr');
+               
+                               /* Use a private property on the node to allow reserve mapping from the node
+                                * to the aoData array for fast look up
+                                */
+                               oData.nTr._DT_RowIndex = iRow;
+               
+                               /* Special parameters can be given by the data source to be used on the row */
+                               if ( oData._aData.DT_RowId )
+                               {
+                                       oData.nTr.id = oData._aData.DT_RowId;
+                               }
+               
+                               if ( oData._aData.DT_RowClass )
+                               {
+                                       oData.nTr.className = oData._aData.DT_RowClass;
+                               }
+               
+                               /* Process each column */
+                               for ( var i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                               {
+                                       var oCol = oSettings.aoColumns[i];
+                                       nTd = document.createElement( oCol.sCellType );
+               
+                                       /* Render if needed - if bUseRendered is true then we already have the rendered
+                                        * value in the data source - so can just use that
+                                        */
+                                       nTd.innerHTML = (typeof oCol.fnRender === 'function' && (!oCol.bUseRendered || oCol.mData === null)) ?
+                                               _fnRender( oSettings, iRow, i ) :
+                                               _fnGetCellData( oSettings, iRow, i, 'display' );
+                               
+                                       /* Add user defined class */
+                                       if ( oCol.sClass !== null )
+                                       {
+                                               nTd.className = oCol.sClass;
+                                       }
+                                       
+                                       if ( oCol.bVisible )
+                                       {
+                                               oData.nTr.appendChild( nTd );
+                                               oData._anHidden[i] = null;
+                                       }
+                                       else
+                                       {
+                                               oData._anHidden[i] = nTd;
+                                       }
+               
+                                       if ( oCol.fnCreatedCell )
+                                       {
+                                               oCol.fnCreatedCell.call( oSettings.oInstance,
+                                                       nTd, _fnGetCellData( oSettings, iRow, i, 'display' ), oData._aData, iRow, i
+                                               );
+                                       }
+                               }
+               
+                               _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [oData.nTr, oData._aData, iRow] );
+                       }
+               }
+               
+               
+               /**
+                * Create the HTML header for the table
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnBuildHead( oSettings )
+               {
+                       var i, nTh, iLen, j, jLen;
+                       var iThs = $('th, td', oSettings.nTHead).length;
+                       var iCorrector = 0;
+                       var jqChildren;
+                       
+                       /* If there is a header in place - then use it - otherwise it's going to get nuked... */
+                       if ( iThs !== 0 )
+                       {
+                               /* We've got a thead from the DOM, so remove hidden columns and apply width to vis cols */
+                               for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                               {
+                                       nTh = oSettings.aoColumns[i].nTh;
+                                       nTh.setAttribute('role', 'columnheader');
+                                       if ( oSettings.aoColumns[i].bSortable )
+                                       {
+                                               nTh.setAttribute('tabindex', oSettings.iTabIndex);
+                                               nTh.setAttribute('aria-controls', oSettings.sTableId);
+                                       }
+               
+                                       if ( oSettings.aoColumns[i].sClass !== null )
+                                       {
+                                               $(nTh).addClass( oSettings.aoColumns[i].sClass );
+                                       }
+                                       
+                                       /* Set the title of the column if it is user defined (not what was auto detected) */
+                                       if ( oSettings.aoColumns[i].sTitle != nTh.innerHTML )
+                                       {
+                                               nTh.innerHTML = oSettings.aoColumns[i].sTitle;
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               /* We don't have a header in the DOM - so we are going to have to create one */
+                               var nTr = document.createElement( "tr" );
+                               
+                               for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                               {
+                                       nTh = oSettings.aoColumns[i].nTh;
+                                       nTh.innerHTML = oSettings.aoColumns[i].sTitle;
+                                       nTh.setAttribute('tabindex', '0');
+                                       
+                                       if ( oSettings.aoColumns[i].sClass !== null )
+                                       {
+                                               $(nTh).addClass( oSettings.aoColumns[i].sClass );
+                                       }
+                                       
+                                       nTr.appendChild( nTh );
+                               }
+                               $(oSettings.nTHead).html( '' )[0].appendChild( nTr );
+                               _fnDetectHeader( oSettings.aoHeader, oSettings.nTHead );
+                       }
+                       
+                       /* ARIA role for the rows */    
+                       $(oSettings.nTHead).children('tr').attr('role', 'row');
+                       
+                       /* Add the extra markup needed by jQuery UI's themes */
+                       if ( oSettings.bJUI )
+                       {
+                               for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                               {
+                                       nTh = oSettings.aoColumns[i].nTh;
+                                       
+                                       var nDiv = document.createElement('div');
+                                       nDiv.className = oSettings.oClasses.sSortJUIWrapper;
+                                       $(nTh).contents().appendTo(nDiv);
+                                       
+                                       var nSpan = document.createElement('span');
+                                       nSpan.className = oSettings.oClasses.sSortIcon;
+                                       nDiv.appendChild( nSpan );
+                                       nTh.appendChild( nDiv );
+                               }
+                       }
+                       
+                       if ( oSettings.oFeatures.bSort )
+                       {
+                               for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+                               {
+                                       if ( oSettings.aoColumns[i].bSortable !== false )
+                                       {
+                                               _fnSortAttachListener( oSettings, oSettings.aoColumns[i].nTh, i );
+                                       }
+                                       else
+                                       {
+                                               $(oSettings.aoColumns[i].nTh).addClass( oSettings.oClasses.sSortableNone );
+                                       }
+                               }
+                       }
+                       
+                       /* Deal with the footer - add classes if required */
+                       if ( oSettings.oClasses.sFooterTH !== "" )
+                       {
+                               $(oSettings.nTFoot).children('tr').children('th').addClass( oSettings.oClasses.sFooterTH );
+                       }
+                       
+                       /* Cache the footer elements */
+                       if ( oSettings.nTFoot !== null )
+                       {
+                               var anCells = _fnGetUniqueThs( oSettings, null, oSettings.aoFooter );
+                               for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                               {
+                                       if ( anCells[i] )
+                                       {
+                                               oSettings.aoColumns[i].nTf = anCells[i];
+                                               if ( oSettings.aoColumns[i].sClass )
+                                               {
+                                                       $(anCells[i]).addClass( oSettings.aoColumns[i].sClass );
+                                               }
+                                       }
+                               }
+                       }
+               }
+               
+               
+               /**
+                * Draw the header (or footer) element based on the column visibility states. The
+                * methodology here is to use the layout array from _fnDetectHeader, modified for
+                * the instantaneous column visibility, to construct the new layout. The grid is
+                * traversed over cell at a time in a rows x columns grid fashion, although each 
+                * cell insert can cover multiple elements in the grid - which is tracks using the
+                * aApplied array. Cell inserts in the grid will only occur where there isn't
+                * already a cell in that position.
+                *  @param {object} oSettings dataTables settings object
+                *  @param array {objects} aoSource Layout array from _fnDetectHeader
+                *  @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc, 
+                *  @memberof DataTable#oApi
+                */
+               function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
+               {
+                       var i, iLen, j, jLen, k, kLen, n, nLocalTr;
+                       var aoLocal = [];
+                       var aApplied = [];
+                       var iColumns = oSettings.aoColumns.length;
+                       var iRowspan, iColspan;
+               
+                       if (  bIncludeHidden === undefined )
+                       {
+                               bIncludeHidden = false;
+                       }
+               
+                       /* Make a copy of the master layout array, but without the visible columns in it */
+                       for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
+                       {
+                               aoLocal[i] = aoSource[i].slice();
+                               aoLocal[i].nTr = aoSource[i].nTr;
+               
+                               /* Remove any columns which are currently hidden */
+                               for ( j=iColumns-1 ; j>=0 ; j-- )
+                               {
+                                       if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
+                                       {
+                                               aoLocal[i].splice( j, 1 );
+                                       }
+                               }
+               
+                               /* Prep the applied array - it needs an element for each row */
+                               aApplied.push( [] );
+                       }
+               
+                       for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
+                       {
+                               nLocalTr = aoLocal[i].nTr;
+                               
+                               /* All cells are going to be replaced, so empty out the row */
+                               if ( nLocalTr )
+                               {
+                                       while( (n = nLocalTr.firstChild) )
+                                       {
+                                               nLocalTr.removeChild( n );
+                                       }
+                               }
+               
+                               for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
+                               {
+                                       iRowspan = 1;
+                                       iColspan = 1;
+               
+                                       /* Check to see if there is already a cell (row/colspan) covering our target
+                                        * insert point. If there is, then there is nothing to do.
+                                        */
+                                       if ( aApplied[i][j] === undefined )
+                                       {
+                                               nLocalTr.appendChild( aoLocal[i][j].cell );
+                                               aApplied[i][j] = 1;
+               
+                                               /* Expand the cell to cover as many rows as needed */
+                                               while ( aoLocal[i+iRowspan] !== undefined &&
+                                                       aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
+                                               {
+                                                       aApplied[i+iRowspan][j] = 1;
+                                                       iRowspan++;
+                                               }
+               
+                                               /* Expand the cell to cover as many columns as needed */
+                                               while ( aoLocal[i][j+iColspan] !== undefined &&
+                                                       aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
+                                               {
+                                                       /* Must update the applied array over the rows for the columns */
+                                                       for ( k=0 ; k<iRowspan ; k++ )
+                                                       {
+                                                               aApplied[i+k][j+iColspan] = 1;
+                                                       }
+                                                       iColspan++;
+                                               }
+               
+                                               /* Do the actual expansion in the DOM */
+                                               aoLocal[i][j].cell.rowSpan = iRowspan;
+                                               aoLocal[i][j].cell.colSpan = iColspan;
+                                       }
+                               }
+                       }
+               }
+               
+               
+               /**
+                * Insert the required TR nodes into the table for display
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnDraw( oSettings )
+               {
+                       /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
+                       var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
+                       if ( $.inArray( false, aPreDraw ) !== -1 )
+                       {
+                               _fnProcessingDisplay( oSettings, false );
+                               return;
+                       }
+                       
+                       var i, iLen, n;
+                       var anRows = [];
+                       var iRowCount = 0;
+                       var iStripes = oSettings.asStripeClasses.length;
+                       var iOpenRows = oSettings.aoOpenRows.length;
+                       
+                       oSettings.bDrawing = true;
+                       
+                       /* Check and see if we have an initial draw position from state saving */
+                       if ( oSettings.iInitDisplayStart !== undefined && oSettings.iInitDisplayStart != -1 )
+                       {
+                               if ( oSettings.oFeatures.bServerSide )
+                               {
+                                       oSettings._iDisplayStart = oSettings.iInitDisplayStart;
+                               }
+                               else
+                               {
+                                       oSettings._iDisplayStart = (oSettings.iInitDisplayStart >= oSettings.fnRecordsDisplay()) ?
+                                               0 : oSettings.iInitDisplayStart;
+                               }
+                               oSettings.iInitDisplayStart = -1;
+                               _fnCalculateEnd( oSettings );
+                       }
+                       
+                       /* Server-side processing draw intercept */
+                       if ( oSettings.bDeferLoading )
+                       {
+                               oSettings.bDeferLoading = false;
+                               oSettings.iDraw++;
+                       }
+                       else if ( !oSettings.oFeatures.bServerSide )
+                       {
+                               oSettings.iDraw++;
+                       }
+                       else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
+                       {
+                               return;
+                       }
+                       
+                       if ( oSettings.aiDisplay.length !== 0 )
+                       {
+                               var iStart = oSettings._iDisplayStart;
+                               var iEnd = oSettings._iDisplayEnd;
+                               
+                               if ( oSettings.oFeatures.bServerSide )
+                               {
+                                       iStart = 0;
+                                       iEnd = oSettings.aoData.length;
+                               }
+                               
+                               for ( var j=iStart ; j<iEnd ; j++ )
+                               {
+                                       var aoData = oSettings.aoData[ oSettings.aiDisplay[j] ];
+                                       if ( aoData.nTr === null )
+                                       {
+                                               _fnCreateTr( oSettings, oSettings.aiDisplay[j] );
+                                       }
+               
+                                       var nRow = aoData.nTr;
+                                       
+                                       /* Remove the old striping classes and then add the new one */
+                                       if ( iStripes !== 0 )
+                                       {
+                                               var sStripe = oSettings.asStripeClasses[ iRowCount % iStripes ];
+                                               if ( aoData._sRowStripe != sStripe )
+                                               {
+                                                       $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
+                                                       aoData._sRowStripe = sStripe;
+                                               }
+                                       }
+                                       
+                                       /* Row callback functions - might want to manipulate the row */
+                                       _fnCallbackFire( oSettings, 'aoRowCallback', null, 
+                                               [nRow, oSettings.aoData[ oSettings.aiDisplay[j] ]._aData, iRowCount, j] );
+                                       
+                                       anRows.push( nRow );
+                                       iRowCount++;
+                                       
+                                       /* If there is an open row - and it is attached to this parent - attach it on redraw */
+                                       if ( iOpenRows !== 0 )
+                                       {
+                                               for ( var k=0 ; k<iOpenRows ; k++ )
+                                               {
+                                                       if ( nRow == oSettings.aoOpenRows[k].nParent )
+                                                       {
+                                                               anRows.push( oSettings.aoOpenRows[k].nTr );
+                                                               break;
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               /* Table is empty - create a row with an empty message in it */
+                               anRows[ 0 ] = document.createElement( 'tr' );
+                               
+                               if ( oSettings.asStripeClasses[0] )
+                               {
+                                       anRows[ 0 ].className = oSettings.asStripeClasses[0];
+                               }
+               
+                               var oLang = oSettings.oLanguage;
+                               var sZero = oLang.sZeroRecords;
+                               if ( oSettings.iDraw == 1 && oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
+                               {
+                                       sZero = oLang.sLoadingRecords;
+                               }
+                               else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
+                               {
+                                       sZero = oLang.sEmptyTable;
+                               }
+               
+                               var nTd = document.createElement( 'td' );
+                               nTd.setAttribute( 'valign', "top" );
+                               nTd.colSpan = _fnVisbleColumns( oSettings );
+                               nTd.className = oSettings.oClasses.sRowEmpty;
+                               nTd.innerHTML = _fnInfoMacros( oSettings, sZero );
+                               
+                               anRows[ iRowCount ].appendChild( nTd );
+                       }
+                       
+                       /* Header and footer callbacks */
+                       _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0], 
+                               _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
+                       
+                       _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0], 
+                               _fnGetDataMaster( oSettings ), oSettings._iDisplayStart, oSettings.fnDisplayEnd(), oSettings.aiDisplay ] );
+                       
+                       /* 
+                        * Need to remove any old row from the display - note we can't just empty the tbody using
+                        * $().html('') since this will unbind the jQuery event handlers (even although the node 
+                        * still exists!) - equally we can't use innerHTML, since IE throws an exception.
+                        */
+                       var
+                               nAddFrag = document.createDocumentFragment(),
+                               nRemoveFrag = document.createDocumentFragment(),
+                               nBodyPar, nTrs;
+                       
+                       if ( oSettings.nTBody )
+                       {
+                               nBodyPar = oSettings.nTBody.parentNode;
+                               nRemoveFrag.appendChild( oSettings.nTBody );
+                               
+                               /* When doing infinite scrolling, only remove child rows when sorting, filtering or start
+                                * up. When not infinite scroll, always do it.
+                                */
+                               if ( !oSettings.oScroll.bInfinite || !oSettings._bInitComplete ||
+                                       oSettings.bSorted || oSettings.bFiltered )
+                               {
+                                       while( (n = oSettings.nTBody.firstChild) )
+                                       {
+                                               oSettings.nTBody.removeChild( n );
+                                       }
+                               }
+                               
+                               /* Put the draw table into the dom */
+                               for ( i=0, iLen=anRows.length ; i<iLen ; i++ )
+                               {
+                                       nAddFrag.appendChild( anRows[i] );
+                               }
+                               
+                               oSettings.nTBody.appendChild( nAddFrag );
+                               if ( nBodyPar !== null )
+                               {
+                                       nBodyPar.appendChild( oSettings.nTBody );
+                               }
+                       }
+                       
+                       /* Call all required callback functions for the end of a draw */
+                       _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
+                       
+                       /* Draw is complete, sorting and filtering must be as well */
+                       oSettings.bSorted = false;
+                       oSettings.bFiltered = false;
+                       oSettings.bDrawing = false;
+                       
+                       if ( oSettings.oFeatures.bServerSide )
+                       {
+                               _fnProcessingDisplay( oSettings, false );
+                               if ( !oSettings._bInitComplete )
+                               {
+                                       _fnInitComplete( oSettings );
+                               }
+                       }
+               }
+               
+               
+               /**
+                * Redraw the table - taking account of the various features which are enabled
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnReDraw( oSettings )
+               {
+                       if ( oSettings.oFeatures.bSort )
+                       {
+                               /* Sorting will refilter and draw for us */
+                               _fnSort( oSettings, oSettings.oPreviousSearch );
+                       }
+                       else if ( oSettings.oFeatures.bFilter )
+                       {
+                               /* Filtering will redraw for us */
+                               _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
+                       }
+                       else
+                       {
+                               _fnCalculateEnd( oSettings );
+                               _fnDraw( oSettings );
+                       }
+               }
+               
+               
+               /**
+                * Add the options to the page HTML for the table
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnAddOptionsHtml ( oSettings )
+               {
+                       /*
+                        * Create a temporary, empty, div which we can later on replace with what we have generated
+                        * we do it this way to rendering the 'options' html offline - speed :-)
+                        */
+                       var nHolding = $('<div></div>')[0];
+                       oSettings.nTable.parentNode.insertBefore( nHolding, oSettings.nTable );
+                       
+                       /* 
+                        * All DataTables are wrapped in a div
+                        */
+                       oSettings.nTableWrapper = $('<div id="'+oSettings.sTableId+'_wrapper" class="'+oSettings.oClasses.sWrapper+'" role="grid"></div>')[0];
+                       oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
+               
+                       /* Track where we want to insert the option */
+                       var nInsertNode = oSettings.nTableWrapper;
+                       
+                       /* Loop over the user set positioning and place the elements as needed */
+                       var aDom = oSettings.sDom.split('');
+                       var nTmp, iPushFeature, cOption, nNewNode, cNext, sAttr, j;
+                       for ( var i=0 ; i<aDom.length ; i++ )
+                       {
+                               iPushFeature = 0;
+                               cOption = aDom[i];
+                               
+                               if ( cOption == '<' )
+                               {
+                                       /* New container div */
+                                       nNewNode = $('<div></div>')[0];
+                                       
+                                       /* Check to see if we should append an id and/or a class name to the container */
+                                       cNext = aDom[i+1];
+                                       if ( cNext == "'" || cNext == '"' )
+                                       {
+                                               sAttr = "";
+                                               j = 2;
+                                               while ( aDom[i+j] != cNext )
+                                               {
+                                                       sAttr += aDom[i+j];
+                                                       j++;
+                                               }
+                                               
+                                               /* Replace jQuery UI constants */
+                                               if ( sAttr == "H" )
+                                               {
+                                                       sAttr = oSettings.oClasses.sJUIHeader;
+                                               }
+                                               else if ( sAttr == "F" )
+                                               {
+                                                       sAttr = oSettings.oClasses.sJUIFooter;
+                                               }
+                                               
+                                               /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
+                                                * breaks the string into parts and applies them as needed
+                                                */
+                                               if ( sAttr.indexOf('.') != -1 )
+                                               {
+                                                       var aSplit = sAttr.split('.');
+                                                       nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
+                                                       nNewNode.className = aSplit[1];
+                                               }
+                                               else if ( sAttr.charAt(0) == "#" )
+                                               {
+                                                       nNewNode.id = sAttr.substr(1, sAttr.length-1);
+                                               }
+                                               else
+                                               {
+                                                       nNewNode.className = sAttr;
+                                               }
+                                               
+                                               i += j; /* Move along the position array */
+                                       }
+                                       
+                                       nInsertNode.appendChild( nNewNode );
+                                       nInsertNode = nNewNode;
+                               }
+                               else if ( cOption == '>' )
+                               {
+                                       /* End container div */
+                                       nInsertNode = nInsertNode.parentNode;
+                               }
+                               else if ( cOption == 'l' && oSettings.oFeatures.bPaginate && oSettings.oFeatures.bLengthChange )
+                               {
+                                       /* Length */
+                                       nTmp = _fnFeatureHtmlLength( oSettings );
+                                       iPushFeature = 1;
+                               }
+                               else if ( cOption == 'f' && oSettings.oFeatures.bFilter )
+                               {
+                                       /* Filter */
+                                       nTmp = _fnFeatureHtmlFilter( oSettings );
+                                       iPushFeature = 1;
+                               }
+                               else if ( cOption == 'r' && oSettings.oFeatures.bProcessing )
+                               {
+                                       /* pRocessing */
+                                       nTmp = _fnFeatureHtmlProcessing( oSettings );
+                                       iPushFeature = 1;
+                               }
+                               else if ( cOption == 't' )
+                               {
+                                       /* Table */
+                                       nTmp = _fnFeatureHtmlTable( oSettings );
+                                       iPushFeature = 1;
+                               }
+                               else if ( cOption ==  'i' && oSettings.oFeatures.bInfo )
+                               {
+                                       /* Info */
+                                       nTmp = _fnFeatureHtmlInfo( oSettings );
+                                       iPushFeature = 1;
+                               }
+                               else if ( cOption == 'p' && oSettings.oFeatures.bPaginate )
+                               {
+                                       /* Pagination */
+                                       nTmp = _fnFeatureHtmlPaginate( oSettings );
+                                       iPushFeature = 1;
+                               }
+                               else if ( DataTable.ext.aoFeatures.length !== 0 )
+                               {
+                                       /* Plug-in features */
+                                       var aoFeatures = DataTable.ext.aoFeatures;
+                                       for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
+                                       {
+                                               if ( cOption == aoFeatures[k].cFeature )
+                                               {
+                                                       nTmp = aoFeatures[k].fnInit( oSettings );
+                                                       if ( nTmp )
+                                                       {
+                                                               iPushFeature = 1;
+                                                       }
+                                                       break;
+                                               }
+                                       }
+                               }
+                               
+                               /* Add to the 2D features array */
+                               if ( iPushFeature == 1 && nTmp !== null )
+                               {
+                                       if ( typeof oSettings.aanFeatures[cOption] !== 'object' )
+                                       {
+                                               oSettings.aanFeatures[cOption] = [];
+                                       }
+                                       oSettings.aanFeatures[cOption].push( nTmp );
+                                       nInsertNode.appendChild( nTmp );
+                               }
+                       }
+                       
+                       /* Built our DOM structure - replace the holding div with what we want */
+                       nHolding.parentNode.replaceChild( oSettings.nTableWrapper, nHolding );
+               }
+               
+               
+               /**
+                * Use the DOM source to create up an array of header cells. The idea here is to
+                * create a layout grid (array) of rows x columns, which contains a reference
+                * to the cell that that point in the grid (regardless of col/rowspan), such that
+                * any column / row could be removed and the new grid constructed
+                *  @param array {object} aLayout Array to store the calculated layout in
+                *  @param {node} nThead The header/footer element for the table
+                *  @memberof DataTable#oApi
+                */
+               function _fnDetectHeader ( aLayout, nThead )
+               {
+                       var nTrs = $(nThead).children('tr');
+                       var nTr, nCell;
+                       var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
+                       var bUnique;
+                       var fnShiftCol = function ( a, i, j ) {
+                               var k = a[i];
+                               while ( k[j] ) {
+                                       j++;
+                               }
+                               return j;
+                       };
+               
+                       aLayout.splice( 0, aLayout.length );
+                       
+                       /* We know how many rows there are in the layout - so prep it */
+                       for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+                       {
+                               aLayout.push( [] );
+                       }
+                       
+                       /* Calculate a layout array */
+                       for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+                       {
+                               nTr = nTrs[i];
+                               iColumn = 0;
+                               
+                               /* For every cell in the row... */
+                               nCell = nTr.firstChild;
+                               while ( nCell ) {
+                                       if ( nCell.nodeName.toUpperCase() == "TD" ||
+                                            nCell.nodeName.toUpperCase() == "TH" )
+                                       {
+                                               /* Get the col and rowspan attributes from the DOM and sanitise them */
+                                               iColspan = nCell.getAttribute('colspan') * 1;
+                                               iRowspan = nCell.getAttribute('rowspan') * 1;
+                                               iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
+                                               iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
+               
+                                               /* There might be colspan cells already in this row, so shift our target 
+                                                * accordingly
+                                                */
+                                               iColShifted = fnShiftCol( aLayout, i, iColumn );
+                                               
+                                               /* Cache calculation for unique columns */
+                                               bUnique = iColspan === 1 ? true : false;
+                                               
+                                               /* If there is col / rowspan, copy the information into the layout grid */
+                                               for ( l=0 ; l<iColspan ; l++ )
+                                               {
+                                                       for ( k=0 ; k<iRowspan ; k++ )
+                                                       {
+                                                               aLayout[i+k][iColShifted+l] = {
+                                                                       "cell": nCell,
+                                                                       "unique": bUnique
+                                                               };
+                                                               aLayout[i+k].nTr = nTr;
+                                                       }
+                                               }
+                                       }
+                                       nCell = nCell.nextSibling;
+                               }
+                       }
+               }
+               
+               
+               /**
+                * Get an array of unique th elements, one for each column
+                *  @param {object} oSettings dataTables settings object
+                *  @param {node} nHeader automatically detect the layout from this node - optional
+                *  @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
+                *  @returns array {node} aReturn list of unique th's
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
+               {
+                       var aReturn = [];
+                       if ( !aLayout )
+                       {
+                               aLayout = oSettings.aoHeader;
+                               if ( nHeader )
+                               {
+                                       aLayout = [];
+                                       _fnDetectHeader( aLayout, nHeader );
+                               }
+                       }
+               
+                       for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
+                       {
+                               for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
+                               {
+                                       if ( aLayout[i][j].unique && 
+                                                (!aReturn[j] || !oSettings.bSortCellsTop) )
+                                       {
+                                               aReturn[j] = aLayout[i][j].cell;
+                                       }
+                               }
+                       }
+                       
+                       return aReturn;
+               }
+               
+               
+               
+               /**
+                * Update the table using an Ajax call
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {boolean} Block the table drawing or not
+                *  @memberof DataTable#oApi
+                */
+               function _fnAjaxUpdate( oSettings )
+               {
+                       if ( oSettings.bAjaxDataGet )
+                       {
+                               oSettings.iDraw++;
+                               _fnProcessingDisplay( oSettings, true );
+                               var iColumns = oSettings.aoColumns.length;
+                               var aoData = _fnAjaxParameters( oSettings );
+                               _fnServerParams( oSettings, aoData );
+                               
+                               oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData,
+                                       function(json) {
+                                               _fnAjaxUpdateDraw( oSettings, json );
+                                       }, oSettings );
+                               return false;
+                       }
+                       else
+                       {
+                               return true;
+                       }
+               }
+               
+               
+               /**
+                * Build up the parameters in an object needed for a server-side processing request
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {bool} block the table drawing or not
+                *  @memberof DataTable#oApi
+                */
+               function _fnAjaxParameters( oSettings )
+               {
+                       var iColumns = oSettings.aoColumns.length;
+                       var aoData = [], mDataProp, aaSort, aDataSort;
+                       var i, j;
+                       
+                       aoData.push( { "name": "sEcho",          "value": oSettings.iDraw } );
+                       aoData.push( { "name": "iColumns",       "value": iColumns } );
+                       aoData.push( { "name": "sColumns",       "value": _fnColumnOrdering(oSettings) } );
+                       aoData.push( { "name": "iDisplayStart",  "value": oSettings._iDisplayStart } );
+                       aoData.push( { "name": "iDisplayLength", "value": oSettings.oFeatures.bPaginate !== false ?
+                               oSettings._iDisplayLength : -1 } );
+                               
+                       for ( i=0 ; i<iColumns ; i++ )
+                       {
+                         mDataProp = oSettings.aoColumns[i].mData;
+                               aoData.push( { "name": "mDataProp_"+i, "value": typeof(mDataProp)==="function" ? 'function' : mDataProp } );
+                       }
+                       
+                       /* Filtering */
+                       if ( oSettings.oFeatures.bFilter !== false )
+                       {
+                               aoData.push( { "name": "sSearch", "value": oSettings.oPreviousSearch.sSearch } );
+                               aoData.push( { "name": "bRegex",  "value": oSettings.oPreviousSearch.bRegex } );
+                               for ( i=0 ; i<iColumns ; i++ )
+                               {
+                                       aoData.push( { "name": "sSearch_"+i,     "value": oSettings.aoPreSearchCols[i].sSearch } );
+                                       aoData.push( { "name": "bRegex_"+i,      "value": oSettings.aoPreSearchCols[i].bRegex } );
+                                       aoData.push( { "name": "bSearchable_"+i, "value": oSettings.aoColumns[i].bSearchable } );
+                               }
+                       }
+                       
+                       /* Sorting */
+                       if ( oSettings.oFeatures.bSort !== false )
+                       {
+                               var iCounter = 0;
+               
+                               aaSort = ( oSettings.aaSortingFixed !== null ) ?
+                                       oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
+                                       oSettings.aaSorting.slice();
+                               
+                               for ( i=0 ; i<aaSort.length ; i++ )
+                               {
+                                       aDataSort = oSettings.aoColumns[ aaSort[i][0] ].aDataSort;
+                                       
+                                       for ( j=0 ; j<aDataSort.length ; j++ )
+                                       {
+                                               aoData.push( { "name": "iSortCol_"+iCounter,  "value": aDataSort[j] } );
+                                               aoData.push( { "name": "sSortDir_"+iCounter,  "value": aaSort[i][1] } );
+                                               iCounter++;
+                                       }
+                               }
+                               aoData.push( { "name": "iSortingCols",   "value": iCounter } );
+                               
+                               for ( i=0 ; i<iColumns ; i++ )
+                               {
+                                       aoData.push( { "name": "bSortable_"+i,  "value": oSettings.aoColumns[i].bSortable } );
+                               }
+                       }
+                       
+                       return aoData;
+               }
+               
+               
+               /**
+                * Add Ajax parameters from plug-ins
+                *  @param {object} oSettings dataTables settings object
+                *  @param array {objects} aoData name/value pairs to send to the server
+                *  @memberof DataTable#oApi
+                */
+               function _fnServerParams( oSettings, aoData )
+               {
+                       _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [aoData] );
+               }
+               
+               
+               /**
+                * Data the data from the server (nuking the old) and redraw the table
+                *  @param {object} oSettings dataTables settings object
+                *  @param {object} json json data return from the server.
+                *  @param {string} json.sEcho Tracking flag for DataTables to match requests
+                *  @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
+                *  @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
+                *  @param {array} json.aaData The data to display on this page
+                *  @param {string} [json.sColumns] Column ordering (sName, comma separated)
+                *  @memberof DataTable#oApi
+                */
+               function _fnAjaxUpdateDraw ( oSettings, json )
+               {
+                       if ( json.sEcho !== undefined )
+                       {
+                               /* Protect against old returns over-writing a new one. Possible when you get
+                                * very fast interaction, and later queries are completed much faster
+                                */
+                               if ( json.sEcho*1 < oSettings.iDraw )
+                               {
+                                       return;
+                               }
+                               else
+                               {
+                                       oSettings.iDraw = json.sEcho * 1;
+                               }
+                       }
+                       
+                       if ( !oSettings.oScroll.bInfinite ||
+                                  (oSettings.oScroll.bInfinite && (oSettings.bSorted || oSettings.bFiltered)) )
+                       {
+                               _fnClearTable( oSettings );
+                       }
+                       oSettings._iRecordsTotal = parseInt(json.iTotalRecords, 10);
+                       oSettings._iRecordsDisplay = parseInt(json.iTotalDisplayRecords, 10);
+                       
+                       /* Determine if reordering is required */
+                       var sOrdering = _fnColumnOrdering(oSettings);
+                       var bReOrder = (json.sColumns !== undefined && sOrdering !== "" && json.sColumns != sOrdering );
+                       var aiIndex;
+                       if ( bReOrder )
+                       {
+                               aiIndex = _fnReOrderIndex( oSettings, json.sColumns );
+                       }
+                       
+                       var aData = _fnGetObjectDataFn( oSettings.sAjaxDataProp )( json );
+                       for ( var i=0, iLen=aData.length ; i<iLen ; i++ )
+                       {
+                               if ( bReOrder )
+                               {
+                                       /* If we need to re-order, then create a new array with the correct order and add it */
+                                       var aDataSorted = [];
+                                       for ( var j=0, jLen=oSettings.aoColumns.length ; j<jLen ; j++ )
+                                       {
+                                               aDataSorted.push( aData[i][ aiIndex[j] ] );
+                                       }
+                                       _fnAddData( oSettings, aDataSorted );
+                               }
+                               else
+                               {
+                                       /* No re-order required, sever got it "right" - just straight add */
+                                       _fnAddData( oSettings, aData[i] );
+                               }
+                       }
+                       oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+                       
+                       oSettings.bAjaxDataGet = false;
+                       _fnDraw( oSettings );
+                       oSettings.bAjaxDataGet = true;
+                       _fnProcessingDisplay( oSettings, false );
+               }
+               
+               
+               
+               /**
+                * Generate the node required for filtering text
+                *  @returns {node} Filter control element
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnFeatureHtmlFilter ( oSettings )
+               {
+                       var oPreviousSearch = oSettings.oPreviousSearch;
+                       
+                       var sSearchStr = oSettings.oLanguage.sSearch;
+                       sSearchStr = (sSearchStr.indexOf('_INPUT_') !== -1) ?
+                         sSearchStr.replace('_INPUT_', '<input type="text" />') :
+                         sSearchStr==="" ? '<input type="text" />' : sSearchStr+' <input type="text" />';
+                       
+                       var nFilter = document.createElement( 'div' );
+                       nFilter.className = oSettings.oClasses.sFilter;
+                       nFilter.innerHTML = '<label>'+sSearchStr+'</label>';
+                       if ( !oSettings.aanFeatures.f )
+                       {
+                               nFilter.id = oSettings.sTableId+'_filter';
+                       }
+                       
+                       var jqFilter = $('input[type="text"]', nFilter);
+               
+                       // Store a reference to the input element, so other input elements could be
+                       // added to the filter wrapper if needed (submit button for example)
+                       nFilter._DT_Input = jqFilter[0];
+               
+                       jqFilter.val( oPreviousSearch.sSearch.replace('"','&quot;') );
+                       jqFilter.bind( 'keyup.DT', function(e) {
+                               /* Update all other filter input elements for the new display */
+                               var n = oSettings.aanFeatures.f;
+                               var val = this.value==="" ? "" : this.value; // mental IE8 fix :-(
+               
+                               for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+                               {
+                                       if ( n[i] != $(this).parents('div.dataTables_filter')[0] )
+                                       {
+                                               $(n[i]._DT_Input).val( val );
+                                       }
+                               }
+                               
+                               /* Now do the filter */
+                               if ( val != oPreviousSearch.sSearch )
+                               {
+                                       _fnFilterComplete( oSettings, { 
+                                               "sSearch": val, 
+                                               "bRegex": oPreviousSearch.bRegex,
+                                               "bSmart": oPreviousSearch.bSmart ,
+                                               "bCaseInsensitive": oPreviousSearch.bCaseInsensitive 
+                                       } );
+                               }
+                       } );
+               
+                       jqFilter
+                               .attr('aria-controls', oSettings.sTableId)
+                               .bind( 'keypress.DT', function(e) {
+                                       /* Prevent form submission */
+                                       if ( e.keyCode == 13 )
+                                       {
+                                               return false;
+                                       }
+                               }
+                       );
+                       
+                       return nFilter;
+               }
+               
+               
+               /**
+                * Filter the table using both the global filter and column based filtering
+                *  @param {object} oSettings dataTables settings object
+                *  @param {object} oSearch search information
+                *  @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
+                *  @memberof DataTable#oApi
+                */
+               function _fnFilterComplete ( oSettings, oInput, iForce )
+               {
+                       var oPrevSearch = oSettings.oPreviousSearch;
+                       var aoPrevSearch = oSettings.aoPreSearchCols;
+                       var fnSaveFilter = function ( oFilter ) {
+                               /* Save the filtering values */
+                               oPrevSearch.sSearch = oFilter.sSearch;
+                               oPrevSearch.bRegex = oFilter.bRegex;
+                               oPrevSearch.bSmart = oFilter.bSmart;
+                               oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
+                       };
+               
+                       /* In server-side processing all filtering is done by the server, so no point hanging around here */
+                       if ( !oSettings.oFeatures.bServerSide )
+                       {
+                               /* Global filter */
+                               _fnFilter( oSettings, oInput.sSearch, iForce, oInput.bRegex, oInput.bSmart, oInput.bCaseInsensitive );
+                               fnSaveFilter( oInput );
+               
+                               /* Now do the individual column filter */
+                               for ( var i=0 ; i<oSettings.aoPreSearchCols.length ; i++ )
+                               {
+                                       _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, aoPrevSearch[i].bRegex, 
+                                               aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
+                               }
+                               
+                               /* Custom filtering */
+                               _fnFilterCustom( oSettings );
+                       }
+                       else
+                       {
+                               fnSaveFilter( oInput );
+                       }
+                       
+                       /* Tell the draw function we have been filtering */
+                       oSettings.bFiltered = true;
+                       $(oSettings.oInstance).trigger('filter', oSettings);
+                       
+                       /* Redraw the table */
+                       oSettings._iDisplayStart = 0;
+                       _fnCalculateEnd( oSettings );
+                       _fnDraw( oSettings );
+                       
+                       /* Rebuild search array 'offline' */
+                       _fnBuildSearchArray( oSettings, 0 );
+               }
+               
+               
+               /**
+                * Apply custom filtering functions
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnFilterCustom( oSettings )
+               {
+                       var afnFilters = DataTable.ext.afnFiltering;
+                       var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
+               
+                       for ( var i=0, iLen=afnFilters.length ; i<iLen ; i++ )
+                       {
+                               var iCorrector = 0;
+                               for ( var j=0, jLen=oSettings.aiDisplay.length ; j<jLen ; j++ )
+                               {
+                                       var iDisIndex = oSettings.aiDisplay[j-iCorrector];
+                                       var bTest = afnFilters[i](
+                                               oSettings,
+                                               _fnGetRowData( oSettings, iDisIndex, 'filter', aiFilterColumns ),
+                                               iDisIndex
+                                       );
+                                       
+                                       /* Check if we should use this row based on the filtering function */
+                                       if ( !bTest )
+                                       {
+                                               oSettings.aiDisplay.splice( j-iCorrector, 1 );
+                                               iCorrector++;
+                                       }
+                               }
+                       }
+               }
+               
+               
+               /**
+                * Filter the table on a per-column basis
+                *  @param {object} oSettings dataTables settings object
+                *  @param {string} sInput string to filter on
+                *  @param {int} iColumn column to filter
+                *  @param {bool} bRegex treat search string as a regular expression or not
+                *  @param {bool} bSmart use smart filtering or not
+                *  @param {bool} bCaseInsensitive Do case insenstive matching or not
+                *  @memberof DataTable#oApi
+                */
+               function _fnFilterColumn ( oSettings, sInput, iColumn, bRegex, bSmart, bCaseInsensitive )
+               {
+                       if ( sInput === "" )
+                       {
+                               return;
+                       }
+                       
+                       var iIndexCorrector = 0;
+                       var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
+                       
+                       for ( var i=oSettings.aiDisplay.length-1 ; i>=0 ; i-- )
+                       {
+                               var sData = _fnDataToSearch( _fnGetCellData( oSettings, oSettings.aiDisplay[i], iColumn, 'filter' ),
+                                       oSettings.aoColumns[iColumn].sType );
+                               if ( ! rpSearch.test( sData ) )
+                               {
+                                       oSettings.aiDisplay.splice( i, 1 );
+                                       iIndexCorrector++;
+                               }
+                       }
+               }
+               
+               
+               /**
+                * Filter the data table based on user input and draw the table
+                *  @param {object} oSettings dataTables settings object
+                *  @param {string} sInput string to filter on
+                *  @param {int} iForce optional - force a research of the master array (1) or not (undefined or 0)
+                *  @param {bool} bRegex treat as a regular expression or not
+                *  @param {bool} bSmart perform smart filtering or not
+                *  @param {bool} bCaseInsensitive Do case insenstive matching or not
+                *  @memberof DataTable#oApi
+                */
+               function _fnFilter( oSettings, sInput, iForce, bRegex, bSmart, bCaseInsensitive )
+               {
+                       var i;
+                       var rpSearch = _fnFilterCreateSearch( sInput, bRegex, bSmart, bCaseInsensitive );
+                       var oPrevSearch = oSettings.oPreviousSearch;
+                       
+                       /* Check if we are forcing or not - optional parameter */
+                       if ( !iForce )
+                       {
+                               iForce = 0;
+                       }
+                       
+                       /* Need to take account of custom filtering functions - always filter */
+                       if ( DataTable.ext.afnFiltering.length !== 0 )
+                       {
+                               iForce = 1;
+                       }
+                       
+                       /*
+                        * If the input is blank - we want the full data set
+                        */
+                       if ( sInput.length <= 0 )
+                       {
+                               oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+                               oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+                       }
+                       else
+                       {
+                               /*
+                                * We are starting a new search or the new search string is smaller 
+                                * then the old one (i.e. delete). Search from the master array
+                                */
+                               if ( oSettings.aiDisplay.length == oSettings.aiDisplayMaster.length ||
+                                          oPrevSearch.sSearch.length > sInput.length || iForce == 1 ||
+                                          sInput.indexOf(oPrevSearch.sSearch) !== 0 )
+                               {
+                                       /* Nuke the old display array - we are going to rebuild it */
+                                       oSettings.aiDisplay.splice( 0, oSettings.aiDisplay.length);
+                                       
+                                       /* Force a rebuild of the search array */
+                                       _fnBuildSearchArray( oSettings, 1 );
+                                       
+                                       /* Search through all records to populate the search array
+                                        * The the oSettings.aiDisplayMaster and asDataSearch arrays have 1 to 1 
+                                        * mapping
+                                        */
+                                       for ( i=0 ; i<oSettings.aiDisplayMaster.length ; i++ )
+                                       {
+                                               if ( rpSearch.test(oSettings.asDataSearch[i]) )
+                                               {
+                                                       oSettings.aiDisplay.push( oSettings.aiDisplayMaster[i] );
+                                               }
+                                       }
+                         }
+                         else
+                               {
+                               /* Using old search array - refine it - do it this way for speed
+                                * Don't have to search the whole master array again
+                                        */
+                               var iIndexCorrector = 0;
+                               
+                               /* Search the current results */
+                               for ( i=0 ; i<oSettings.asDataSearch.length ; i++ )
+                                       {
+                                       if ( ! rpSearch.test(oSettings.asDataSearch[i]) )
+                                               {
+                                               oSettings.aiDisplay.splice( i-iIndexCorrector, 1 );
+                                               iIndexCorrector++;
+                                       }
+                               }
+                         }
+                       }
+               }
+               
+               
+               /**
+                * Create an array which can be quickly search through
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iMaster use the master data array - optional
+                *  @memberof DataTable#oApi
+                */
+               function _fnBuildSearchArray ( oSettings, iMaster )
+               {
+                       if ( !oSettings.oFeatures.bServerSide )
+                       {
+                               /* Clear out the old data */
+                               oSettings.asDataSearch = [];
+               
+                               var aiFilterColumns = _fnGetColumns( oSettings, 'bSearchable' );
+                               var aiIndex = (iMaster===1) ?
+                                       oSettings.aiDisplayMaster :
+                                       oSettings.aiDisplay;
+                               
+                               for ( var i=0, iLen=aiIndex.length ; i<iLen ; i++ )
+                               {
+                                       oSettings.asDataSearch[i] = _fnBuildSearchRow(
+                                               oSettings,
+                                               _fnGetRowData( oSettings, aiIndex[i], 'filter', aiFilterColumns )
+                                       );
+                               }
+                       }
+               }
+               
+               
+               /**
+                * Create a searchable string from a single data row
+                *  @param {object} oSettings dataTables settings object
+                *  @param {array} aData Row data array to use for the data to search
+                *  @memberof DataTable#oApi
+                */
+               function _fnBuildSearchRow( oSettings, aData )
+               {
+                       var sSearch = aData.join('  ');
+                       
+                       /* If it looks like there is an HTML entity in the string, attempt to decode it */
+                       if ( sSearch.indexOf('&') !== -1 )
+                       {
+                               sSearch = $('<div>').html(sSearch).text();
+                       }
+                       
+                       // Strip newline characters
+                       return sSearch.replace( /[\n\r]/g, " " );
+               }
+               
+               /**
+                * Build a regular expression object suitable for searching a table
+                *  @param {string} sSearch string to search for
+                *  @param {bool} bRegex treat as a regular expression or not
+                *  @param {bool} bSmart perform smart filtering or not
+                *  @param {bool} bCaseInsensitive Do case insensitive matching or not
+                *  @returns {RegExp} constructed object
+                *  @memberof DataTable#oApi
+                */
+               function _fnFilterCreateSearch( sSearch, bRegex, bSmart, bCaseInsensitive )
+               {
+                       var asSearch, sRegExpString;
+                       
+                       if ( bSmart )
+                       {
+                               /* Generate the regular expression to use. Something along the lines of:
+                                * ^(?=.*?\bone\b)(?=.*?\btwo\b)(?=.*?\bthree\b).*$
+                                */
+                               asSearch = bRegex ? sSearch.split( ' ' ) : _fnEscapeRegex( sSearch ).split( ' ' );
+                               sRegExpString = '^(?=.*?'+asSearch.join( ')(?=.*?' )+').*$';
+                               return new RegExp( sRegExpString, bCaseInsensitive ? "i" : "" );
+                       }
+                       else
+                       {
+                               sSearch = bRegex ? sSearch : _fnEscapeRegex( sSearch );
+                               return new RegExp( sSearch, bCaseInsensitive ? "i" : "" );
+                       }
+               }
+               
+               
+               /**
+                * Convert raw data into something that the user can search on
+                *  @param {string} sData data to be modified
+                *  @param {string} sType data type
+                *  @returns {string} search string
+                *  @memberof DataTable#oApi
+                */
+               function _fnDataToSearch ( sData, sType )
+               {
+                       if ( typeof DataTable.ext.ofnSearch[sType] === "function" )
+                       {
+                               return DataTable.ext.ofnSearch[sType]( sData );
+                       }
+                       else if ( sData === null )
+                       {
+                               return '';
+                       }
+                       else if ( sType == "html" )
+                       {
+                               return sData.replace(/[\r\n]/g," ").replace( /<.*?>/g, "" );
+                       }
+                       else if ( typeof sData === "string" )
+                       {
+                               return sData.replace(/[\r\n]/g," ");
+                       }
+                       return sData;
+               }
+               
+               
+               /**
+                * scape a string such that it can be used in a regular expression
+                *  @param {string} sVal string to escape
+                *  @returns {string} escaped string
+                *  @memberof DataTable#oApi
+                */
+               function _fnEscapeRegex ( sVal )
+               {
+                       var acEscape = [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ];
+                       var reReplace = new RegExp( '(\\' + acEscape.join('|\\') + ')', 'g' );
+                       return sVal.replace(reReplace, '\\$1');
+               }
+               
+               
+               /**
+                * Generate the node required for the info display
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {node} Information element
+                *  @memberof DataTable#oApi
+                */
+               function _fnFeatureHtmlInfo ( oSettings )
+               {
+                       var nInfo = document.createElement( 'div' );
+                       nInfo.className = oSettings.oClasses.sInfo;
+                       
+                       /* Actions that are to be taken once only for this feature */
+                       if ( !oSettings.aanFeatures.i )
+                       {
+                               /* Add draw callback */
+                               oSettings.aoDrawCallback.push( {
+                                       "fn": _fnUpdateInfo,
+                                       "sName": "information"
+                               } );
+                               
+                               /* Add id */
+                               nInfo.id = oSettings.sTableId+'_info';
+                       }
+                       oSettings.nTable.setAttribute( 'aria-describedby', oSettings.sTableId+'_info' );
+                       
+                       return nInfo;
+               }
+               
+               
+               /**
+                * Update the information elements in the display
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnUpdateInfo ( oSettings )
+               {
+                       /* Show information about the table */
+                       if ( !oSettings.oFeatures.bInfo || oSettings.aanFeatures.i.length === 0 )
+                       {
+                               return;
+                       }
+                       
+                       var
+                               oLang = oSettings.oLanguage,
+                               iStart = oSettings._iDisplayStart+1,
+                               iEnd = oSettings.fnDisplayEnd(),
+                               iMax = oSettings.fnRecordsTotal(),
+                               iTotal = oSettings.fnRecordsDisplay(),
+                               sOut;
+                       
+                       if ( iTotal === 0 )
+                       {
+                               /* Empty record set */
+                               sOut = oLang.sInfoEmpty;
+                       }
+                       else {
+                               /* Normal record set */
+                               sOut = oLang.sInfo;
+                       }
+               
+                       if ( iTotal != iMax )
+                       {
+                               /* Record set after filtering */
+                               sOut += ' ' + oLang.sInfoFiltered;
+                       }
+               
+                       // Convert the macros
+                       sOut += oLang.sInfoPostFix;
+                       sOut = _fnInfoMacros( oSettings, sOut );
+                       
+                       if ( oLang.fnInfoCallback !== null )
+                       {
+                               sOut = oLang.fnInfoCallback.call( oSettings.oInstance, 
+                                       oSettings, iStart, iEnd, iMax, iTotal, sOut );
+                       }
+                       
+                       var n = oSettings.aanFeatures.i;
+                       for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+                       {
+                               $(n[i]).html( sOut );
+                       }
+               }
+               
+               
+               function _fnInfoMacros ( oSettings, str )
+               {
+                       var
+                               iStart = oSettings._iDisplayStart+1,
+                               sStart = oSettings.fnFormatNumber( iStart ),
+                               iEnd = oSettings.fnDisplayEnd(),
+                               sEnd = oSettings.fnFormatNumber( iEnd ),
+                               iTotal = oSettings.fnRecordsDisplay(),
+                               sTotal = oSettings.fnFormatNumber( iTotal ),
+                               iMax = oSettings.fnRecordsTotal(),
+                               sMax = oSettings.fnFormatNumber( iMax );
+               
+                       // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
+                       // internally
+                       if ( oSettings.oScroll.bInfinite )
+                       {
+                               sStart = oSettings.fnFormatNumber( 1 );
+                       }
+               
+                       return str.
+                               replace(/_START_/g, sStart).
+                               replace(/_END_/g,   sEnd).
+                               replace(/_TOTAL_/g, sTotal).
+                               replace(/_MAX_/g,   sMax);
+               }
+               
+               
+               
+               /**
+                * Draw the table for the first time, adding all required features
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnInitialise ( oSettings )
+               {
+                       var i, iLen, iAjaxStart=oSettings.iInitDisplayStart;
+                       
+                       /* Ensure that the table data is fully initialised */
+                       if ( oSettings.bInitialised === false )
+                       {
+                               setTimeout( function(){ _fnInitialise( oSettings ); }, 200 );
+                               return;
+                       }
+                       
+                       /* Show the display HTML options */
+                       _fnAddOptionsHtml( oSettings );
+                       
+                       /* Build and draw the header / footer for the table */
+                       _fnBuildHead( oSettings );
+                       _fnDrawHead( oSettings, oSettings.aoHeader );
+                       if ( oSettings.nTFoot )
+                       {
+                               _fnDrawHead( oSettings, oSettings.aoFooter );
+                       }
+               
+                       /* Okay to show that something is going on now */
+                       _fnProcessingDisplay( oSettings, true );
+                       
+                       /* Calculate sizes for columns */
+                       if ( oSettings.oFeatures.bAutoWidth )
+                       {
+                               _fnCalculateColumnWidths( oSettings );
+                       }
+                       
+                       for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                       {
+                               if ( oSettings.aoColumns[i].sWidth !== null )
+                               {
+                                       oSettings.aoColumns[i].nTh.style.width = _fnStringToCss( oSettings.aoColumns[i].sWidth );
+                               }
+                       }
+                       
+                       /* If there is default sorting required - let's do it. The sort function will do the
+                        * drawing for us. Otherwise we draw the table regardless of the Ajax source - this allows
+                        * the table to look initialised for Ajax sourcing data (show 'loading' message possibly)
+                        */
+                       if ( oSettings.oFeatures.bSort )
+                       {
+                               _fnSort( oSettings );
+                       }
+                       else if ( oSettings.oFeatures.bFilter )
+                       {
+                               _fnFilterComplete( oSettings, oSettings.oPreviousSearch );
+                       }
+                       else
+                       {
+                               oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+                               _fnCalculateEnd( oSettings );
+                               _fnDraw( oSettings );
+                       }
+                       
+                       /* if there is an ajax source load the data */
+                       if ( oSettings.sAjaxSource !== null && !oSettings.oFeatures.bServerSide )
+                       {
+                               var aoData = [];
+                               _fnServerParams( oSettings, aoData );
+                               oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aoData, function(json) {
+                                       var aData = (oSettings.sAjaxDataProp !== "") ?
+                                               _fnGetObjectDataFn( oSettings.sAjaxDataProp )(json) : json;
+               
+                                       /* Got the data - add it to the table */
+                                       for ( i=0 ; i<aData.length ; i++ )
+                                       {
+                                               _fnAddData( oSettings, aData[i] );
+                                       }
+                                       
+                                       /* Reset the init display for cookie saving. We've already done a filter, and
+                                        * therefore cleared it before. So we need to make it appear 'fresh'
+                                        */
+                                       oSettings.iInitDisplayStart = iAjaxStart;
+                                       
+                                       if ( oSettings.oFeatures.bSort )
+                                       {
+                                               _fnSort( oSettings );
+                                       }
+                                       else
+                                       {
+                                               oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+                                               _fnCalculateEnd( oSettings );
+                                               _fnDraw( oSettings );
+                                       }
+                                       
+                                       _fnProcessingDisplay( oSettings, false );
+                                       _fnInitComplete( oSettings, json );
+                               }, oSettings );
+                               return;
+                       }
+                       
+                       /* Server-side processing initialisation complete is done at the end of _fnDraw */
+                       if ( !oSettings.oFeatures.bServerSide )
+                       {
+                               _fnProcessingDisplay( oSettings, false );
+                               _fnInitComplete( oSettings );
+                       }
+               }
+               
+               
+               /**
+                * Draw the table for the first time, adding all required features
+                *  @param {object} oSettings dataTables settings object
+                *  @param {object} [json] JSON from the server that completed the table, if using Ajax source
+                *    with client-side processing (optional)
+                *  @memberof DataTable#oApi
+                */
+               function _fnInitComplete ( oSettings, json )
+               {
+                       oSettings._bInitComplete = true;
+                       _fnCallbackFire( oSettings, 'aoInitComplete', 'init', [oSettings, json] );
+               }
+               
+               
+               /**
+                * Language compatibility - when certain options are given, and others aren't, we
+                * need to duplicate the values over, in order to provide backwards compatibility
+                * with older language files.
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnLanguageCompat( oLanguage )
+               {
+                       var oDefaults = DataTable.defaults.oLanguage;
+               
+                       /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
+                        * sZeroRecords - assuming that is given.
+                        */
+                       if ( !oLanguage.sEmptyTable && oLanguage.sZeroRecords &&
+                               oDefaults.sEmptyTable === "No data available in table" )
+                       {
+                               _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sEmptyTable' );
+                       }
+               
+                       /* Likewise with loading records */
+                       if ( !oLanguage.sLoadingRecords && oLanguage.sZeroRecords &&
+                               oDefaults.sLoadingRecords === "Loading..." )
+                       {
+                               _fnMap( oLanguage, oLanguage, 'sZeroRecords', 'sLoadingRecords' );
+                       }
+               }
+               
+               
+               
+               /**
+                * Generate the node required for user display length changing
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {node} Display length feature node
+                *  @memberof DataTable#oApi
+                */
+               function _fnFeatureHtmlLength ( oSettings )
+               {
+                       if ( oSettings.oScroll.bInfinite )
+                       {
+                               return null;
+                       }
+                       
+                       /* This can be overruled by not using the _MENU_ var/macro in the language variable */
+                       var sName = 'name="'+oSettings.sTableId+'_length"';
+                       var sStdMenu = '<select size="1" '+sName+'>';
+                       var i, iLen;
+                       var aLengthMenu = oSettings.aLengthMenu;
+                       
+                       if ( aLengthMenu.length == 2 && typeof aLengthMenu[0] === 'object' && 
+                                       typeof aLengthMenu[1] === 'object' )
+                       {
+                               for ( i=0, iLen=aLengthMenu[0].length ; i<iLen ; i++ )
+                               {
+                                       sStdMenu += '<option value="'+aLengthMenu[0][i]+'">'+aLengthMenu[1][i]+'</option>';
+                               }
+                       }
+                       else
+                       {
+                               for ( i=0, iLen=aLengthMenu.length ; i<iLen ; i++ )
+                               {
+                                       sStdMenu += '<option value="'+aLengthMenu[i]+'">'+aLengthMenu[i]+'</option>';
+                               }
+                       }
+                       sStdMenu += '</select>';
+                       
+                       var nLength = document.createElement( 'div' );
+                       if ( !oSettings.aanFeatures.l )
+                       {
+                               nLength.id = oSettings.sTableId+'_length';
+                       }
+                       nLength.className = oSettings.oClasses.sLength;
+                       nLength.innerHTML = '<label>'+oSettings.oLanguage.sLengthMenu.replace( '_MENU_', sStdMenu )+'</label>';
+                       
+                       /*
+                        * Set the length to the current display length - thanks to Andrea Pavlovic for this fix,
+                        * and Stefan Skopnik for fixing the fix!
+                        */
+                       $('select option[value="'+oSettings._iDisplayLength+'"]', nLength).attr("selected", true);
+                       
+                       $('select', nLength).bind( 'change.DT', function(e) {
+                               var iVal = $(this).val();
+                               
+                               /* Update all other length options for the new display */
+                               var n = oSettings.aanFeatures.l;
+                               for ( i=0, iLen=n.length ; i<iLen ; i++ )
+                               {
+                                       if ( n[i] != this.parentNode )
+                                       {
+                                               $('select', n[i]).val( iVal );
+                                       }
+                               }
+                               
+                               /* Redraw the table */
+                               oSettings._iDisplayLength = parseInt(iVal, 10);
+                               _fnCalculateEnd( oSettings );
+                               
+                               /* If we have space to show extra rows (backing up from the end point - then do so */
+                               if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() )
+                               {
+                                       oSettings._iDisplayStart = oSettings.fnDisplayEnd() - oSettings._iDisplayLength;
+                                       if ( oSettings._iDisplayStart < 0 )
+                                       {
+                                               oSettings._iDisplayStart = 0;
+                                       }
+                               }
+                               
+                               if ( oSettings._iDisplayLength == -1 )
+                               {
+                                       oSettings._iDisplayStart = 0;
+                               }
+                               
+                               _fnDraw( oSettings );
+                       } );
+               
+               
+                       $('select', nLength).attr('aria-controls', oSettings.sTableId);
+                       
+                       return nLength;
+               }
+               
+               
+               /**
+                * Recalculate the end point based on the start point
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnCalculateEnd( oSettings )
+               {
+                       if ( oSettings.oFeatures.bPaginate === false )
+                       {
+                               oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+                       }
+                       else
+                       {
+                               /* Set the end point of the display - based on how many elements there are
+                                * still to display
+                                */
+                               if ( oSettings._iDisplayStart + oSettings._iDisplayLength > oSettings.aiDisplay.length ||
+                                          oSettings._iDisplayLength == -1 )
+                               {
+                                       oSettings._iDisplayEnd = oSettings.aiDisplay.length;
+                               }
+                               else
+                               {
+                                       oSettings._iDisplayEnd = oSettings._iDisplayStart + oSettings._iDisplayLength;
+                               }
+                       }
+               }
+               
+               
+               
+               /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+                * Note that most of the paging logic is done in 
+                * DataTable.ext.oPagination
+                */
+               
+               /**
+                * Generate the node required for default pagination
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {node} Pagination feature node
+                *  @memberof DataTable#oApi
+                */
+               function _fnFeatureHtmlPaginate ( oSettings )
+               {
+                       if ( oSettings.oScroll.bInfinite )
+                       {
+                               return null;
+                       }
+                       
+                       var nPaginate = document.createElement( 'div' );
+                       nPaginate.className = oSettings.oClasses.sPaging+oSettings.sPaginationType;
+                       
+                       DataTable.ext.oPagination[ oSettings.sPaginationType ].fnInit( oSettings, nPaginate, 
+                               function( oSettings ) {
+                                       _fnCalculateEnd( oSettings );
+                                       _fnDraw( oSettings );
+                               }
+                       );
+                       
+                       /* Add a draw callback for the pagination on first instance, to update the paging display */
+                       if ( !oSettings.aanFeatures.p )
+                       {
+                               oSettings.aoDrawCallback.push( {
+                                       "fn": function( oSettings ) {
+                                               DataTable.ext.oPagination[ oSettings.sPaginationType ].fnUpdate( oSettings, function( oSettings ) {
+                                                       _fnCalculateEnd( oSettings );
+                                                       _fnDraw( oSettings );
+                                               } );
+                                       },
+                                       "sName": "pagination"
+                               } );
+                       }
+                       return nPaginate;
+               }
+               
+               
+               /**
+                * Alter the display settings to change the page
+                *  @param {object} oSettings dataTables settings object
+                *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
+                *    or page number to jump to (integer)
+                *  @returns {bool} true page has changed, false - no change (no effect) eg 'first' on page 1
+                *  @memberof DataTable#oApi
+                */
+               function _fnPageChange ( oSettings, mAction )
+               {
+                       var iOldStart = oSettings._iDisplayStart;
+                       
+                       if ( typeof mAction === "number" )
+                       {
+                               oSettings._iDisplayStart = mAction * oSettings._iDisplayLength;
+                               if ( oSettings._iDisplayStart > oSettings.fnRecordsDisplay() )
+                               {
+                                       oSettings._iDisplayStart = 0;
+                               }
+                       }
+                       else if ( mAction == "first" )
+                       {
+                               oSettings._iDisplayStart = 0;
+                       }
+                       else if ( mAction == "previous" )
+                       {
+                               oSettings._iDisplayStart = oSettings._iDisplayLength>=0 ?
+                                       oSettings._iDisplayStart - oSettings._iDisplayLength :
+                                       0;
+                               
+                               /* Correct for under-run */
+                               if ( oSettings._iDisplayStart < 0 )
+                               {
+                                 oSettings._iDisplayStart = 0;
+                               }
+                       }
+                       else if ( mAction == "next" )
+                       {
+                               if ( oSettings._iDisplayLength >= 0 )
+                               {
+                                       /* Make sure we are not over running the display array */
+                                       if ( oSettings._iDisplayStart + oSettings._iDisplayLength < oSettings.fnRecordsDisplay() )
+                                       {
+                                               oSettings._iDisplayStart += oSettings._iDisplayLength;
+                                       }
+                               }
+                               else
+                               {
+                                       oSettings._iDisplayStart = 0;
+                               }
+                       }
+                       else if ( mAction == "last" )
+                       {
+                               if ( oSettings._iDisplayLength >= 0 )
+                               {
+                                       var iPages = parseInt( (oSettings.fnRecordsDisplay()-1) / oSettings._iDisplayLength, 10 ) + 1;
+                                       oSettings._iDisplayStart = (iPages-1) * oSettings._iDisplayLength;
+                               }
+                               else
+                               {
+                                       oSettings._iDisplayStart = 0;
+                               }
+                       }
+                       else
+                       {
+                               _fnLog( oSettings, 0, "Unknown paging action: "+mAction );
+                       }
+                       $(oSettings.oInstance).trigger('page', oSettings);
+                       
+                       return iOldStart != oSettings._iDisplayStart;
+               }
+               
+               
+               
+               /**
+                * Generate the node required for the processing node
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {node} Processing element
+                *  @memberof DataTable#oApi
+                */
+               function _fnFeatureHtmlProcessing ( oSettings )
+               {
+                       var nProcessing = document.createElement( 'div' );
+                       
+                       if ( !oSettings.aanFeatures.r )
+                       {
+                               nProcessing.id = oSettings.sTableId+'_processing';
+                       }
+                       nProcessing.innerHTML = oSettings.oLanguage.sProcessing;
+                       nProcessing.className = oSettings.oClasses.sProcessing;
+                       oSettings.nTable.parentNode.insertBefore( nProcessing, oSettings.nTable );
+                       
+                       return nProcessing;
+               }
+               
+               
+               /**
+                * Display or hide the processing indicator
+                *  @param {object} oSettings dataTables settings object
+                *  @param {bool} bShow Show the processing indicator (true) or not (false)
+                *  @memberof DataTable#oApi
+                */
+               function _fnProcessingDisplay ( oSettings, bShow )
+               {
+                       if ( oSettings.oFeatures.bProcessing )
+                       {
+                               var an = oSettings.aanFeatures.r;
+                               for ( var i=0, iLen=an.length ; i<iLen ; i++ )
+                               {
+                                       an[i].style.visibility = bShow ? "visible" : "hidden";
+                               }
+                       }
+               
+                       $(oSettings.oInstance).trigger('processing', [oSettings, bShow]);
+               }
+               
+               /**
+                * Add any control elements for the table - specifically scrolling
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {node} Node to add to the DOM
+                *  @memberof DataTable#oApi
+                */
+               function _fnFeatureHtmlTable ( oSettings )
+               {
+                       /* Check if scrolling is enabled or not - if not then leave the DOM unaltered */
+                       if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
+                       {
+                               return oSettings.nTable;
+                       }
+                       
+                       /*
+                        * The HTML structure that we want to generate in this function is:
+                        *  div - nScroller
+                        *    div - nScrollHead
+                        *      div - nScrollHeadInner
+                        *        table - nScrollHeadTable
+                        *          thead - nThead
+                        *    div - nScrollBody
+                        *      table - oSettings.nTable
+                        *        thead - nTheadSize
+                        *        tbody - nTbody
+                        *    div - nScrollFoot
+                        *      div - nScrollFootInner
+                        *        table - nScrollFootTable
+                        *          tfoot - nTfoot
+                        */
+                       var
+                               nScroller = document.createElement('div'),
+                               nScrollHead = document.createElement('div'),
+                               nScrollHeadInner = document.createElement('div'),
+                               nScrollBody = document.createElement('div'),
+                               nScrollFoot = document.createElement('div'),
+                               nScrollFootInner = document.createElement('div'),
+                               nScrollHeadTable = oSettings.nTable.cloneNode(false),
+                               nScrollFootTable = oSettings.nTable.cloneNode(false),
+                               nThead = oSettings.nTable.getElementsByTagName('thead')[0],
+                               nTfoot = oSettings.nTable.getElementsByTagName('tfoot').length === 0 ? null : 
+                                       oSettings.nTable.getElementsByTagName('tfoot')[0],
+                               oClasses = oSettings.oClasses;
+                       
+                       nScrollHead.appendChild( nScrollHeadInner );
+                       nScrollFoot.appendChild( nScrollFootInner );
+                       nScrollBody.appendChild( oSettings.nTable );
+                       nScroller.appendChild( nScrollHead );
+                       nScroller.appendChild( nScrollBody );
+                       nScrollHeadInner.appendChild( nScrollHeadTable );
+                       nScrollHeadTable.appendChild( nThead );
+                       if ( nTfoot !== null )
+                       {
+                               nScroller.appendChild( nScrollFoot );
+                               nScrollFootInner.appendChild( nScrollFootTable );
+                               nScrollFootTable.appendChild( nTfoot );
+                       }
+                       
+                       nScroller.className = oClasses.sScrollWrapper;
+                       nScrollHead.className = oClasses.sScrollHead;
+                       nScrollHeadInner.className = oClasses.sScrollHeadInner;
+                       nScrollBody.className = oClasses.sScrollBody;
+                       nScrollFoot.className = oClasses.sScrollFoot;
+                       nScrollFootInner.className = oClasses.sScrollFootInner;
+                       
+                       if ( oSettings.oScroll.bAutoCss )
+                       {
+                               nScrollHead.style.overflow = "hidden";
+                               nScrollHead.style.position = "relative";
+                               nScrollFoot.style.overflow = "hidden";
+                               nScrollBody.style.overflow = "auto";
+                       }
+                       
+                       nScrollHead.style.border = "0";
+                       nScrollHead.style.width = "100%";
+                       nScrollFoot.style.border = "0";
+                       nScrollHeadInner.style.width = oSettings.oScroll.sXInner !== "" ?
+                               oSettings.oScroll.sXInner : "100%"; /* will be overwritten */
+                       
+                       /* Modify attributes to respect the clones */
+                       nScrollHeadTable.removeAttribute('id');
+                       nScrollHeadTable.style.marginLeft = "0";
+                       oSettings.nTable.style.marginLeft = "0";
+                       if ( nTfoot !== null )
+                       {
+                               nScrollFootTable.removeAttribute('id');
+                               nScrollFootTable.style.marginLeft = "0";
+                       }
+                       
+                       /* Move caption elements from the body to the header, footer or leave where it is
+                        * depending on the configuration. Note that the DTD says there can be only one caption */
+                       var nCaption = $(oSettings.nTable).children('caption');
+                       if ( nCaption.length > 0 )
+                       {
+                               nCaption = nCaption[0];
+                               if ( nCaption._captionSide === "top" )
+                               {
+                                       nScrollHeadTable.appendChild( nCaption );
+                               }
+                               else if ( nCaption._captionSide === "bottom" && nTfoot )
+                               {
+                                       nScrollFootTable.appendChild( nCaption );
+                               }
+                       }
+                       
+                       /*
+                        * Sizing
+                        */
+                       /* When x-scrolling add the width and a scroller to move the header with the body */
+                       if ( oSettings.oScroll.sX !== "" )
+                       {
+                               nScrollHead.style.width = _fnStringToCss( oSettings.oScroll.sX );
+                               nScrollBody.style.width = _fnStringToCss( oSettings.oScroll.sX );
+                               
+                               if ( nTfoot !== null )
+                               {
+                                       nScrollFoot.style.width = _fnStringToCss( oSettings.oScroll.sX );       
+                               }
+                               
+                               /* When the body is scrolled, then we also want to scroll the headers */
+                               $(nScrollBody).scroll( function (e) {
+                                       nScrollHead.scrollLeft = this.scrollLeft;
+                                       
+                                       if ( nTfoot !== null )
+                                       {
+                                               nScrollFoot.scrollLeft = this.scrollLeft;
+                                       }
+                               } );
+                       }
+                       
+                       /* When yscrolling, add the height */
+                       if ( oSettings.oScroll.sY !== "" )
+                       {
+                               nScrollBody.style.height = _fnStringToCss( oSettings.oScroll.sY );
+                       }
+                       
+                       /* Redraw - align columns across the tables */
+                       oSettings.aoDrawCallback.push( {
+                               "fn": _fnScrollDraw,
+                               "sName": "scrolling"
+                       } );
+                       
+                       /* Infinite scrolling event handlers */
+                       if ( oSettings.oScroll.bInfinite )
+                       {
+                               $(nScrollBody).scroll( function() {
+                                       /* Use a blocker to stop scrolling from loading more data while other data is still loading */
+                                       if ( !oSettings.bDrawing && $(this).scrollTop() !== 0 )
+                                       {
+                                               /* Check if we should load the next data set */
+                                               if ( $(this).scrollTop() + $(this).height() > 
+                                                       $(oSettings.nTable).height() - oSettings.oScroll.iLoadGap )
+                                               {
+                                                       /* Only do the redraw if we have to - we might be at the end of the data */
+                                                       if ( oSettings.fnDisplayEnd() < oSettings.fnRecordsDisplay() )
+                                                       {
+                                                               _fnPageChange( oSettings, 'next' );
+                                                               _fnCalculateEnd( oSettings );
+                                                               _fnDraw( oSettings );
+                                                       }
+                                               }
+                                       }
+                               } );
+                       }
+                       
+                       oSettings.nScrollHead = nScrollHead;
+                       oSettings.nScrollFoot = nScrollFoot;
+                       
+                       return nScroller;
+               }
+               
+               
+               /**
+                * Update the various tables for resizing. It's a bit of a pig this function, but
+                * basically the idea to:
+                *   1. Re-create the table inside the scrolling div
+                *   2. Take live measurements from the DOM
+                *   3. Apply the measurements
+                *   4. Clean up
+                *  @param {object} o dataTables settings object
+                *  @returns {node} Node to add to the DOM
+                *  @memberof DataTable#oApi
+                */
+               function _fnScrollDraw ( o )
+               {
+                       var
+                               nScrollHeadInner = o.nScrollHead.getElementsByTagName('div')[0],
+                               nScrollHeadTable = nScrollHeadInner.getElementsByTagName('table')[0],
+                               nScrollBody = o.nTable.parentNode,
+                               i, iLen, j, jLen, anHeadToSize, anHeadSizers, anFootSizers, anFootToSize, oStyle, iVis,
+                               nTheadSize, nTfootSize,
+                               iWidth, aApplied=[], aAppliedFooter=[], iSanityWidth,
+                               nScrollFootInner = (o.nTFoot !== null) ? o.nScrollFoot.getElementsByTagName('div')[0] : null,
+                               nScrollFootTable = (o.nTFoot !== null) ? nScrollFootInner.getElementsByTagName('table')[0] : null,
+                               ie67 = o.oBrowser.bScrollOversize,
+                               zeroOut = function(nSizer) {
+                                       oStyle = nSizer.style;
+                                       oStyle.paddingTop = "0";
+                                       oStyle.paddingBottom = "0";
+                                       oStyle.borderTopWidth = "0";
+                                       oStyle.borderBottomWidth = "0";
+                                       oStyle.height = 0;
+                               };
+                       
+                       /*
+                        * 1. Re-create the table inside the scrolling div
+                        */
+                       
+                       /* Remove the old minimised thead and tfoot elements in the inner table */
+                       $(o.nTable).children('thead, tfoot').remove();
+               
+                       /* Clone the current header and footer elements and then place it into the inner table */
+                       nTheadSize = $(o.nTHead).clone()[0];
+                       o.nTable.insertBefore( nTheadSize, o.nTable.childNodes[0] );
+                       anHeadToSize = o.nTHead.getElementsByTagName('tr');
+                       anHeadSizers = nTheadSize.getElementsByTagName('tr');
+                       
+                       if ( o.nTFoot !== null )
+                       {
+                               nTfootSize = $(o.nTFoot).clone()[0];
+                               o.nTable.insertBefore( nTfootSize, o.nTable.childNodes[1] );
+                               anFootToSize = o.nTFoot.getElementsByTagName('tr');
+                               anFootSizers = nTfootSize.getElementsByTagName('tr');
+                       }
+                       
+                       /*
+                        * 2. Take live measurements from the DOM - do not alter the DOM itself!
+                        */
+                       
+                       /* Remove old sizing and apply the calculated column widths
+                        * Get the unique column headers in the newly created (cloned) header. We want to apply the
+                        * calculated sizes to this header
+                        */
+                       if ( o.oScroll.sX === "" )
+                       {
+                               nScrollBody.style.width = '100%';
+                               nScrollHeadInner.parentNode.style.width = '100%';
+                       }
+                       
+                       var nThs = _fnGetUniqueThs( o, nTheadSize );
+                       for ( i=0, iLen=nThs.length ; i<iLen ; i++ )
+                       {
+                               iVis = _fnVisibleToColumnIndex( o, i );
+                               nThs[i].style.width = o.aoColumns[iVis].sWidth;
+                       }
+                       
+                       if ( o.nTFoot !== null )
+                       {
+                               _fnApplyToChildren( function(n) {
+                                       n.style.width = "";
+                               }, anFootSizers );
+                       }
+               
+                       // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
+                       // will end up forcing the scrollbar to appear, making our measurements wrong for when we
+                       // then hide it (end of this function), so add the header height to the body scroller.
+                       if ( o.oScroll.bCollapse && o.oScroll.sY !== "" )
+                       {
+                               nScrollBody.style.height = (nScrollBody.offsetHeight + o.nTHead.offsetHeight)+"px";
+                       }
+                       
+                       /* Size the table as a whole */
+                       iSanityWidth = $(o.nTable).outerWidth();
+                       if ( o.oScroll.sX === "" )
+                       {
+                               /* No x scrolling */
+                               o.nTable.style.width = "100%";
+                               
+                               /* I know this is rubbish - but IE7 will make the width of the table when 100% include
+                                * the scrollbar - which is shouldn't. When there is a scrollbar we need to take this
+                                * into account.
+                                */
+                               if ( ie67 && ($('tbody', nScrollBody).height() > nScrollBody.offsetHeight || 
+                                       $(nScrollBody).css('overflow-y') == "scroll")  )
+                               {
+                                       o.nTable.style.width = _fnStringToCss( $(o.nTable).outerWidth() - o.oScroll.iBarWidth);
+                               }
+                       }
+                       else
+                       {
+                               if ( o.oScroll.sXInner !== "" )
+                               {
+                                       /* x scroll inner has been given - use it */
+                                       o.nTable.style.width = _fnStringToCss(o.oScroll.sXInner);
+                               }
+                               else if ( iSanityWidth == $(nScrollBody).width() &&
+                                  $(nScrollBody).height() < $(o.nTable).height() )
+                               {
+                                       /* There is y-scrolling - try to take account of the y scroll bar */
+                                       o.nTable.style.width = _fnStringToCss( iSanityWidth-o.oScroll.iBarWidth );
+                                       if ( $(o.nTable).outerWidth() > iSanityWidth-o.oScroll.iBarWidth )
+                                       {
+                                               /* Not possible to take account of it */
+                                               o.nTable.style.width = _fnStringToCss( iSanityWidth );
+                                       }
+                               }
+                               else
+                               {
+                                       /* All else fails */
+                                       o.nTable.style.width = _fnStringToCss( iSanityWidth );
+                               }
+                       }
+                       
+                       /* Recalculate the sanity width - now that we've applied the required width, before it was
+                        * a temporary variable. This is required because the column width calculation is done
+                        * before this table DOM is created.
+                        */
+                       iSanityWidth = $(o.nTable).outerWidth();
+                       
+                       /* We want the hidden header to have zero height, so remove padding and borders. Then
+                        * set the width based on the real headers
+                        */
+                       
+                       // Apply all styles in one pass. Invalidates layout only once because we don't read any 
+                       // DOM properties.
+                       _fnApplyToChildren( zeroOut, anHeadSizers );
+                        
+                       // Read all widths in next pass. Forces layout only once because we do not change 
+                       // any DOM properties.
+                       _fnApplyToChildren( function(nSizer) {
+                               aApplied.push( _fnStringToCss( $(nSizer).width() ) );
+                       }, anHeadSizers );
+                        
+                       // Apply all widths in final pass. Invalidates layout only once because we do not
+                       // read any DOM properties.
+                       _fnApplyToChildren( function(nToSize, i) {
+                               nToSize.style.width = aApplied[i];
+                       }, anHeadToSize );
+               
+                       $(anHeadSizers).height(0);
+                       
+                       /* Same again with the footer if we have one */
+                       if ( o.nTFoot !== null )
+                       {
+                               _fnApplyToChildren( zeroOut, anFootSizers );
+                                
+                               _fnApplyToChildren( function(nSizer) {
+                                       aAppliedFooter.push( _fnStringToCss( $(nSizer).width() ) );
+                               }, anFootSizers );
+                                
+                               _fnApplyToChildren( function(nToSize, i) {
+                                       nToSize.style.width = aAppliedFooter[i];
+                               }, anFootToSize );
+               
+                               $(anFootSizers).height(0);
+                       }
+                       
+                       /*
+                        * 3. Apply the measurements
+                        */
+                       
+                       /* "Hide" the header and footer that we used for the sizing. We want to also fix their width
+                        * to what they currently are
+                        */
+                       _fnApplyToChildren( function(nSizer, i) {
+                               nSizer.innerHTML = "";
+                               nSizer.style.width = aApplied[i];
+                       }, anHeadSizers );
+                       
+                       if ( o.nTFoot !== null )
+                       {
+                               _fnApplyToChildren( function(nSizer, i) {
+                                       nSizer.innerHTML = "";
+                                       nSizer.style.width = aAppliedFooter[i];
+                               }, anFootSizers );
+                       }
+                       
+                       /* Sanity check that the table is of a sensible width. If not then we are going to get
+                        * misalignment - try to prevent this by not allowing the table to shrink below its min width
+                        */
+                       if ( $(o.nTable).outerWidth() < iSanityWidth )
+                       {
+                               /* The min width depends upon if we have a vertical scrollbar visible or not */
+                               var iCorrection = ((nScrollBody.scrollHeight > nScrollBody.offsetHeight || 
+                                       $(nScrollBody).css('overflow-y') == "scroll")) ?
+                                               iSanityWidth+o.oScroll.iBarWidth : iSanityWidth;
+                               
+                               /* IE6/7 are a law unto themselves... */
+                               if ( ie67 && (nScrollBody.scrollHeight > 
+                                       nScrollBody.offsetHeight || $(nScrollBody).css('overflow-y') == "scroll")  )
+                               {
+                                       o.nTable.style.width = _fnStringToCss( iCorrection-o.oScroll.iBarWidth );
+                               }
+                               
+                               /* Apply the calculated minimum width to the table wrappers */
+                               nScrollBody.style.width = _fnStringToCss( iCorrection );
+                               o.nScrollHead.style.width = _fnStringToCss( iCorrection );
+                               
+                               if ( o.nTFoot !== null )
+                               {
+                                       o.nScrollFoot.style.width = _fnStringToCss( iCorrection );
+                               }
+                               
+                               /* And give the user a warning that we've stopped the table getting too small */
+                               if ( o.oScroll.sX === "" )
+                               {
+                                       _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+                                               " misalignment. The table has been drawn at its minimum possible width." );
+                               }
+                               else if ( o.oScroll.sXInner !== "" )
+                               {
+                                       _fnLog( o, 1, "The table cannot fit into the current element which will cause column"+
+                                               " misalignment. Increase the sScrollXInner value or remove it to allow automatic"+
+                                               " calculation" );
+                               }
+                       }
+                       else
+                       {
+                               nScrollBody.style.width = _fnStringToCss( '100%' );
+                               o.nScrollHead.style.width = _fnStringToCss( '100%' );
+                               
+                               if ( o.nTFoot !== null )
+                               {
+                                       o.nScrollFoot.style.width = _fnStringToCss( '100%' );
+                               }
+                       }
+                       
+                       
+                       /*
+                        * 4. Clean up
+                        */
+                       if ( o.oScroll.sY === "" )
+                       {
+                               /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
+                                * the scrollbar height from the visible display, rather than adding it on. We need to
+                                * set the height in order to sort this. Don't want to do it in any other browsers.
+                                */
+                               if ( ie67 )
+                               {
+                                       nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+o.oScroll.iBarWidth );
+                               }
+                       }
+                       
+                       if ( o.oScroll.sY !== "" && o.oScroll.bCollapse )
+                       {
+                               nScrollBody.style.height = _fnStringToCss( o.oScroll.sY );
+                               
+                               var iExtra = (o.oScroll.sX !== "" && o.nTable.offsetWidth > nScrollBody.offsetWidth) ?
+                                       o.oScroll.iBarWidth : 0;
+                               if ( o.nTable.offsetHeight < nScrollBody.offsetHeight )
+                               {
+                                       nScrollBody.style.height = _fnStringToCss( o.nTable.offsetHeight+iExtra );
+                               }
+                       }
+                       
+                       /* Finally set the width's of the header and footer tables */
+                       var iOuterWidth = $(o.nTable).outerWidth();
+                       nScrollHeadTable.style.width = _fnStringToCss( iOuterWidth );
+                       nScrollHeadInner.style.width = _fnStringToCss( iOuterWidth );
+               
+                       // Figure out if there are scrollbar present - if so then we need a the header and footer to
+                       // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
+                       var bScrolling = $(o.nTable).height() > nScrollBody.clientHeight || $(nScrollBody).css('overflow-y') == "scroll";
+                       nScrollHeadInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
+                       
+                       if ( o.nTFoot !== null )
+                       {
+                               nScrollFootTable.style.width = _fnStringToCss( iOuterWidth );
+                               nScrollFootInner.style.width = _fnStringToCss( iOuterWidth );
+                               nScrollFootInner.style.paddingRight = bScrolling ? o.oScroll.iBarWidth+"px" : "0px";
+                       }
+               
+                       /* Adjust the position of the header in case we loose the y-scrollbar */
+                       $(nScrollBody).scroll();
+                       
+                       /* If sorting or filtering has occurred, jump the scrolling back to the top */
+                       if ( o.bSorted || o.bFiltered )
+                       {
+                               nScrollBody.scrollTop = 0;
+                       }
+               }
+               
+               
+               /**
+                * Apply a given function to the display child nodes of an element array (typically
+                * TD children of TR rows
+                *  @param {function} fn Method to apply to the objects
+                *  @param array {nodes} an1 List of elements to look through for display children
+                *  @param array {nodes} an2 Another list (identical structure to the first) - optional
+                *  @memberof DataTable#oApi
+                */
+               function _fnApplyToChildren( fn, an1, an2 )
+               {
+                       var index=0, i=0, iLen=an1.length;
+                       var nNode1, nNode2;
+               
+                       while ( i < iLen )
+                       {
+                               nNode1 = an1[i].firstChild;
+                               nNode2 = an2 ? an2[i].firstChild : null;
+                               while ( nNode1 )
+                               {
+                                       if ( nNode1.nodeType === 1 )
+                                       {
+                                               if ( an2 )
+                                               {
+                                                       fn( nNode1, nNode2, index );
+                                               }
+                                               else
+                                               {
+                                                       fn( nNode1, index );
+                                               }
+                                               index++;
+                                       }
+                                       nNode1 = nNode1.nextSibling;
+                                       nNode2 = an2 ? nNode2.nextSibling : null;
+                               }
+                               i++;
+                       }
+               }
+               
+               /**
+                * Convert a CSS unit width to pixels (e.g. 2em)
+                *  @param {string} sWidth width to be converted
+                *  @param {node} nParent parent to get the with for (required for relative widths) - optional
+                *  @returns {int} iWidth width in pixels
+                *  @memberof DataTable#oApi
+                */
+               function _fnConvertToWidth ( sWidth, nParent )
+               {
+                       if ( !sWidth || sWidth === null || sWidth === '' )
+                       {
+                               return 0;
+                       }
+                       
+                       if ( !nParent )
+                       {
+                               nParent = document.body;
+                       }
+                       
+                       var iWidth;
+                       var nTmp = document.createElement( "div" );
+                       nTmp.style.width = _fnStringToCss( sWidth );
+                       
+                       nParent.appendChild( nTmp );
+                       iWidth = nTmp.offsetWidth;
+                       nParent.removeChild( nTmp );
+                       
+                       return ( iWidth );
+               }
+               
+               
+               /**
+                * Calculate the width of columns for the table
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnCalculateColumnWidths ( oSettings )
+               {
+                       var iTableWidth = oSettings.nTable.offsetWidth;
+                       var iUserInputs = 0;
+                       var iTmpWidth;
+                       var iVisibleColumns = 0;
+                       var iColums = oSettings.aoColumns.length;
+                       var i, iIndex, iCorrector, iWidth;
+                       var oHeaders = $('th', oSettings.nTHead);
+                       var widthAttr = oSettings.nTable.getAttribute('width');
+                       var nWrapper = oSettings.nTable.parentNode;
+                       
+                       /* Convert any user input sizes into pixel sizes */
+                       for ( i=0 ; i<iColums ; i++ )
+                       {
+                               if ( oSettings.aoColumns[i].bVisible )
+                               {
+                                       iVisibleColumns++;
+                                       
+                                       if ( oSettings.aoColumns[i].sWidth !== null )
+                                       {
+                                               iTmpWidth = _fnConvertToWidth( oSettings.aoColumns[i].sWidthOrig, 
+                                                       nWrapper );
+                                               if ( iTmpWidth !== null )
+                                               {
+                                                       oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
+                                               }
+                                                       
+                                               iUserInputs++;
+                                       }
+                               }
+                       }
+                       
+                       /* If the number of columns in the DOM equals the number that we have to process in 
+                        * DataTables, then we can use the offsets that are created by the web-browser. No custom 
+                        * sizes can be set in order for this to happen, nor scrolling used
+                        */
+                       if ( iColums == oHeaders.length && iUserInputs === 0 && iVisibleColumns == iColums &&
+                               oSettings.oScroll.sX === "" && oSettings.oScroll.sY === "" )
+                       {
+                               for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+                               {
+                                       iTmpWidth = $(oHeaders[i]).width();
+                                       if ( iTmpWidth !== null )
+                                       {
+                                               oSettings.aoColumns[i].sWidth = _fnStringToCss( iTmpWidth );
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               /* Otherwise we are going to have to do some calculations to get the width of each column.
+                                * Construct a 1 row table with the widest node in the data, and any user defined widths,
+                                * then insert it into the DOM and allow the browser to do all the hard work of
+                                * calculating table widths.
+                                */
+                               var
+                                       nCalcTmp = oSettings.nTable.cloneNode( false ),
+                                       nTheadClone = oSettings.nTHead.cloneNode(true),
+                                       nBody = document.createElement( 'tbody' ),
+                                       nTr = document.createElement( 'tr' ),
+                                       nDivSizing;
+                               
+                               nCalcTmp.removeAttribute( "id" );
+                               nCalcTmp.appendChild( nTheadClone );
+                               if ( oSettings.nTFoot !== null )
+                               {
+                                       nCalcTmp.appendChild( oSettings.nTFoot.cloneNode(true) );
+                                       _fnApplyToChildren( function(n) {
+                                               n.style.width = "";
+                                       }, nCalcTmp.getElementsByTagName('tr') );
+                               }
+                               
+                               nCalcTmp.appendChild( nBody );
+                               nBody.appendChild( nTr );
+                               
+                               /* Remove any sizing that was previously applied by the styles */
+                               var jqColSizing = $('thead th', nCalcTmp);
+                               if ( jqColSizing.length === 0 )
+                               {
+                                       jqColSizing = $('tbody tr:eq(0)>td', nCalcTmp);
+                               }
+               
+                               /* Apply custom sizing to the cloned header */
+                               var nThs = _fnGetUniqueThs( oSettings, nTheadClone );
+                               iCorrector = 0;
+                               for ( i=0 ; i<iColums ; i++ )
+                               {
+                                       var oColumn = oSettings.aoColumns[i];
+                                       if ( oColumn.bVisible && oColumn.sWidthOrig !== null && oColumn.sWidthOrig !== "" )
+                                       {
+                                               nThs[i-iCorrector].style.width = _fnStringToCss( oColumn.sWidthOrig );
+                                       }
+                                       else if ( oColumn.bVisible )
+                                       {
+                                               nThs[i-iCorrector].style.width = "";
+                                       }
+                                       else
+                                       {
+                                               iCorrector++;
+                                       }
+                               }
+               
+                               /* Find the biggest td for each column and put it into the table */
+                               for ( i=0 ; i<iColums ; i++ )
+                               {
+                                       if ( oSettings.aoColumns[i].bVisible )
+                                       {
+                                               var nTd = _fnGetWidestNode( oSettings, i );
+                                               if ( nTd !== null )
+                                               {
+                                                       nTd = nTd.cloneNode(true);
+                                                       if ( oSettings.aoColumns[i].sContentPadding !== "" )
+                                                       {
+                                                               nTd.innerHTML += oSettings.aoColumns[i].sContentPadding;
+                                                       }
+                                                       nTr.appendChild( nTd );
+                                               }
+                                       }
+                               }
+                               
+                               /* Build the table and 'display' it */
+                               nWrapper.appendChild( nCalcTmp );
+                               
+                               /* When scrolling (X or Y) we want to set the width of the table as appropriate. However,
+                                * when not scrolling leave the table width as it is. This results in slightly different,
+                                * but I think correct behaviour
+                                */
+                               if ( oSettings.oScroll.sX !== "" && oSettings.oScroll.sXInner !== "" )
+                               {
+                                       nCalcTmp.style.width = _fnStringToCss(oSettings.oScroll.sXInner);
+                               }
+                               else if ( oSettings.oScroll.sX !== "" )
+                               {
+                                       nCalcTmp.style.width = "";
+                                       if ( $(nCalcTmp).width() < nWrapper.offsetWidth )
+                                       {
+                                               nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
+                                       }
+                               }
+                               else if ( oSettings.oScroll.sY !== "" )
+                               {
+                                       nCalcTmp.style.width = _fnStringToCss( nWrapper.offsetWidth );
+                               }
+                               else if ( widthAttr )
+                               {
+                                       nCalcTmp.style.width = _fnStringToCss( widthAttr );
+                               }
+                               nCalcTmp.style.visibility = "hidden";
+                               
+                               /* Scrolling considerations */
+                               _fnScrollingWidthAdjust( oSettings, nCalcTmp );
+                               
+                               /* Read the width's calculated by the browser and store them for use by the caller. We
+                                * first of all try to use the elements in the body, but it is possible that there are
+                                * no elements there, under which circumstances we use the header elements
+                                */
+                               var oNodes = $("tbody tr:eq(0)", nCalcTmp).children();
+                               if ( oNodes.length === 0 )
+                               {
+                                       oNodes = _fnGetUniqueThs( oSettings, $('thead', nCalcTmp)[0] );
+                               }
+               
+                               /* Browsers need a bit of a hand when a width is assigned to any columns when 
+                                * x-scrolling as they tend to collapse the table to the min-width, even if
+                                * we sent the column widths. So we need to keep track of what the table width
+                                * should be by summing the user given values, and the automatic values
+                                */
+                               if ( oSettings.oScroll.sX !== "" )
+                               {
+                                       var iTotal = 0;
+                                       iCorrector = 0;
+                                       for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+                                       {
+                                               if ( oSettings.aoColumns[i].bVisible )
+                                               {
+                                                       if ( oSettings.aoColumns[i].sWidthOrig === null )
+                                                       {
+                                                               iTotal += $(oNodes[iCorrector]).outerWidth();
+                                                       }
+                                                       else
+                                                       {
+                                                               iTotal += parseInt(oSettings.aoColumns[i].sWidth.replace('px',''), 10) +
+                                                                       ($(oNodes[iCorrector]).outerWidth() - $(oNodes[iCorrector]).width());
+                                                       }
+                                                       iCorrector++;
+                                               }
+                                       }
+                                       
+                                       nCalcTmp.style.width = _fnStringToCss( iTotal );
+                                       oSettings.nTable.style.width = _fnStringToCss( iTotal );
+                               }
+               
+                               iCorrector = 0;
+                               for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+                               {
+                                       if ( oSettings.aoColumns[i].bVisible )
+                                       {
+                                               iWidth = $(oNodes[iCorrector]).width();
+                                               if ( iWidth !== null && iWidth > 0 )
+                                               {
+                                                       oSettings.aoColumns[i].sWidth = _fnStringToCss( iWidth );
+                                               }
+                                               iCorrector++;
+                                       }
+                               }
+               
+                               var cssWidth = $(nCalcTmp).css('width');
+                               oSettings.nTable.style.width = (cssWidth.indexOf('%') !== -1) ?
+                                   cssWidth : _fnStringToCss( $(nCalcTmp).outerWidth() );
+                               nCalcTmp.parentNode.removeChild( nCalcTmp );
+                       }
+               
+                       if ( widthAttr )
+                       {
+                               oSettings.nTable.style.width = _fnStringToCss( widthAttr );
+                       }
+               }
+               
+               
+               /**
+                * Adjust a table's width to take account of scrolling
+                *  @param {object} oSettings dataTables settings object
+                *  @param {node} n table node
+                *  @memberof DataTable#oApi
+                */
+               function _fnScrollingWidthAdjust ( oSettings, n )
+               {
+                       if ( oSettings.oScroll.sX === "" && oSettings.oScroll.sY !== "" )
+                       {
+                               /* When y-scrolling only, we want to remove the width of the scroll bar so the table
+                                * + scroll bar will fit into the area avaialble.
+                                */
+                               var iOrigWidth = $(n).width();
+                               n.style.width = _fnStringToCss( $(n).outerWidth()-oSettings.oScroll.iBarWidth );
+                       }
+                       else if ( oSettings.oScroll.sX !== "" )
+                       {
+                               /* When x-scrolling both ways, fix the table at it's current size, without adjusting */
+                               n.style.width = _fnStringToCss( $(n).outerWidth() );
+                       }
+               }
+               
+               
+               /**
+                * Get the widest node
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iCol column of interest
+                *  @returns {node} widest table node
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetWidestNode( oSettings, iCol )
+               {
+                       var iMaxIndex = _fnGetMaxLenString( oSettings, iCol );
+                       if ( iMaxIndex < 0 )
+                       {
+                               return null;
+                       }
+               
+                       if ( oSettings.aoData[iMaxIndex].nTr === null )
+                       {
+                               var n = document.createElement('td');
+                               n.innerHTML = _fnGetCellData( oSettings, iMaxIndex, iCol, '' );
+                               return n;
+                       }
+                       return _fnGetTdNodes(oSettings, iMaxIndex)[iCol];
+               }
+               
+               
+               /**
+                * Get the maximum strlen for each data column
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iCol column of interest
+                *  @returns {string} max string length for each column
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetMaxLenString( oSettings, iCol )
+               {
+                       var iMax = -1;
+                       var iMaxIndex = -1;
+                       
+                       for ( var i=0 ; i<oSettings.aoData.length ; i++ )
+                       {
+                               var s = _fnGetCellData( oSettings, i, iCol, 'display' )+"";
+                               s = s.replace( /<.*?>/g, "" );
+                               if ( s.length > iMax )
+                               {
+                                       iMax = s.length;
+                                       iMaxIndex = i;
+                               }
+                       }
+                       
+                       return iMaxIndex;
+               }
+               
+               
+               /**
+                * Append a CSS unit (only if required) to a string
+                *  @param {array} aArray1 first array
+                *  @param {array} aArray2 second array
+                *  @returns {int} 0 if match, 1 if length is different, 2 if no match
+                *  @memberof DataTable#oApi
+                */
+               function _fnStringToCss( s )
+               {
+                       if ( s === null )
+                       {
+                               return "0px";
+                       }
+                       
+                       if ( typeof s == 'number' )
+                       {
+                               if ( s < 0 )
+                               {
+                                       return "0px";
+                               }
+                               return s+"px";
+                       }
+                       
+                       /* Check if the last character is not 0-9 */
+                       var c = s.charCodeAt( s.length-1 );
+                       if (c < 0x30 || c > 0x39)
+                       {
+                               return s;
+                       }
+                       return s+"px";
+               }
+               
+               
+               /**
+                * Get the width of a scroll bar in this browser being used
+                *  @returns {int} width in pixels
+                *  @memberof DataTable#oApi
+                */
+               function _fnScrollBarWidth ()
+               {  
+                       var inner = document.createElement('p');
+                       var style = inner.style;
+                       style.width = "100%";
+                       style.height = "200px";
+                       style.padding = "0px";
+                       
+                       var outer = document.createElement('div');
+                       style = outer.style;
+                       style.position = "absolute";
+                       style.top = "0px";
+                       style.left = "0px";
+                       style.visibility = "hidden";
+                       style.width = "200px";
+                       style.height = "150px";
+                       style.padding = "0px";
+                       style.overflow = "hidden";
+                       outer.appendChild(inner);
+                       
+                       document.body.appendChild(outer);
+                       var w1 = inner.offsetWidth;
+                       outer.style.overflow = 'scroll';
+                       var w2 = inner.offsetWidth;
+                       if ( w1 == w2 )
+                       {
+                               w2 = outer.clientWidth;
+                       }
+                       
+                       document.body.removeChild(outer);
+                       return (w1 - w2);  
+               }
+               
+               /**
+                * Change the order of the table
+                *  @param {object} oSettings dataTables settings object
+                *  @param {bool} bApplyClasses optional - should we apply classes or not
+                *  @memberof DataTable#oApi
+                */
+               function _fnSort ( oSettings, bApplyClasses )
+               {
+                       var
+                               i, iLen, j, jLen, k, kLen,
+                               sDataType, nTh,
+                               aaSort = [],
+                               aiOrig = [],
+                               oSort = DataTable.ext.oSort,
+                               aoData = oSettings.aoData,
+                               aoColumns = oSettings.aoColumns,
+                               oAria = oSettings.oLanguage.oAria;
+                       
+                       /* No sorting required if server-side or no sorting array */
+                       if ( !oSettings.oFeatures.bServerSide && 
+                               (oSettings.aaSorting.length !== 0 || oSettings.aaSortingFixed !== null) )
+                       {
+                               aaSort = ( oSettings.aaSortingFixed !== null ) ?
+                                       oSettings.aaSortingFixed.concat( oSettings.aaSorting ) :
+                                       oSettings.aaSorting.slice();
+                               
+                               /* If there is a sorting data type, and a function belonging to it, then we need to
+                                * get the data from the developer's function and apply it for this column
+                                */
+                               for ( i=0 ; i<aaSort.length ; i++ )
+                               {
+                                       var iColumn = aaSort[i][0];
+                                       var iVisColumn = _fnColumnIndexToVisible( oSettings, iColumn );
+                                       sDataType = oSettings.aoColumns[ iColumn ].sSortDataType;
+                                       if ( DataTable.ext.afnSortData[sDataType] )
+                                       {
+                                               var aData = DataTable.ext.afnSortData[sDataType].call( 
+                                                       oSettings.oInstance, oSettings, iColumn, iVisColumn
+                                               );
+                                               if ( aData.length === aoData.length )
+                                               {
+                                                       for ( j=0, jLen=aoData.length ; j<jLen ; j++ )
+                                                       {
+                                                               _fnSetCellData( oSettings, j, iColumn, aData[j] );
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       _fnLog( oSettings, 0, "Returned data sort array (col "+iColumn+") is the wrong length" );
+                                               }
+                                       }
+                               }
+                               
+                               /* Create a value - key array of the current row positions such that we can use their
+                                * current position during the sort, if values match, in order to perform stable sorting
+                                */
+                               for ( i=0, iLen=oSettings.aiDisplayMaster.length ; i<iLen ; i++ )
+                               {
+                                       aiOrig[ oSettings.aiDisplayMaster[i] ] = i;
+                               }
+               
+                               /* Build an internal data array which is specific to the sort, so we can get and prep
+                                * the data to be sorted only once, rather than needing to do it every time the sorting
+                                * function runs. This make the sorting function a very simple comparison
+                                */
+                               var iSortLen = aaSort.length;
+                               var fnSortFormat, aDataSort;
+                               for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+                               {
+                                       for ( j=0 ; j<iSortLen ; j++ )
+                                       {
+                                               aDataSort = aoColumns[ aaSort[j][0] ].aDataSort;
+               
+                                               for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
+                                               {
+                                                       sDataType = aoColumns[ aDataSort[k] ].sType;
+                                                       fnSortFormat = oSort[ (sDataType ? sDataType : 'string')+"-pre" ];
+                                                       
+                                                       aoData[i]._aSortData[ aDataSort[k] ] = fnSortFormat ?
+                                                               fnSortFormat( _fnGetCellData( oSettings, i, aDataSort[k], 'sort' ) ) :
+                                                               _fnGetCellData( oSettings, i, aDataSort[k], 'sort' );
+                                               }
+                                       }
+                               }
+                               
+                               /* Do the sort - here we want multi-column sorting based on a given data source (column)
+                                * and sorting function (from oSort) in a certain direction. It's reasonably complex to
+                                * follow on it's own, but this is what we want (example two column sorting):
+                                *  fnLocalSorting = function(a,b){
+                                *      var iTest;
+                                *      iTest = oSort['string-asc']('data11', 'data12');
+                                *      if (iTest !== 0)
+                                *              return iTest;
+                                *    iTest = oSort['numeric-desc']('data21', 'data22');
+                                *    if (iTest !== 0)
+                                *              return iTest;
+                                *      return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
+                                *  }
+                                * Basically we have a test for each sorting column, if the data in that column is equal,
+                                * test the next column. If all columns match, then we use a numeric sort on the row 
+                                * positions in the original data array to provide a stable sort.
+                                */
+                               oSettings.aiDisplayMaster.sort( function ( a, b ) {
+                                       var k, l, lLen, iTest, aDataSort, sDataType;
+                                       for ( k=0 ; k<iSortLen ; k++ )
+                                       {
+                                               aDataSort = aoColumns[ aaSort[k][0] ].aDataSort;
+               
+                                               for ( l=0, lLen=aDataSort.length ; l<lLen ; l++ )
+                                               {
+                                                       sDataType = aoColumns[ aDataSort[l] ].sType;
+                                                       
+                                                       iTest = oSort[ (sDataType ? sDataType : 'string')+"-"+aaSort[k][1] ](
+                                                               aoData[a]._aSortData[ aDataSort[l] ],
+                                                               aoData[b]._aSortData[ aDataSort[l] ]
+                                                       );
+                                               
+                                                       if ( iTest !== 0 )
+                                                       {
+                                                               return iTest;
+                                                       }
+                                               }
+                                       }
+                                       
+                                       return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
+                               } );
+                       }
+                       
+                       /* Alter the sorting classes to take account of the changes */
+                       if ( (bApplyClasses === undefined || bApplyClasses) && !oSettings.oFeatures.bDeferRender )
+                       {
+                               _fnSortingClasses( oSettings );
+                       }
+               
+                       for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                       {
+                               var sTitle = aoColumns[i].sTitle.replace( /<.*?>/g, "" );
+                               nTh = aoColumns[i].nTh;
+                               nTh.removeAttribute('aria-sort');
+                               nTh.removeAttribute('aria-label');
+                               
+                               /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
+                               if ( aoColumns[i].bSortable )
+                               {
+                                       if ( aaSort.length > 0 && aaSort[0][0] == i )
+                                       {
+                                               nTh.setAttribute('aria-sort', aaSort[0][1]=="asc" ? "ascending" : "descending" );
+                                               
+                                               var nextSort = (aoColumns[i].asSorting[ aaSort[0][2]+1 ]) ? 
+                                                       aoColumns[i].asSorting[ aaSort[0][2]+1 ] : aoColumns[i].asSorting[0];
+                                               nTh.setAttribute('aria-label', sTitle+
+                                                       (nextSort=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
+                                       }
+                                       else
+                                       {
+                                               nTh.setAttribute('aria-label', sTitle+
+                                                       (aoColumns[i].asSorting[0]=="asc" ? oAria.sSortAscending : oAria.sSortDescending) );
+                                       }
+                               }
+                               else
+                               {
+                                       nTh.setAttribute('aria-label', sTitle);
+                               }
+                       }
+                       
+                       /* Tell the draw function that we have sorted the data */
+                       oSettings.bSorted = true;
+                       $(oSettings.oInstance).trigger('sort', oSettings);
+                       
+                       /* Copy the master data into the draw array and re-draw */
+                       if ( oSettings.oFeatures.bFilter )
+                       {
+                               /* _fnFilter() will redraw the table for us */
+                               _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
+                       }
+                       else
+                       {
+                               oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+                               oSettings._iDisplayStart = 0; /* reset display back to page 0 */
+                               _fnCalculateEnd( oSettings );
+                               _fnDraw( oSettings );
+                       }
+               }
+               
+               
+               /**
+                * Attach a sort handler (click) to a node
+                *  @param {object} oSettings dataTables settings object
+                *  @param {node} nNode node to attach the handler to
+                *  @param {int} iDataIndex column sorting index
+                *  @param {function} [fnCallback] callback function
+                *  @memberof DataTable#oApi
+                */
+               function _fnSortAttachListener ( oSettings, nNode, iDataIndex, fnCallback )
+               {
+                       _fnBindAction( nNode, {}, function (e) {
+                               /* If the column is not sortable - don't to anything */
+                               if ( oSettings.aoColumns[iDataIndex].bSortable === false )
+                               {
+                                       return;
+                               }
+                               
+                               /*
+                                * This is a little bit odd I admit... I declare a temporary function inside the scope of
+                                * _fnBuildHead and the click handler in order that the code presented here can be used 
+                                * twice - once for when bProcessing is enabled, and another time for when it is 
+                                * disabled, as we need to perform slightly different actions.
+                                *   Basically the issue here is that the Javascript engine in modern browsers don't 
+                                * appear to allow the rendering engine to update the display while it is still executing
+                                * it's thread (well - it does but only after long intervals). This means that the 
+                                * 'processing' display doesn't appear for a table sort. To break the js thread up a bit
+                                * I force an execution break by using setTimeout - but this breaks the expected 
+                                * thread continuation for the end-developer's point of view (their code would execute
+                                * too early), so we only do it when we absolutely have to.
+                                */
+                               var fnInnerSorting = function () {
+                                       var iColumn, iNextSort;
+                                       
+                                       /* If the shift key is pressed then we are multiple column sorting */
+                                       if ( e.shiftKey )
+                                       {
+                                               /* Are we already doing some kind of sort on this column? */
+                                               var bFound = false;
+                                               for ( var i=0 ; i<oSettings.aaSorting.length ; i++ )
+                                               {
+                                                       if ( oSettings.aaSorting[i][0] == iDataIndex )
+                                                       {
+                                                               bFound = true;
+                                                               iColumn = oSettings.aaSorting[i][0];
+                                                               iNextSort = oSettings.aaSorting[i][2]+1;
+                                                               
+                                                               if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
+                                                               {
+                                                                       /* Reached the end of the sorting options, remove from multi-col sort */
+                                                                       oSettings.aaSorting.splice( i, 1 );
+                                                               }
+                                                               else
+                                                               {
+                                                                       /* Move onto next sorting direction */
+                                                                       oSettings.aaSorting[i][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
+                                                                       oSettings.aaSorting[i][2] = iNextSort;
+                                                               }
+                                                               break;
+                                                       }
+                                               }
+                                               
+                                               /* No sort yet - add it in */
+                                               if ( bFound === false )
+                                               {
+                                                       oSettings.aaSorting.push( [ iDataIndex, 
+                                                               oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* If no shift key then single column sort */
+                                               if ( oSettings.aaSorting.length == 1 && oSettings.aaSorting[0][0] == iDataIndex )
+                                               {
+                                                       iColumn = oSettings.aaSorting[0][0];
+                                                       iNextSort = oSettings.aaSorting[0][2]+1;
+                                                       if ( !oSettings.aoColumns[iColumn].asSorting[iNextSort] )
+                                                       {
+                                                               iNextSort = 0;
+                                                       }
+                                                       oSettings.aaSorting[0][1] = oSettings.aoColumns[iColumn].asSorting[iNextSort];
+                                                       oSettings.aaSorting[0][2] = iNextSort;
+                                               }
+                                               else
+                                               {
+                                                       oSettings.aaSorting.splice( 0, oSettings.aaSorting.length );
+                                                       oSettings.aaSorting.push( [ iDataIndex, 
+                                                               oSettings.aoColumns[iDataIndex].asSorting[0], 0 ] );
+                                               }
+                                       }
+                                       
+                                       /* Run the sort */
+                                       _fnSort( oSettings );
+                               }; /* /fnInnerSorting */
+                               
+                               if ( !oSettings.oFeatures.bProcessing )
+                               {
+                                       fnInnerSorting();
+                               }
+                               else
+                               {
+                                       _fnProcessingDisplay( oSettings, true );
+                                       setTimeout( function() {
+                                               fnInnerSorting();
+                                               if ( !oSettings.oFeatures.bServerSide )
+                                               {
+                                                       _fnProcessingDisplay( oSettings, false );
+                                               }
+                                       }, 0 );
+                               }
+                               
+                               /* Call the user specified callback function - used for async user interaction */
+                               if ( typeof fnCallback == 'function' )
+                               {
+                                       fnCallback( oSettings );
+                               }
+                       } );
+               }
+               
+               
+               /**
+                * Set the sorting classes on the header, Note: it is safe to call this function 
+                * when bSort and bSortClasses are false
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnSortingClasses( oSettings )
+               {
+                       var i, iLen, j, jLen, iFound;
+                       var aaSort, sClass;
+                       var iColumns = oSettings.aoColumns.length;
+                       var oClasses = oSettings.oClasses;
+                       
+                       for ( i=0 ; i<iColumns ; i++ )
+                       {
+                               if ( oSettings.aoColumns[i].bSortable )
+                               {
+                                       $(oSettings.aoColumns[i].nTh).removeClass( oClasses.sSortAsc +" "+ oClasses.sSortDesc +
+                                               " "+ oSettings.aoColumns[i].sSortingClass );
+                               }
+                       }
+                       
+                       if ( oSettings.aaSortingFixed !== null )
+                       {
+                               aaSort = oSettings.aaSortingFixed.concat( oSettings.aaSorting );
+                       }
+                       else
+                       {
+                               aaSort = oSettings.aaSorting.slice();
+                       }
+                       
+                       /* Apply the required classes to the header */
+                       for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+                       {
+                               if ( oSettings.aoColumns[i].bSortable )
+                               {
+                                       sClass = oSettings.aoColumns[i].sSortingClass;
+                                       iFound = -1;
+                                       for ( j=0 ; j<aaSort.length ; j++ )
+                                       {
+                                               if ( aaSort[j][0] == i )
+                                               {
+                                                       sClass = ( aaSort[j][1] == "asc" ) ?
+                                                               oClasses.sSortAsc : oClasses.sSortDesc;
+                                                       iFound = j;
+                                                       break;
+                                               }
+                                       }
+                                       $(oSettings.aoColumns[i].nTh).addClass( sClass );
+                                       
+                                       if ( oSettings.bJUI )
+                                       {
+                                               /* jQuery UI uses extra markup */
+                                               var jqSpan = $("span."+oClasses.sSortIcon,  oSettings.aoColumns[i].nTh);
+                                               jqSpan.removeClass(oClasses.sSortJUIAsc +" "+ oClasses.sSortJUIDesc +" "+ 
+                                                       oClasses.sSortJUI +" "+ oClasses.sSortJUIAscAllowed +" "+ oClasses.sSortJUIDescAllowed );
+                                               
+                                               var sSpanClass;
+                                               if ( iFound == -1 )
+                                               {
+                                                       sSpanClass = oSettings.aoColumns[i].sSortingClassJUI;
+                                               }
+                                               else if ( aaSort[iFound][1] == "asc" )
+                                               {
+                                                       sSpanClass = oClasses.sSortJUIAsc;
+                                               }
+                                               else
+                                               {
+                                                       sSpanClass = oClasses.sSortJUIDesc;
+                                               }
+                                               
+                                               jqSpan.addClass( sSpanClass );
+                                       }
+                               }
+                               else
+                               {
+                                       /* No sorting on this column, so add the base class. This will have been assigned by
+                                        * _fnAddColumn
+                                        */
+                                       $(oSettings.aoColumns[i].nTh).addClass( oSettings.aoColumns[i].sSortingClass );
+                               }
+                       }
+                       
+                       /* 
+                        * Apply the required classes to the table body
+                        * Note that this is given as a feature switch since it can significantly slow down a sort
+                        * on large data sets (adding and removing of classes is always slow at the best of times..)
+                        * Further to this, note that this code is admittedly fairly ugly. It could be made a lot 
+                        * simpler using jQuery selectors and add/removeClass, but that is significantly slower
+                        * (on the order of 5 times slower) - hence the direct DOM manipulation here.
+                        * Note that for deferred drawing we do use jQuery - the reason being that taking the first
+                        * row found to see if the whole column needs processed can miss classes since the first
+                        * column might be new.
+                        */
+                       sClass = oClasses.sSortColumn;
+                       
+                       if ( oSettings.oFeatures.bSort && oSettings.oFeatures.bSortClasses )
+                       {
+                               var nTds = _fnGetTdNodes( oSettings );
+                               
+                               /* Determine what the sorting class for each column should be */
+                               var iClass, iTargetCol;
+                               var asClasses = [];
+                               for (i = 0; i < iColumns; i++)
+                               {
+                                       asClasses.push("");
+                               }
+                               for (i = 0, iClass = 1; i < aaSort.length; i++)
+                               {
+                                       iTargetCol = parseInt( aaSort[i][0], 10 );
+                                       asClasses[iTargetCol] = sClass + iClass;
+                                       
+                                       if ( iClass < 3 )
+                                       {
+                                               iClass++;
+                                       }
+                               }
+                               
+                               /* Make changes to the classes for each cell as needed */
+                               var reClass = new RegExp(sClass + "[123]");
+                               var sTmpClass, sCurrentClass, sNewClass;
+                               for ( i=0, iLen=nTds.length; i<iLen; i++ )
+                               {
+                                       /* Determine which column we're looking at */
+                                       iTargetCol = i % iColumns;
+                                       
+                                       /* What is the full list of classes now */
+                                       sCurrentClass = nTds[i].className;
+                                       /* What sorting class should be applied? */
+                                       sNewClass = asClasses[iTargetCol];
+                                       /* What would the new full list be if we did a replacement? */
+                                       sTmpClass = sCurrentClass.replace(reClass, sNewClass);
+                                       
+                                       if ( sTmpClass != sCurrentClass )
+                                       {
+                                               /* We changed something */
+                                               nTds[i].className = $.trim( sTmpClass );
+                                       }
+                                       else if ( sNewClass.length > 0 && sCurrentClass.indexOf(sNewClass) == -1 )
+                                       {
+                                               /* We need to add a class */
+                                               nTds[i].className = sCurrentClass + " " + sNewClass;
+                                       }
+                               }
+                       }
+               }
+               
+               
+               
+               /**
+                * Save the state of a table in a cookie such that the page can be reloaded
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnSaveState ( oSettings )
+               {
+                       if ( !oSettings.oFeatures.bStateSave || oSettings.bDestroying )
+                       {
+                               return;
+                       }
+               
+                       /* Store the interesting variables */
+                       var i, iLen, bInfinite=oSettings.oScroll.bInfinite;
+                       var oState = {
+                               "iCreate":      new Date().getTime(),
+                               "iStart":       (bInfinite ? 0 : oSettings._iDisplayStart),
+                               "iEnd":         (bInfinite ? oSettings._iDisplayLength : oSettings._iDisplayEnd),
+                               "iLength":      oSettings._iDisplayLength,
+                               "aaSorting":    $.extend( true, [], oSettings.aaSorting ),
+                               "oSearch":      $.extend( true, {}, oSettings.oPreviousSearch ),
+                               "aoSearchCols": $.extend( true, [], oSettings.aoPreSearchCols ),
+                               "abVisCols":    []
+                       };
+               
+                       for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                       {
+                               oState.abVisCols.push( oSettings.aoColumns[i].bVisible );
+                       }
+               
+                       _fnCallbackFire( oSettings, "aoStateSaveParams", 'stateSaveParams', [oSettings, oState] );
+                       
+                       oSettings.fnStateSave.call( oSettings.oInstance, oSettings, oState );
+               }
+               
+               
+               /**
+                * Attempt to load a saved table state from a cookie
+                *  @param {object} oSettings dataTables settings object
+                *  @param {object} oInit DataTables init object so we can override settings
+                *  @memberof DataTable#oApi
+                */
+               function _fnLoadState ( oSettings, oInit )
+               {
+                       if ( !oSettings.oFeatures.bStateSave )
+                       {
+                               return;
+                       }
+               
+                       var oData = oSettings.fnStateLoad.call( oSettings.oInstance, oSettings );
+                       if ( !oData )
+                       {
+                               return;
+                       }
+                       
+                       /* Allow custom and plug-in manipulation functions to alter the saved data set and
+                        * cancelling of loading by returning false
+                        */
+                       var abStateLoad = _fnCallbackFire( oSettings, 'aoStateLoadParams', 'stateLoadParams', [oSettings, oData] );
+                       if ( $.inArray( false, abStateLoad ) !== -1 )
+                       {
+                               return;
+                       }
+                       
+                       /* Store the saved state so it might be accessed at any time */
+                       oSettings.oLoadedState = $.extend( true, {}, oData );
+                       
+                       /* Restore key features */
+                       oSettings._iDisplayStart    = oData.iStart;
+                       oSettings.iInitDisplayStart = oData.iStart;
+                       oSettings._iDisplayEnd      = oData.iEnd;
+                       oSettings._iDisplayLength   = oData.iLength;
+                       oSettings.aaSorting         = oData.aaSorting.slice();
+                       oSettings.saved_aaSorting   = oData.aaSorting.slice();
+                       
+                       /* Search filtering  */
+                       $.extend( oSettings.oPreviousSearch, oData.oSearch );
+                       $.extend( true, oSettings.aoPreSearchCols, oData.aoSearchCols );
+                       
+                       /* Column visibility state
+                        * Pass back visibility settings to the init handler, but to do not here override
+                        * the init object that the user might have passed in
+                        */
+                       oInit.saved_aoColumns = [];
+                       for ( var i=0 ; i<oData.abVisCols.length ; i++ )
+                       {
+                               oInit.saved_aoColumns[i] = {};
+                               oInit.saved_aoColumns[i].bVisible = oData.abVisCols[i];
+                       }
+               
+                       _fnCallbackFire( oSettings, 'aoStateLoaded', 'stateLoaded', [oSettings, oData] );
+               }
+               
+               
+               /**
+                * Create a new cookie with a value to store the state of a table
+                *  @param {string} sName name of the cookie to create
+                *  @param {string} sValue the value the cookie should take
+                *  @param {int} iSecs duration of the cookie
+                *  @param {string} sBaseName sName is made up of the base + file name - this is the base
+                *  @param {function} fnCallback User definable function to modify the cookie
+                *  @memberof DataTable#oApi
+                */
+               function _fnCreateCookie ( sName, sValue, iSecs, sBaseName, fnCallback )
+               {
+                       var date = new Date();
+                       date.setTime( date.getTime()+(iSecs*1000) );
+                       
+                       /* 
+                        * Shocking but true - it would appear IE has major issues with having the path not having
+                        * a trailing slash on it. We need the cookie to be available based on the path, so we
+                        * have to append the file name to the cookie name. Appalling. Thanks to vex for adding the
+                        * patch to use at least some of the path
+                        */
+                       var aParts = window.location.pathname.split('/');
+                       var sNameFile = sName + '_' + aParts.pop().replace(/[\/:]/g,"").toLowerCase();
+                       var sFullCookie, oData;
+                       
+                       if ( fnCallback !== null )
+                       {
+                               oData = (typeof $.parseJSON === 'function') ? 
+                                       $.parseJSON( sValue ) : eval( '('+sValue+')' );
+                               sFullCookie = fnCallback( sNameFile, oData, date.toGMTString(),
+                                       aParts.join('/')+"/" );
+                       }
+                       else
+                       {
+                               sFullCookie = sNameFile + "=" + encodeURIComponent(sValue) +
+                                       "; expires=" + date.toGMTString() +"; path=" + aParts.join('/')+"/";
+                       }
+                       
+                       /* Are we going to go over the cookie limit of 4KiB? If so, try to delete a cookies
+                        * belonging to DataTables.
+                        */
+                       var
+                               aCookies =document.cookie.split(';'),
+                               iNewCookieLen = sFullCookie.split(';')[0].length,
+                               aOldCookies = [];
+                       
+                       if ( iNewCookieLen+document.cookie.length+10 > 4096 ) /* Magic 10 for padding */
+                       {
+                               for ( var i=0, iLen=aCookies.length ; i<iLen ; i++ )
+                               {
+                                       if ( aCookies[i].indexOf( sBaseName ) != -1 )
+                                       {
+                                               /* It's a DataTables cookie, so eval it and check the time stamp */
+                                               var aSplitCookie = aCookies[i].split('=');
+                                               try {
+                                                       oData = eval( '('+decodeURIComponent(aSplitCookie[1])+')' );
+               
+                                                       if ( oData && oData.iCreate )
+                                                       {
+                                                               aOldCookies.push( {
+                                                                       "name": aSplitCookie[0],
+                                                                       "time": oData.iCreate
+                                                               } );
+                                                       }
+                                               }
+                                               catch( e ) {}
+                                       }
+                               }
+               
+                               // Make sure we delete the oldest ones first
+                               aOldCookies.sort( function (a, b) {
+                                       return b.time - a.time;
+                               } );
+               
+                               // Eliminate as many old DataTables cookies as we need to
+                               while ( iNewCookieLen + document.cookie.length + 10 > 4096 ) {
+                                       if ( aOldCookies.length === 0 ) {
+                                               // Deleted all DT cookies and still not enough space. Can't state save
+                                               return;
+                                       }
+                                       
+                                       var old = aOldCookies.pop();
+                                       document.cookie = old.name+"=; expires=Thu, 01-Jan-1970 00:00:01 GMT; path="+
+                                               aParts.join('/') + "/";
+                               }
+                       }
+                       
+                       document.cookie = sFullCookie;
+               }
+               
+               
+               /**
+                * Read an old cookie to get a cookie with an old table state
+                *  @param {string} sName name of the cookie to read
+                *  @returns {string} contents of the cookie - or null if no cookie with that name found
+                *  @memberof DataTable#oApi
+                */
+               function _fnReadCookie ( sName )
+               {
+                       var
+                               aParts = window.location.pathname.split('/'),
+                               sNameEQ = sName + '_' + aParts[aParts.length-1].replace(/[\/:]/g,"").toLowerCase() + '=',
+                               sCookieContents = document.cookie.split(';');
+                       
+                       for( var i=0 ; i<sCookieContents.length ; i++ )
+                       {
+                               var c = sCookieContents[i];
+                               
+                               while (c.charAt(0)==' ')
+                               {
+                                       c = c.substring(1,c.length);
+                               }
+                               
+                               if (c.indexOf(sNameEQ) === 0)
+                               {
+                                       return decodeURIComponent( c.substring(sNameEQ.length,c.length) );
+                               }
+                       }
+                       return null;
+               }
+               
+               
+               /**
+                * Return the settings object for a particular table
+                *  @param {node} nTable table we are using as a dataTable
+                *  @returns {object} Settings object - or null if not found
+                *  @memberof DataTable#oApi
+                */
+               function _fnSettingsFromNode ( nTable )
+               {
+                       for ( var i=0 ; i<DataTable.settings.length ; i++ )
+                       {
+                               if ( DataTable.settings[i].nTable === nTable )
+                               {
+                                       return DataTable.settings[i];
+                               }
+                       }
+                       
+                       return null;
+               }
+               
+               
+               /**
+                * Return an array with the TR nodes for the table
+                *  @param {object} oSettings dataTables settings object
+                *  @returns {array} TR array
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetTrNodes ( oSettings )
+               {
+                       var aNodes = [];
+                       var aoData = oSettings.aoData;
+                       for ( var i=0, iLen=aoData.length ; i<iLen ; i++ )
+                       {
+                               if ( aoData[i].nTr !== null )
+                               {
+                                       aNodes.push( aoData[i].nTr );
+                               }
+                       }
+                       return aNodes;
+               }
+               
+               
+               /**
+                * Return an flat array with all TD nodes for the table, or row
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} [iIndividualRow] aoData index to get the nodes for - optional 
+                *    if not given then the return array will contain all nodes for the table
+                *  @returns {array} TD array
+                *  @memberof DataTable#oApi
+                */
+               function _fnGetTdNodes ( oSettings, iIndividualRow )
+               {
+                       var anReturn = [];
+                       var iCorrector;
+                       var anTds, nTd;
+                       var iRow, iRows=oSettings.aoData.length,
+                               iColumn, iColumns, oData, sNodeName, iStart=0, iEnd=iRows;
+                       
+                       /* Allow the collection to be limited to just one row */
+                       if ( iIndividualRow !== undefined )
+                       {
+                               iStart = iIndividualRow;
+                               iEnd = iIndividualRow+1;
+                       }
+               
+                       for ( iRow=iStart ; iRow<iEnd ; iRow++ )
+                       {
+                               oData = oSettings.aoData[iRow];
+                               if ( oData.nTr !== null )
+                               {
+                                       /* get the TD child nodes - taking into account text etc nodes */
+                                       anTds = [];
+                                       nTd = oData.nTr.firstChild;
+                                       while ( nTd )
+                                       {
+                                               sNodeName = nTd.nodeName.toLowerCase();
+                                               if ( sNodeName == 'td' || sNodeName == 'th' )
+                                               {
+                                                       anTds.push( nTd );
+                                               }
+                                               nTd = nTd.nextSibling;
+                                       }
+               
+                                       iCorrector = 0;
+                                       for ( iColumn=0, iColumns=oSettings.aoColumns.length ; iColumn<iColumns ; iColumn++ )
+                                       {
+                                               if ( oSettings.aoColumns[iColumn].bVisible )
+                                               {
+                                                       anReturn.push( anTds[iColumn-iCorrector] );
+                                               }
+                                               else
+                                               {
+                                                       anReturn.push( oData._anHidden[iColumn] );
+                                                       iCorrector++;
+                                               }
+                                       }
+                               }
+                       }
+               
+                       return anReturn;
+               }
+               
+               
+               /**
+                * Log an error message
+                *  @param {object} oSettings dataTables settings object
+                *  @param {int} iLevel log error messages, or display them to the user
+                *  @param {string} sMesg error message
+                *  @memberof DataTable#oApi
+                */
+               function _fnLog( oSettings, iLevel, sMesg )
+               {
+                       var sAlert = (oSettings===null) ?
+                               "DataTables warning: "+sMesg :
+                               "DataTables warning (table id = '"+oSettings.sTableId+"'): "+sMesg;
+                       
+                       if ( iLevel === 0 )
+                       {
+                               if ( DataTable.ext.sErrMode == 'alert' )
+                               {
+                                       alert( sAlert );
+                               }
+                               else
+                               {
+                                       throw new Error(sAlert);
+                               }
+                               return;
+                       }
+                       else if ( window.console && console.log )
+                       {
+                               console.log( sAlert );
+                       }
+               }
+               
+               
+               /**
+                * See if a property is defined on one object, if so assign it to the other object
+                *  @param {object} oRet target object
+                *  @param {object} oSrc source object
+                *  @param {string} sName property
+                *  @param {string} [sMappedName] name to map too - optional, sName used if not given
+                *  @memberof DataTable#oApi
+                */
+               function _fnMap( oRet, oSrc, sName, sMappedName )
+               {
+                       if ( sMappedName === undefined )
+                       {
+                               sMappedName = sName;
+                       }
+                       if ( oSrc[sName] !== undefined )
+                       {
+                               oRet[sMappedName] = oSrc[sName];
+                       }
+               }
+               
+               
+               /**
+                * Extend objects - very similar to jQuery.extend, but deep copy objects, and shallow
+                * copy arrays. The reason we need to do this, is that we don't want to deep copy array
+                * init values (such as aaSorting) since the dev wouldn't be able to override them, but
+                * we do want to deep copy arrays.
+                *  @param {object} oOut Object to extend
+                *  @param {object} oExtender Object from which the properties will be applied to oOut
+                *  @returns {object} oOut Reference, just for convenience - oOut === the return.
+                *  @memberof DataTable#oApi
+                *  @todo This doesn't take account of arrays inside the deep copied objects.
+                */
+               function _fnExtend( oOut, oExtender )
+               {
+                       var val;
+                       
+                       for ( var prop in oExtender )
+                       {
+                               if ( oExtender.hasOwnProperty(prop) )
+                               {
+                                       val = oExtender[prop];
+               
+                                       if ( typeof oInit[prop] === 'object' && val !== null && $.isArray(val) === false )
+                                       {
+                                               $.extend( true, oOut[prop], val );
+                                       }
+                                       else
+                                       {
+                                               oOut[prop] = val;
+                                       }
+                               }
+                       }
+               
+                       return oOut;
+               }
+               
+               
+               /**
+                * Bind an event handers to allow a click or return key to activate the callback.
+                * This is good for accessibility since a return on the keyboard will have the
+                * same effect as a click, if the element has focus.
+                *  @param {element} n Element to bind the action to
+                *  @param {object} oData Data object to pass to the triggered function
+                *  @param {function} fn Callback function for when the event is triggered
+                *  @memberof DataTable#oApi
+                */
+               function _fnBindAction( n, oData, fn )
+               {
+                       $(n)
+                               .bind( 'click.DT', oData, function (e) {
+                                               n.blur(); // Remove focus outline for mouse users
+                                               fn(e);
+                                       } )
+                               .bind( 'keypress.DT', oData, function (e){
+                                       if ( e.which === 13 ) {
+                                               fn(e);
+                                       } } )
+                               .bind( 'selectstart.DT', function () {
+                                       /* Take the brutal approach to cancelling text selection */
+                                       return false;
+                                       } );
+               }
+               
+               
+               /**
+                * Register a callback function. Easily allows a callback function to be added to
+                * an array store of callback functions that can then all be called together.
+                *  @param {object} oSettings dataTables settings object
+                *  @param {string} sStore Name of the array storage for the callbacks in oSettings
+                *  @param {function} fn Function to be called back
+                *  @param {string} sName Identifying name for the callback (i.e. a label)
+                *  @memberof DataTable#oApi
+                */
+               function _fnCallbackReg( oSettings, sStore, fn, sName )
+               {
+                       if ( fn )
+                       {
+                               oSettings[sStore].push( {
+                                       "fn": fn,
+                                       "sName": sName
+                               } );
+                       }
+               }
+               
+               
+               /**
+                * Fire callback functions and trigger events. Note that the loop over the callback
+                * array store is done backwards! Further note that you do not want to fire off triggers
+                * in time sensitive applications (for example cell creation) as its slow.
+                *  @param {object} oSettings dataTables settings object
+                *  @param {string} sStore Name of the array storage for the callbacks in oSettings
+                *  @param {string} sTrigger Name of the jQuery custom event to trigger. If null no trigger
+                *    is fired
+                *  @param {array} aArgs Array of arguments to pass to the callback function / trigger
+                *  @memberof DataTable#oApi
+                */
+               function _fnCallbackFire( oSettings, sStore, sTrigger, aArgs )
+               {
+                       var aoStore = oSettings[sStore];
+                       var aRet =[];
+               
+                       for ( var i=aoStore.length-1 ; i>=0 ; i-- )
+                       {
+                               aRet.push( aoStore[i].fn.apply( oSettings.oInstance, aArgs ) );
+                       }
+               
+                       if ( sTrigger !== null )
+                       {
+                               $(oSettings.oInstance).trigger(sTrigger, aArgs);
+                       }
+               
+                       return aRet;
+               }
+               
+               
+               /**
+                * JSON stringify. If JSON.stringify it provided by the browser, json2.js or any other
+                * library, then we use that as it is fast, safe and accurate. If the function isn't 
+                * available then we need to built it ourselves - the inspiration for this function comes
+                * from Craig Buckler ( http://www.sitepoint.com/javascript-json-serialization/ ). It is
+                * not perfect and absolutely should not be used as a replacement to json2.js - but it does
+                * do what we need, without requiring a dependency for DataTables.
+                *  @param {object} o JSON object to be converted
+                *  @returns {string} JSON string
+                *  @memberof DataTable#oApi
+                */
+               var _fnJsonString = (window.JSON) ? JSON.stringify : function( o )
+               {
+                       /* Not an object or array */
+                       var sType = typeof o;
+                       if (sType !== "object" || o === null)
+                       {
+                               // simple data type
+                               if (sType === "string")
+                               {
+                                       o = '"'+o+'"';
+                               }
+                               return o+"";
+                       }
+               
+                       /* If object or array, need to recurse over it */
+                       var
+                               sProp, mValue,
+                               json = [],
+                               bArr = $.isArray(o);
+                       
+                       for (sProp in o)
+                       {
+                               mValue = o[sProp];
+                               sType = typeof mValue;
+               
+                               if (sType === "string")
+                               {
+                                       mValue = '"'+mValue+'"';
+                               }
+                               else if (sType === "object" && mValue !== null)
+                               {
+                                       mValue = _fnJsonString(mValue);
+                               }
+               
+                               json.push((bArr ? "" : '"'+sProp+'":') + mValue);
+                       }
+               
+                       return (bArr ? "[" : "{") + json + (bArr ? "]" : "}");
+               };
+               
+               
+               /**
+                * From some browsers (specifically IE6/7) we need special handling to work around browser
+                * bugs - this function is used to detect when these workarounds are needed.
+                *  @param {object} oSettings dataTables settings object
+                *  @memberof DataTable#oApi
+                */
+               function _fnBrowserDetect( oSettings )
+               {
+                       /* IE6/7 will oversize a width 100% element inside a scrolling element, to include the
+                        * width of the scrollbar, while other browsers ensure the inner element is contained
+                        * without forcing scrolling
+                        */
+                       var n = $(
+                               '<div style="position:absolute; top:0; left:0; height:1px; width:1px; overflow:hidden">'+
+                                       '<div style="position:absolute; top:1px; left:1px; width:100px; overflow:scroll;">'+
+                                               '<div id="DT_BrowserTest" style="width:100%; height:10px;"></div>'+
+                                       '</div>'+
+                               '</div>')[0];
+               
+                       document.body.appendChild( n );
+                       oSettings.oBrowser.bScrollOversize = $('#DT_BrowserTest', n)[0].offsetWidth === 100 ? true : false;
+                       document.body.removeChild( n );
+               }
+               
+
+               /**
+                * Perform a jQuery selector action on the table's TR elements (from the tbody) and
+                * return the resulting jQuery object.
+                *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+                *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
+                *  @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
+                *    criterion ("applied") or all TR elements (i.e. no filter).
+                *  @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
+                *    Can be either 'current', whereby the current sorting of the table is used, or
+                *    'original' whereby the original order the data was read into the table is used.
+                *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+                *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
+                *    'current' and filter is 'applied', regardless of what they might be given as.
+                *  @returns {object} jQuery object, filtered by the given selector.
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *
+                *      // Highlight every second row
+                *      oTable.$('tr:odd').css('backgroundColor', 'blue');
+                *    } );
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *
+                *      // Filter to rows with 'Webkit' in them, add a background colour and then
+                *      // remove the filter, thus highlighting the 'Webkit' rows only.
+                *      oTable.fnFilter('Webkit');
+                *      oTable.$('tr', {"filter": "applied"}).css('backgroundColor', 'blue');
+                *      oTable.fnFilter('');
+                *    } );
+                */
+               this.$ = function ( sSelector, oOpts )
+               {
+                       var i, iLen, a = [], tr;
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       var aoData = oSettings.aoData;
+                       var aiDisplay = oSettings.aiDisplay;
+                       var aiDisplayMaster = oSettings.aiDisplayMaster;
+               
+                       if ( !oOpts )
+                       {
+                               oOpts = {};
+                       }
+               
+                       oOpts = $.extend( {}, {
+                               "filter": "none", // applied
+                               "order": "current", // "original"
+                               "page": "all" // current
+                       }, oOpts );
+               
+                       // Current page implies that order=current and fitler=applied, since it is fairly
+                       // senseless otherwise
+                       if ( oOpts.page == 'current' )
+                       {
+                               for ( i=oSettings._iDisplayStart, iLen=oSettings.fnDisplayEnd() ; i<iLen ; i++ )
+                               {
+                                       tr = aoData[ aiDisplay[i] ].nTr;
+                                       if ( tr )
+                                       {
+                                               a.push( tr );
+                                       }
+                               }
+                       }
+                       else if ( oOpts.order == "current" && oOpts.filter == "none" )
+                       {
+                               for ( i=0, iLen=aiDisplayMaster.length ; i<iLen ; i++ )
+                               {
+                                       tr = aoData[ aiDisplayMaster[i] ].nTr;
+                                       if ( tr )
+                                       {
+                                               a.push( tr );
+                                       }
+                               }
+                       }
+                       else if ( oOpts.order == "current" && oOpts.filter == "applied" )
+                       {
+                               for ( i=0, iLen=aiDisplay.length ; i<iLen ; i++ )
+                               {
+                                       tr = aoData[ aiDisplay[i] ].nTr;
+                                       if ( tr )
+                                       {
+                                               a.push( tr );
+                                       }
+                               }
+                       }
+                       else if ( oOpts.order == "original" && oOpts.filter == "none" )
+                       {
+                               for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+                               {
+                                       tr = aoData[ i ].nTr ;
+                                       if ( tr )
+                                       {
+                                               a.push( tr );
+                                       }
+                               }
+                       }
+                       else if ( oOpts.order == "original" && oOpts.filter == "applied" )
+                       {
+                               for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+                               {
+                                       tr = aoData[ i ].nTr;
+                                       if ( $.inArray( i, aiDisplay ) !== -1 && tr )
+                                       {
+                                               a.push( tr );
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               _fnLog( oSettings, 1, "Unknown selection options" );
+                       }
+               
+                       /* We need to filter on the TR elements and also 'find' in their descendants
+                        * to make the selector act like it would in a full table - so we need
+                        * to build both results and then combine them together
+                        */
+                       var jqA = $(a);
+                       var jqTRs = jqA.filter( sSelector );
+                       var jqDescendants = jqA.find( sSelector );
+               
+                       return $( [].concat($.makeArray(jqTRs), $.makeArray(jqDescendants)) );
+               };
+               
+               
+               /**
+                * Almost identical to $ in operation, but in this case returns the data for the matched
+                * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
+                * rather than any descendants, so the data can be obtained for the row/cell. If matching
+                * rows are found, the data returned is the original data array/object that was used to  
+                * create the row (or a generated array if from a DOM source).
+                *
+                * This method is often useful in-combination with $ where both functions are given the
+                * same parameters and the array indexes will match identically.
+                *  @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+                *  @param {object} [oOpts] Optional parameters for modifying the rows to be included
+                *  @param {string} [oOpts.filter=none] Select elements that meet the current filter
+                *    criterion ("applied") or all elements (i.e. no filter).
+                *  @param {string} [oOpts.order=current] Order of the data in the processed array.
+                *    Can be either 'current', whereby the current sorting of the table is used, or
+                *    'original' whereby the original order the data was read into the table is used.
+                *  @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+                *    ("current") or not ("all"). If 'current' is given, then order is assumed to be 
+                *    'current' and filter is 'applied', regardless of what they might be given as.
+                *  @returns {array} Data for the matched elements. If any elements, as a result of the
+                *    selector, were not TR, TD or TH elements in the DataTable, they will have a null 
+                *    entry in the array.
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *
+                *      // Get the data from the first row in the table
+                *      var data = oTable._('tr:first');
+                *
+                *      // Do something useful with the data
+                *      alert( "First cell is: "+data[0] );
+                *    } );
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *
+                *      // Filter to 'Webkit' and get all data for 
+                *      oTable.fnFilter('Webkit');
+                *      var data = oTable._('tr', {"filter": "applied"});
+                *      
+                *      // Do something with the data
+                *      alert( data.length+" rows matched the filter" );
+                *    } );
+                */
+               this._ = function ( sSelector, oOpts )
+               {
+                       var aOut = [];
+                       var i, iLen, iIndex;
+                       var aTrs = this.$( sSelector, oOpts );
+               
+                       for ( i=0, iLen=aTrs.length ; i<iLen ; i++ )
+                       {
+                               aOut.push( this.fnGetData(aTrs[i]) );
+                       }
+               
+                       return aOut;
+               };
+               
+               
+               /**
+                * Add a single new row or multiple rows of data to the table. Please note
+                * that this is suitable for client-side processing only - if you are using 
+                * server-side processing (i.e. "bServerSide": true), then to add data, you
+                * must add it to the data source, i.e. the server-side, through an Ajax call.
+                *  @param {array|object} mData The data to be added to the table. This can be:
+                *    <ul>
+                *      <li>1D array of data - add a single row with the data provided</li>
+                *      <li>2D array of arrays - add multiple rows in a single call</li>
+                *      <li>object - data object when using <i>mData</i></li>
+                *      <li>array of objects - multiple data objects when using <i>mData</i></li>
+                *    </ul>
+                *  @param {bool} [bRedraw=true] redraw the table or not
+                *  @returns {array} An array of integers, representing the list of indexes in 
+                *    <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to 
+                *    the table.
+                *  @dtopt API
+                *
+                *  @example
+                *    // Global var for counter
+                *    var giCount = 2;
+                *    
+                *    $(document).ready(function() {
+                *      $('#example').dataTable();
+                *    } );
+                *    
+                *    function fnClickAddRow() {
+                *      $('#example').dataTable().fnAddData( [
+                *        giCount+".1",
+                *        giCount+".2",
+                *        giCount+".3",
+                *        giCount+".4" ]
+                *      );
+                *        
+                *      giCount++;
+                *    }
+                */
+               this.fnAddData = function( mData, bRedraw )
+               {
+                       if ( mData.length === 0 )
+                       {
+                               return [];
+                       }
+                       
+                       var aiReturn = [];
+                       var iTest;
+                       
+                       /* Find settings from table node */
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       
+                       /* Check if we want to add multiple rows or not */
+                       if ( typeof mData[0] === "object" && mData[0] !== null )
+                       {
+                               for ( var i=0 ; i<mData.length ; i++ )
+                               {
+                                       iTest = _fnAddData( oSettings, mData[i] );
+                                       if ( iTest == -1 )
+                                       {
+                                               return aiReturn;
+                                       }
+                                       aiReturn.push( iTest );
+                               }
+                       }
+                       else
+                       {
+                               iTest = _fnAddData( oSettings, mData );
+                               if ( iTest == -1 )
+                               {
+                                       return aiReturn;
+                               }
+                               aiReturn.push( iTest );
+                       }
+                       
+                       oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+                       
+                       if ( bRedraw === undefined || bRedraw )
+                       {
+                               _fnReDraw( oSettings );
+                       }
+                       return aiReturn;
+               };
+               
+               
+               /**
+                * This function will make DataTables recalculate the column sizes, based on the data 
+                * contained in the table and the sizes applied to the columns (in the DOM, CSS or 
+                * through the sWidth parameter). This can be useful when the width of the table's 
+                * parent element changes (for example a window resize).
+                *  @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable( {
+                *        "sScrollY": "200px",
+                *        "bPaginate": false
+                *      } );
+                *      
+                *      $(window).bind('resize', function () {
+                *        oTable.fnAdjustColumnSizing();
+                *      } );
+                *    } );
+                */
+               this.fnAdjustColumnSizing = function ( bRedraw )
+               {
+                       var oSettings = _fnSettingsFromNode(this[DataTable.ext.iApiIndex]);
+                       _fnAdjustColumnSizing( oSettings );
+                       
+                       if ( bRedraw === undefined || bRedraw )
+                       {
+                               this.fnDraw( false );
+                       }
+                       else if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
+                       {
+                               /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
+                               this.oApi._fnScrollDraw(oSettings);
+                       }
+               };
+               
+               
+               /**
+                * Quickly and simply clear a table
+                *  @param {bool} [bRedraw=true] redraw the table or not
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      
+                *      // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
+                *      oTable.fnClearTable();
+                *    } );
+                */
+               this.fnClearTable = function( bRedraw )
+               {
+                       /* Find settings from table node */
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       _fnClearTable( oSettings );
+                       
+                       if ( bRedraw === undefined || bRedraw )
+                       {
+                               _fnDraw( oSettings );
+                       }
+               };
+               
+               
+               /**
+                * The exact opposite of 'opening' a row, this function will close any rows which 
+                * are currently 'open'.
+                *  @param {node} nTr the table row to 'close'
+                *  @returns {int} 0 on success, or 1 if failed (can't find the row)
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable;
+                *      
+                *      // 'open' an information row when a row is clicked on
+                *      $('#example tbody tr').click( function () {
+                *        if ( oTable.fnIsOpen(this) ) {
+                *          oTable.fnClose( this );
+                *        } else {
+                *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
+                *        }
+                *      } );
+                *      
+                *      oTable = $('#example').dataTable();
+                *    } );
+                */
+               this.fnClose = function( nTr )
+               {
+                       /* Find settings from table node */
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       
+                       for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
+                       {
+                               if ( oSettings.aoOpenRows[i].nParent == nTr )
+                               {
+                                       var nTrParent = oSettings.aoOpenRows[i].nTr.parentNode;
+                                       if ( nTrParent )
+                                       {
+                                               /* Remove it if it is currently on display */
+                                               nTrParent.removeChild( oSettings.aoOpenRows[i].nTr );
+                                       }
+                                       oSettings.aoOpenRows.splice( i, 1 );
+                                       return 0;
+                               }
+                       }
+                       return 1;
+               };
+               
+               
+               /**
+                * Remove a row for the table
+                *  @param {mixed} mTarget The index of the row from aoData to be deleted, or
+                *    the TR element you want to delete
+                *  @param {function|null} [fnCallBack] Callback function
+                *  @param {bool} [bRedraw=true] Redraw the table or not
+                *  @returns {array} The row that was deleted
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      
+                *      // Immediately remove the first row
+                *      oTable.fnDeleteRow( 0 );
+                *    } );
+                */
+               this.fnDeleteRow = function( mTarget, fnCallBack, bRedraw )
+               {
+                       /* Find settings from table node */
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       var i, iLen, iAODataIndex;
+                       
+                       iAODataIndex = (typeof mTarget === 'object') ? 
+                               _fnNodeToDataIndex(oSettings, mTarget) : mTarget;
+                       
+                       /* Return the data array from this row */
+                       var oData = oSettings.aoData.splice( iAODataIndex, 1 );
+               
+                       /* Update the _DT_RowIndex parameter */
+                       for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+                       {
+                               if ( oSettings.aoData[i].nTr !== null )
+                               {
+                                       oSettings.aoData[i].nTr._DT_RowIndex = i;
+                               }
+                       }
+                       
+                       /* Remove the target row from the search array */
+                       var iDisplayIndex = $.inArray( iAODataIndex, oSettings.aiDisplay );
+                       oSettings.asDataSearch.splice( iDisplayIndex, 1 );
+                       
+                       /* Delete from the display arrays */
+                       _fnDeleteIndex( oSettings.aiDisplayMaster, iAODataIndex );
+                       _fnDeleteIndex( oSettings.aiDisplay, iAODataIndex );
+                       
+                       /* If there is a user callback function - call it */
+                       if ( typeof fnCallBack === "function" )
+                       {
+                               fnCallBack.call( this, oSettings, oData );
+                       }
+                       
+                       /* Check for an 'overflow' they case for displaying the table */
+                       if ( oSettings._iDisplayStart >= oSettings.fnRecordsDisplay() )
+                       {
+                               oSettings._iDisplayStart -= oSettings._iDisplayLength;
+                               if ( oSettings._iDisplayStart < 0 )
+                               {
+                                       oSettings._iDisplayStart = 0;
+                               }
+                       }
+                       
+                       if ( bRedraw === undefined || bRedraw )
+                       {
+                               _fnCalculateEnd( oSettings );
+                               _fnDraw( oSettings );
+                       }
+                       
+                       return oData;
+               };
+               
+               
+               /**
+                * Restore the table to it's original state in the DOM by removing all of DataTables 
+                * enhancements, alterations to the DOM structure of the table and event listeners.
+                *  @param {boolean} [bRemove=false] Completely remove the table from the DOM
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      // This example is fairly pointless in reality, but shows how fnDestroy can be used
+                *      var oTable = $('#example').dataTable();
+                *      oTable.fnDestroy();
+                *    } );
+                */
+               this.fnDestroy = function ( bRemove )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       var nOrig = oSettings.nTableWrapper.parentNode;
+                       var nBody = oSettings.nTBody;
+                       var i, iLen;
+               
+                       bRemove = (bRemove===undefined) ? false : bRemove;
+                       
+                       /* Flag to note that the table is currently being destroyed - no action should be taken */
+                       oSettings.bDestroying = true;
+                       
+                       /* Fire off the destroy callbacks for plug-ins etc */
+                       _fnCallbackFire( oSettings, "aoDestroyCallback", "destroy", [oSettings] );
+               
+                       /* If the table is not being removed, restore the hidden columns */
+                       if ( !bRemove )
+                       {
+                               for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+                               {
+                                       if ( oSettings.aoColumns[i].bVisible === false )
+                                       {
+                                               this.fnSetColumnVis( i, true );
+                                       }
+                               }
+                       }
+                       
+                       /* Blitz all DT events */
+                       $(oSettings.nTableWrapper).find('*').andSelf().unbind('.DT');
+                       
+                       /* If there is an 'empty' indicator row, remove it */
+                       $('tbody>tr>td.'+oSettings.oClasses.sRowEmpty, oSettings.nTable).parent().remove();
+                       
+                       /* When scrolling we had to break the table up - restore it */
+                       if ( oSettings.nTable != oSettings.nTHead.parentNode )
+                       {
+                               $(oSettings.nTable).children('thead').remove();
+                               oSettings.nTable.appendChild( oSettings.nTHead );
+                       }
+                       
+                       if ( oSettings.nTFoot && oSettings.nTable != oSettings.nTFoot.parentNode )
+                       {
+                               $(oSettings.nTable).children('tfoot').remove();
+                               oSettings.nTable.appendChild( oSettings.nTFoot );
+                       }
+                       
+                       /* Remove the DataTables generated nodes, events and classes */
+                       oSettings.nTable.parentNode.removeChild( oSettings.nTable );
+                       $(oSettings.nTableWrapper).remove();
+                       
+                       oSettings.aaSorting = [];
+                       oSettings.aaSortingFixed = [];
+                       _fnSortingClasses( oSettings );
+                       
+                       $(_fnGetTrNodes( oSettings )).removeClass( oSettings.asStripeClasses.join(' ') );
+                       
+                       $('th, td', oSettings.nTHead).removeClass( [
+                               oSettings.oClasses.sSortable,
+                               oSettings.oClasses.sSortableAsc,
+                               oSettings.oClasses.sSortableDesc,
+                               oSettings.oClasses.sSortableNone ].join(' ')
+                       );
+                       if ( oSettings.bJUI )
+                       {
+                               $('th span.'+oSettings.oClasses.sSortIcon
+                                       + ', td span.'+oSettings.oClasses.sSortIcon, oSettings.nTHead).remove();
+               
+                               $('th, td', oSettings.nTHead).each( function () {
+                                       var jqWrapper = $('div.'+oSettings.oClasses.sSortJUIWrapper, this);
+                                       var kids = jqWrapper.contents();
+                                       $(this).append( kids );
+                                       jqWrapper.remove();
+                               } );
+                       }
+                       
+                       /* Add the TR elements back into the table in their original order */
+                       if ( !bRemove && oSettings.nTableReinsertBefore )
+                       {
+                               nOrig.insertBefore( oSettings.nTable, oSettings.nTableReinsertBefore );
+                       }
+                       else if ( !bRemove )
+                       {
+                               nOrig.appendChild( oSettings.nTable );
+                       }
+               
+                       for ( i=0, iLen=oSettings.aoData.length ; i<iLen ; i++ )
+                       {
+                               if ( oSettings.aoData[i].nTr !== null )
+                               {
+                                       nBody.appendChild( oSettings.aoData[i].nTr );
+                               }
+                       }
+                       
+                       /* Restore the width of the original table */
+                       if ( oSettings.oFeatures.bAutoWidth === true )
+                       {
+                         oSettings.nTable.style.width = _fnStringToCss(oSettings.sDestroyWidth);
+                       }
+                       
+                       /* If the were originally stripe classes - then we add them back here. Note
+                        * this is not fool proof (for example if not all rows had stripe classes - but
+                        * it's a good effort without getting carried away
+                        */
+                       iLen = oSettings.asDestroyStripes.length;
+                       if (iLen)
+                       {
+                               var anRows = $(nBody).children('tr');
+                               for ( i=0 ; i<iLen ; i++ )
+                               {
+                                       anRows.filter(':nth-child(' + iLen + 'n + ' + i + ')').addClass( oSettings.asDestroyStripes[i] );
+                               }
+                       }
+                       
+                       /* Remove the settings object from the settings array */
+                       for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
+                       {
+                               if ( DataTable.settings[i] == oSettings )
+                               {
+                                       DataTable.settings.splice( i, 1 );
+                               }
+                       }
+                       
+                       /* End it all */
+                       oSettings = null;
+                       oInit = null;
+               };
+               
+               
+               /**
+                * Redraw the table
+                *  @param {bool} [bComplete=true] Re-filter and resort (if enabled) the table before the draw.
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      
+                *      // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
+                *      oTable.fnDraw();
+                *    } );
+                */
+               this.fnDraw = function( bComplete )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       if ( bComplete === false )
+                       {
+                               _fnCalculateEnd( oSettings );
+                               _fnDraw( oSettings );
+                       }
+                       else
+                       {
+                               _fnReDraw( oSettings );
+                       }
+               };
+               
+               
+               /**
+                * Filter the input based on data
+                *  @param {string} sInput String to filter the table on
+                *  @param {int|null} [iColumn] Column to limit filtering to
+                *  @param {bool} [bRegex=false] Treat as regular expression or not
+                *  @param {bool} [bSmart=true] Perform smart filtering or not
+                *  @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
+                *  @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      
+                *      // Sometime later - filter...
+                *      oTable.fnFilter( 'test string' );
+                *    } );
+                */
+               this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       
+                       if ( !oSettings.oFeatures.bFilter )
+                       {
+                               return;
+                       }
+                       
+                       if ( bRegex === undefined || bRegex === null )
+                       {
+                               bRegex = false;
+                       }
+                       
+                       if ( bSmart === undefined || bSmart === null )
+                       {
+                               bSmart = true;
+                       }
+                       
+                       if ( bShowGlobal === undefined || bShowGlobal === null )
+                       {
+                               bShowGlobal = true;
+                       }
+                       
+                       if ( bCaseInsensitive === undefined || bCaseInsensitive === null )
+                       {
+                               bCaseInsensitive = true;
+                       }
+                       
+                       if ( iColumn === undefined || iColumn === null )
+                       {
+                               /* Global filter */
+                               _fnFilterComplete( oSettings, {
+                                       "sSearch":sInput+"",
+                                       "bRegex": bRegex,
+                                       "bSmart": bSmart,
+                                       "bCaseInsensitive": bCaseInsensitive
+                               }, 1 );
+                               
+                               if ( bShowGlobal && oSettings.aanFeatures.f )
+                               {
+                                       var n = oSettings.aanFeatures.f;
+                                       for ( var i=0, iLen=n.length ; i<iLen ; i++ )
+                                       {
+                                               // IE9 throws an 'unknown error' if document.activeElement is used
+                                               // inside an iframe or frame...
+                                               try {
+                                                       if ( n[i]._DT_Input != document.activeElement )
+                                                       {
+                                                               $(n[i]._DT_Input).val( sInput );
+                                                       }
+                                               }
+                                               catch ( e ) {
+                                                       $(n[i]._DT_Input).val( sInput );
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               /* Single column filter */
+                               $.extend( oSettings.aoPreSearchCols[ iColumn ], {
+                                       "sSearch": sInput+"",
+                                       "bRegex": bRegex,
+                                       "bSmart": bSmart,
+                                       "bCaseInsensitive": bCaseInsensitive
+                               } );
+                               _fnFilterComplete( oSettings, oSettings.oPreviousSearch, 1 );
+                       }
+               };
+               
+               
+               /**
+                * Get the data for the whole table, an individual row or an individual cell based on the 
+                * provided parameters.
+                *  @param {int|node} [mRow] A TR row node, TD/TH cell node or an integer. If given as
+                *    a TR node then the data source for the whole row will be returned. If given as a
+                *    TD/TH cell node then iCol will be automatically calculated and the data for the
+                *    cell returned. If given as an integer, then this is treated as the aoData internal
+                *    data index for the row (see fnGetPosition) and the data for that row used.
+                *  @param {int} [iCol] Optional column index that you want the data of.
+                *  @returns {array|object|string} If mRow is undefined, then the data for all rows is
+                *    returned. If mRow is defined, just data for that row, and is iCol is
+                *    defined, only data for the designated cell is returned.
+                *  @dtopt API
+                *
+                *  @example
+                *    // Row data
+                *    $(document).ready(function() {
+                *      oTable = $('#example').dataTable();
+                *
+                *      oTable.$('tr').click( function () {
+                *        var data = oTable.fnGetData( this );
+                *        // ... do something with the array / object of data for the row
+                *      } );
+                *    } );
+                *
+                *  @example
+                *    // Individual cell data
+                *    $(document).ready(function() {
+                *      oTable = $('#example').dataTable();
+                *
+                *      oTable.$('td').click( function () {
+                *        var sData = oTable.fnGetData( this );
+                *        alert( 'The cell clicked on had the value of '+sData );
+                *      } );
+                *    } );
+                */
+               this.fnGetData = function( mRow, iCol )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       
+                       if ( mRow !== undefined )
+                       {
+                               var iRow = mRow;
+                               if ( typeof mRow === 'object' )
+                               {
+                                       var sNode = mRow.nodeName.toLowerCase();
+                                       if (sNode === "tr" )
+                                       {
+                                               iRow = _fnNodeToDataIndex(oSettings, mRow);
+                                       }
+                                       else if ( sNode === "td" )
+                                       {
+                                               iRow = _fnNodeToDataIndex(oSettings, mRow.parentNode);
+                                               iCol = _fnNodeToColumnIndex( oSettings, iRow, mRow );
+                                       }
+                               }
+               
+                               if ( iCol !== undefined )
+                               {
+                                       return _fnGetCellData( oSettings, iRow, iCol, '' );
+                               }
+                               return (oSettings.aoData[iRow]!==undefined) ?
+                                       oSettings.aoData[iRow]._aData : null;
+                       }
+                       return _fnGetDataMaster( oSettings );
+               };
+               
+               
+               /**
+                * Get an array of the TR nodes that are used in the table's body. Note that you will 
+                * typically want to use the '$' API method in preference to this as it is more 
+                * flexible.
+                *  @param {int} [iRow] Optional row index for the TR element you want
+                *  @returns {array|node} If iRow is undefined, returns an array of all TR elements
+                *    in the table's body, or iRow is defined, just the TR element requested.
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      
+                *      // Get the nodes from the table
+                *      var nNodes = oTable.fnGetNodes( );
+                *    } );
+                */
+               this.fnGetNodes = function( iRow )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       
+                       if ( iRow !== undefined ) {
+                               return (oSettings.aoData[iRow]!==undefined) ?
+                                       oSettings.aoData[iRow].nTr : null;
+                       }
+                       return _fnGetTrNodes( oSettings );
+               };
+               
+               
+               /**
+                * Get the array indexes of a particular cell from it's DOM element
+                * and column index including hidden columns
+                *  @param {node} nNode this can either be a TR, TD or TH in the table's body
+                *  @returns {int} If nNode is given as a TR, then a single index is returned, or
+                *    if given as a cell, an array of [row index, column index (visible), 
+                *    column index (all)] is given.
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      $('#example tbody td').click( function () {
+                *        // Get the position of the current data from the node
+                *        var aPos = oTable.fnGetPosition( this );
+                *        
+                *        // Get the data array for this row
+                *        var aData = oTable.fnGetData( aPos[0] );
+                *        
+                *        // Update the data array and return the value
+                *        aData[ aPos[1] ] = 'clicked';
+                *        this.innerHTML = 'clicked';
+                *      } );
+                *      
+                *      // Init DataTables
+                *      oTable = $('#example').dataTable();
+                *    } );
+                */
+               this.fnGetPosition = function( nNode )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       var sNodeName = nNode.nodeName.toUpperCase();
+                       
+                       if ( sNodeName == "TR" )
+                       {
+                               return _fnNodeToDataIndex(oSettings, nNode);
+                       }
+                       else if ( sNodeName == "TD" || sNodeName == "TH" )
+                       {
+                               var iDataIndex = _fnNodeToDataIndex( oSettings, nNode.parentNode );
+                               var iColumnIndex = _fnNodeToColumnIndex( oSettings, iDataIndex, nNode );
+                               return [ iDataIndex, _fnColumnIndexToVisible(oSettings, iColumnIndex ), iColumnIndex ];
+                       }
+                       return null;
+               };
+               
+               
+               /**
+                * Check to see if a row is 'open' or not.
+                *  @param {node} nTr the table row to check
+                *  @returns {boolean} true if the row is currently open, false otherwise
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable;
+                *      
+                *      // 'open' an information row when a row is clicked on
+                *      $('#example tbody tr').click( function () {
+                *        if ( oTable.fnIsOpen(this) ) {
+                *          oTable.fnClose( this );
+                *        } else {
+                *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
+                *        }
+                *      } );
+                *      
+                *      oTable = $('#example').dataTable();
+                *    } );
+                */
+               this.fnIsOpen = function( nTr )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       var aoOpenRows = oSettings.aoOpenRows;
+                       
+                       for ( var i=0 ; i<oSettings.aoOpenRows.length ; i++ )
+                       {
+                               if ( oSettings.aoOpenRows[i].nParent == nTr )
+                               {
+                                       return true;
+                               }
+                       }
+                       return false;
+               };
+               
+               
+               /**
+                * This function will place a new row directly after a row which is currently 
+                * on display on the page, with the HTML contents that is passed into the 
+                * function. This can be used, for example, to ask for confirmation that a 
+                * particular record should be deleted.
+                *  @param {node} nTr The table row to 'open'
+                *  @param {string|node|jQuery} mHtml The HTML to put into the row
+                *  @param {string} sClass Class to give the new TD cell
+                *  @returns {node} The row opened. Note that if the table row passed in as the
+                *    first parameter, is not found in the table, this method will silently
+                *    return.
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable;
+                *      
+                *      // 'open' an information row when a row is clicked on
+                *      $('#example tbody tr').click( function () {
+                *        if ( oTable.fnIsOpen(this) ) {
+                *          oTable.fnClose( this );
+                *        } else {
+                *          oTable.fnOpen( this, "Temporary row opened", "info_row" );
+                *        }
+                *      } );
+                *      
+                *      oTable = $('#example').dataTable();
+                *    } );
+                */
+               this.fnOpen = function( nTr, mHtml, sClass )
+               {
+                       /* Find settings from table node */
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+               
+                       /* Check that the row given is in the table */
+                       var nTableRows = _fnGetTrNodes( oSettings );
+                       if ( $.inArray(nTr, nTableRows) === -1 )
+                       {
+                               return;
+                       }
+                       
+                       /* the old open one if there is one */
+                       this.fnClose( nTr );
+                       
+                       var nNewRow = document.createElement("tr");
+                       var nNewCell = document.createElement("td");
+                       nNewRow.appendChild( nNewCell );
+                       nNewCell.className = sClass;
+                       nNewCell.colSpan = _fnVisbleColumns( oSettings );
+               
+                       if (typeof mHtml === "string")
+                       {
+                               nNewCell.innerHTML = mHtml;
+                       }
+                       else
+                       {
+                               $(nNewCell).html( mHtml );
+                       }
+               
+                       /* If the nTr isn't on the page at the moment - then we don't insert at the moment */
+                       var nTrs = $('tr', oSettings.nTBody);
+                       if ( $.inArray(nTr, nTrs) != -1  )
+                       {
+                               $(nNewRow).insertAfter(nTr);
+                       }
+                       
+                       oSettings.aoOpenRows.push( {
+                               "nTr": nNewRow,
+                               "nParent": nTr
+                       } );
+                       
+                       return nNewRow;
+               };
+               
+               
+               /**
+                * Change the pagination - provides the internal logic for pagination in a simple API 
+                * function. With this function you can have a DataTables table go to the next, 
+                * previous, first or last pages.
+                *  @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
+                *    or page number to jump to (integer), note that page 0 is the first page.
+                *  @param {bool} [bRedraw=true] Redraw the table or not
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      oTable.fnPageChange( 'next' );
+                *    } );
+                */
+               this.fnPageChange = function ( mAction, bRedraw )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       _fnPageChange( oSettings, mAction );
+                       _fnCalculateEnd( oSettings );
+                       
+                       if ( bRedraw === undefined || bRedraw )
+                       {
+                               _fnDraw( oSettings );
+                       }
+               };
+               
+               
+               /**
+                * Show a particular column
+                *  @param {int} iCol The column whose display should be changed
+                *  @param {bool} bShow Show (true) or hide (false) the column
+                *  @param {bool} [bRedraw=true] Redraw the table or not
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      
+                *      // Hide the second column after initialisation
+                *      oTable.fnSetColumnVis( 1, false );
+                *    } );
+                */
+               this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       var i, iLen;
+                       var aoColumns = oSettings.aoColumns;
+                       var aoData = oSettings.aoData;
+                       var nTd, bAppend, iBefore;
+                       
+                       /* No point in doing anything if we are requesting what is already true */
+                       if ( aoColumns[iCol].bVisible == bShow )
+                       {
+                               return;
+                       }
+                       
+                       /* Show the column */
+                       if ( bShow )
+                       {
+                               var iInsert = 0;
+                               for ( i=0 ; i<iCol ; i++ )
+                               {
+                                       if ( aoColumns[i].bVisible )
+                                       {
+                                               iInsert++;
+                                       }
+                               }
+                               
+                               /* Need to decide if we should use appendChild or insertBefore */
+                               bAppend = (iInsert >= _fnVisbleColumns( oSettings ));
+               
+                               /* Which coloumn should we be inserting before? */
+                               if ( !bAppend )
+                               {
+                                       for ( i=iCol ; i<aoColumns.length ; i++ )
+                                       {
+                                               if ( aoColumns[i].bVisible )
+                                               {
+                                                       iBefore = i;
+                                                       break;
+                                               }
+                                       }
+                               }
+               
+                               for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+                               {
+                                       if ( aoData[i].nTr !== null )
+                                       {
+                                               if ( bAppend )
+                                               {
+                                                       aoData[i].nTr.appendChild( 
+                                                               aoData[i]._anHidden[iCol]
+                                                       );
+                                               }
+                                               else
+                                               {
+                                                       aoData[i].nTr.insertBefore(
+                                                               aoData[i]._anHidden[iCol], 
+                                                               _fnGetTdNodes( oSettings, i )[iBefore] );
+                                               }
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               /* Remove a column from display */
+                               for ( i=0, iLen=aoData.length ; i<iLen ; i++ )
+                               {
+                                       if ( aoData[i].nTr !== null )
+                                       {
+                                               nTd = _fnGetTdNodes( oSettings, i )[iCol];
+                                               aoData[i]._anHidden[iCol] = nTd;
+                                               nTd.parentNode.removeChild( nTd );
+                                       }
+                               }
+                       }
+               
+                       /* Clear to set the visible flag */
+                       aoColumns[iCol].bVisible = bShow;
+               
+                       /* Redraw the header and footer based on the new column visibility */
+                       _fnDrawHead( oSettings, oSettings.aoHeader );
+                       if ( oSettings.nTFoot )
+                       {
+                               _fnDrawHead( oSettings, oSettings.aoFooter );
+                       }
+                       
+                       /* If there are any 'open' rows, then we need to alter the colspan for this col change */
+                       for ( i=0, iLen=oSettings.aoOpenRows.length ; i<iLen ; i++ )
+                       {
+                               oSettings.aoOpenRows[i].nTr.colSpan = _fnVisbleColumns( oSettings );
+                       }
+                       
+                       /* Do a redraw incase anything depending on the table columns needs it 
+                        * (built-in: scrolling) 
+                        */
+                       if ( bRedraw === undefined || bRedraw )
+                       {
+                               _fnAdjustColumnSizing( oSettings );
+                               _fnDraw( oSettings );
+                       }
+                       
+                       _fnSaveState( oSettings );
+               };
+               
+               
+               /**
+                * Get the settings for a particular table for external manipulation
+                *  @returns {object} DataTables settings object. See 
+                *    {@link DataTable.models.oSettings}
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      var oSettings = oTable.fnSettings();
+                *      
+                *      // Show an example parameter from the settings
+                *      alert( oSettings._iDisplayStart );
+                *    } );
+                */
+               this.fnSettings = function()
+               {
+                       return _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+               };
+               
+               
+               /**
+                * Sort the table by a particular column
+                *  @param {int} iCol the data index to sort on. Note that this will not match the 
+                *    'display index' if you have hidden data entries
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      
+                *      // Sort immediately with columns 0 and 1
+                *      oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
+                *    } );
+                */
+               this.fnSort = function( aaSort )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       oSettings.aaSorting = aaSort;
+                       _fnSort( oSettings );
+               };
+               
+               
+               /**
+                * Attach a sort listener to an element for a given column
+                *  @param {node} nNode the element to attach the sort listener to
+                *  @param {int} iColumn the column that a click on this node will sort on
+                *  @param {function} [fnCallback] callback function when sort is run
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      
+                *      // Sort on column 1, when 'sorter' is clicked on
+                *      oTable.fnSortListener( document.getElementById('sorter'), 1 );
+                *    } );
+                */
+               this.fnSortListener = function( nNode, iColumn, fnCallback )
+               {
+                       _fnSortAttachListener( _fnSettingsFromNode( this[DataTable.ext.iApiIndex] ), nNode, iColumn,
+                               fnCallback );
+               };
+               
+               
+               /**
+                * Update a table cell or row - this method will accept either a single value to
+                * update the cell with, an array of values with one element for each column or
+                * an object in the same format as the original data source. The function is
+                * self-referencing in order to make the multi column updates easier.
+                *  @param {object|array|string} mData Data to update the cell/row with
+                *  @param {node|int} mRow TR element you want to update or the aoData index
+                *  @param {int} [iColumn] The column to update (not used of mData is an array or object)
+                *  @param {bool} [bRedraw=true] Redraw the table or not
+                *  @param {bool} [bAction=true] Perform pre-draw actions or not
+                *  @returns {int} 0 on success, 1 on error
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
+                *      oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], 1, 0 ); // Row
+                *    } );
+                */
+               this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
+               {
+                       var oSettings = _fnSettingsFromNode( this[DataTable.ext.iApiIndex] );
+                       var i, iLen, sDisplay;
+                       var iRow = (typeof mRow === 'object') ? 
+                               _fnNodeToDataIndex(oSettings, mRow) : mRow;
+                       
+                       if ( $.isArray(mData) && iColumn === undefined )
+                       {
+                               /* Array update - update the whole row */
+                               oSettings.aoData[iRow]._aData = mData.slice();
+                               
+                               /* Flag to the function that we are recursing */
+                               for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+                               {
+                                       this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
+                               }
+                       }
+                       else if ( $.isPlainObject(mData) && iColumn === undefined )
+                       {
+                               /* Object update - update the whole row - assume the developer gets the object right */
+                               oSettings.aoData[iRow]._aData = $.extend( true, {}, mData );
+               
+                               for ( i=0 ; i<oSettings.aoColumns.length ; i++ )
+                               {
+                                       this.fnUpdate( _fnGetCellData( oSettings, iRow, i ), iRow, i, false, false );
+                               }
+                       }
+                       else
+                       {
+                               /* Individual cell update */
+                               _fnSetCellData( oSettings, iRow, iColumn, mData );
+                               sDisplay = _fnGetCellData( oSettings, iRow, iColumn, 'display' );
+                               
+                               var oCol = oSettings.aoColumns[iColumn];
+                               if ( oCol.fnRender !== null )
+                               {
+                                       sDisplay = _fnRender( oSettings, iRow, iColumn );
+                                       if ( oCol.bUseRendered )
+                                       {
+                                               _fnSetCellData( oSettings, iRow, iColumn, sDisplay );
+                                       }
+                               }
+                               
+                               if ( oSettings.aoData[iRow].nTr !== null )
+                               {
+                                       /* Do the actual HTML update */
+                                       _fnGetTdNodes( oSettings, iRow )[iColumn].innerHTML = sDisplay;
+                               }
+                       }
+                       
+                       /* Modify the search index for this row (strictly this is likely not needed, since fnReDraw
+                        * will rebuild the search array - however, the redraw might be disabled by the user)
+                        */
+                       var iDisplayIndex = $.inArray( iRow, oSettings.aiDisplay );
+                       oSettings.asDataSearch[iDisplayIndex] = _fnBuildSearchRow(
+                               oSettings, 
+                               _fnGetRowData( oSettings, iRow, 'filter', _fnGetColumns( oSettings, 'bSearchable' ) )
+                       );
+                       
+                       /* Perform pre-draw actions */
+                       if ( bAction === undefined || bAction )
+                       {
+                               _fnAdjustColumnSizing( oSettings );
+                       }
+                       
+                       /* Redraw the table */
+                       if ( bRedraw === undefined || bRedraw )
+                       {
+                               _fnReDraw( oSettings );
+                       }
+                       return 0;
+               };
+               
+               
+               /**
+                * Provide a common method for plug-ins to check the version of DataTables being used, in order
+                * to ensure compatibility.
+                *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
+                *    formats "X" and "X.Y" are also acceptable.
+                *  @returns {boolean} true if this version of DataTables is greater or equal to the required
+                *    version, or false if this version of DataTales is not suitable
+                *  @method
+                *  @dtopt API
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      alert( oTable.fnVersionCheck( '1.9.0' ) );
+                *    } );
+                */
+               this.fnVersionCheck = DataTable.ext.fnVersionCheck;
+               
+               
+               /*
+                * This is really a good bit rubbish this method of exposing the internal methods
+                * publicly... - To be fixed in 2.0 using methods on the prototype
+                */
+               
+               
+               /**
+                * Create a wrapper function for exporting an internal functions to an external API.
+                *  @param {string} sFunc API function name
+                *  @returns {function} wrapped function
+                *  @memberof DataTable#oApi
+                */
+               function _fnExternApiFunc (sFunc)
+               {
+                       return function() {
+                               var aArgs = [_fnSettingsFromNode(this[DataTable.ext.iApiIndex])].concat( 
+                                       Array.prototype.slice.call(arguments) );
+                               return DataTable.ext.oApi[sFunc].apply( this, aArgs );
+                       };
+               }
+               
+               
+               /**
+                * Reference to internal functions for use by plug-in developers. Note that these
+                * methods are references to internal functions and are considered to be private.
+                * If you use these methods, be aware that they are liable to change between versions
+                * (check the upgrade notes).
+                *  @namespace
+                */
+               this.oApi = {
+                       "_fnExternApiFunc": _fnExternApiFunc,
+                       "_fnInitialise": _fnInitialise,
+                       "_fnInitComplete": _fnInitComplete,
+                       "_fnLanguageCompat": _fnLanguageCompat,
+                       "_fnAddColumn": _fnAddColumn,
+                       "_fnColumnOptions": _fnColumnOptions,
+                       "_fnAddData": _fnAddData,
+                       "_fnCreateTr": _fnCreateTr,
+                       "_fnGatherData": _fnGatherData,
+                       "_fnBuildHead": _fnBuildHead,
+                       "_fnDrawHead": _fnDrawHead,
+                       "_fnDraw": _fnDraw,
+                       "_fnReDraw": _fnReDraw,
+                       "_fnAjaxUpdate": _fnAjaxUpdate,
+                       "_fnAjaxParameters": _fnAjaxParameters,
+                       "_fnAjaxUpdateDraw": _fnAjaxUpdateDraw,
+                       "_fnServerParams": _fnServerParams,
+                       "_fnAddOptionsHtml": _fnAddOptionsHtml,
+                       "_fnFeatureHtmlTable": _fnFeatureHtmlTable,
+                       "_fnScrollDraw": _fnScrollDraw,
+                       "_fnAdjustColumnSizing": _fnAdjustColumnSizing,
+                       "_fnFeatureHtmlFilter": _fnFeatureHtmlFilter,
+                       "_fnFilterComplete": _fnFilterComplete,
+                       "_fnFilterCustom": _fnFilterCustom,
+                       "_fnFilterColumn": _fnFilterColumn,
+                       "_fnFilter": _fnFilter,
+                       "_fnBuildSearchArray": _fnBuildSearchArray,
+                       "_fnBuildSearchRow": _fnBuildSearchRow,
+                       "_fnFilterCreateSearch": _fnFilterCreateSearch,
+                       "_fnDataToSearch": _fnDataToSearch,
+                       "_fnSort": _fnSort,
+                       "_fnSortAttachListener": _fnSortAttachListener,
+                       "_fnSortingClasses": _fnSortingClasses,
+                       "_fnFeatureHtmlPaginate": _fnFeatureHtmlPaginate,
+                       "_fnPageChange": _fnPageChange,
+                       "_fnFeatureHtmlInfo": _fnFeatureHtmlInfo,
+                       "_fnUpdateInfo": _fnUpdateInfo,
+                       "_fnFeatureHtmlLength": _fnFeatureHtmlLength,
+                       "_fnFeatureHtmlProcessing": _fnFeatureHtmlProcessing,
+                       "_fnProcessingDisplay": _fnProcessingDisplay,
+                       "_fnVisibleToColumnIndex": _fnVisibleToColumnIndex,
+                       "_fnColumnIndexToVisible": _fnColumnIndexToVisible,
+                       "_fnNodeToDataIndex": _fnNodeToDataIndex,
+                       "_fnVisbleColumns": _fnVisbleColumns,
+                       "_fnCalculateEnd": _fnCalculateEnd,
+                       "_fnConvertToWidth": _fnConvertToWidth,
+                       "_fnCalculateColumnWidths": _fnCalculateColumnWidths,
+                       "_fnScrollingWidthAdjust": _fnScrollingWidthAdjust,
+                       "_fnGetWidestNode": _fnGetWidestNode,
+                       "_fnGetMaxLenString": _fnGetMaxLenString,
+                       "_fnStringToCss": _fnStringToCss,
+                       "_fnDetectType": _fnDetectType,
+                       "_fnSettingsFromNode": _fnSettingsFromNode,
+                       "_fnGetDataMaster": _fnGetDataMaster,
+                       "_fnGetTrNodes": _fnGetTrNodes,
+                       "_fnGetTdNodes": _fnGetTdNodes,
+                       "_fnEscapeRegex": _fnEscapeRegex,
+                       "_fnDeleteIndex": _fnDeleteIndex,
+                       "_fnReOrderIndex": _fnReOrderIndex,
+                       "_fnColumnOrdering": _fnColumnOrdering,
+                       "_fnLog": _fnLog,
+                       "_fnClearTable": _fnClearTable,
+                       "_fnSaveState": _fnSaveState,
+                       "_fnLoadState": _fnLoadState,
+                       "_fnCreateCookie": _fnCreateCookie,
+                       "_fnReadCookie": _fnReadCookie,
+                       "_fnDetectHeader": _fnDetectHeader,
+                       "_fnGetUniqueThs": _fnGetUniqueThs,
+                       "_fnScrollBarWidth": _fnScrollBarWidth,
+                       "_fnApplyToChildren": _fnApplyToChildren,
+                       "_fnMap": _fnMap,
+                       "_fnGetRowData": _fnGetRowData,
+                       "_fnGetCellData": _fnGetCellData,
+                       "_fnSetCellData": _fnSetCellData,
+                       "_fnGetObjectDataFn": _fnGetObjectDataFn,
+                       "_fnSetObjectDataFn": _fnSetObjectDataFn,
+                       "_fnApplyColumnDefs": _fnApplyColumnDefs,
+                       "_fnBindAction": _fnBindAction,
+                       "_fnExtend": _fnExtend,
+                       "_fnCallbackReg": _fnCallbackReg,
+                       "_fnCallbackFire": _fnCallbackFire,
+                       "_fnJsonString": _fnJsonString,
+                       "_fnRender": _fnRender,
+                       "_fnNodeToColumnIndex": _fnNodeToColumnIndex,
+                       "_fnInfoMacros": _fnInfoMacros,
+                       "_fnBrowserDetect": _fnBrowserDetect,
+                       "_fnGetColumns": _fnGetColumns
+               };
+               
+               $.extend( DataTable.ext.oApi, this.oApi );
+               
+               for ( var sFunc in DataTable.ext.oApi )
+               {
+                       if ( sFunc )
+                       {
+                               this[sFunc] = _fnExternApiFunc(sFunc);
+                       }
+               }
+               
+               
+               var _that = this;
+               this.each(function() {
+                       var i=0, iLen, j, jLen, k, kLen;
+                       var sId = this.getAttribute( 'id' );
+                       var bInitHandedOff = false;
+                       var bUsePassedData = false;
+                       
+                       
+                       /* Sanity check */
+                       if ( this.nodeName.toLowerCase() != 'table' )
+                       {
+                               _fnLog( null, 0, "Attempted to initialise DataTables on a node which is not a "+
+                                       "table: "+this.nodeName );
+                               return;
+                       }
+                       
+                       /* Check to see if we are re-initialising a table */
+                       for ( i=0, iLen=DataTable.settings.length ; i<iLen ; i++ )
+                       {
+                               /* Base check on table node */
+                               if ( DataTable.settings[i].nTable == this )
+                               {
+                                       if ( oInit === undefined || oInit.bRetrieve )
+                                       {
+                                               return DataTable.settings[i].oInstance;
+                                       }
+                                       else if ( oInit.bDestroy )
+                                       {
+                                               DataTable.settings[i].oInstance.fnDestroy();
+                                               break;
+                                       }
+                                       else
+                                       {
+                                               _fnLog( DataTable.settings[i], 0, "Cannot reinitialise DataTable.\n\n"+
+                                                       "To retrieve the DataTables object for this table, pass no arguments or see "+
+                                                       "the docs for bRetrieve and bDestroy" );
+                                               return;
+                                       }
+                               }
+                               
+                               /* If the element we are initialising has the same ID as a table which was previously
+                                * initialised, but the table nodes don't match (from before) then we destroy the old
+                                * instance by simply deleting it. This is under the assumption that the table has been
+                                * destroyed by other methods. Anyone using non-id selectors will need to do this manually
+                                */
+                               if ( DataTable.settings[i].sTableId == this.id )
+                               {
+                                       DataTable.settings.splice( i, 1 );
+                                       break;
+                               }
+                       }
+                       
+                       /* Ensure the table has an ID - required for accessibility */
+                       if ( sId === null || sId === "" )
+                       {
+                               sId = "DataTables_Table_"+(DataTable.ext._oExternConfig.iNextUnique++);
+                               this.id = sId;
+                       }
+                       
+                       /* Create the settings object for this table and set some of the default parameters */
+                       var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
+                               "nTable":        this,
+                               "oApi":          _that.oApi,
+                               "oInit":         oInit,
+                               "sDestroyWidth": $(this).width(),
+                               "sInstance":     sId,
+                               "sTableId":      sId
+                       } );
+                       DataTable.settings.push( oSettings );
+                       
+                       // Need to add the instance after the instance after the settings object has been added
+                       // to the settings array, so we can self reference the table instance if more than one
+                       oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
+                       
+                       /* Setting up the initialisation object */
+                       if ( !oInit )
+                       {
+                               oInit = {};
+                       }
+                       
+                       // Backwards compatibility, before we apply all the defaults
+                       if ( oInit.oLanguage )
+                       {
+                               _fnLanguageCompat( oInit.oLanguage );
+                       }
+                       
+                       oInit = _fnExtend( $.extend(true, {}, DataTable.defaults), oInit );
+                       
+                       // Map the initialisation options onto the settings object
+                       _fnMap( oSettings.oFeatures, oInit, "bPaginate" );
+                       _fnMap( oSettings.oFeatures, oInit, "bLengthChange" );
+                       _fnMap( oSettings.oFeatures, oInit, "bFilter" );
+                       _fnMap( oSettings.oFeatures, oInit, "bSort" );
+                       _fnMap( oSettings.oFeatures, oInit, "bInfo" );
+                       _fnMap( oSettings.oFeatures, oInit, "bProcessing" );
+                       _fnMap( oSettings.oFeatures, oInit, "bAutoWidth" );
+                       _fnMap( oSettings.oFeatures, oInit, "bSortClasses" );
+                       _fnMap( oSettings.oFeatures, oInit, "bServerSide" );
+                       _fnMap( oSettings.oFeatures, oInit, "bDeferRender" );
+                       _fnMap( oSettings.oScroll, oInit, "sScrollX", "sX" );
+                       _fnMap( oSettings.oScroll, oInit, "sScrollXInner", "sXInner" );
+                       _fnMap( oSettings.oScroll, oInit, "sScrollY", "sY" );
+                       _fnMap( oSettings.oScroll, oInit, "bScrollCollapse", "bCollapse" );
+                       _fnMap( oSettings.oScroll, oInit, "bScrollInfinite", "bInfinite" );
+                       _fnMap( oSettings.oScroll, oInit, "iScrollLoadGap", "iLoadGap" );
+                       _fnMap( oSettings.oScroll, oInit, "bScrollAutoCss", "bAutoCss" );
+                       _fnMap( oSettings, oInit, "asStripeClasses" );
+                       _fnMap( oSettings, oInit, "asStripClasses", "asStripeClasses" ); // legacy
+                       _fnMap( oSettings, oInit, "fnServerData" );
+                       _fnMap( oSettings, oInit, "fnFormatNumber" );
+                       _fnMap( oSettings, oInit, "sServerMethod" );
+                       _fnMap( oSettings, oInit, "aaSorting" );
+                       _fnMap( oSettings, oInit, "aaSortingFixed" );
+                       _fnMap( oSettings, oInit, "aLengthMenu" );
+                       _fnMap( oSettings, oInit, "sPaginationType" );
+                       _fnMap( oSettings, oInit, "sAjaxSource" );
+                       _fnMap( oSettings, oInit, "sAjaxDataProp" );
+                       _fnMap( oSettings, oInit, "iCookieDuration" );
+                       _fnMap( oSettings, oInit, "sCookiePrefix" );
+                       _fnMap( oSettings, oInit, "sDom" );
+                       _fnMap( oSettings, oInit, "bSortCellsTop" );
+                       _fnMap( oSettings, oInit, "iTabIndex" );
+                       _fnMap( oSettings, oInit, "oSearch", "oPreviousSearch" );
+                       _fnMap( oSettings, oInit, "aoSearchCols", "aoPreSearchCols" );
+                       _fnMap( oSettings, oInit, "iDisplayLength", "_iDisplayLength" );
+                       _fnMap( oSettings, oInit, "bJQueryUI", "bJUI" );
+                       _fnMap( oSettings, oInit, "fnCookieCallback" );
+                       _fnMap( oSettings, oInit, "fnStateLoad" );
+                       _fnMap( oSettings, oInit, "fnStateSave" );
+                       _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
+                       
+                       /* Callback functions which are array driven */
+                       _fnCallbackReg( oSettings, 'aoDrawCallback',       oInit.fnDrawCallback,      'user' );
+                       _fnCallbackReg( oSettings, 'aoServerParams',       oInit.fnServerParams,      'user' );
+                       _fnCallbackReg( oSettings, 'aoStateSaveParams',    oInit.fnStateSaveParams,   'user' );
+                       _fnCallbackReg( oSettings, 'aoStateLoadParams',    oInit.fnStateLoadParams,   'user' );
+                       _fnCallbackReg( oSettings, 'aoStateLoaded',        oInit.fnStateLoaded,       'user' );
+                       _fnCallbackReg( oSettings, 'aoRowCallback',        oInit.fnRowCallback,       'user' );
+                       _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow,        'user' );
+                       _fnCallbackReg( oSettings, 'aoHeaderCallback',     oInit.fnHeaderCallback,    'user' );
+                       _fnCallbackReg( oSettings, 'aoFooterCallback',     oInit.fnFooterCallback,    'user' );
+                       _fnCallbackReg( oSettings, 'aoInitComplete',       oInit.fnInitComplete,      'user' );
+                       _fnCallbackReg( oSettings, 'aoPreDrawCallback',    oInit.fnPreDrawCallback,   'user' );
+                       
+                       if ( oSettings.oFeatures.bServerSide && oSettings.oFeatures.bSort &&
+                                  oSettings.oFeatures.bSortClasses )
+                       {
+                               /* Enable sort classes for server-side processing. Safe to do it here, since server-side
+                                * processing must be enabled by the developer
+                                */
+                               _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'server_side_sort_classes' );
+                       }
+                       else if ( oSettings.oFeatures.bDeferRender )
+                       {
+                               _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSortingClasses, 'defer_sort_classes' );
+                       }
+                       
+                       if ( oInit.bJQueryUI )
+                       {
+                               /* Use the JUI classes object for display. You could clone the oStdClasses object if 
+                                * you want to have multiple tables with multiple independent classes 
+                                */
+                               $.extend( oSettings.oClasses, DataTable.ext.oJUIClasses );
+                               
+                               if ( oInit.sDom === DataTable.defaults.sDom && DataTable.defaults.sDom === "lfrtip" )
+                               {
+                                       /* Set the DOM to use a layout suitable for jQuery UI's theming */
+                                       oSettings.sDom = '<"H"lfr>t<"F"ip>';
+                               }
+                       }
+                       else
+                       {
+                               $.extend( oSettings.oClasses, DataTable.ext.oStdClasses );
+                       }
+                       $(this).addClass( oSettings.oClasses.sTable );
+                       
+                       /* Calculate the scroll bar width and cache it for use later on */
+                       if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
+                       {
+                               oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
+                       }
+                       
+                       if ( oSettings.iInitDisplayStart === undefined )
+                       {
+                               /* Display start point, taking into account the save saving */
+                               oSettings.iInitDisplayStart = oInit.iDisplayStart;
+                               oSettings._iDisplayStart = oInit.iDisplayStart;
+                       }
+                       
+                       /* Must be done after everything which can be overridden by a cookie! */
+                       if ( oInit.bStateSave )
+                       {
+                               oSettings.oFeatures.bStateSave = true;
+                               _fnLoadState( oSettings, oInit );
+                               _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
+                       }
+                       
+                       if ( oInit.iDeferLoading !== null )
+                       {
+                               oSettings.bDeferLoading = true;
+                               var tmp = $.isArray( oInit.iDeferLoading );
+                               oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
+                               oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
+                       }
+                       
+                       if ( oInit.aaData !== null )
+                       {
+                               bUsePassedData = true;
+                       }
+                       
+                       /* Language definitions */
+                       if ( oInit.oLanguage.sUrl !== "" )
+                       {
+                               /* Get the language definitions from a file - because this Ajax call makes the language
+                                * get async to the remainder of this function we use bInitHandedOff to indicate that 
+                                * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
+                                */
+                               oSettings.oLanguage.sUrl = oInit.oLanguage.sUrl;
+                               $.getJSON( oSettings.oLanguage.sUrl, null, function( json ) {
+                                       _fnLanguageCompat( json );
+                                       $.extend( true, oSettings.oLanguage, oInit.oLanguage, json );
+                                       _fnInitialise( oSettings );
+                               } );
+                               bInitHandedOff = true;
+                       }
+                       else
+                       {
+                               $.extend( true, oSettings.oLanguage, oInit.oLanguage );
+                       }
+                       
+                       
+                       /*
+                        * Stripes
+                        */
+                       if ( oInit.asStripeClasses === null )
+                       {
+                               oSettings.asStripeClasses =[
+                                       oSettings.oClasses.sStripeOdd,
+                                       oSettings.oClasses.sStripeEven
+                               ];
+                       }
+                       
+                       /* Remove row stripe classes if they are already on the table row */
+                       iLen=oSettings.asStripeClasses.length;
+                       oSettings.asDestroyStripes = [];
+                       if (iLen)
+                       {
+                               var bStripeRemove = false;
+                               var anRows = $(this).children('tbody').children('tr:lt(' + iLen + ')');
+                               for ( i=0 ; i<iLen ; i++ )
+                               {
+                                       if ( anRows.hasClass( oSettings.asStripeClasses[i] ) )
+                                       {
+                                               bStripeRemove = true;
+                                               
+                                               /* Store the classes which we are about to remove so they can be re-added on destroy */
+                                               oSettings.asDestroyStripes.push( oSettings.asStripeClasses[i] );
+                                       }
+                               }
+                               
+                               if ( bStripeRemove )
+                               {
+                                       anRows.removeClass( oSettings.asStripeClasses.join(' ') );
+                               }
+                       }
+                       
+                       /*
+                        * Columns
+                        * See if we should load columns automatically or use defined ones
+                        */
+                       var anThs = [];
+                       var aoColumnsInit;
+                       var nThead = this.getElementsByTagName('thead');
+                       if ( nThead.length !== 0 )
+                       {
+                               _fnDetectHeader( oSettings.aoHeader, nThead[0] );
+                               anThs = _fnGetUniqueThs( oSettings );
+                       }
+                       
+                       /* If not given a column array, generate one with nulls */
+                       if ( oInit.aoColumns === null )
+                       {
+                               aoColumnsInit = [];
+                               for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
+                               {
+                                       aoColumnsInit.push( null );
+                               }
+                       }
+                       else
+                       {
+                               aoColumnsInit = oInit.aoColumns;
+                       }
+                       
+                       /* Add the columns */
+                       for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
+                       {
+                               /* Short cut - use the loop to check if we have column visibility state to restore */
+                               if ( oInit.saved_aoColumns !== undefined && oInit.saved_aoColumns.length == iLen )
+                               {
+                                       if ( aoColumnsInit[i] === null )
+                                       {
+                                               aoColumnsInit[i] = {};
+                                       }
+                                       aoColumnsInit[i].bVisible = oInit.saved_aoColumns[i].bVisible;
+                               }
+                               
+                               _fnAddColumn( oSettings, anThs ? anThs[i] : null );
+                       }
+                       
+                       /* Apply the column definitions */
+                       _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
+                               _fnColumnOptions( oSettings, iCol, oDef );
+                       } );
+                       
+                       
+                       /*
+                        * Sorting
+                        * Check the aaSorting array
+                        */
+                       for ( i=0, iLen=oSettings.aaSorting.length ; i<iLen ; i++ )
+                       {
+                               if ( oSettings.aaSorting[i][0] >= oSettings.aoColumns.length )
+                               {
+                                       oSettings.aaSorting[i][0] = 0;
+                               }
+                               var oColumn = oSettings.aoColumns[ oSettings.aaSorting[i][0] ];
+                               
+                               /* Add a default sorting index */
+                               if ( oSettings.aaSorting[i][2] === undefined )
+                               {
+                                       oSettings.aaSorting[i][2] = 0;
+                               }
+                               
+                               /* If aaSorting is not defined, then we use the first indicator in asSorting */
+                               if ( oInit.aaSorting === undefined && oSettings.saved_aaSorting === undefined )
+                               {
+                                       oSettings.aaSorting[i][1] = oColumn.asSorting[0];
+                               }
+                               
+                               /* Set the current sorting index based on aoColumns.asSorting */
+                               for ( j=0, jLen=oColumn.asSorting.length ; j<jLen ; j++ )
+                               {
+                                       if ( oSettings.aaSorting[i][1] == oColumn.asSorting[j] )
+                                       {
+                                               oSettings.aaSorting[i][2] = j;
+                                               break;
+                                       }
+                               }
+                       }
+                               
+                       /* Do a first pass on the sorting classes (allows any size changes to be taken into
+                        * account, and also will apply sorting disabled classes if disabled
+                        */
+                       _fnSortingClasses( oSettings );
+                       
+                       
+                       /*
+                        * Final init
+                        * Cache the header, body and footer as required, creating them if needed
+                        */
+                       
+                       /* Browser support detection */
+                       _fnBrowserDetect( oSettings );
+                       
+                       // Work around for Webkit bug 83867 - store the caption-side before removing from doc
+                       var captions = $(this).children('caption').each( function () {
+                               this._captionSide = $(this).css('caption-side');
+                       } );
+                       
+                       var thead = $(this).children('thead');
+                       if ( thead.length === 0 )
+                       {
+                               thead = [ document.createElement( 'thead' ) ];
+                               this.appendChild( thead[0] );
+                       }
+                       oSettings.nTHead = thead[0];
+                       
+                       var tbody = $(this).children('tbody');
+                       if ( tbody.length === 0 )
+                       {
+                               tbody = [ document.createElement( 'tbody' ) ];
+                               this.appendChild( tbody[0] );
+                       }
+                       oSettings.nTBody = tbody[0];
+                       oSettings.nTBody.setAttribute( "role", "alert" );
+                       oSettings.nTBody.setAttribute( "aria-live", "polite" );
+                       oSettings.nTBody.setAttribute( "aria-relevant", "all" );
+                       
+                       var tfoot = $(this).children('tfoot');
+                       if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
+                       {
+                               // If we are a scrolling table, and no footer has been given, then we need to create
+                               // a tfoot element for the caption element to be appended to
+                               tfoot = [ document.createElement( 'tfoot' ) ];
+                               this.appendChild( tfoot[0] );
+                       }
+                       
+                       if ( tfoot.length > 0 )
+                       {
+                               oSettings.nTFoot = tfoot[0];
+                               _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
+                       }
+                       
+                       /* Check if there is data passing into the constructor */
+                       if ( bUsePassedData )
+                       {
+                               for ( i=0 ; i<oInit.aaData.length ; i++ )
+                               {
+                                       _fnAddData( oSettings, oInit.aaData[ i ] );
+                               }
+                       }
+                       else
+                       {
+                               /* Grab the data from the page */
+                               _fnGatherData( oSettings );
+                       }
+                       
+                       /* Copy the data index array */
+                       oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+                       
+                       /* Initialisation complete - table can be drawn */
+                       oSettings.bInitialised = true;
+                       
+                       /* Check if we need to initialise the table (it might not have been handed off to the
+                        * language processor)
+                        */
+                       if ( bInitHandedOff === false )
+                       {
+                               _fnInitialise( oSettings );
+                       }
+               } );
+               _that = null;
+               return this;
+       };
+
+       
+       
+       /**
+        * Provide a common method for plug-ins to check the version of DataTables being used, in order
+        * to ensure compatibility.
+        *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
+        *    formats "X" and "X.Y" are also acceptable.
+        *  @returns {boolean} true if this version of DataTables is greater or equal to the required
+        *    version, or false if this version of DataTales is not suitable
+        *  @static
+        *  @dtopt API-Static
+        *
+        *  @example
+        *    alert( $.fn.dataTable.fnVersionCheck( '1.9.0' ) );
+        */
+       DataTable.fnVersionCheck = function( sVersion )
+       {
+               /* This is cheap, but effective */
+               var fnZPad = function (Zpad, count)
+               {
+                       while(Zpad.length < count) {
+                               Zpad += '0';
+                       }
+                       return Zpad;
+               };
+               var aThis = DataTable.ext.sVersion.split('.');
+               var aThat = sVersion.split('.');
+               var sThis = '', sThat = '';
+               
+               for ( var i=0, iLen=aThat.length ; i<iLen ; i++ )
+               {
+                       sThis += fnZPad( aThis[i], 3 );
+                       sThat += fnZPad( aThat[i], 3 );
+               }
+               
+               return parseInt(sThis, 10) >= parseInt(sThat, 10);
+       };
+       
+       
+       /**
+        * Check if a TABLE node is a DataTable table already or not.
+        *  @param {node} nTable The TABLE node to check if it is a DataTable or not (note that other
+        *    node types can be passed in, but will always return false).
+        *  @returns {boolean} true the table given is a DataTable, or false otherwise
+        *  @static
+        *  @dtopt API-Static
+        *
+        *  @example
+        *    var ex = document.getElementById('example');
+        *    if ( ! $.fn.DataTable.fnIsDataTable( ex ) ) {
+        *      $(ex).dataTable();
+        *    }
+        */
+       DataTable.fnIsDataTable = function ( nTable )
+       {
+               var o = DataTable.settings;
+       
+               for ( var i=0 ; i<o.length ; i++ )
+               {
+                       if ( o[i].nTable === nTable || o[i].nScrollHead === nTable || o[i].nScrollFoot === nTable )
+                       {
+                               return true;
+                       }
+               }
+       
+               return false;
+       };
+       
+       
+       /**
+        * Get all DataTable tables that have been initialised - optionally you can select to
+        * get only currently visible tables.
+        *  @param {boolean} [bVisible=false] Flag to indicate if you want all (default) or 
+        *    visible tables only.
+        *  @returns {array} Array of TABLE nodes (not DataTable instances) which are DataTables
+        *  @static
+        *  @dtopt API-Static
+        *
+        *  @example
+        *    var table = $.fn.dataTable.fnTables(true);
+        *    if ( table.length > 0 ) {
+        *      $(table).dataTable().fnAdjustColumnSizing();
+        *    }
+        */
+       DataTable.fnTables = function ( bVisible )
+       {
+               var out = [];
+       
+               jQuery.each( DataTable.settings, function (i, o) {
+                       if ( !bVisible || (bVisible === true && $(o.nTable).is(':visible')) )
+                       {
+                               out.push( o.nTable );
+                       }
+               } );
+       
+               return out;
+       };
+       
+
+       /**
+        * Version string for plug-ins to check compatibility. Allowed format is
+        * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
+        * e are optional
+        *  @member
+        *  @type string
+        *  @default Version number
+        */
+       DataTable.version = "1.9.4";
+
+       /**
+        * Private data store, containing all of the settings objects that are created for the
+        * tables on a given page.
+        * 
+        * Note that the <i>DataTable.settings</i> object is aliased to <i>jQuery.fn.dataTableExt</i> 
+        * through which it may be accessed and manipulated, or <i>jQuery.fn.dataTable.settings</i>.
+        *  @member
+        *  @type array
+        *  @default []
+        *  @private
+        */
+       DataTable.settings = [];
+
+       /**
+        * Object models container, for the various models that DataTables has available
+        * to it. These models define the objects that are used to hold the active state 
+        * and configuration of the table.
+        *  @namespace
+        */
+       DataTable.models = {};
+       
+       
+       /**
+        * DataTables extension options and plug-ins. This namespace acts as a collection "area"
+        * for plug-ins that can be used to extend the default DataTables behaviour - indeed many
+        * of the build in methods use this method to provide their own capabilities (sorting methods
+        * for example).
+        * 
+        * Note that this namespace is aliased to jQuery.fn.dataTableExt so it can be readily accessed
+        * and modified by plug-ins.
+        *  @namespace
+        */
+       DataTable.models.ext = {
+               /**
+                * Plug-in filtering functions - this method of filtering is complimentary to the default
+                * type based filtering, and a lot more comprehensive as it allows you complete control
+                * over the filtering logic. Each element in this array is a function (parameters
+                * described below) that is called for every row in the table, and your logic decides if
+                * it should be included in the filtered data set or not.
+                *   <ul>
+                *     <li>
+                *       Function input parameters:
+                *       <ul>
+                *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+                *         <li>{array|object} Data for the row to be processed (same as the original format
+                *           that was passed in as the data source, or an array from a DOM data source</li>
+                *         <li>{int} Row index in aoData ({@link DataTable.models.oSettings.aoData}), which can
+                *           be useful to retrieve the TR element if you need DOM interaction.</li>
+                *       </ul>
+                *     </li>
+                *     <li>
+                *       Function return:
+                *       <ul>
+                *         <li>{boolean} Include the row in the filtered result set (true) or not (false)</li>
+                *       </ul>
+                *     </il>
+                *   </ul>
+                *  @type array
+                *  @default []
+                *
+                *  @example
+                *    // The following example shows custom filtering being applied to the fourth column (i.e.
+                *    // the aData[3] index) based on two input values from the end-user, matching the data in 
+                *    // a certain range.
+                *    $.fn.dataTableExt.afnFiltering.push(
+                *      function( oSettings, aData, iDataIndex ) {
+                *        var iMin = document.getElementById('min').value * 1;
+                *        var iMax = document.getElementById('max').value * 1;
+                *        var iVersion = aData[3] == "-" ? 0 : aData[3]*1;
+                *        if ( iMin == "" && iMax == "" ) {
+                *          return true;
+                *        }
+                *        else if ( iMin == "" && iVersion < iMax ) {
+                *          return true;
+                *        }
+                *        else if ( iMin < iVersion && "" == iMax ) {
+                *          return true;
+                *        }
+                *        else if ( iMin < iVersion && iVersion < iMax ) {
+                *          return true;
+                *        }
+                *        return false;
+                *      }
+                *    );
+                */
+               "afnFiltering": [],
+       
+       
+               /**
+                * Plug-in sorting functions - this method of sorting is complimentary to the default type
+                * based sorting that DataTables does automatically, allowing much greater control over the
+                * the data that is being used to sort a column. This is useful if you want to do sorting
+                * based on live data (for example the contents of an 'input' element) rather than just the
+                * static string that DataTables knows of. The way these plug-ins work is that you create
+                * an array of the values you wish to be sorted for the column in question and then return
+                * that array. Which pre-sorting function is run here depends on the sSortDataType parameter
+                * that is used for the column (if any). This is the corollary of <i>ofnSearch</i> for sort 
+                * data.
+                *   <ul>
+            *     <li>
+            *       Function input parameters:
+            *       <ul>
+                *         <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+            *         <li>{int} Target column index</li>
+            *       </ul>
+            *     </li>
+                *     <li>
+                *       Function return:
+                *       <ul>
+                *         <li>{array} Data for the column to be sorted upon</li>
+                *       </ul>
+                *     </il>
+                *   </ul>
+                *  
+                * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
+                * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
+                * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
+                * prepare the data as required for the different types. As such, this method is deprecated.
+                *  @type array
+                *  @default []
+                *  @deprecated
+                *
+                *  @example
+                *    // Updating the cached sorting information with user entered values in HTML input elements
+                *    jQuery.fn.dataTableExt.afnSortData['dom-text'] = function ( oSettings, iColumn )
+                *    {
+                *      var aData = [];
+                *      $( 'td:eq('+iColumn+') input', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
+                *        aData.push( this.value );
+                *      } );
+                *      return aData;
+                *    }
+                */
+               "afnSortData": [],
+       
+       
+               /**
+                * Feature plug-ins - This is an array of objects which describe the feature plug-ins that are
+                * available to DataTables. These feature plug-ins are accessible through the sDom initialisation
+                * option. As such, each feature plug-in must describe a function that is used to initialise
+                * itself (fnInit), a character so the feature can be enabled by sDom (cFeature) and the name
+                * of the feature (sFeature). Thus the objects attached to this method must provide:
+                *   <ul>
+                *     <li>{function} fnInit Initialisation of the plug-in
+                *       <ul>
+            *         <li>
+            *           Function input parameters:
+            *           <ul>
+                *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+            *           </ul>
+            *         </li>
+                *         <li>
+                *           Function return:
+                *           <ul>
+                *             <li>{node|null} The element which contains your feature. Note that the return
+                *                may also be void if your plug-in does not require to inject any DOM elements 
+                *                into DataTables control (sDom) - for example this might be useful when 
+                *                developing a plug-in which allows table control via keyboard entry.</li>
+                *           </ul>
+                *         </il>
+                *       </ul>
+                *     </li>
+                *     <li>{character} cFeature Character that will be matched in sDom - case sensitive</li>
+                *     <li>{string} sFeature Feature name</li>
+                *   </ul>
+                *  @type array
+                *  @default []
+                * 
+                *  @example
+                *    // How TableTools initialises itself.
+                *    $.fn.dataTableExt.aoFeatures.push( {
+                *      "fnInit": function( oSettings ) {
+                *        return new TableTools( { "oDTSettings": oSettings } );
+                *      },
+                *      "cFeature": "T",
+                *      "sFeature": "TableTools"
+                *    } );
+                */
+               "aoFeatures": [],
+       
+       
+               /**
+                * Type detection plug-in functions - DataTables utilises types to define how sorting and
+                * filtering behave, and types can be either  be defined by the developer (sType for the
+                * column) or they can be automatically detected by the methods in this array. The functions
+                * defined in the array are quite simple, taking a single parameter (the data to analyse) 
+                * and returning the type if it is a known type, or null otherwise.
+                *   <ul>
+            *     <li>
+            *       Function input parameters:
+            *       <ul>
+                *         <li>{*} Data from the column cell to be analysed</li>
+            *       </ul>
+            *     </li>
+                *     <li>
+                *       Function return:
+                *       <ul>
+                *         <li>{string|null} Data type detected, or null if unknown (and thus pass it
+                *           on to the other type detection functions.</li>
+                *       </ul>
+                *     </il>
+                *   </ul>
+                *  @type array
+                *  @default []
+                *  
+                *  @example
+                *    // Currency type detection plug-in:
+                *    jQuery.fn.dataTableExt.aTypes.push(
+                *      function ( sData ) {
+                *        var sValidChars = "0123456789.-";
+                *        var Char;
+                *        
+                *        // Check the numeric part
+                *        for ( i=1 ; i<sData.length ; i++ ) {
+                *          Char = sData.charAt(i); 
+                *          if (sValidChars.indexOf(Char) == -1) {
+                *            return null;
+                *          }
+                *        }
+                *        
+                *        // Check prefixed by currency
+                *        if ( sData.charAt(0) == '$' || sData.charAt(0) == '&pound;' ) {
+                *          return 'currency';
+                *        }
+                *        return null;
+                *      }
+                *    );
+                */
+               "aTypes": [],
+       
+       
+               /**
+                * Provide a common method for plug-ins to check the version of DataTables being used, 
+                * in order to ensure compatibility.
+                *  @type function
+                *  @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note 
+                *    that the formats "X" and "X.Y" are also acceptable.
+                *  @returns {boolean} true if this version of DataTables is greater or equal to the 
+                *    required version, or false if this version of DataTales is not suitable
+                *
+                *  @example
+                *    $(document).ready(function() {
+                *      var oTable = $('#example').dataTable();
+                *      alert( oTable.fnVersionCheck( '1.9.0' ) );
+                *    } );
+                */
+               "fnVersionCheck": DataTable.fnVersionCheck,
+       
+       
+               /**
+                * Index for what 'this' index API functions should use
+                *  @type int
+                *  @default 0
+                */
+               "iApiIndex": 0,
+       
+       
+               /**
+                * Pre-processing of filtering data plug-ins - When you assign the sType for a column
+                * (or have it automatically detected for you by DataTables or a type detection plug-in), 
+                * you will typically be using this for custom sorting, but it can also be used to provide 
+                * custom filtering by allowing you to pre-processing the data and returning the data in
+                * the format that should be filtered upon. This is done by adding functions this object 
+                * with a parameter name which matches the sType for that target column. This is the
+                * corollary of <i>afnSortData</i> for filtering data.
+                *   <ul>
+            *     <li>
+            *       Function input parameters:
+            *       <ul>
+                *         <li>{*} Data from the column cell to be prepared for filtering</li>
+            *       </ul>
+            *     </li>
+                *     <li>
+                *       Function return:
+                *       <ul>
+                *         <li>{string|null} Formatted string that will be used for the filtering.</li>
+                *       </ul>
+                *     </il>
+                *   </ul>
+                * 
+                * Note that as of v1.9, it is typically preferable to use <i>mData</i> to prepare data for
+                * the different uses that DataTables can put the data to. Specifically <i>mData</i> when
+                * used as a function will give you a 'type' (sorting, filtering etc) that you can use to 
+                * prepare the data as required for the different types. As such, this method is deprecated.
+                *  @type object
+                *  @default {}
+                *  @deprecated
+                *
+                *  @example
+                *    $.fn.dataTableExt.ofnSearch['title-numeric'] = function ( sData ) {
+                *      return sData.replace(/\n/g," ").replace( /<.*?>/g, "" );
+                *    }
+                */
+               "ofnSearch": {},
+       
+       
+               /**
+                * Container for all private functions in DataTables so they can be exposed externally
+                *  @type object
+                *  @default {}
+                */
+               "oApi": {},
+       
+       
+               /**
+                * Storage for the various classes that DataTables uses
+                *  @type object
+                *  @default {}
+                */
+               "oStdClasses": {},
+               
+       
+               /**
+                * Storage for the various classes that DataTables uses - jQuery UI suitable
+                *  @type object
+                *  @default {}
+                */
+               "oJUIClasses": {},
+       
+       
+               /**
+                * Pagination plug-in methods - The style and controls of the pagination can significantly 
+                * impact on how the end user interacts with the data in your table, and DataTables allows 
+                * the addition of pagination controls by extending this object, which can then be enabled
+                * through the <i>sPaginationType</i> initialisation parameter. Each pagination type that
+                * is added is an object (the property name of which is what <i>sPaginationType</i> refers
+                * to) that has two properties, both methods that are used by DataTables to update the
+                * control's state.
+                *   <ul>
+                *     <li>
+                *       fnInit -  Initialisation of the paging controls. Called only during initialisation 
+                *         of the table. It is expected that this function will add the required DOM elements 
+                *         to the page for the paging controls to work. The element pointer 
+                *         'oSettings.aanFeatures.p' array is provided by DataTables to contain the paging 
+                *         controls (note that this is a 2D array to allow for multiple instances of each 
+                *         DataTables DOM element). It is suggested that you add the controls to this element 
+                *         as children
+                *       <ul>
+            *         <li>
+            *           Function input parameters:
+            *           <ul>
+                *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+                *             <li>{node} Container into which the pagination controls must be inserted</li>
+                *             <li>{function} Draw callback function - whenever the controls cause a page
+                *               change, this method must be called to redraw the table.</li>
+            *           </ul>
+            *         </li>
+                *         <li>
+                *           Function return:
+                *           <ul>
+                *             <li>No return required</li>
+                *           </ul>
+                *         </il>
+                *       </ul>
+                *     </il>
+                *     <li>
+                *       fnInit -  This function is called whenever the paging status of the table changes and is
+                *         typically used to update classes and/or text of the paging controls to reflex the new 
+                *         status.
+                *       <ul>
+            *         <li>
+            *           Function input parameters:
+            *           <ul>
+                *             <li>{object} DataTables settings object: see {@link DataTable.models.oSettings}.</li>
+                *             <li>{function} Draw callback function - in case you need to redraw the table again
+                *               or attach new event listeners</li>
+            *           </ul>
+            *         </li>
+                *         <li>
+                *           Function return:
+                *           <ul>
+                *             <li>No return required</li>
+                *           </ul>
+                *         </il>
+                *       </ul>
+                *     </il>
+                *   </ul>
+                *  @type object
+                *  @default {}
+                *
+                *  @example
+                *    $.fn.dataTableExt.oPagination.four_button = {
+                *      "fnInit": function ( oSettings, nPaging, fnCallbackDraw ) {
+                *        nFirst = document.createElement( 'span' );
+                *        nPrevious = document.createElement( 'span' );
+                *        nNext = document.createElement( 'span' );
+                *        nLast = document.createElement( 'span' );
+                *        
+                *        nFirst.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sFirst ) );
+                *        nPrevious.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sPrevious ) );
+                *        nNext.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sNext ) );
+                *        nLast.appendChild( document.createTextNode( oSettings.oLanguage.oPaginate.sLast ) );
+                *        
+                *        nFirst.className = "paginate_button first";
+                *        nPrevious.className = "paginate_button previous";
+                *        nNext.className="paginate_button next";
+                *        nLast.className = "paginate_button last";
+                *        
+                *        nPaging.appendChild( nFirst );
+                *        nPaging.appendChild( nPrevious );
+                *        nPaging.appendChild( nNext );
+                *        nPaging.appendChild( nLast );
+                *        
+                *        $(nFirst).click( function () {
+                *          oSettings.oApi._fnPageChange( oSettings, "first" );
+                *          fnCallbackDraw( oSettings );
+                *        } );
+                *        
+                *        $(nPrevious).click( function() {
+                *          oSettings.oApi._fnPageChange( oSettings, "previous" );
+                *          fnCallbackDraw( oSettings );
+                *        } );
+                *        
+                *        $(nNext).click( function() {
+                *          oSettings.oApi._fnPageChange( oSettings, "next" );
+                *          fnCallbackDraw( oSettings );
+                *        } );
+                *        
+                *        $(nLast).click( function() {
+                *          oSettings.oApi._fnPageChange( oSettings, "last" );
+                *          fnCallbackDraw( oSettings );
+                *        } );
+                *        
+                *        $(nFirst).bind( 'selectstart', function () { return false; } );
+                *        $(nPrevious).bind( 'selectstart', function () { return false; } );
+                *        $(nNext).bind( 'selectstart', function () { return false; } );
+                *        $(nLast).bind( 'selectstart', function () { return false; } );
+                *      },
+                *      
+                *      "fnUpdate": function ( oSettings, fnCallbackDraw ) {
+                *        if ( !oSettings.aanFeatures.p ) {
+                *          return;
+                *        }
+                *        
+                *        // Loop over each instance of the pager
+                *        var an = oSettings.aanFeatures.p;
+                *        for ( var i=0, iLen=an.length ; i<iLen ; i++ ) {
+                *          var buttons = an[i].getElementsByTagName('span');
+                *          if ( oSettings._iDisplayStart === 0 ) {
+                *            buttons[0].className = "paginate_disabled_previous";
+                *            buttons[1].className = "paginate_disabled_previous";
+                *          }
+                *          else {
+                *            buttons[0].className = "paginate_enabled_previous";
+                *            buttons[1].className = "paginate_enabled_previous";
+                *          }
+                *          
+                *          if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) {
+                *            buttons[2].className = "paginate_disabled_next";
+                *            buttons[3].className = "paginate_disabled_next";
+                *          }
+                *          else {
+                *            buttons[2].className = "paginate_enabled_next";
+                *            buttons[3].className = "paginate_enabled_next";
+                *          }
+                *        }
+                *      }
+                *    };
+                */
+               "oPagination": {},
+       
+       
+               /**
+                * Sorting plug-in methods - Sorting in DataTables is based on the detected type of the
+                * data column (you can add your own type detection functions, or override automatic 
+                * detection using sType). With this specific type given to the column, DataTables will 
+                * apply the required sort from the functions in the object. Each sort type must provide
+                * two mandatory methods, one each for ascending and descending sorting, and can optionally
+                * provide a pre-formatting method that will help speed up sorting by allowing DataTables
+                * to pre-format the sort data only once (rather than every time the actual sort functions
+                * are run). The two sorting functions are typical Javascript sort methods:
+                *   <ul>
+            *     <li>
+            *       Function input parameters:
+            *       <ul>
+                *         <li>{*} Data to compare to the second parameter</li>
+                *         <li>{*} Data to compare to the first parameter</li>
+            *       </ul>
+            *     </li>
+                *     <li>
+                *       Function return:
+                *       <ul>
+                *         <li>{int} Sorting match: <0 if first parameter should be sorted lower than
+                *           the second parameter, ===0 if the two parameters are equal and >0 if
+                *           the first parameter should be sorted height than the second parameter.</li>
+                *       </ul>
+                *     </il>
+                *   </ul>
+                *  @type object
+                *  @default {}
+                *
+                *  @example
+                *    // Case-sensitive string sorting, with no pre-formatting method
+                *    $.extend( $.fn.dataTableExt.oSort, {
+                *      "string-case-asc": function(x,y) {
+                *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+                *      },
+                *      "string-case-desc": function(x,y) {
+                *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+                *      }
+                *    } );
+                *
+                *  @example
+                *    // Case-insensitive string sorting, with pre-formatting
+                *    $.extend( $.fn.dataTableExt.oSort, {
+                *      "string-pre": function(x) {
+                *        return x.toLowerCase();
+                *      },
+                *      "string-asc": function(x,y) {
+                *        return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+                *      },
+                *      "string-desc": function(x,y) {
+                *        return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+                *      }
+                *    } );
+                */
+               "oSort": {},
+       
+       
+               /**
+                * Version string for plug-ins to check compatibility. Allowed format is
+                * a.b.c.d.e where: a:int, b:int, c:int, d:string(dev|beta), e:int. d and
+                * e are optional
+                *  @type string
+                *  @default Version number
+                */
+               "sVersion": DataTable.version,
+       
+       
+               /**
+                * How should DataTables report an error. Can take the value 'alert' or 'throw'
+                *  @type string
+                *  @default alert
+                */
+               "sErrMode": "alert",
+       
+       
+               /**
+                * Store information for DataTables to access globally about other instances
+                *  @namespace
+                *  @private
+                */
+               "_oExternConfig": {
+                       /* int:iNextUnique - next unique number for an instance */
+                       "iNextUnique": 0
+               }
+       };
+       
+       
+       
+       
+       /**
+        * Template object for the way in which DataTables holds information about
+        * search information for the global filter and individual column filters.
+        *  @namespace
+        */
+       DataTable.models.oSearch = {
+               /**
+                * Flag to indicate if the filtering should be case insensitive or not
+                *  @type boolean
+                *  @default true
+                */
+               "bCaseInsensitive": true,
+       
+               /**
+                * Applied search term
+                *  @type string
+                *  @default <i>Empty string</i>
+                */
+               "sSearch": "",
+       
+               /**
+                * Flag to indicate if the search term should be interpreted as a
+                * regular expression (true) or not (false) and therefore and special
+                * regex characters escaped.
+                *  @type boolean
+                *  @default false
+                */
+               "bRegex": false,
+       
+               /**
+                * Flag to indicate if DataTables is to use its smart filtering or not.
+                *  @type boolean
+                *  @default true
+                */
+               "bSmart": true
+       };
+       
+       
+       
+       
+       /**
+        * Template object for the way in which DataTables holds information about
+        * each individual row. This is the object format used for the settings 
+        * aoData array.
+        *  @namespace
+        */
+       DataTable.models.oRow = {
+               /**
+                * TR element for the row
+                *  @type node
+                *  @default null
+                */
+               "nTr": null,
+       
+               /**
+                * Data object from the original data source for the row. This is either
+                * an array if using the traditional form of DataTables, or an object if
+                * using mData options. The exact type will depend on the passed in
+                * data from the data source, or will be an array if using DOM a data 
+                * source.
+                *  @type array|object
+                *  @default []
+                */
+               "_aData": [],
+       
+               /**
+                * Sorting data cache - this array is ostensibly the same length as the
+                * number of columns (although each index is generated only as it is 
+                * needed), and holds the data that is used for sorting each column in the
+                * row. We do this cache generation at the start of the sort in order that
+                * the formatting of the sort data need be done only once for each cell
+                * per sort. This array should not be read from or written to by anything
+                * other than the master sorting methods.
+                *  @type array
+                *  @default []
+                *  @private
+                */
+               "_aSortData": [],
+       
+               /**
+                * Array of TD elements that are cached for hidden rows, so they can be
+                * reinserted into the table if a column is made visible again (or to act
+                * as a store if a column is made hidden). Only hidden columns have a 
+                * reference in the array. For non-hidden columns the value is either
+                * undefined or null.
+                *  @type array nodes
+                *  @default []
+                *  @private
+                */
+               "_anHidden": [],
+       
+               /**
+                * Cache of the class name that DataTables has applied to the row, so we
+                * can quickly look at this variable rather than needing to do a DOM check
+                * on className for the nTr property.
+                *  @type string
+                *  @default <i>Empty string</i>
+                *  @private
+                */
+               "_sRowStripe": ""
+       };
+       
+       
+       
+       /**
+        * Template object for the column information object in DataTables. This object
+        * is held in the settings aoColumns array and contains all the information that
+        * DataTables needs about each individual column.
+        * 
+        * Note that this object is related to {@link DataTable.defaults.columns} 
+        * but this one is the internal data store for DataTables's cache of columns.
+        * It should NOT be manipulated outside of DataTables. Any configuration should
+        * be done through the initialisation options.
+        *  @namespace
+        */
+       DataTable.models.oColumn = {
+               /**
+                * A list of the columns that sorting should occur on when this column
+                * is sorted. That this property is an array allows multi-column sorting
+                * to be defined for a column (for example first name / last name columns
+                * would benefit from this). The values are integers pointing to the
+                * columns to be sorted on (typically it will be a single integer pointing
+                * at itself, but that doesn't need to be the case).
+                *  @type array
+                */
+               "aDataSort": null,
+       
+               /**
+                * Define the sorting directions that are applied to the column, in sequence
+                * as the column is repeatedly sorted upon - i.e. the first value is used
+                * as the sorting direction when the column if first sorted (clicked on).
+                * Sort it again (click again) and it will move on to the next index.
+                * Repeat until loop.
+                *  @type array
+                */
+               "asSorting": null,
+               
+               /**
+                * Flag to indicate if the column is searchable, and thus should be included
+                * in the filtering or not.
+                *  @type boolean
+                */
+               "bSearchable": null,
+               
+               /**
+                * Flag to indicate if the column is sortable or not.
+                *  @type boolean
+                */
+               "bSortable": null,
+               
+               /**
+                * <code>Deprecated</code> When using fnRender, you have two options for what 
+                * to do with the data, and this property serves as the switch. Firstly, you 
+                * can have the sorting and filtering use the rendered value (true - default), 
+                * or you can have the sorting and filtering us the original value (false).
+                *
+                * Please note that this option has now been deprecated and will be removed
+                * in the next version of DataTables. Please use mRender / mData rather than
+                * fnRender.
+                *  @type boolean
+                *  @deprecated
+                */
+               "bUseRendered": null,
+               
+               /**
+                * Flag to indicate if the column is currently visible in the table or not
+                *  @type boolean
+                */
+               "bVisible": null,
+               
+               /**
+                * Flag to indicate to the type detection method if the automatic type
+                * detection should be used, or if a column type (sType) has been specified
+                *  @type boolean
+                *  @default true
+                *  @private
+                */
+               "_bAutoType": true,
+               
+               /**
+                * Developer definable function that is called whenever a cell is created (Ajax source,
+                * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+                * allowing you to modify the DOM element (add background colour for example) when the
+                * element is available.
+                *  @type function
+                *  @param {element} nTd The TD node that has been created
+                *  @param {*} sData The Data for the cell
+                *  @param {array|object} oData The data for the whole row
+                *  @param {int} iRow The row index for the aoData data store
+                *  @default null
+                */
+               "fnCreatedCell": null,
+               
+               /**
+                * Function to get data from a cell in a column. You should <b>never</b>
+                * access data directly through _aData internally in DataTables - always use
+                * the method attached to this property. It allows mData to function as
+                * required. This function is automatically assigned by the column 
+                * initialisation method
+                *  @type function
+                *  @param {array|object} oData The data array/object for the array 
+                *    (i.e. aoData[]._aData)
+                *  @param {string} sSpecific The specific data type you want to get - 
+                *    'display', 'type' 'filter' 'sort'
+                *  @returns {*} The data for the cell from the given row's data
+                *  @default null
+                */
+               "fnGetData": null,
+               
+               /**
+                * <code>Deprecated</code> Custom display function that will be called for the 
+                * display of each cell in this column.
+                *
+                * Please note that this option has now been deprecated and will be removed
+                * in the next version of DataTables. Please use mRender / mData rather than
+                * fnRender.
+                *  @type function
+                *  @param {object} o Object with the following parameters:
+                *  @param {int}    o.iDataRow The row in aoData
+                *  @param {int}    o.iDataColumn The column in question
+                *  @param {array}  o.aData The data for the row in question
+                *  @param {object} o.oSettings The settings object for this DataTables instance
+                *  @returns {string} The string you which to use in the display
+                *  @default null
+                *  @deprecated
+                */
+               "fnRender": null,
+               
+               /**
+                * Function to set data for a cell in the column. You should <b>never</b> 
+                * set the data directly to _aData internally in DataTables - always use
+                * this method. It allows mData to function as required. This function
+                * is automatically assigned by the column initialisation method
+                *  @type function
+                *  @param {array|object} oData The data array/object for the array 
+                *    (i.e. aoData[]._aData)
+                *  @param {*} sValue Value to set
+                *  @default null
+                */
+               "fnSetData": null,
+               
+               /**
+                * Property to read the value for the cells in the column from the data 
+                * source array / object. If null, then the default content is used, if a
+                * function is given then the return from the function is used.
+                *  @type function|int|string|null
+                *  @default null
+                */
+               "mData": null,
+               
+               /**
+                * Partner property to mData which is used (only when defined) to get
+                * the data - i.e. it is basically the same as mData, but without the
+                * 'set' option, and also the data fed to it is the result from mData.
+                * This is the rendering method to match the data method of mData.
+                *  @type function|int|string|null
+                *  @default null
+                */
+               "mRender": null,
+               
+               /**
+                * Unique header TH/TD element for this column - this is what the sorting
+                * listener is attached to (if sorting is enabled.)
+                *  @type node
+                *  @default null
+                */
+               "nTh": null,
+               
+               /**
+                * Unique footer TH/TD element for this column (if there is one). Not used 
+                * in DataTables as such, but can be used for plug-ins to reference the 
+                * footer for each column.
+                *  @type node
+                *  @default null
+                */
+               "nTf": null,
+               
+               /**
+                * The class to apply to all TD elements in the table's TBODY for the column
+                *  @type string
+                *  @default null
+                */
+               "sClass": null,
+               
+               /**
+                * When DataTables calculates the column widths to assign to each column,
+                * it finds the longest string in each column and then constructs a
+                * temporary table and reads the widths from that. The problem with this
+                * is that "mmm" is much wider then "iiii", but the latter is a longer 
+                * string - thus the calculation can go wrong (doing it properly and putting
+                * it into an DOM object and measuring that is horribly(!) slow). Thus as
+                * a "work around" we provide this option. It will append its value to the
+                * text that is found to be the longest string for the column - i.e. padding.
+                *  @type string
+                */
+               "sContentPadding": null,
+               
+               /**
+                * Allows a default value to be given for a column's data, and will be used
+                * whenever a null data source is encountered (this can be because mData
+                * is set to null, or because the data source itself is null).
+                *  @type string
+                *  @default null
+                */
+               "sDefaultContent": null,
+               
+               /**
+                * Name for the column, allowing reference to the column by name as well as
+                * by index (needs a lookup to work by name).
+                *  @type string
+                */
+               "sName": null,
+               
+               /**
+                * Custom sorting data type - defines which of the available plug-ins in
+                * afnSortData the custom sorting will use - if any is defined.
+                *  @type string
+                *  @default std
+                */
+               "sSortDataType": 'std',
+               
+               /**
+                * Class to be applied to the header element when sorting on this column
+                *  @type string
+                *  @default null
+                */
+               "sSortingClass": null,
+               
+               /**
+                * Class to be applied to the header element when sorting on this column -
+                * when jQuery UI theming is used.
+                *  @type string
+                *  @default null
+                */
+               "sSortingClassJUI": null,
+               
+               /**
+                * Title of the column - what is seen in the TH element (nTh).
+                *  @type string
+                */
+               "sTitle": null,
+               
+               /**
+                * Column sorting and filtering type
+                *  @type string
+                *  @default null
+                */
+               "sType": null,
+               
+               /**
+                * Width of the column
+                *  @type string
+                *  @default null
+                */
+               "sWidth": null,
+               
+               /**
+                * Width of the column when it was first "encountered"
+                *  @type string
+                *  @default null
+                */
+               "sWidthOrig": null
+       };
+       
+       
+       
+       /**
+        * Initialisation options that can be given to DataTables at initialisation 
+        * time.
+        *  @namespace
+        */
+       DataTable.defaults = {
+               /**
+                * An array of data to use for the table, passed in at initialisation which 
+                * will be used in preference to any data which is already in the DOM. This is
+                * particularly useful for constructing tables purely in Javascript, for
+                * example with a custom Ajax call.
+                *  @type array
+                *  @default null
+                *  @dtopt Option
+                * 
+                *  @example
+                *    // Using a 2D array data source
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "aaData": [
+                *          ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
+                *          ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
+                *        ],
+                *        "aoColumns": [
+                *          { "sTitle": "Engine" },
+                *          { "sTitle": "Browser" },
+                *          { "sTitle": "Platform" },
+                *          { "sTitle": "Version" },
+                *          { "sTitle": "Grade" }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using an array of objects as a data source (mData)
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "aaData": [
+                *          {
+                *            "engine":   "Trident",
+                *            "browser":  "Internet Explorer 4.0",
+                *            "platform": "Win 95+",
+                *            "version":  4,
+                *            "grade":    "X"
+                *          },
+                *          {
+                *            "engine":   "Trident",
+                *            "browser":  "Internet Explorer 5.0",
+                *            "platform": "Win 95+",
+                *            "version":  5,
+                *            "grade":    "C"
+                *          }
+                *        ],
+                *        "aoColumns": [
+                *          { "sTitle": "Engine",   "mData": "engine" },
+                *          { "sTitle": "Browser",  "mData": "browser" },
+                *          { "sTitle": "Platform", "mData": "platform" },
+                *          { "sTitle": "Version",  "mData": "version" },
+                *          { "sTitle": "Grade",    "mData": "grade" }
+                *        ]
+                *      } );
+                *    } );
+                */
+               "aaData": null,
+       
+       
+               /**
+                * If sorting is enabled, then DataTables will perform a first pass sort on 
+                * initialisation. You can define which column(s) the sort is performed upon, 
+                * and the sorting direction, with this variable. The aaSorting array should 
+                * contain an array for each column to be sorted initially containing the 
+                * column's index and a direction string ('asc' or 'desc').
+                *  @type array
+                *  @default [[0,'asc']]
+                *  @dtopt Option
+                * 
+                *  @example
+                *    // Sort by 3rd column first, and then 4th column
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aaSorting": [[2,'asc'], [3,'desc']]
+                *      } );
+                *    } );
+                *    
+                *    // No initial sorting
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aaSorting": []
+                *      } );
+                *    } );
+                */
+               "aaSorting": [[0,'asc']],
+       
+       
+               /**
+                * This parameter is basically identical to the aaSorting parameter, but 
+                * cannot be overridden by user interaction with the table. What this means 
+                * is that you could have a column (visible or hidden) which the sorting will 
+                * always be forced on first - any sorting after that (from the user) will 
+                * then be performed as required. This can be useful for grouping rows 
+                * together.
+                *  @type array
+                *  @default null
+                *  @dtopt Option
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aaSortingFixed": [[0,'asc']]
+                *      } );
+                *    } )
+                */
+               "aaSortingFixed": null,
+       
+       
+               /**
+                * This parameter allows you to readily specify the entries in the length drop
+                * down menu that DataTables shows when pagination is enabled. It can be 
+                * either a 1D array of options which will be used for both the displayed 
+                * option and the value, or a 2D array which will use the array in the first 
+                * position as the value, and the array in the second position as the 
+                * displayed options (useful for language strings such as 'All').
+                *  @type array
+                *  @default [ 10, 25, 50, 100 ]
+                *  @dtopt Option
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aLengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
+                *      } );
+                *    } );
+                *  
+                *  @example
+                *    // Setting the default display length as well as length menu
+                *    // This is likely to be wanted if you remove the '10' option which
+                *    // is the iDisplayLength default.
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "iDisplayLength": 25,
+                *        "aLengthMenu": [[25, 50, 100, -1], [25, 50, 100, "All"]]
+                *      } );
+                *    } );
+                */
+               "aLengthMenu": [ 10, 25, 50, 100 ],
+       
+       
+               /**
+                * The aoColumns option in the initialisation parameter allows you to define
+                * details about the way individual columns behave. For a full list of
+                * column options that can be set, please see 
+                * {@link DataTable.defaults.columns}. Note that if you use aoColumns to
+                * define your columns, you must have an entry in the array for every single
+                * column that you have in your table (these can be null if you don't which
+                * to specify any options).
+                *  @member
+                */
+               "aoColumns": null,
+       
+               /**
+                * Very similar to aoColumns, aoColumnDefs allows you to target a specific 
+                * column, multiple columns, or all columns, using the aTargets property of 
+                * each object in the array. This allows great flexibility when creating 
+                * tables, as the aoColumnDefs arrays can be of any length, targeting the 
+                * columns you specifically want. aoColumnDefs may use any of the column 
+                * options available: {@link DataTable.defaults.columns}, but it _must_
+                * have aTargets defined in each object in the array. Values in the aTargets
+                * array may be:
+                *   <ul>
+                *     <li>a string - class name will be matched on the TH for the column</li>
+                *     <li>0 or a positive integer - column index counting from the left</li>
+                *     <li>a negative integer - column index counting from the right</li>
+                *     <li>the string "_all" - all columns (i.e. assign a default)</li>
+                *   </ul>
+                *  @member
+                */
+               "aoColumnDefs": null,
+       
+       
+               /**
+                * Basically the same as oSearch, this parameter defines the individual column
+                * filtering state at initialisation time. The array must be of the same size 
+                * as the number of columns, and each element be an object with the parameters
+                * "sSearch" and "bEscapeRegex" (the latter is optional). 'null' is also
+                * accepted and the default will be used.
+                *  @type array
+                *  @default []
+                *  @dtopt Option
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoSearchCols": [
+                *          null,
+                *          { "sSearch": "My filter" },
+                *          null,
+                *          { "sSearch": "^[0-9]", "bEscapeRegex": false }
+                *        ]
+                *      } );
+                *    } )
+                */
+               "aoSearchCols": [],
+       
+       
+               /**
+                * An array of CSS classes that should be applied to displayed rows. This 
+                * array may be of any length, and DataTables will apply each class 
+                * sequentially, looping when required.
+                *  @type array
+                *  @default null <i>Will take the values determined by the oClasses.sStripe*
+                *    options</i>
+                *  @dtopt Option
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "asStripeClasses": [ 'strip1', 'strip2', 'strip3' ]
+                *      } );
+                *    } )
+                */
+               "asStripeClasses": null,
+       
+       
+               /**
+                * Enable or disable automatic column width calculation. This can be disabled
+                * as an optimisation (it takes some time to calculate the widths) if the
+                * tables widths are passed in using aoColumns.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bAutoWidth": false
+                *      } );
+                *    } );
+                */
+               "bAutoWidth": true,
+       
+       
+               /**
+                * Deferred rendering can provide DataTables with a huge speed boost when you
+                * are using an Ajax or JS data source for the table. This option, when set to
+                * true, will cause DataTables to defer the creation of the table elements for
+                * each row until they are needed for a draw - saving a significant amount of
+                * time.
+                *  @type boolean
+                *  @default false
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      var oTable = $('#example').dataTable( {
+                *        "sAjaxSource": "sources/arrays.txt",
+                *        "bDeferRender": true
+                *      } );
+                *    } );
+                */
+               "bDeferRender": false,
+       
+       
+               /**
+                * Replace a DataTable which matches the given selector and replace it with 
+                * one which has the properties of the new initialisation object passed. If no
+                * table matches the selector, then the new DataTable will be constructed as
+                * per normal.
+                *  @type boolean
+                *  @default false
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "sScrollY": "200px",
+                *        "bPaginate": false
+                *      } );
+                *      
+                *      // Some time later....
+                *      $('#example').dataTable( {
+                *        "bFilter": false,
+                *        "bDestroy": true
+                *      } );
+                *    } );
+                */
+               "bDestroy": false,
+       
+       
+               /**
+                * Enable or disable filtering of data. Filtering in DataTables is "smart" in
+                * that it allows the end user to input multiple words (space separated) and
+                * will match a row containing those words, even if not in the order that was
+                * specified (this allow matching across multiple columns). Note that if you
+                * wish to use filtering in DataTables this must remain 'true' - to remove the
+                * default filtering input box and retain filtering abilities, please use
+                * {@link DataTable.defaults.sDom}.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bFilter": false
+                *      } );
+                *    } );
+                */
+               "bFilter": true,
+       
+       
+               /**
+                * Enable or disable the table information display. This shows information 
+                * about the data that is currently visible on the page, including information
+                * about filtered data if that action is being performed.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bInfo": false
+                *      } );
+                *    } );
+                */
+               "bInfo": true,
+       
+       
+               /**
+                * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
+                * slightly different and additional mark-up from what DataTables has
+                * traditionally used).
+                *  @type boolean
+                *  @default false
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bJQueryUI": true
+                *      } );
+                *    } );
+                */
+               "bJQueryUI": false,
+       
+       
+               /**
+                * Allows the end user to select the size of a formatted page from a select
+                * menu (sizes are 10, 25, 50 and 100). Requires pagination (bPaginate).
+                *  @type boolean
+                *  @default true
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bLengthChange": false
+                *      } );
+                *    } );
+                */
+               "bLengthChange": true,
+       
+       
+               /**
+                * Enable or disable pagination.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bPaginate": false
+                *      } );
+                *    } );
+                */
+               "bPaginate": true,
+       
+       
+               /**
+                * Enable or disable the display of a 'processing' indicator when the table is
+                * being processed (e.g. a sort). This is particularly useful for tables with
+                * large amounts of data where it can take a noticeable amount of time to sort
+                * the entries.
+                *  @type boolean
+                *  @default false
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bProcessing": true
+                *      } );
+                *    } );
+                */
+               "bProcessing": false,
+       
+       
+               /**
+                * Retrieve the DataTables object for the given selector. Note that if the
+                * table has already been initialised, this parameter will cause DataTables
+                * to simply return the object that has already been set up - it will not take
+                * account of any changes you might have made to the initialisation object
+                * passed to DataTables (setting this parameter to true is an acknowledgement
+                * that you understand this). bDestroy can be used to reinitialise a table if
+                * you need.
+                *  @type boolean
+                *  @default false
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      initTable();
+                *      tableActions();
+                *    } );
+                *    
+                *    function initTable ()
+                *    {
+                *      return $('#example').dataTable( {
+                *        "sScrollY": "200px",
+                *        "bPaginate": false,
+                *        "bRetrieve": true
+                *      } );
+                *    }
+                *    
+                *    function tableActions ()
+                *    {
+                *      var oTable = initTable();
+                *      // perform API operations with oTable 
+                *    }
+                */
+               "bRetrieve": false,
+       
+       
+               /**
+                * Indicate if DataTables should be allowed to set the padding / margin
+                * etc for the scrolling header elements or not. Typically you will want
+                * this.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bScrollAutoCss": false,
+                *        "sScrollY": "200px"
+                *      } );
+                *    } );
+                */
+               "bScrollAutoCss": true,
+       
+       
+               /**
+                * When vertical (y) scrolling is enabled, DataTables will force the height of
+                * the table's viewport to the given height at all times (useful for layout).
+                * However, this can look odd when filtering data down to a small data set,
+                * and the footer is left "floating" further down. This parameter (when
+                * enabled) will cause DataTables to collapse the table's viewport down when
+                * the result set will fit within the given Y height.
+                *  @type boolean
+                *  @default false
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "sScrollY": "200",
+                *        "bScrollCollapse": true
+                *      } );
+                *    } );
+                */
+               "bScrollCollapse": false,
+       
+       
+               /**
+                * Enable infinite scrolling for DataTables (to be used in combination with
+                * sScrollY). Infinite scrolling means that DataTables will continually load
+                * data as a user scrolls through a table, which is very useful for large
+                * dataset. This cannot be used with pagination, which is automatically
+                * disabled. Note - the Scroller extra for DataTables is recommended in
+                * in preference to this option.
+                *  @type boolean
+                *  @default false
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bScrollInfinite": true,
+                *        "bScrollCollapse": true,
+                *        "sScrollY": "200px"
+                *      } );
+                *    } );
+                */
+               "bScrollInfinite": false,
+       
+       
+               /**
+                * Configure DataTables to use server-side processing. Note that the
+                * sAjaxSource parameter must also be given in order to give DataTables a
+                * source to obtain the required data for each draw.
+                *  @type boolean
+                *  @default false
+                *  @dtopt Features
+                *  @dtopt Server-side
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bServerSide": true,
+                *        "sAjaxSource": "xhr.php"
+                *      } );
+                *    } );
+                */
+               "bServerSide": false,
+       
+       
+               /**
+                * Enable or disable sorting of columns. Sorting of individual columns can be
+                * disabled by the "bSortable" option for each column.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bSort": false
+                *      } );
+                *    } );
+                */
+               "bSort": true,
+       
+       
+               /**
+                * Allows control over whether DataTables should use the top (true) unique
+                * cell that is found for a single column, or the bottom (false - default).
+                * This is useful when using complex headers.
+                *  @type boolean
+                *  @default false
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bSortCellsTop": true
+                *      } );
+                *    } );
+                */
+               "bSortCellsTop": false,
+       
+       
+               /**
+                * Enable or disable the addition of the classes 'sorting_1', 'sorting_2' and
+                * 'sorting_3' to the columns which are currently being sorted on. This is
+                * presented as a feature switch as it can increase processing time (while
+                * classes are removed and added) so for large data sets you might want to
+                * turn this off.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bSortClasses": false
+                *      } );
+                *    } );
+                */
+               "bSortClasses": true,
+       
+       
+               /**
+                * Enable or disable state saving. When enabled a cookie will be used to save
+                * table display information such as pagination information, display length,
+                * filtering and sorting. As such when the end user reloads the page the
+                * display display will match what thy had previously set up.
+                *  @type boolean
+                *  @default false
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "bStateSave": true
+                *      } );
+                *    } );
+                */
+               "bStateSave": false,
+       
+       
+               /**
+                * Customise the cookie and / or the parameters being stored when using
+                * DataTables with state saving enabled. This function is called whenever
+                * the cookie is modified, and it expects a fully formed cookie string to be
+                * returned. Note that the data object passed in is a Javascript object which
+                * must be converted to a string (JSON.stringify for example).
+                *  @type function
+                *  @param {string} sName Name of the cookie defined by DataTables
+                *  @param {object} oData Data to be stored in the cookie
+                *  @param {string} sExpires Cookie expires string
+                *  @param {string} sPath Path of the cookie to set
+                *  @returns {string} Cookie formatted string (which should be encoded by
+                *    using encodeURIComponent())
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function () {
+                *      $('#example').dataTable( {
+                *        "fnCookieCallback": function (sName, oData, sExpires, sPath) {
+                *          // Customise oData or sName or whatever else here
+                *          return sName + "="+JSON.stringify(oData)+"; expires=" + sExpires +"; path=" + sPath;
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnCookieCallback": null,
+       
+       
+               /**
+                * This function is called when a TR element is created (and all TD child
+                * elements have been inserted), or registered if using a DOM source, allowing
+                * manipulation of the TR element (adding classes etc).
+                *  @type function
+                *  @param {node} nRow "TR" element for the current row
+                *  @param {array} aData Raw data array for this row
+                *  @param {int} iDataIndex The index of this row in aoData
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "fnCreatedRow": function( nRow, aData, iDataIndex ) {
+                *          // Bold the grade for all 'A' grade browsers
+                *          if ( aData[4] == "A" )
+                *          {
+                *            $('td:eq(4)', nRow).html( '<b>A</b>' );
+                *          }
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnCreatedRow": null,
+       
+       
+               /**
+                * This function is called on every 'draw' event, and allows you to
+                * dynamically modify any aspect you want about the created DOM.
+                *  @type function
+                *  @param {object} oSettings DataTables settings object
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "fnDrawCallback": function( oSettings ) {
+                *          alert( 'DataTables has redrawn the table' );
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnDrawCallback": null,
+       
+       
+               /**
+                * Identical to fnHeaderCallback() but for the table footer this function
+                * allows you to modify the table footer on every 'draw' even.
+                *  @type function
+                *  @param {node} nFoot "TR" element for the footer
+                *  @param {array} aData Full table data (as derived from the original HTML)
+                *  @param {int} iStart Index for the current display starting point in the 
+                *    display array
+                *  @param {int} iEnd Index for the current display ending point in the 
+                *    display array
+                *  @param {array int} aiDisplay Index array to translate the visual position
+                *    to the full data array
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "fnFooterCallback": function( nFoot, aData, iStart, iEnd, aiDisplay ) {
+                *          nFoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+iStart;
+                *        }
+                *      } );
+                *    } )
+                */
+               "fnFooterCallback": null,
+       
+       
+               /**
+                * When rendering large numbers in the information element for the table
+                * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
+                * to have a comma separator for the 'thousands' units (e.g. 1 million is
+                * rendered as "1,000,000") to help readability for the end user. This
+                * function will override the default method DataTables uses.
+                *  @type function
+                *  @member
+                *  @param {int} iIn number to be formatted
+                *  @returns {string} formatted string for DataTables to show the number
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "fnFormatNumber": function ( iIn ) {
+                *          if ( iIn &lt; 1000 ) {
+                *            return iIn;
+                *          } else {
+                *            var 
+                *              s=(iIn+""), 
+                *              a=s.split(""), out="", 
+                *              iLen=s.length;
+                *            
+                *            for ( var i=0 ; i&lt;iLen ; i++ ) {
+                *              if ( i%3 === 0 &amp;&amp; i !== 0 ) {
+                *                out = "'"+out;
+                *              }
+                *              out = a[iLen-i-1]+out;
+                *            }
+                *          }
+                *          return out;
+                *        };
+                *      } );
+                *    } );
+                */
+               "fnFormatNumber": function ( iIn ) {
+                       if ( iIn < 1000 )
+                       {
+                               // A small optimisation for what is likely to be the majority of use cases
+                               return iIn;
+                       }
+       
+                       var s=(iIn+""), a=s.split(""), out="", iLen=s.length;
+                       
+                       for ( var i=0 ; i<iLen ; i++ )
+                       {
+                               if ( i%3 === 0 && i !== 0 )
+                               {
+                                       out = this.oLanguage.sInfoThousands+out;
+                               }
+                               out = a[iLen-i-1]+out;
+                       }
+                       return out;
+               },
+       
+       
+               /**
+                * This function is called on every 'draw' event, and allows you to
+                * dynamically modify the header row. This can be used to calculate and
+                * display useful information about the table.
+                *  @type function
+                *  @param {node} nHead "TR" element for the header
+                *  @param {array} aData Full table data (as derived from the original HTML)
+                *  @param {int} iStart Index for the current display starting point in the
+                *    display array
+                *  @param {int} iEnd Index for the current display ending point in the
+                *    display array
+                *  @param {array int} aiDisplay Index array to translate the visual position
+                *    to the full data array
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "fnHeaderCallback": function( nHead, aData, iStart, iEnd, aiDisplay ) {
+                *          nHead.getElementsByTagName('th')[0].innerHTML = "Displaying "+(iEnd-iStart)+" records";
+                *        }
+                *      } );
+                *    } )
+                */
+               "fnHeaderCallback": null,
+       
+       
+               /**
+                * The information element can be used to convey information about the current
+                * state of the table. Although the internationalisation options presented by
+                * DataTables are quite capable of dealing with most customisations, there may
+                * be times where you wish to customise the string further. This callback
+                * allows you to do exactly that.
+                *  @type function
+                *  @param {object} oSettings DataTables settings object
+                *  @param {int} iStart Starting position in data for the draw
+                *  @param {int} iEnd End position in data for the draw
+                *  @param {int} iMax Total number of rows in the table (regardless of
+                *    filtering)
+                *  @param {int} iTotal Total number of rows in the data set, after filtering
+                *  @param {string} sPre The string that DataTables has formatted using it's
+                *    own rules
+                *  @returns {string} The string to be displayed in the information element.
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $('#example').dataTable( {
+                *      "fnInfoCallback": function( oSettings, iStart, iEnd, iMax, iTotal, sPre ) {
+                *        return iStart +" to "+ iEnd;
+                *      }
+                *    } );
+                */
+               "fnInfoCallback": null,
+       
+       
+               /**
+                * Called when the table has been initialised. Normally DataTables will
+                * initialise sequentially and there will be no need for this function,
+                * however, this does not hold true when using external language information
+                * since that is obtained using an async XHR call.
+                *  @type function
+                *  @param {object} oSettings DataTables settings object
+                *  @param {object} json The JSON object request from the server - only
+                *    present if client-side Ajax sourced data is used
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "fnInitComplete": function(oSettings, json) {
+                *          alert( 'DataTables has finished its initialisation.' );
+                *        }
+                *      } );
+                *    } )
+                */
+               "fnInitComplete": null,
+       
+       
+               /**
+                * Called at the very start of each table draw and can be used to cancel the
+                * draw by returning false, any other return (including undefined) results in
+                * the full draw occurring).
+                *  @type function
+                *  @param {object} oSettings DataTables settings object
+                *  @returns {boolean} False will cancel the draw, anything else (including no
+                *    return) will allow it to complete.
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "fnPreDrawCallback": function( oSettings ) {
+                *          if ( $('#test').val() == 1 ) {
+                *            return false;
+                *          }
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnPreDrawCallback": null,
+       
+       
+               /**
+                * This function allows you to 'post process' each row after it have been
+                * generated for each table draw, but before it is rendered on screen. This
+                * function might be used for setting the row class name etc.
+                *  @type function
+                *  @param {node} nRow "TR" element for the current row
+                *  @param {array} aData Raw data array for this row
+                *  @param {int} iDisplayIndex The display index for the current table draw
+                *  @param {int} iDisplayIndexFull The index of the data in the full list of
+                *    rows (after filtering)
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "fnRowCallback": function( nRow, aData, iDisplayIndex, iDisplayIndexFull ) {
+                *          // Bold the grade for all 'A' grade browsers
+                *          if ( aData[4] == "A" )
+                *          {
+                *            $('td:eq(4)', nRow).html( '<b>A</b>' );
+                *          }
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnRowCallback": null,
+       
+       
+               /**
+                * This parameter allows you to override the default function which obtains
+                * the data from the server ($.getJSON) so something more suitable for your
+                * application. For example you could use POST data, or pull information from
+                * a Gears or AIR database.
+                *  @type function
+                *  @member
+                *  @param {string} sSource HTTP source to obtain the data from (sAjaxSource)
+                *  @param {array} aoData A key/value pair object containing the data to send
+                *    to the server
+                *  @param {function} fnCallback to be called on completion of the data get
+                *    process that will draw the data on the page.
+                *  @param {object} oSettings DataTables settings object
+                *  @dtopt Callbacks
+                *  @dtopt Server-side
+                * 
+                *  @example
+                *    // POST data to server
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bProcessing": true,
+                *        "bServerSide": true,
+                *        "sAjaxSource": "xhr.php",
+                *        "fnServerData": function ( sSource, aoData, fnCallback, oSettings ) {
+                *          oSettings.jqXHR = $.ajax( {
+                *            "dataType": 'json', 
+                *            "type": "POST", 
+                *            "url": sSource, 
+                *            "data": aoData, 
+                *            "success": fnCallback
+                *          } );
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnServerData": function ( sUrl, aoData, fnCallback, oSettings ) {
+                       oSettings.jqXHR = $.ajax( {
+                               "url":  sUrl,
+                               "data": aoData,
+                               "success": function (json) {
+                                       if ( json.sError ) {
+                                               oSettings.oApi._fnLog( oSettings, 0, json.sError );
+                                       }
+                                       
+                                       $(oSettings.oInstance).trigger('xhr', [oSettings, json]);
+                                       fnCallback( json );
+                               },
+                               "dataType": "json",
+                               "cache": false,
+                               "type": oSettings.sServerMethod,
+                               "error": function (xhr, error, thrown) {
+                                       if ( error == "parsererror" ) {
+                                               oSettings.oApi._fnLog( oSettings, 0, "DataTables warning: JSON data from "+
+                                                       "server could not be parsed. This is caused by a JSON formatting error." );
+                                       }
+                               }
+                       } );
+               },
+       
+       
+               /**
+                * It is often useful to send extra data to the server when making an Ajax
+                * request - for example custom filtering information, and this callback
+                * function makes it trivial to send extra information to the server. The
+                * passed in parameter is the data set that has been constructed by
+                * DataTables, and you can add to this or modify it as you require.
+                *  @type function
+                *  @param {array} aoData Data array (array of objects which are name/value
+                *    pairs) that has been constructed by DataTables and will be sent to the
+                *    server. In the case of Ajax sourced data with server-side processing
+                *    this will be an empty array, for server-side processing there will be a
+                *    significant number of parameters!
+                *  @returns {undefined} Ensure that you modify the aoData array passed in,
+                *    as this is passed by reference.
+                *  @dtopt Callbacks
+                *  @dtopt Server-side
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bProcessing": true,
+                *        "bServerSide": true,
+                *        "sAjaxSource": "scripts/server_processing.php",
+                *        "fnServerParams": function ( aoData ) {
+                *          aoData.push( { "name": "more_data", "value": "my_value" } );
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnServerParams": null,
+       
+       
+               /**
+                * Load the table state. With this function you can define from where, and how, the
+                * state of a table is loaded. By default DataTables will load from its state saving
+                * cookie, but you might wish to use local storage (HTML5) or a server-side database.
+                *  @type function
+                *  @member
+                *  @param {object} oSettings DataTables settings object
+                *  @return {object} The DataTables state object to be loaded
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bStateSave": true,
+                *        "fnStateLoad": function (oSettings) {
+                *          var o;
+                *          
+                *          // Send an Ajax request to the server to get the data. Note that
+                *          // this is a synchronous request.
+                *          $.ajax( {
+                *            "url": "/state_load",
+                *            "async": false,
+                *            "dataType": "json",
+                *            "success": function (json) {
+                *              o = json;
+                *            }
+                *          } );
+                *          
+                *          return o;
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnStateLoad": function ( oSettings ) {
+                       var sData = this.oApi._fnReadCookie( oSettings.sCookiePrefix+oSettings.sInstance );
+                       var oData;
+       
+                       try {
+                               oData = (typeof $.parseJSON === 'function') ? 
+                                       $.parseJSON(sData) : eval( '('+sData+')' );
+                       } catch (e) {
+                               oData = null;
+                       }
+       
+                       return oData;
+               },
+       
+       
+               /**
+                * Callback which allows modification of the saved state prior to loading that state.
+                * This callback is called when the table is loading state from the stored data, but
+                * prior to the settings object being modified by the saved state. Note that for 
+                * plug-in authors, you should use the 'stateLoadParams' event to load parameters for 
+                * a plug-in.
+                *  @type function
+                *  @param {object} oSettings DataTables settings object
+                *  @param {object} oData The state object that is to be loaded
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    // Remove a saved filter, so filtering is never loaded
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bStateSave": true,
+                *        "fnStateLoadParams": function (oSettings, oData) {
+                *          oData.oSearch.sSearch = "";
+                *        }
+                *      } );
+                *    } );
+                * 
+                *  @example
+                *    // Disallow state loading by returning false
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bStateSave": true,
+                *        "fnStateLoadParams": function (oSettings, oData) {
+                *          return false;
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnStateLoadParams": null,
+       
+       
+               /**
+                * Callback that is called when the state has been loaded from the state saving method
+                * and the DataTables settings object has been modified as a result of the loaded state.
+                *  @type function
+                *  @param {object} oSettings DataTables settings object
+                *  @param {object} oData The state object that was loaded
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    // Show an alert with the filtering value that was saved
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bStateSave": true,
+                *        "fnStateLoaded": function (oSettings, oData) {
+                *          alert( 'Saved filter was: '+oData.oSearch.sSearch );
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnStateLoaded": null,
+       
+       
+               /**
+                * Save the table state. This function allows you to define where and how the state
+                * information for the table is stored - by default it will use a cookie, but you
+                * might want to use local storage (HTML5) or a server-side database.
+                *  @type function
+                *  @member
+                *  @param {object} oSettings DataTables settings object
+                *  @param {object} oData The state object to be saved
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bStateSave": true,
+                *        "fnStateSave": function (oSettings, oData) {
+                *          // Send an Ajax request to the server with the state object
+                *          $.ajax( {
+                *            "url": "/state_save",
+                *            "data": oData,
+                *            "dataType": "json",
+                *            "method": "POST"
+                *            "success": function () {}
+                *          } );
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnStateSave": function ( oSettings, oData ) {
+                       this.oApi._fnCreateCookie( 
+                               oSettings.sCookiePrefix+oSettings.sInstance, 
+                               this.oApi._fnJsonString(oData), 
+                               oSettings.iCookieDuration, 
+                               oSettings.sCookiePrefix, 
+                               oSettings.fnCookieCallback
+                       );
+               },
+       
+       
+               /**
+                * Callback which allows modification of the state to be saved. Called when the table 
+                * has changed state a new state save is required. This method allows modification of
+                * the state saving object prior to actually doing the save, including addition or 
+                * other state properties or modification. Note that for plug-in authors, you should 
+                * use the 'stateSaveParams' event to save parameters for a plug-in.
+                *  @type function
+                *  @param {object} oSettings DataTables settings object
+                *  @param {object} oData The state object to be saved
+                *  @dtopt Callbacks
+                * 
+                *  @example
+                *    // Remove a saved filter, so filtering is never saved
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bStateSave": true,
+                *        "fnStateSaveParams": function (oSettings, oData) {
+                *          oData.oSearch.sSearch = "";
+                *        }
+                *      } );
+                *    } );
+                */
+               "fnStateSaveParams": null,
+       
+       
+               /**
+                * Duration of the cookie which is used for storing session information. This
+                * value is given in seconds.
+                *  @type int
+                *  @default 7200 <i>(2 hours)</i>
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "iCookieDuration": 60*60*24; // 1 day
+                *      } );
+                *    } )
+                */
+               "iCookieDuration": 7200,
+       
+       
+               /**
+                * When enabled DataTables will not make a request to the server for the first
+                * page draw - rather it will use the data already on the page (no sorting etc
+                * will be applied to it), thus saving on an XHR at load time. iDeferLoading
+                * is used to indicate that deferred loading is required, but it is also used
+                * to tell DataTables how many records there are in the full table (allowing
+                * the information element and pagination to be displayed correctly). In the case
+                * where a filtering is applied to the table on initial load, this can be
+                * indicated by giving the parameter as an array, where the first element is
+                * the number of records available after filtering and the second element is the
+                * number of records without filtering (allowing the table information element
+                * to be shown correctly).
+                *  @type int | array
+                *  @default null
+                *  @dtopt Options
+                * 
+                *  @example
+                *    // 57 records available in the table, no filtering applied
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bServerSide": true,
+                *        "sAjaxSource": "scripts/server_processing.php",
+                *        "iDeferLoading": 57
+                *      } );
+                *    } );
+                * 
+                *  @example
+                *    // 57 records after filtering, 100 without filtering (an initial filter applied)
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bServerSide": true,
+                *        "sAjaxSource": "scripts/server_processing.php",
+                *        "iDeferLoading": [ 57, 100 ],
+                *        "oSearch": {
+                *          "sSearch": "my_filter"
+                *        }
+                *      } );
+                *    } );
+                */
+               "iDeferLoading": null,
+       
+       
+               /**
+                * Number of rows to display on a single page when using pagination. If
+                * feature enabled (bLengthChange) then the end user will be able to override
+                * this to a custom setting using a pop-up menu.
+                *  @type int
+                *  @default 10
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "iDisplayLength": 50
+                *      } );
+                *    } )
+                */
+               "iDisplayLength": 10,
+       
+       
+               /**
+                * Define the starting point for data display when using DataTables with
+                * pagination. Note that this parameter is the number of records, rather than
+                * the page number, so if you have 10 records per page and want to start on
+                * the third page, it should be "20".
+                *  @type int
+                *  @default 0
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "iDisplayStart": 20
+                *      } );
+                *    } )
+                */
+               "iDisplayStart": 0,
+       
+       
+               /**
+                * The scroll gap is the amount of scrolling that is left to go before
+                * DataTables will load the next 'page' of data automatically. You typically
+                * want a gap which is big enough that the scrolling will be smooth for the
+                * user, while not so large that it will load more data than need.
+                *  @type int
+                *  @default 100
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bScrollInfinite": true,
+                *        "bScrollCollapse": true,
+                *        "sScrollY": "200px",
+                *        "iScrollLoadGap": 50
+                *      } );
+                *    } );
+                */
+               "iScrollLoadGap": 100,
+       
+       
+               /**
+                * By default DataTables allows keyboard navigation of the table (sorting, paging,
+                * and filtering) by adding a tabindex attribute to the required elements. This
+                * allows you to tab through the controls and press the enter key to activate them.
+                * The tabindex is default 0, meaning that the tab follows the flow of the document.
+                * You can overrule this using this parameter if you wish. Use a value of -1 to
+                * disable built-in keyboard navigation.
+                *  @type int
+                *  @default 0
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "iTabIndex": 1
+                *      } );
+                *    } );
+                */
+               "iTabIndex": 0,
+       
+       
+               /**
+                * All strings that DataTables uses in the user interface that it creates
+                * are defined in this object, allowing you to modified them individually or
+                * completely replace them all as required.
+                *  @namespace
+                */
+               "oLanguage": {
+                       /**
+                        * Strings that are used for WAI-ARIA labels and controls only (these are not
+                        * actually visible on the page, but will be read by screenreaders, and thus
+                        * must be internationalised as well).
+                        *  @namespace
+                        */
+                       "oAria": {
+                               /**
+                                * ARIA label that is added to the table headers when the column may be
+                                * sorted ascending by activing the column (click or return when focused).
+                                * Note that the column header is prefixed to this string.
+                                *  @type string
+                                *  @default : activate to sort column ascending
+                                *  @dtopt Language
+                                * 
+                                *  @example
+                                *    $(document).ready( function() {
+                                *      $('#example').dataTable( {
+                                *        "oLanguage": {
+                                *          "oAria": {
+                                *            "sSortAscending": " - click/return to sort ascending"
+                                *          }
+                                *        }
+                                *      } );
+                                *    } );
+                                */
+                               "sSortAscending": ": activate to sort column ascending",
+       
+                               /**
+                                * ARIA label that is added to the table headers when the column may be
+                                * sorted descending by activing the column (click or return when focused).
+                                * Note that the column header is prefixed to this string.
+                                *  @type string
+                                *  @default : activate to sort column ascending
+                                *  @dtopt Language
+                                * 
+                                *  @example
+                                *    $(document).ready( function() {
+                                *      $('#example').dataTable( {
+                                *        "oLanguage": {
+                                *          "oAria": {
+                                *            "sSortDescending": " - click/return to sort descending"
+                                *          }
+                                *        }
+                                *      } );
+                                *    } );
+                                */
+                               "sSortDescending": ": activate to sort column descending"
+                       },
+       
+                       /**
+                        * Pagination string used by DataTables for the two built-in pagination
+                        * control types ("two_button" and "full_numbers")
+                        *  @namespace
+                        */
+                       "oPaginate": {
+                               /**
+                                * Text to use when using the 'full_numbers' type of pagination for the
+                                * button to take the user to the first page.
+                                *  @type string
+                                *  @default First
+                                *  @dtopt Language
+                                * 
+                                *  @example
+                                *    $(document).ready( function() {
+                                *      $('#example').dataTable( {
+                                *        "oLanguage": {
+                                *          "oPaginate": {
+                                *            "sFirst": "First page"
+                                *          }
+                                *        }
+                                *      } );
+                                *    } );
+                                */
+                               "sFirst": "First",
+                       
+                       
+                               /**
+                                * Text to use when using the 'full_numbers' type of pagination for the
+                                * button to take the user to the last page.
+                                *  @type string
+                                *  @default Last
+                                *  @dtopt Language
+                                * 
+                                *  @example
+                                *    $(document).ready( function() {
+                                *      $('#example').dataTable( {
+                                *        "oLanguage": {
+                                *          "oPaginate": {
+                                *            "sLast": "Last page"
+                                *          }
+                                *        }
+                                *      } );
+                                *    } );
+                                */
+                               "sLast": "Last",
+                       
+                       
+                               /**
+                                * Text to use for the 'next' pagination button (to take the user to the 
+                                * next page).
+                                *  @type string
+                                *  @default Next
+                                *  @dtopt Language
+                                * 
+                                *  @example
+                                *    $(document).ready( function() {
+                                *      $('#example').dataTable( {
+                                *        "oLanguage": {
+                                *          "oPaginate": {
+                                *            "sNext": "Next page"
+                                *          }
+                                *        }
+                                *      } );
+                                *    } );
+                                */
+                               "sNext": "Next",
+                       
+                       
+                               /**
+                                * Text to use for the 'previous' pagination button (to take the user to  
+                                * the previous page).
+                                *  @type string
+                                *  @default Previous
+                                *  @dtopt Language
+                                * 
+                                *  @example
+                                *    $(document).ready( function() {
+                                *      $('#example').dataTable( {
+                                *        "oLanguage": {
+                                *          "oPaginate": {
+                                *            "sPrevious": "Previous page"
+                                *          }
+                                *        }
+                                *      } );
+                                *    } );
+                                */
+                               "sPrevious": "Previous"
+                       },
+               
+                       /**
+                        * This string is shown in preference to sZeroRecords when the table is
+                        * empty of data (regardless of filtering). Note that this is an optional
+                        * parameter - if it is not given, the value of sZeroRecords will be used
+                        * instead (either the default or given value).
+                        *  @type string
+                        *  @default No data available in table
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sEmptyTable": "No data available in table"
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sEmptyTable": "No data available in table",
+               
+               
+                       /**
+                        * This string gives information to the end user about the information that 
+                        * is current on display on the page. The _START_, _END_ and _TOTAL_ 
+                        * variables are all dynamically replaced as the table display updates, and 
+                        * can be freely moved or removed as the language requirements change.
+                        *  @type string
+                        *  @default Showing _START_ to _END_ of _TOTAL_ entries
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sInfo": "Got a total of _TOTAL_ entries to show (_START_ to _END_)"
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
+               
+               
+                       /**
+                        * Display information string for when the table is empty. Typically the 
+                        * format of this string should match sInfo.
+                        *  @type string
+                        *  @default Showing 0 to 0 of 0 entries
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sInfoEmpty": "No entries to show"
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sInfoEmpty": "Showing 0 to 0 of 0 entries",
+               
+               
+                       /**
+                        * When a user filters the information in a table, this string is appended 
+                        * to the information (sInfo) to give an idea of how strong the filtering 
+                        * is. The variable _MAX_ is dynamically updated.
+                        *  @type string
+                        *  @default (filtered from _MAX_ total entries)
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sInfoFiltered": " - filtering from _MAX_ records"
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sInfoFiltered": "(filtered from _MAX_ total entries)",
+               
+               
+                       /**
+                        * If can be useful to append extra information to the info string at times,
+                        * and this variable does exactly that. This information will be appended to
+                        * the sInfo (sInfoEmpty and sInfoFiltered in whatever combination they are
+                        * being used) at all times.
+                        *  @type string
+                        *  @default <i>Empty string</i>
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sInfoPostFix": "All records shown are derived from real information."
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sInfoPostFix": "",
+               
+               
+                       /**
+                        * DataTables has a build in number formatter (fnFormatNumber) which is used
+                        * to format large numbers that are used in the table information. By
+                        * default a comma is used, but this can be trivially changed to any
+                        * character you wish with this parameter.
+                        *  @type string
+                        *  @default ,
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sInfoThousands": "'"
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sInfoThousands": ",",
+               
+               
+                       /**
+                        * Detail the action that will be taken when the drop down menu for the
+                        * pagination length option is changed. The '_MENU_' variable is replaced
+                        * with a default select list of 10, 25, 50 and 100, and can be replaced
+                        * with a custom select box if required.
+                        *  @type string
+                        *  @default Show _MENU_ entries
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    // Language change only
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sLengthMenu": "Display _MENU_ records"
+                        *        }
+                        *      } );
+                        *    } );
+                        *    
+                        *  @example
+                        *    // Language and options change
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sLengthMenu": 'Display <select>'+
+                        *            '<option value="10">10</option>'+
+                        *            '<option value="20">20</option>'+
+                        *            '<option value="30">30</option>'+
+                        *            '<option value="40">40</option>'+
+                        *            '<option value="50">50</option>'+
+                        *            '<option value="-1">All</option>'+
+                        *            '</select> records'
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sLengthMenu": "Show _MENU_ entries",
+               
+               
+                       /**
+                        * When using Ajax sourced data and during the first draw when DataTables is
+                        * gathering the data, this message is shown in an empty row in the table to
+                        * indicate to the end user the the data is being loaded. Note that this
+                        * parameter is not used when loading data by server-side processing, just
+                        * Ajax sourced data with client-side processing.
+                        *  @type string
+                        *  @default Loading...
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sLoadingRecords": "Please wait - loading..."
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sLoadingRecords": "Loading...",
+               
+               
+                       /**
+                        * Text which is displayed when the table is processing a user action
+                        * (usually a sort command or similar).
+                        *  @type string
+                        *  @default Processing...
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sProcessing": "DataTables is currently busy"
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sProcessing": "Processing...",
+               
+               
+                       /**
+                        * Details the actions that will be taken when the user types into the
+                        * filtering input text box. The variable "_INPUT_", if used in the string,
+                        * is replaced with the HTML text box for the filtering input allowing
+                        * control over where it appears in the string. If "_INPUT_" is not given
+                        * then the input box is appended to the string automatically.
+                        *  @type string
+                        *  @default Search:
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    // Input text box will be appended at the end automatically
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sSearch": "Filter records:"
+                        *        }
+                        *      } );
+                        *    } );
+                        *    
+                        *  @example
+                        *    // Specify where the filter should appear
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sSearch": "Apply filter _INPUT_ to table"
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sSearch": "Search:",
+               
+               
+                       /**
+                        * All of the language information can be stored in a file on the
+                        * server-side, which DataTables will look up if this parameter is passed.
+                        * It must store the URL of the language file, which is in a JSON format,
+                        * and the object has the same properties as the oLanguage object in the
+                        * initialiser object (i.e. the above parameters). Please refer to one of
+                        * the example language files to see how this works in action.
+                        *  @type string
+                        *  @default <i>Empty string - i.e. disabled</i>
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sUrl": "http://www.sprymedia.co.uk/dataTables/lang.txt"
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sUrl": "",
+               
+               
+                       /**
+                        * Text shown inside the table records when the is no information to be
+                        * displayed after filtering. sEmptyTable is shown when there is simply no
+                        * information in the table at all (regardless of filtering).
+                        *  @type string
+                        *  @default No matching records found
+                        *  @dtopt Language
+                        * 
+                        *  @example
+                        *    $(document).ready( function() {
+                        *      $('#example').dataTable( {
+                        *        "oLanguage": {
+                        *          "sZeroRecords": "No records to display"
+                        *        }
+                        *      } );
+                        *    } );
+                        */
+                       "sZeroRecords": "No matching records found"
+               },
+       
+       
+               /**
+                * This parameter allows you to have define the global filtering state at
+                * initialisation time. As an object the "sSearch" parameter must be
+                * defined, but all other parameters are optional. When "bRegex" is true,
+                * the search string will be treated as a regular expression, when false
+                * (default) it will be treated as a straight string. When "bSmart"
+                * DataTables will use it's smart filtering methods (to word match at
+                * any point in the data), when false this will not be done.
+                *  @namespace
+                *  @extends DataTable.models.oSearch
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "oSearch": {"sSearch": "Initial search"}
+                *      } );
+                *    } )
+                */
+               "oSearch": $.extend( {}, DataTable.models.oSearch ),
+       
+       
+               /**
+                * By default DataTables will look for the property 'aaData' when obtaining
+                * data from an Ajax source or for server-side processing - this parameter
+                * allows that property to be changed. You can use Javascript dotted object
+                * notation to get a data source for multiple levels of nesting.
+                *  @type string
+                *  @default aaData
+                *  @dtopt Options
+                *  @dtopt Server-side
+                * 
+                *  @example
+                *    // Get data from { "data": [...] }
+                *    $(document).ready( function() {
+                *      var oTable = $('#example').dataTable( {
+                *        "sAjaxSource": "sources/data.txt",
+                *        "sAjaxDataProp": "data"
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Get data from { "data": { "inner": [...] } }
+                *    $(document).ready( function() {
+                *      var oTable = $('#example').dataTable( {
+                *        "sAjaxSource": "sources/data.txt",
+                *        "sAjaxDataProp": "data.inner"
+                *      } );
+                *    } );
+                */
+               "sAjaxDataProp": "aaData",
+       
+       
+               /**
+                * You can instruct DataTables to load data from an external source using this
+                * parameter (use aData if you want to pass data in you already have). Simply
+                * provide a url a JSON object can be obtained from. This object must include
+                * the parameter 'aaData' which is the data source for the table.
+                *  @type string
+                *  @default null
+                *  @dtopt Options
+                *  @dtopt Server-side
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "sAjaxSource": "http://www.sprymedia.co.uk/dataTables/json.php"
+                *      } );
+                *    } )
+                */
+               "sAjaxSource": null,
+       
+       
+               /**
+                * This parameter can be used to override the default prefix that DataTables
+                * assigns to a cookie when state saving is enabled.
+                *  @type string
+                *  @default SpryMedia_DataTables_
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "sCookiePrefix": "my_datatable_",
+                *      } );
+                *    } );
+                */
+               "sCookiePrefix": "SpryMedia_DataTables_",
+       
+       
+               /**
+                * This initialisation variable allows you to specify exactly where in the
+                * DOM you want DataTables to inject the various controls it adds to the page
+                * (for example you might want the pagination controls at the top of the
+                * table). DIV elements (with or without a custom class) can also be added to
+                * aid styling. The follow syntax is used:
+                *   <ul>
+                *     <li>The following options are allowed:   
+                *       <ul>
+                *         <li>'l' - Length changing</li
+                *         <li>'f' - Filtering input</li>
+                *         <li>'t' - The table!</li>
+                *         <li>'i' - Information</li>
+                *         <li>'p' - Pagination</li>
+                *         <li>'r' - pRocessing</li>
+                *       </ul>
+                *     </li>
+                *     <li>The following constants are allowed:
+                *       <ul>
+                *         <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
+                *         <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
+                *       </ul>
+                *     </li>
+                *     <li>The following syntax is expected:
+                *       <ul>
+                *         <li>'&lt;' and '&gt;' - div elements</li>
+                *         <li>'&lt;"class" and '&gt;' - div with a class</li>
+                *         <li>'&lt;"#id" and '&gt;' - div with an ID</li>
+                *       </ul>
+                *     </li>
+                *     <li>Examples:
+                *       <ul>
+                *         <li>'&lt;"wrapper"flipt&gt;'</li>
+                *         <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
+                *       </ul>
+                *     </li>
+                *   </ul>
+                *  @type string
+                *  @default lfrtip <i>(when bJQueryUI is false)</i> <b>or</b> 
+                *    <"H"lfr>t<"F"ip> <i>(when bJQueryUI is true)</i>
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "sDom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
+                *      } );
+                *    } );
+                */
+               "sDom": "lfrtip",
+       
+       
+               /**
+                * DataTables features two different built-in pagination interaction methods
+                * ('two_button' or 'full_numbers') which present different page controls to
+                * the end user. Further methods can be added using the API (see below).
+                *  @type string
+                *  @default two_button
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "sPaginationType": "full_numbers"
+                *      } );
+                *    } )
+                */
+               "sPaginationType": "two_button",
+       
+       
+               /**
+                * Enable horizontal scrolling. When a table is too wide to fit into a certain
+                * layout, or you have a large number of columns in the table, you can enable
+                * x-scrolling to show the table in a viewport, which can be scrolled. This
+                * property can be any CSS unit, or a number (in which case it will be treated
+                * as a pixel measurement).
+                *  @type string
+                *  @default <i>blank string - i.e. disabled</i>
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "sScrollX": "100%",
+                *        "bScrollCollapse": true
+                *      } );
+                *    } );
+                */
+               "sScrollX": "",
+       
+       
+               /**
+                * This property can be used to force a DataTable to use more width than it
+                * might otherwise do when x-scrolling is enabled. For example if you have a
+                * table which requires to be well spaced, this parameter is useful for
+                * "over-sizing" the table, and thus forcing scrolling. This property can by
+                * any CSS unit, or a number (in which case it will be treated as a pixel
+                * measurement).
+                *  @type string
+                *  @default <i>blank string - i.e. disabled</i>
+                *  @dtopt Options
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "sScrollX": "100%",
+                *        "sScrollXInner": "110%"
+                *      } );
+                *    } );
+                */
+               "sScrollXInner": "",
+       
+       
+               /**
+                * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
+                * to the given height, and enable scrolling for any data which overflows the
+                * current viewport. This can be used as an alternative to paging to display
+                * a lot of data in a small area (although paging and scrolling can both be
+                * enabled at the same time). This property can be any CSS unit, or a number
+                * (in which case it will be treated as a pixel measurement).
+                *  @type string
+                *  @default <i>blank string - i.e. disabled</i>
+                *  @dtopt Features
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "sScrollY": "200px",
+                *        "bPaginate": false
+                *      } );
+                *    } );
+                */
+               "sScrollY": "",
+       
+       
+               /**
+                * Set the HTTP method that is used to make the Ajax call for server-side
+                * processing or Ajax sourced data.
+                *  @type string
+                *  @default GET
+                *  @dtopt Options
+                *  @dtopt Server-side
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "bServerSide": true,
+                *        "sAjaxSource": "scripts/post.php",
+                *        "sServerMethod": "POST"
+                *      } );
+                *    } );
+                */
+               "sServerMethod": "GET"
+       };
+       
+       
+       
+       /**
+        * Column options that can be given to DataTables at initialisation time.
+        *  @namespace
+        */
+       DataTable.defaults.columns = {
+               /**
+                * Allows a column's sorting to take multiple columns into account when 
+                * doing a sort. For example first name / last name columns make sense to 
+                * do a multi-column sort over the two columns.
+                *  @type array
+                *  @default null <i>Takes the value of the column index automatically</i>
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [
+                *          { "aDataSort": [ 0, 1 ], "aTargets": [ 0 ] },
+                *          { "aDataSort": [ 1, 0 ], "aTargets": [ 1 ] },
+                *          { "aDataSort": [ 2, 3, 4 ], "aTargets": [ 2 ] }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [
+                *          { "aDataSort": [ 0, 1 ] },
+                *          { "aDataSort": [ 1, 0 ] },
+                *          { "aDataSort": [ 2, 3, 4 ] },
+                *          null,
+                *          null
+                *        ]
+                *      } );
+                *    } );
+                */
+               "aDataSort": null,
+       
+       
+               /**
+                * You can control the default sorting direction, and even alter the behaviour
+                * of the sort handler (i.e. only allow ascending sorting etc) using this
+                * parameter.
+                *  @type array
+                *  @default [ 'asc', 'desc' ]
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [
+                *          { "asSorting": [ "asc" ], "aTargets": [ 1 ] },
+                *          { "asSorting": [ "desc", "asc", "asc" ], "aTargets": [ 2 ] },
+                *          { "asSorting": [ "desc" ], "aTargets": [ 3 ] }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [
+                *          null,
+                *          { "asSorting": [ "asc" ] },
+                *          { "asSorting": [ "desc", "asc", "asc" ] },
+                *          { "asSorting": [ "desc" ] },
+                *          null
+                *        ]
+                *      } );
+                *    } );
+                */
+               "asSorting": [ 'asc', 'desc' ],
+       
+       
+               /**
+                * Enable or disable filtering on the data in this column.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          { "bSearchable": false, "aTargets": [ 0 ] }
+                *        ] } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          { "bSearchable": false },
+                *          null,
+                *          null,
+                *          null,
+                *          null
+                *        ] } );
+                *    } );
+                */
+               "bSearchable": true,
+       
+       
+               /**
+                * Enable or disable sorting on this column.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          { "bSortable": false, "aTargets": [ 0 ] }
+                *        ] } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          { "bSortable": false },
+                *          null,
+                *          null,
+                *          null,
+                *          null
+                *        ] } );
+                *    } );
+                */
+               "bSortable": true,
+       
+       
+               /**
+                * <code>Deprecated</code> When using fnRender() for a column, you may wish 
+                * to use the original data (before rendering) for sorting and filtering 
+                * (the default is to used the rendered data that the user can see). This 
+                * may be useful for dates etc.
+                * 
+                * Please note that this option has now been deprecated and will be removed
+                * in the next version of DataTables. Please use mRender / mData rather than
+                * fnRender.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Columns
+                *  @deprecated
+                */
+               "bUseRendered": true,
+       
+       
+               /**
+                * Enable or disable the display of this column.
+                *  @type boolean
+                *  @default true
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          { "bVisible": false, "aTargets": [ 0 ] }
+                *        ] } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          { "bVisible": false },
+                *          null,
+                *          null,
+                *          null,
+                *          null
+                *        ] } );
+                *    } );
+                */
+               "bVisible": true,
+               
+               
+               /**
+                * Developer definable function that is called whenever a cell is created (Ajax source,
+                * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+                * allowing you to modify the DOM element (add background colour for example) when the
+                * element is available.
+                *  @type function
+                *  @param {element} nTd The TD node that has been created
+                *  @param {*} sData The Data for the cell
+                *  @param {array|object} oData The data for the whole row
+                *  @param {int} iRow The row index for the aoData data store
+                *  @param {int} iCol The column index for aoColumns
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ {
+                *          "aTargets": [3],
+                *          "fnCreatedCell": function (nTd, sData, oData, iRow, iCol) {
+                *            if ( sData == "1.7" ) {
+                *              $(nTd).css('color', 'blue')
+                *            }
+                *          }
+                *        } ]
+                *      });
+                *    } );
+                */
+               "fnCreatedCell": null,
+       
+       
+               /**
+                * <code>Deprecated</code> Custom display function that will be called for the 
+                * display of each cell in this column.
+                *
+                * Please note that this option has now been deprecated and will be removed
+                * in the next version of DataTables. Please use mRender / mData rather than
+                * fnRender.
+                *  @type function
+                *  @param {object} o Object with the following parameters:
+                *  @param {int}    o.iDataRow The row in aoData
+                *  @param {int}    o.iDataColumn The column in question
+                *  @param {array}  o.aData The data for the row in question
+                *  @param {object} o.oSettings The settings object for this DataTables instance
+                *  @param {object} o.mDataProp The data property used for this column
+                *  @param {*}      val The current cell value
+                *  @returns {string} The string you which to use in the display
+                *  @dtopt Columns
+                *  @deprecated
+                */
+               "fnRender": null,
+       
+       
+               /**
+                * The column index (starting from 0!) that you wish a sort to be performed
+                * upon when this column is selected for sorting. This can be used for sorting
+                * on hidden columns for example.
+                *  @type int
+                *  @default -1 <i>Use automatically calculated column index</i>
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          { "iDataSort": 1, "aTargets": [ 0 ] }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          { "iDataSort": 1 },
+                *          null,
+                *          null,
+                *          null,
+                *          null
+                *        ]
+                *      } );
+                *    } );
+                */
+               "iDataSort": -1,
+       
+       
+               /**
+                * This parameter has been replaced by mData in DataTables to ensure naming
+                * consistency. mDataProp can still be used, as there is backwards compatibility
+                * in DataTables for this option, but it is strongly recommended that you use
+                * mData in preference to mDataProp.
+                *  @name DataTable.defaults.columns.mDataProp
+                */
+       
+       
+               /**
+                * This property can be used to read data from any JSON data source property,
+                * including deeply nested objects / properties. mData can be given in a
+                * number of different ways which effect its behaviour:
+                *   <ul>
+                *     <li>integer - treated as an array index for the data source. This is the
+                *       default that DataTables uses (incrementally increased for each column).</li>
+                *     <li>string - read an object property from the data source. Note that you can
+                *       use Javascript dotted notation to read deep properties / arrays from the
+                *       data source.</li>
+                *     <li>null - the sDefaultContent option will be used for the cell (null
+                *       by default, so you will need to specify the default content you want -
+                *       typically an empty string). This can be useful on generated columns such 
+                *       as edit / delete action columns.</li>
+                *     <li>function - the function given will be executed whenever DataTables 
+                *       needs to set or get the data for a cell in the column. The function 
+                *       takes three parameters:
+                *       <ul>
+                *         <li>{array|object} The data source for the row</li>
+                *         <li>{string} The type call data requested - this will be 'set' when
+                *           setting data or 'filter', 'display', 'type', 'sort' or undefined when 
+                *           gathering data. Note that when <i>undefined</i> is given for the type
+                *           DataTables expects to get the raw data for the object back</li>
+                *         <li>{*} Data to set when the second parameter is 'set'.</li>
+                *       </ul>
+                *       The return value from the function is not required when 'set' is the type
+                *       of call, but otherwise the return is what will be used for the data
+                *       requested.</li>
+                *    </ul>
+                *
+                * Note that prior to DataTables 1.9.2 mData was called mDataProp. The name change
+                * reflects the flexibility of this property and is consistent with the naming of
+                * mRender. If 'mDataProp' is given, then it will still be used by DataTables, as
+                * it automatically maps the old name to the new if required.
+                *  @type string|int|function|null
+                *  @default null <i>Use automatically calculated column index</i>
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Read table data from objects
+                *    $(document).ready( function() {
+                *      var oTable = $('#example').dataTable( {
+                *        "sAjaxSource": "sources/deep.txt",
+                *        "aoColumns": [
+                *          { "mData": "engine" },
+                *          { "mData": "browser" },
+                *          { "mData": "platform.inner" },
+                *          { "mData": "platform.details.0" },
+                *          { "mData": "platform.details.1" }
+                *        ]
+                *      } );
+                *    } );
+                * 
+                *  @example
+                *    // Using mData as a function to provide different information for
+                *    // sorting, filtering and display. In this case, currency (price)
+                *    $(document).ready( function() {
+                *      var oTable = $('#example').dataTable( {
+                *        "aoColumnDefs": [ {
+                *          "aTargets": [ 0 ],
+                *          "mData": function ( source, type, val ) {
+                *            if (type === 'set') {
+                *              source.price = val;
+                *              // Store the computed dislay and filter values for efficiency
+                *              source.price_display = val=="" ? "" : "$"+numberFormat(val);
+                *              source.price_filter  = val=="" ? "" : "$"+numberFormat(val)+" "+val;
+                *              return;
+                *            }
+                *            else if (type === 'display') {
+                *              return source.price_display;
+                *            }
+                *            else if (type === 'filter') {
+                *              return source.price_filter;
+                *            }
+                *            // 'sort', 'type' and undefined all just use the integer
+                *            return source.price;
+                *          }
+                *        } ]
+                *      } );
+                *    } );
+                */
+               "mData": null,
+       
+       
+               /**
+                * This property is the rendering partner to mData and it is suggested that
+                * when you want to manipulate data for display (including filtering, sorting etc)
+                * but not altering the underlying data for the table, use this property. mData
+                * can actually do everything this property can and more, but this parameter is
+                * easier to use since there is no 'set' option. Like mData is can be given
+                * in a number of different ways to effect its behaviour, with the addition of 
+                * supporting array syntax for easy outputting of arrays (including arrays of
+                * objects):
+                *   <ul>
+                *     <li>integer - treated as an array index for the data source. This is the
+                *       default that DataTables uses (incrementally increased for each column).</li>
+                *     <li>string - read an object property from the data source. Note that you can
+                *       use Javascript dotted notation to read deep properties / arrays from the
+                *       data source and also array brackets to indicate that the data reader should
+                *       loop over the data source array. When characters are given between the array
+                *       brackets, these characters are used to join the data source array together.
+                *       For example: "accounts[, ].name" would result in a comma separated list with
+                *       the 'name' value from the 'accounts' array of objects.</li>
+                *     <li>function - the function given will be executed whenever DataTables 
+                *       needs to set or get the data for a cell in the column. The function 
+                *       takes three parameters:
+                *       <ul>
+                *         <li>{array|object} The data source for the row (based on mData)</li>
+                *         <li>{string} The type call data requested - this will be 'filter', 'display', 
+                *           'type' or 'sort'.</li>
+                *         <li>{array|object} The full data source for the row (not based on mData)</li>
+                *       </ul>
+                *       The return value from the function is what will be used for the data
+                *       requested.</li>
+                *    </ul>
+                *  @type string|int|function|null
+                *  @default null <i>Use mData</i>
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Create a comma separated list from an array of objects
+                *    $(document).ready( function() {
+                *      var oTable = $('#example').dataTable( {
+                *        "sAjaxSource": "sources/deep.txt",
+                *        "aoColumns": [
+                *          { "mData": "engine" },
+                *          { "mData": "browser" },
+                *          {
+                *            "mData": "platform",
+                *            "mRender": "[, ].name"
+                *          }
+                *        ]
+                *      } );
+                *    } );
+                * 
+                *  @example
+                *    // Use as a function to create a link from the data source
+                *    $(document).ready( function() {
+                *      var oTable = $('#example').dataTable( {
+                *        "aoColumnDefs": [
+                *        {
+                *          "aTargets": [ 0 ],
+                *          "mData": "download_link",
+                *          "mRender": function ( data, type, full ) {
+                *            return '<a href="'+data+'">Download</a>';
+                *          }
+                *        ]
+                *      } );
+                *    } );
+                */
+               "mRender": null,
+       
+       
+               /**
+                * Change the cell type created for the column - either TD cells or TH cells. This
+                * can be useful as TH cells have semantic meaning in the table body, allowing them
+                * to act as a header for a row (you may wish to add scope='row' to the TH elements).
+                *  @type string
+                *  @default td
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Make the first column use TH cells
+                *    $(document).ready( function() {
+                *      var oTable = $('#example').dataTable( {
+                *        "aoColumnDefs": [ {
+                *          "aTargets": [ 0 ],
+                *          "sCellType": "th"
+                *        } ]
+                *      } );
+                *    } );
+                */
+               "sCellType": "td",
+       
+       
+               /**
+                * Class to give to each cell in this column.
+                *  @type string
+                *  @default <i>Empty string</i>
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          { "sClass": "my_class", "aTargets": [ 0 ] }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          { "sClass": "my_class" },
+                *          null,
+                *          null,
+                *          null,
+                *          null
+                *        ]
+                *      } );
+                *    } );
+                */
+               "sClass": "",
+               
+               /**
+                * When DataTables calculates the column widths to assign to each column,
+                * it finds the longest string in each column and then constructs a
+                * temporary table and reads the widths from that. The problem with this
+                * is that "mmm" is much wider then "iiii", but the latter is a longer 
+                * string - thus the calculation can go wrong (doing it properly and putting
+                * it into an DOM object and measuring that is horribly(!) slow). Thus as
+                * a "work around" we provide this option. It will append its value to the
+                * text that is found to be the longest string for the column - i.e. padding.
+                * Generally you shouldn't need this, and it is not documented on the 
+                * general DataTables.net documentation
+                *  @type string
+                *  @default <i>Empty string<i>
+                *  @dtopt Columns
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          null,
+                *          null,
+                *          null,
+                *          {
+                *            "sContentPadding": "mmm"
+                *          }
+                *        ]
+                *      } );
+                *    } );
+                */
+               "sContentPadding": "",
+       
+       
+               /**
+                * Allows a default value to be given for a column's data, and will be used
+                * whenever a null data source is encountered (this can be because mData
+                * is set to null, or because the data source itself is null).
+                *  @type string
+                *  @default null
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          {
+                *            "mData": null,
+                *            "sDefaultContent": "Edit",
+                *            "aTargets": [ -1 ]
+                *          }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          null,
+                *          null,
+                *          null,
+                *          {
+                *            "mData": null,
+                *            "sDefaultContent": "Edit"
+                *          }
+                *        ]
+                *      } );
+                *    } );
+                */
+               "sDefaultContent": null,
+       
+       
+               /**
+                * This parameter is only used in DataTables' server-side processing. It can
+                * be exceptionally useful to know what columns are being displayed on the
+                * client side, and to map these to database fields. When defined, the names
+                * also allow DataTables to reorder information from the server if it comes
+                * back in an unexpected order (i.e. if you switch your columns around on the
+                * client-side, your server-side code does not also need updating).
+                *  @type string
+                *  @default <i>Empty string</i>
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          { "sName": "engine", "aTargets": [ 0 ] },
+                *          { "sName": "browser", "aTargets": [ 1 ] },
+                *          { "sName": "platform", "aTargets": [ 2 ] },
+                *          { "sName": "version", "aTargets": [ 3 ] },
+                *          { "sName": "grade", "aTargets": [ 4 ] }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          { "sName": "engine" },
+                *          { "sName": "browser" },
+                *          { "sName": "platform" },
+                *          { "sName": "version" },
+                *          { "sName": "grade" }
+                *        ]
+                *      } );
+                *    } );
+                */
+               "sName": "",
+       
+       
+               /**
+                * Defines a data source type for the sorting which can be used to read
+                * real-time information from the table (updating the internally cached
+                * version) prior to sorting. This allows sorting to occur on user editable
+                * elements such as form inputs.
+                *  @type string
+                *  @default std
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [
+                *          { "sSortDataType": "dom-text", "aTargets": [ 2, 3 ] },
+                *          { "sType": "numeric", "aTargets": [ 3 ] },
+                *          { "sSortDataType": "dom-select", "aTargets": [ 4 ] },
+                *          { "sSortDataType": "dom-checkbox", "aTargets": [ 5 ] }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [
+                *          null,
+                *          null,
+                *          { "sSortDataType": "dom-text" },
+                *          { "sSortDataType": "dom-text", "sType": "numeric" },
+                *          { "sSortDataType": "dom-select" },
+                *          { "sSortDataType": "dom-checkbox" }
+                *        ]
+                *      } );
+                *    } );
+                */
+               "sSortDataType": "std",
+       
+       
+               /**
+                * The title of this column.
+                *  @type string
+                *  @default null <i>Derived from the 'TH' value for this column in the 
+                *    original HTML table.</i>
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          { "sTitle": "My column title", "aTargets": [ 0 ] }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          { "sTitle": "My column title" },
+                *          null,
+                *          null,
+                *          null,
+                *          null
+                *        ]
+                *      } );
+                *    } );
+                */
+               "sTitle": null,
+       
+       
+               /**
+                * The type allows you to specify how the data for this column will be sorted.
+                * Four types (string, numeric, date and html (which will strip HTML tags
+                * before sorting)) are currently available. Note that only date formats
+                * understood by Javascript's Date() object will be accepted as type date. For
+                * example: "Mar 26, 2008 5:03 PM". May take the values: 'string', 'numeric',
+                * 'date' or 'html' (by default). Further types can be adding through
+                * plug-ins.
+                *  @type string
+                *  @default null <i>Auto-detected from raw data</i>
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          { "sType": "html", "aTargets": [ 0 ] }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          { "sType": "html" },
+                *          null,
+                *          null,
+                *          null,
+                *          null
+                *        ]
+                *      } );
+                *    } );
+                */
+               "sType": null,
+       
+       
+               /**
+                * Defining the width of the column, this parameter may take any CSS value
+                * (3em, 20px etc). DataTables apples 'smart' widths to columns which have not
+                * been given a specific width through this interface ensuring that the table
+                * remains readable.
+                *  @type string
+                *  @default null <i>Automatic</i>
+                *  @dtopt Columns
+                * 
+                *  @example
+                *    // Using aoColumnDefs
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumnDefs": [ 
+                *          { "sWidth": "20%", "aTargets": [ 0 ] }
+                *        ]
+                *      } );
+                *    } );
+                *    
+                *  @example
+                *    // Using aoColumns
+                *    $(document).ready( function() {
+                *      $('#example').dataTable( {
+                *        "aoColumns": [ 
+                *          { "sWidth": "20%" },
+                *          null,
+                *          null,
+                *          null,
+                *          null
+                *        ]
+                *      } );
+                *    } );
+                */
+               "sWidth": null
+       };
+       
+       
+       
+       /**
+        * DataTables settings object - this holds all the information needed for a
+        * given table, including configuration, data and current application of the
+        * table options. DataTables does not have a single instance for each DataTable
+        * with the settings attached to that instance, but rather instances of the
+        * DataTable "class" are created on-the-fly as needed (typically by a 
+        * $().dataTable() call) and the settings object is then applied to that
+        * instance.
+        * 
+        * Note that this object is related to {@link DataTable.defaults} but this 
+        * one is the internal data store for DataTables's cache of columns. It should
+        * NOT be manipulated outside of DataTables. Any configuration should be done
+        * through the initialisation options.
+        *  @namespace
+        *  @todo Really should attach the settings object to individual instances so we
+        *    don't need to create new instances on each $().dataTable() call (if the
+        *    table already exists). It would also save passing oSettings around and
+        *    into every single function. However, this is a very significant 
+        *    architecture change for DataTables and will almost certainly break
+        *    backwards compatibility with older installations. This is something that
+        *    will be done in 2.0.
+        */
+       DataTable.models.oSettings = {
+               /**
+                * Primary features of DataTables and their enablement state.
+                *  @namespace
+                */
+               "oFeatures": {
+                       
+                       /**
+                        * Flag to say if DataTables should automatically try to calculate the
+                        * optimum table and columns widths (true) or not (false).
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bAutoWidth": null,
+       
+                       /**
+                        * Delay the creation of TR and TD elements until they are actually
+                        * needed by a driven page draw. This can give a significant speed
+                        * increase for Ajax source and Javascript source data, but makes no
+                        * difference at all fro DOM and server-side processing tables.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bDeferRender": null,
+                       
+                       /**
+                        * Enable filtering on the table or not. Note that if this is disabled
+                        * then there is no filtering at all on the table, including fnFilter.
+                        * To just remove the filtering input use sDom and remove the 'f' option.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bFilter": null,
+                       
+                       /**
+                        * Table information element (the 'Showing x of y records' div) enable
+                        * flag.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bInfo": null,
+                       
+                       /**
+                        * Present a user control allowing the end user to change the page size
+                        * when pagination is enabled.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bLengthChange": null,
+       
+                       /**
+                        * Pagination enabled or not. Note that if this is disabled then length
+                        * changing must also be disabled.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bPaginate": null,
+                       
+                       /**
+                        * Processing indicator enable flag whenever DataTables is enacting a
+                        * user request - typically an Ajax request for server-side processing.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bProcessing": null,
+                       
+                       /**
+                        * Server-side processing enabled flag - when enabled DataTables will
+                        * get all data from the server for every draw - there is no filtering,
+                        * sorting or paging done on the client-side.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bServerSide": null,
+                       
+                       /**
+                        * Sorting enablement flag.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bSort": null,
+                       
+                       /**
+                        * Apply a class to the columns which are being sorted to provide a
+                        * visual highlight or not. This can slow things down when enabled since
+                        * there is a lot of DOM interaction.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bSortClasses": null,
+                       
+                       /**
+                        * State saving enablement flag.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bStateSave": null
+               },
+               
+       
+               /**
+                * Scrolling settings for a table.
+                *  @namespace
+                */
+               "oScroll": {
+                       /**
+                        * Indicate if DataTables should be allowed to set the padding / margin
+                        * etc for the scrolling header elements or not. Typically you will want
+                        * this.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bAutoCss": null,
+                       
+                       /**
+                        * When the table is shorter in height than sScrollY, collapse the
+                        * table container down to the height of the table (when true).
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bCollapse": null,
+                       
+                       /**
+                        * Infinite scrolling enablement flag. Now deprecated in favour of
+                        * using the Scroller plug-in.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type boolean
+                        */
+                       "bInfinite": null,
+                       
+                       /**
+                        * Width of the scrollbar for the web-browser's platform. Calculated
+                        * during table initialisation.
+                        *  @type int
+                        *  @default 0
+                        */
+                       "iBarWidth": 0,
+                       
+                       /**
+                        * Space (in pixels) between the bottom of the scrolling container and 
+                        * the bottom of the scrolling viewport before the next page is loaded
+                        * when using infinite scrolling.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type int
+                        */
+                       "iLoadGap": null,
+                       
+                       /**
+                        * Viewport width for horizontal scrolling. Horizontal scrolling is 
+                        * disabled if an empty string.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type string
+                        */
+                       "sX": null,
+                       
+                       /**
+                        * Width to expand the table to when using x-scrolling. Typically you
+                        * should not need to use this.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type string
+                        *  @deprecated
+                        */
+                       "sXInner": null,
+                       
+                       /**
+                        * Viewport height for vertical scrolling. Vertical scrolling is disabled
+                        * if an empty string.
+                        * Note that this parameter will be set by the initialisation routine. To
+                        * set a default use {@link DataTable.defaults}.
+                        *  @type string
+                        */
+                       "sY": null
+               },
+               
+               /**
+                * Language information for the table.
+                *  @namespace
+                *  @extends DataTable.defaults.oLanguage
+                */
+               "oLanguage": {
+                       /**
+                        * Information callback function. See 
+                        * {@link DataTable.defaults.fnInfoCallback}
+                        *  @type function
+                        *  @default null
+                        */
+                       "fnInfoCallback": null
+               },
+               
+               /**
+                * Browser support parameters
+                *  @namespace
+                */
+               "oBrowser": {
+                       /**
+                        * Indicate if the browser incorrectly calculates width:100% inside a
+                        * scrolling element (IE6/7)
+                        *  @type boolean
+                        *  @default false
+                        */
+                       "bScrollOversize": false
+               },
+               
+               /**
+                * Array referencing the nodes which are used for the features. The 
+                * parameters of this object match what is allowed by sDom - i.e.
+                *   <ul>
+                *     <li>'l' - Length changing</li>
+                *     <li>'f' - Filtering input</li>
+                *     <li>'t' - The table!</li>
+                *     <li>'i' - Information</li>
+                *     <li>'p' - Pagination</li>
+                *     <li>'r' - pRocessing</li>
+                *   </ul>
+                *  @type array
+                *  @default []
+                */
+               "aanFeatures": [],
+               
+               /**
+                * Store data information - see {@link DataTable.models.oRow} for detailed
+                * information.
+                *  @type array
+                *  @default []
+                */
+               "aoData": [],
+               
+               /**
+                * Array of indexes which are in the current display (after filtering etc)
+                *  @type array
+                *  @default []
+                */
+               "aiDisplay": [],
+               
+               /**
+                * Array of indexes for display - no filtering
+                *  @type array
+                *  @default []
+                */
+               "aiDisplayMaster": [],
+               
+               /**
+                * Store information about each column that is in use
+                *  @type array
+                *  @default []
+                */
+               "aoColumns": [],
+               
+               /**
+                * Store information about the table's header
+                *  @type array
+                *  @default []
+                */
+               "aoHeader": [],
+               
+               /**
+                * Store information about the table's footer
+                *  @type array
+                *  @default []
+                */
+               "aoFooter": [],
+               
+               /**
+                * Search data array for regular expression searching
+                *  @type array
+                *  @default []
+                */
+               "asDataSearch": [],
+               
+               /**
+                * Store the applied global search information in case we want to force a 
+                * research or compare the old search to a new one.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @namespace
+                *  @extends DataTable.models.oSearch
+                */
+               "oPreviousSearch": {},
+               
+               /**
+                * Store the applied search for each column - see 
+                * {@link DataTable.models.oSearch} for the format that is used for the
+                * filtering information for each column.
+                *  @type array
+                *  @default []
+                */
+               "aoPreSearchCols": [],
+               
+               /**
+                * Sorting that is applied to the table. Note that the inner arrays are
+                * used in the following manner:
+                * <ul>
+                *   <li>Index 0 - column number</li>
+                *   <li>Index 1 - current sorting direction</li>
+                *   <li>Index 2 - index of asSorting for this column</li>
+                * </ul>
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type array
+                *  @todo These inner arrays should really be objects
+                */
+               "aaSorting": null,
+               
+               /**
+                * Sorting that is always applied to the table (i.e. prefixed in front of
+                * aaSorting).
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type array|null
+                *  @default null
+                */
+               "aaSortingFixed": null,
+               
+               /**
+                * Classes to use for the striping of a table.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type array
+                *  @default []
+                */
+               "asStripeClasses": null,
+               
+               /**
+                * If restoring a table - we should restore its striping classes as well
+                *  @type array
+                *  @default []
+                */
+               "asDestroyStripes": [],
+               
+               /**
+                * If restoring a table - we should restore its width 
+                *  @type int
+                *  @default 0
+                */
+               "sDestroyWidth": 0,
+               
+               /**
+                * Callback functions array for every time a row is inserted (i.e. on a draw).
+                *  @type array
+                *  @default []
+                */
+               "aoRowCallback": [],
+               
+               /**
+                * Callback functions for the header on each draw.
+                *  @type array
+                *  @default []
+                */
+               "aoHeaderCallback": [],
+               
+               /**
+                * Callback function for the footer on each draw.
+                *  @type array
+                *  @default []
+                */
+               "aoFooterCallback": [],
+               
+               /**
+                * Array of callback functions for draw callback functions
+                *  @type array
+                *  @default []
+                */
+               "aoDrawCallback": [],
+               
+               /**
+                * Array of callback functions for row created function
+                *  @type array
+                *  @default []
+                */
+               "aoRowCreatedCallback": [],
+               
+               /**
+                * Callback functions for just before the table is redrawn. A return of 
+                * false will be used to cancel the draw.
+                *  @type array
+                *  @default []
+                */
+               "aoPreDrawCallback": [],
+               
+               /**
+                * Callback functions for when the table has been initialised.
+                *  @type array
+                *  @default []
+                */
+               "aoInitComplete": [],
+       
+               
+               /**
+                * Callbacks for modifying the settings to be stored for state saving, prior to
+                * saving state.
+                *  @type array
+                *  @default []
+                */
+               "aoStateSaveParams": [],
+               
+               /**
+                * Callbacks for modifying the settings that have been stored for state saving
+                * prior to using the stored values to restore the state.
+                *  @type array
+                *  @default []
+                */
+               "aoStateLoadParams": [],
+               
+               /**
+                * Callbacks for operating on the settings object once the saved state has been
+                * loaded
+                *  @type array
+                *  @default []
+                */
+               "aoStateLoaded": [],
+               
+               /**
+                * Cache the table ID for quick access
+                *  @type string
+                *  @default <i>Empty string</i>
+                */
+               "sTableId": "",
+               
+               /**
+                * The TABLE node for the main table
+                *  @type node
+                *  @default null
+                */
+               "nTable": null,
+               
+               /**
+                * Permanent ref to the thead element
+                *  @type node
+                *  @default null
+                */
+               "nTHead": null,
+               
+               /**
+                * Permanent ref to the tfoot element - if it exists
+                *  @type node
+                *  @default null
+                */
+               "nTFoot": null,
+               
+               /**
+                * Permanent ref to the tbody element
+                *  @type node
+                *  @default null
+                */
+               "nTBody": null,
+               
+               /**
+                * Cache the wrapper node (contains all DataTables controlled elements)
+                *  @type node
+                *  @default null
+                */
+               "nTableWrapper": null,
+               
+               /**
+                * Indicate if when using server-side processing the loading of data 
+                * should be deferred until the second draw.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type boolean
+                *  @default false
+                */
+               "bDeferLoading": false,
+               
+               /**
+                * Indicate if all required information has been read in
+                *  @type boolean
+                *  @default false
+                */
+               "bInitialised": false,
+               
+               /**
+                * Information about open rows. Each object in the array has the parameters
+                * 'nTr' and 'nParent'
+                *  @type array
+                *  @default []
+                */
+               "aoOpenRows": [],
+               
+               /**
+                * Dictate the positioning of DataTables' control elements - see
+                * {@link DataTable.model.oInit.sDom}.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type string
+                *  @default null
+                */
+               "sDom": null,
+               
+               /**
+                * Which type of pagination should be used.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type string 
+                *  @default two_button
+                */
+               "sPaginationType": "two_button",
+               
+               /**
+                * The cookie duration (for bStateSave) in seconds.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type int
+                *  @default 0
+                */
+               "iCookieDuration": 0,
+               
+               /**
+                * The cookie name prefix.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type string
+                *  @default <i>Empty string</i>
+                */
+               "sCookiePrefix": "",
+               
+               /**
+                * Callback function for cookie creation.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type function
+                *  @default null
+                */
+               "fnCookieCallback": null,
+               
+               /**
+                * Array of callback functions for state saving. Each array element is an 
+                * object with the following parameters:
+                *   <ul>
+                *     <li>function:fn - function to call. Takes two parameters, oSettings
+                *       and the JSON string to save that has been thus far created. Returns
+                *       a JSON string to be inserted into a json object 
+                *       (i.e. '"param": [ 0, 1, 2]')</li>
+                *     <li>string:sName - name of callback</li>
+                *   </ul>
+                *  @type array
+                *  @default []
+                */
+               "aoStateSave": [],
+               
+               /**
+                * Array of callback functions for state loading. Each array element is an 
+                * object with the following parameters:
+                *   <ul>
+                *     <li>function:fn - function to call. Takes two parameters, oSettings 
+                *       and the object stored. May return false to cancel state loading</li>
+                *     <li>string:sName - name of callback</li>
+                *   </ul>
+                *  @type array
+                *  @default []
+                */
+               "aoStateLoad": [],
+               
+               /**
+                * State that was loaded from the cookie. Useful for back reference
+                *  @type object
+                *  @default null
+                */
+               "oLoadedState": null,
+               
+               /**
+                * Source url for AJAX data for the table.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type string
+                *  @default null
+                */
+               "sAjaxSource": null,
+               
+               /**
+                * Property from a given object from which to read the table data from. This
+                * can be an empty string (when not server-side processing), in which case 
+                * it is  assumed an an array is given directly.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type string
+                */
+               "sAjaxDataProp": null,
+               
+               /**
+                * Note if draw should be blocked while getting data
+                *  @type boolean
+                *  @default true
+                */
+               "bAjaxDataGet": true,
+               
+               /**
+                * The last jQuery XHR object that was used for server-side data gathering. 
+                * This can be used for working with the XHR information in one of the 
+                * callbacks
+                *  @type object
+                *  @default null
+                */
+               "jqXHR": null,
+               
+               /**
+                * Function to get the server-side data.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type function
+                */
+               "fnServerData": null,
+               
+               /**
+                * Functions which are called prior to sending an Ajax request so extra 
+                * parameters can easily be sent to the server
+                *  @type array
+                *  @default []
+                */
+               "aoServerParams": [],
+               
+               /**
+                * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if 
+                * required).
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type string
+                */
+               "sServerMethod": null,
+               
+               /**
+                * Format numbers for display.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type function
+                */
+               "fnFormatNumber": null,
+               
+               /**
+                * List of options that can be used for the user selectable length menu.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type array
+                *  @default []
+                */
+               "aLengthMenu": null,
+               
+               /**
+                * Counter for the draws that the table does. Also used as a tracker for
+                * server-side processing
+                *  @type int
+                *  @default 0
+                */
+               "iDraw": 0,
+               
+               /**
+                * Indicate if a redraw is being done - useful for Ajax
+                *  @type boolean
+                *  @default false
+                */
+               "bDrawing": false,
+               
+               /**
+                * Draw index (iDraw) of the last error when parsing the returned data
+                *  @type int
+                *  @default -1
+                */
+               "iDrawError": -1,
+               
+               /**
+                * Paging display length
+                *  @type int
+                *  @default 10
+                */
+               "_iDisplayLength": 10,
+       
+               /**
+                * Paging start point - aiDisplay index
+                *  @type int
+                *  @default 0
+                */
+               "_iDisplayStart": 0,
+       
+               /**
+                * Paging end point - aiDisplay index. Use fnDisplayEnd rather than
+                * this property to get the end point
+                *  @type int
+                *  @default 10
+                *  @private
+                */
+               "_iDisplayEnd": 10,
+               
+               /**
+                * Server-side processing - number of records in the result set
+                * (i.e. before filtering), Use fnRecordsTotal rather than
+                * this property to get the value of the number of records, regardless of
+                * the server-side processing setting.
+                *  @type int
+                *  @default 0
+                *  @private
+                */
+               "_iRecordsTotal": 0,
+       
+               /**
+                * Server-side processing - number of records in the current display set
+                * (i.e. after filtering). Use fnRecordsDisplay rather than
+                * this property to get the value of the number of records, regardless of
+                * the server-side processing setting.
+                *  @type boolean
+                *  @default 0
+                *  @private
+                */
+               "_iRecordsDisplay": 0,
+               
+               /**
+                * Flag to indicate if jQuery UI marking and classes should be used.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type boolean
+                */
+               "bJUI": null,
+               
+               /**
+                * The classes to use for the table
+                *  @type object
+                *  @default {}
+                */
+               "oClasses": {},
+               
+               /**
+                * Flag attached to the settings object so you can check in the draw 
+                * callback if filtering has been done in the draw. Deprecated in favour of
+                * events.
+                *  @type boolean
+                *  @default false
+                *  @deprecated
+                */
+               "bFiltered": false,
+               
+               /**
+                * Flag attached to the settings object so you can check in the draw 
+                * callback if sorting has been done in the draw. Deprecated in favour of
+                * events.
+                *  @type boolean
+                *  @default false
+                *  @deprecated
+                */
+               "bSorted": false,
+               
+               /**
+                * Indicate that if multiple rows are in the header and there is more than 
+                * one unique cell per column, if the top one (true) or bottom one (false) 
+                * should be used for sorting / title by DataTables.
+                * Note that this parameter will be set by the initialisation routine. To
+                * set a default use {@link DataTable.defaults}.
+                *  @type boolean
+                */
+               "bSortCellsTop": null,
+               
+               /**
+                * Initialisation object that is used for the table
+                *  @type object
+                *  @default null
+                */
+               "oInit": null,
+               
+               /**
+                * Destroy callback functions - for plug-ins to attach themselves to the
+                * destroy so they can clean up markup and events.
+                *  @type array
+                *  @default []
+                */
+               "aoDestroyCallback": [],
+       
+               
+               /**
+                * Get the number of records in the current record set, before filtering
+                *  @type function
+                */
+               "fnRecordsTotal": function ()
+               {
+                       if ( this.oFeatures.bServerSide ) {
+                               return parseInt(this._iRecordsTotal, 10);
+                       } else {
+                               return this.aiDisplayMaster.length;
+                       }
+               },
+               
+               /**
+                * Get the number of records in the current record set, after filtering
+                *  @type function
+                */
+               "fnRecordsDisplay": function ()
+               {
+                       if ( this.oFeatures.bServerSide ) {
+                               return parseInt(this._iRecordsDisplay, 10);
+                       } else {
+                               return this.aiDisplay.length;
+                       }
+               },
+               
+               /**
+                * Set the display end point - aiDisplay index
+                *  @type function
+                *  @todo Should do away with _iDisplayEnd and calculate it on-the-fly here
+                */
+               "fnDisplayEnd": function ()
+               {
+                       if ( this.oFeatures.bServerSide ) {
+                               if ( this.oFeatures.bPaginate === false || this._iDisplayLength == -1 ) {
+                                       return this._iDisplayStart+this.aiDisplay.length;
+                               } else {
+                                       return Math.min( this._iDisplayStart+this._iDisplayLength, 
+                                               this._iRecordsDisplay );
+                               }
+                       } else {
+                               return this._iDisplayEnd;
+                       }
+               },
+               
+               /**
+                * The DataTables object for this table
+                *  @type object
+                *  @default null
+                */
+               "oInstance": null,
+               
+               /**
+                * Unique identifier for each instance of the DataTables object. If there
+                * is an ID on the table node, then it takes that value, otherwise an
+                * incrementing internal counter is used.
+                *  @type string
+                *  @default null
+                */
+               "sInstance": null,
+       
+               /**
+                * tabindex attribute value that is added to DataTables control elements, allowing
+                * keyboard navigation of the table and its controls.
+                */
+               "iTabIndex": 0,
+       
+               /**
+                * DIV container for the footer scrolling table if scrolling
+                */
+               "nScrollHead": null,
+       
+               /**
+                * DIV container for the footer scrolling table if scrolling
+                */
+               "nScrollFoot": null
+       };
+
+       /**
+        * Extension object for DataTables that is used to provide all extension options.
+        * 
+        * Note that the <i>DataTable.ext</i> object is available through
+        * <i>jQuery.fn.dataTable.ext</i> where it may be accessed and manipulated. It is
+        * also aliased to <i>jQuery.fn.dataTableExt</i> for historic reasons.
+        *  @namespace
+        *  @extends DataTable.models.ext
+        */
+       DataTable.ext = $.extend( true, {}, DataTable.models.ext );
+       
+       $.extend( DataTable.ext.oStdClasses, {
+               "sTable": "dataTable",
+       
+               /* Two buttons buttons */
+               "sPagePrevEnabled": "paginate_enabled_previous",
+               "sPagePrevDisabled": "paginate_disabled_previous",
+               "sPageNextEnabled": "paginate_enabled_next",
+               "sPageNextDisabled": "paginate_disabled_next",
+               "sPageJUINext": "",
+               "sPageJUIPrev": "",
+               
+               /* Full numbers paging buttons */
+               "sPageButton": "paginate_button",
+               "sPageButtonActive": "paginate_active",
+               "sPageButtonStaticDisabled": "paginate_button paginate_button_disabled",
+               "sPageFirst": "first",
+               "sPagePrevious": "previous",
+               "sPageNext": "next",
+               "sPageLast": "last",
+               
+               /* Striping classes */
+               "sStripeOdd": "odd",
+               "sStripeEven": "even",
+               
+               /* Empty row */
+               "sRowEmpty": "dataTables_empty",
+               
+               /* Features */
+               "sWrapper": "dataTables_wrapper",
+               "sFilter": "dataTables_filter",
+               "sInfo": "dataTables_info",
+               "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
+               "sLength": "dataTables_length",
+               "sProcessing": "dataTables_processing",
+               
+               /* Sorting */
+               "sSortAsc": "sorting_asc",
+               "sSortDesc": "sorting_desc",
+               "sSortable": "sorting", /* Sortable in both directions */
+               "sSortableAsc": "sorting_asc_disabled",
+               "sSortableDesc": "sorting_desc_disabled",
+               "sSortableNone": "sorting_disabled",
+               "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+               "sSortJUIAsc": "",
+               "sSortJUIDesc": "",
+               "sSortJUI": "",
+               "sSortJUIAscAllowed": "",
+               "sSortJUIDescAllowed": "",
+               "sSortJUIWrapper": "",
+               "sSortIcon": "",
+               
+               /* Scrolling */
+               "sScrollWrapper": "dataTables_scroll",
+               "sScrollHead": "dataTables_scrollHead",
+               "sScrollHeadInner": "dataTables_scrollHeadInner",
+               "sScrollBody": "dataTables_scrollBody",
+               "sScrollFoot": "dataTables_scrollFoot",
+               "sScrollFootInner": "dataTables_scrollFootInner",
+               
+               /* Misc */
+               "sFooterTH": "",
+               "sJUIHeader": "",
+               "sJUIFooter": ""
+       } );
+       
+       
+       $.extend( DataTable.ext.oJUIClasses, DataTable.ext.oStdClasses, {
+               /* Two buttons buttons */
+               "sPagePrevEnabled": "fg-button ui-button ui-state-default ui-corner-left",
+               "sPagePrevDisabled": "fg-button ui-button ui-state-default ui-corner-left ui-state-disabled",
+               "sPageNextEnabled": "fg-button ui-button ui-state-default ui-corner-right",
+               "sPageNextDisabled": "fg-button ui-button ui-state-default ui-corner-right ui-state-disabled",
+               "sPageJUINext": "ui-icon ui-icon-circle-arrow-e",
+               "sPageJUIPrev": "ui-icon ui-icon-circle-arrow-w",
+               
+               /* Full numbers paging buttons */
+               "sPageButton": "fg-button ui-button ui-state-default",
+               "sPageButtonActive": "fg-button ui-button ui-state-default ui-state-disabled",
+               "sPageButtonStaticDisabled": "fg-button ui-button ui-state-default ui-state-disabled",
+               "sPageFirst": "first ui-corner-tl ui-corner-bl",
+               "sPageLast": "last ui-corner-tr ui-corner-br",
+               
+               /* Features */
+               "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
+                       "ui-buttonset-multi paging_", /* Note that the type is postfixed */
+               
+               /* Sorting */
+               "sSortAsc": "ui-state-default",
+               "sSortDesc": "ui-state-default",
+               "sSortable": "ui-state-default",
+               "sSortableAsc": "ui-state-default",
+               "sSortableDesc": "ui-state-default",
+               "sSortableNone": "ui-state-default",
+               "sSortJUIAsc": "css_right ui-icon ui-icon-triangle-1-n",
+               "sSortJUIDesc": "css_right ui-icon ui-icon-triangle-1-s",
+               "sSortJUI": "css_right ui-icon ui-icon-carat-2-n-s",
+               "sSortJUIAscAllowed": "css_right ui-icon ui-icon-carat-1-n",
+               "sSortJUIDescAllowed": "css_right ui-icon ui-icon-carat-1-s",
+               "sSortJUIWrapper": "DataTables_sort_wrapper",
+               "sSortIcon": "DataTables_sort_icon",
+               
+               /* Scrolling */
+               "sScrollHead": "dataTables_scrollHead ui-state-default",
+               "sScrollFoot": "dataTables_scrollFoot ui-state-default",
+               
+               /* Misc */
+               "sFooterTH": "ui-state-default",
+               "sJUIHeader": "fg-toolbar ui-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix",
+               "sJUIFooter": "fg-toolbar ui-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix"
+       } );
+       
+       /*
+        * Variable: oPagination
+        * Purpose:  
+        * Scope:    jQuery.fn.dataTableExt
+        */
+       $.extend( DataTable.ext.oPagination, {
+               /*
+                * Variable: two_button
+                * Purpose:  Standard two button (forward/back) pagination
+                * Scope:    jQuery.fn.dataTableExt.oPagination
+                */
+               "two_button": {
+                       /*
+                        * Function: oPagination.two_button.fnInit
+                        * Purpose:  Initialise dom elements required for pagination with forward/back buttons only
+                        * Returns:  -
+                        * Inputs:   object:oSettings - dataTables settings object
+                        *           node:nPaging - the DIV which contains this pagination control
+                        *           function:fnCallbackDraw - draw function which must be called on update
+                        */
+                       "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
+                       {
+                               var oLang = oSettings.oLanguage.oPaginate;
+                               var oClasses = oSettings.oClasses;
+                               var fnClickHandler = function ( e ) {
+                                       if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
+                                       {
+                                               fnCallbackDraw( oSettings );
+                                       }
+                               };
+       
+                               var sAppend = (!oSettings.bJUI) ?
+                                       '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sPrevious+'</a>'+
+                                       '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button">'+oLang.sNext+'</a>'
+                                       :
+                                       '<a class="'+oSettings.oClasses.sPagePrevDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUIPrev+'"></span></a>'+
+                                       '<a class="'+oSettings.oClasses.sPageNextDisabled+'" tabindex="'+oSettings.iTabIndex+'" role="button"><span class="'+oSettings.oClasses.sPageJUINext+'"></span></a>';
+                               $(nPaging).append( sAppend );
+                               
+                               var els = $('a', nPaging);
+                               var nPrevious = els[0],
+                                       nNext = els[1];
+                               
+                               oSettings.oApi._fnBindAction( nPrevious, {action: "previous"}, fnClickHandler );
+                               oSettings.oApi._fnBindAction( nNext,     {action: "next"},     fnClickHandler );
+                               
+                               /* ID the first elements only */
+                               if ( !oSettings.aanFeatures.p )
+                               {
+                                       nPaging.id = oSettings.sTableId+'_paginate';
+                                       nPrevious.id = oSettings.sTableId+'_previous';
+                                       nNext.id = oSettings.sTableId+'_next';
+       
+                                       nPrevious.setAttribute('aria-controls', oSettings.sTableId);
+                                       nNext.setAttribute('aria-controls', oSettings.sTableId);
+                               }
+                       },
+                       
+                       /*
+                        * Function: oPagination.two_button.fnUpdate
+                        * Purpose:  Update the two button pagination at the end of the draw
+                        * Returns:  -
+                        * Inputs:   object:oSettings - dataTables settings object
+                        *           function:fnCallbackDraw - draw function to call on page change
+                        */
+                       "fnUpdate": function ( oSettings, fnCallbackDraw )
+                       {
+                               if ( !oSettings.aanFeatures.p )
+                               {
+                                       return;
+                               }
+                               
+                               var oClasses = oSettings.oClasses;
+                               var an = oSettings.aanFeatures.p;
+                               var nNode;
+       
+                               /* Loop over each instance of the pager */
+                               for ( var i=0, iLen=an.length ; i<iLen ; i++ )
+                               {
+                                       nNode = an[i].firstChild;
+                                       if ( nNode )
+                                       {
+                                               /* Previous page */
+                                               nNode.className = ( oSettings._iDisplayStart === 0 ) ?
+                                                   oClasses.sPagePrevDisabled : oClasses.sPagePrevEnabled;
+                                                   
+                                               /* Next page */
+                                               nNode = nNode.nextSibling;
+                                               nNode.className = ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ) ?
+                                                   oClasses.sPageNextDisabled : oClasses.sPageNextEnabled;
+                                       }
+                               }
+                       }
+               },
+               
+               
+               /*
+                * Variable: iFullNumbersShowPages
+                * Purpose:  Change the number of pages which can be seen
+                * Scope:    jQuery.fn.dataTableExt.oPagination
+                */
+               "iFullNumbersShowPages": 5,
+               
+               /*
+                * Variable: full_numbers
+                * Purpose:  Full numbers pagination
+                * Scope:    jQuery.fn.dataTableExt.oPagination
+                */
+               "full_numbers": {
+                       /*
+                        * Function: oPagination.full_numbers.fnInit
+                        * Purpose:  Initialise dom elements required for pagination with a list of the pages
+                        * Returns:  -
+                        * Inputs:   object:oSettings - dataTables settings object
+                        *           node:nPaging - the DIV which contains this pagination control
+                        *           function:fnCallbackDraw - draw function which must be called on update
+                        */
+                       "fnInit": function ( oSettings, nPaging, fnCallbackDraw )
+                       {
+                               var oLang = oSettings.oLanguage.oPaginate;
+                               var oClasses = oSettings.oClasses;
+                               var fnClickHandler = function ( e ) {
+                                       if ( oSettings.oApi._fnPageChange( oSettings, e.data.action ) )
+                                       {
+                                               fnCallbackDraw( oSettings );
+                                       }
+                               };
+       
+                               $(nPaging).append(
+                                       '<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageFirst+'">'+oLang.sFirst+'</a>'+
+                                       '<a  tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPagePrevious+'">'+oLang.sPrevious+'</a>'+
+                                       '<span></span>'+
+                                       '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageNext+'">'+oLang.sNext+'</a>'+
+                                       '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+" "+oClasses.sPageLast+'">'+oLang.sLast+'</a>'
+                               );
+                               var els = $('a', nPaging);
+                               var nFirst = els[0],
+                                       nPrev = els[1],
+                                       nNext = els[2],
+                                       nLast = els[3];
+                               
+                               oSettings.oApi._fnBindAction( nFirst, {action: "first"},    fnClickHandler );
+                               oSettings.oApi._fnBindAction( nPrev,  {action: "previous"}, fnClickHandler );
+                               oSettings.oApi._fnBindAction( nNext,  {action: "next"},     fnClickHandler );
+                               oSettings.oApi._fnBindAction( nLast,  {action: "last"},     fnClickHandler );
+                               
+                               /* ID the first elements only */
+                               if ( !oSettings.aanFeatures.p )
+                               {
+                                       nPaging.id = oSettings.sTableId+'_paginate';
+                                       nFirst.id =oSettings.sTableId+'_first';
+                                       nPrev.id =oSettings.sTableId+'_previous';
+                                       nNext.id =oSettings.sTableId+'_next';
+                                       nLast.id =oSettings.sTableId+'_last';
+                               }
+                       },
+                       
+                       /*
+                        * Function: oPagination.full_numbers.fnUpdate
+                        * Purpose:  Update the list of page buttons shows
+                        * Returns:  -
+                        * Inputs:   object:oSettings - dataTables settings object
+                        *           function:fnCallbackDraw - draw function to call on page change
+                        */
+                       "fnUpdate": function ( oSettings, fnCallbackDraw )
+                       {
+                               if ( !oSettings.aanFeatures.p )
+                               {
+                                       return;
+                               }
+                               
+                               var iPageCount = DataTable.ext.oPagination.iFullNumbersShowPages;
+                               var iPageCountHalf = Math.floor(iPageCount / 2);
+                               var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
+                               var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1;
+                               var sList = "";
+                               var iStartButton, iEndButton, i, iLen;
+                               var oClasses = oSettings.oClasses;
+                               var anButtons, anStatic, nPaginateList, nNode;
+                               var an = oSettings.aanFeatures.p;
+                               var fnBind = function (j) {
+                                       oSettings.oApi._fnBindAction( this, {"page": j+iStartButton-1}, function(e) {
+                                               /* Use the information in the element to jump to the required page */
+                                               oSettings.oApi._fnPageChange( oSettings, e.data.page );
+                                               fnCallbackDraw( oSettings );
+                                               e.preventDefault();
+                                       } );
+                               };
+                               
+                               /* Pages calculation */
+                               if ( oSettings._iDisplayLength === -1 )
+                               {
+                                       iStartButton = 1;
+                                       iEndButton = 1;
+                                       iCurrentPage = 1;
+                               }
+                               else if (iPages < iPageCount)
+                               {
+                                       iStartButton = 1;
+                                       iEndButton = iPages;
+                               }
+                               else if (iCurrentPage <= iPageCountHalf)
+                               {
+                                       iStartButton = 1;
+                                       iEndButton = iPageCount;
+                               }
+                               else if (iCurrentPage >= (iPages - iPageCountHalf))
+                               {
+                                       iStartButton = iPages - iPageCount + 1;
+                                       iEndButton = iPages;
+                               }
+                               else
+                               {
+                                       iStartButton = iCurrentPage - Math.ceil(iPageCount / 2) + 1;
+                                       iEndButton = iStartButton + iPageCount - 1;
+                               }
+       
+                               
+                               /* Build the dynamic list */
+                               for ( i=iStartButton ; i<=iEndButton ; i++ )
+                               {
+                                       sList += (iCurrentPage !== i) ?
+                                               '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButton+'">'+oSettings.fnFormatNumber(i)+'</a>' :
+                                               '<a tabindex="'+oSettings.iTabIndex+'" class="'+oClasses.sPageButtonActive+'">'+oSettings.fnFormatNumber(i)+'</a>';
+                               }
+                               
+                               /* Loop over each instance of the pager */
+                               for ( i=0, iLen=an.length ; i<iLen ; i++ )
+                               {
+                                       nNode = an[i];
+                                       if ( !nNode.hasChildNodes() )
+                                       {
+                                               continue;
+                                       }
+                                       
+                                       /* Build up the dynamic list first - html and listeners */
+                                       $('span:eq(0)', nNode)
+                                               .html( sList )
+                                               .children('a').each( fnBind );
+                                       
+                                       /* Update the permanent button's classes */
+                                       anButtons = nNode.getElementsByTagName('a');
+                                       anStatic = [
+                                               anButtons[0], anButtons[1], 
+                                               anButtons[anButtons.length-2], anButtons[anButtons.length-1]
+                                       ];
+       
+                                       $(anStatic).removeClass( oClasses.sPageButton+" "+oClasses.sPageButtonActive+" "+oClasses.sPageButtonStaticDisabled );
+                                       $([anStatic[0], anStatic[1]]).addClass( 
+                                               (iCurrentPage==1) ?
+                                                       oClasses.sPageButtonStaticDisabled :
+                                                       oClasses.sPageButton
+                                       );
+                                       $([anStatic[2], anStatic[3]]).addClass(
+                                               (iPages===0 || iCurrentPage===iPages || oSettings._iDisplayLength===-1) ?
+                                                       oClasses.sPageButtonStaticDisabled :
+                                                       oClasses.sPageButton
+                                       );
+                               }
+                       }
+               }
+       } );
+       
+       $.extend( DataTable.ext.oSort, {
+               /*
+                * text sorting
+                */
+               "string-pre": function ( a )
+               {
+                       if ( typeof a != 'string' ) {
+                               a = (a !== null && a.toString) ? a.toString() : '';
+                       }
+                       return a.toLowerCase();
+               },
+       
+               "string-asc": function ( x, y )
+               {
+                       return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+               },
+               
+               "string-desc": function ( x, y )
+               {
+                       return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+               },
+               
+               
+               /*
+                * html sorting (ignore html tags)
+                */
+               "html-pre": function ( a )
+               {
+                       return a.replace( /<.*?>/g, "" ).toLowerCase();
+               },
+               
+               "html-asc": function ( x, y )
+               {
+                       return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+               },
+               
+               "html-desc": function ( x, y )
+               {
+                       return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+               },
+               
+               
+               /*
+                * date sorting
+                */
+               "date-pre": function ( a )
+               {
+                       var x = Date.parse( a );
+                       
+                       if ( isNaN(x) || x==="" )
+                       {
+                               x = Date.parse( "01/01/1970 00:00:00" );
+                       }
+                       return x;
+               },
+       
+               "date-asc": function ( x, y )
+               {
+                       return x - y;
+               },
+               
+               "date-desc": function ( x, y )
+               {
+                       return y - x;
+               },
+               
+               
+               /*
+                * numerical sorting
+                */
+               "numeric-pre": function ( a )
+               {
+                       return (a=="-" || a==="") ? 0 : a*1;
+               },
+       
+               "numeric-asc": function ( x, y )
+               {
+                       return x - y;
+               },
+               
+               "numeric-desc": function ( x, y )
+               {
+                       return y - x;
+               }
+       } );
+       
+       
+       $.extend( DataTable.ext.aTypes, [
+               /*
+                * Function: -
+                * Purpose:  Check to see if a string is numeric
+                * Returns:  string:'numeric' or null
+                * Inputs:   mixed:sText - string to check
+                */
+               function ( sData )
+               {
+                       /* Allow zero length strings as a number */
+                       if ( typeof sData === 'number' )
+                       {
+                               return 'numeric';
+                       }
+                       else if ( typeof sData !== 'string' )
+                       {
+                               return null;
+                       }
+                       
+                       var sValidFirstChars = "0123456789-";
+                       var sValidChars = "0123456789.";
+                       var Char;
+                       var bDecimal = false;
+                       
+                       /* Check for a valid first char (no period and allow negatives) */
+                       Char = sData.charAt(0); 
+                       if (sValidFirstChars.indexOf(Char) == -1) 
+                       {
+                               return null;
+                       }
+                       
+                       /* Check all the other characters are valid */
+                       for ( var i=1 ; i<sData.length ; i++ ) 
+                       {
+                               Char = sData.charAt(i); 
+                               if (sValidChars.indexOf(Char) == -1) 
+                               {
+                                       return null;
+                               }
+                               
+                               /* Only allowed one decimal place... */
+                               if ( Char == "." )
+                               {
+                                       if ( bDecimal )
+                                       {
+                                               return null;
+                                       }
+                                       bDecimal = true;
+                               }
+                       }
+                       
+                       return 'numeric';
+               },
+               
+               /*
+                * Function: -
+                * Purpose:  Check to see if a string is actually a formatted date
+                * Returns:  string:'date' or null
+                * Inputs:   string:sText - string to check
+                */
+               function ( sData )
+               {
+                       var iParse = Date.parse(sData);
+                       if ( (iParse !== null && !isNaN(iParse)) || (typeof sData === 'string' && sData.length === 0) )
+                       {
+                               return 'date';
+                       }
+                       return null;
+               },
+               
+               /*
+                * Function: -
+                * Purpose:  Check to see if a string should be treated as an HTML string
+                * Returns:  string:'html' or null
+                * Inputs:   string:sText - string to check
+                */
+               function ( sData )
+               {
+                       if ( typeof sData === 'string' && sData.indexOf('<') != -1 && sData.indexOf('>') != -1 )
+                       {
+                               return 'html';
+                       }
+                       return null;
+               }
+       ] );
+       
+
+       // jQuery aliases
+       $.fn.DataTable = DataTable;
+       $.fn.dataTable = DataTable;
+       $.fn.dataTableSettings = DataTable.settings;
+       $.fn.dataTableExt = DataTable.ext;
+
+
+       // Information about events fired by DataTables - for documentation.
+       /**
+        * Draw event, fired whenever the table is redrawn on the page, at the same point as
+        * fnDrawCallback. This may be useful for binding events or performing calculations when
+        * the table is altered at all.
+        *  @name DataTable#draw
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+        */
+
+       /**
+        * Filter event, fired when the filtering applied to the table (using the build in global
+        * global filter, or column filters) is altered.
+        *  @name DataTable#filter
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+        */
+
+       /**
+        * Page change event, fired when the paging of the table is altered.
+        *  @name DataTable#page
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+        */
+
+       /**
+        * Sort event, fired when the sorting applied to the table is altered.
+        *  @name DataTable#sort
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+        */
+
+       /**
+        * DataTables initialisation complete event, fired when the table is fully drawn,
+        * including Ajax data loaded, if Ajax data is required.
+        *  @name DataTable#init
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} oSettings DataTables settings object
+        *  @param {object} json The JSON object request from the server - only
+        *    present if client-side Ajax sourced data is used</li></ol>
+        */
+
+       /**
+        * State save event, fired when the table has changed state a new state save is required.
+        * This method allows modification of the state saving object prior to actually doing the
+        * save, including addition or other state properties (for plug-ins) or modification
+        * of a DataTables core property.
+        *  @name DataTable#stateSaveParams
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} oSettings DataTables settings object
+        *  @param {object} json The state information to be saved
+        */
+
+       /**
+        * State load event, fired when the table is loading state from the stored data, but
+        * prior to the settings object being modified by the saved state - allowing modification
+        * of the saved state is required or loading of state for a plug-in.
+        *  @name DataTable#stateLoadParams
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} oSettings DataTables settings object
+        *  @param {object} json The saved state information
+        */
+
+       /**
+        * State loaded event, fired when state has been loaded from stored data and the settings
+        * object has been modified by the loaded data.
+        *  @name DataTable#stateLoaded
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} oSettings DataTables settings object
+        *  @param {object} json The saved state information
+        */
+
+       /**
+        * Processing event, fired when DataTables is doing some kind of processing (be it,
+        * sort, filter or anything else). Can be used to indicate to the end user that
+        * there is something happening, or that something has finished.
+        *  @name DataTable#processing
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} oSettings DataTables settings object
+        *  @param {boolean} bShow Flag for if DataTables is doing processing or not
+        */
+
+       /**
+        * Ajax (XHR) event, fired whenever an Ajax request is completed from a request to 
+        * made to the server for new data (note that this trigger is called in fnServerData,
+        * if you override fnServerData and which to use this event, you need to trigger it in
+        * you success function).
+        *  @name DataTable#xhr
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+        *  @param {object} json JSON returned from the server
+        */
+
+       /**
+        * Destroy event, fired when the DataTable is destroyed by calling fnDestroy or passing
+        * the bDestroy:true parameter in the initialisation object. This can be used to remove
+        * bound events, added DOM nodes, etc.
+        *  @name DataTable#destroy
+        *  @event
+        *  @param {event} e jQuery event object
+        *  @param {object} o DataTables settings object {@link DataTable.models.oSettings}
+        */
+}));
+
+}(window, document));
+
diff --git a/html5/verto/demo/js/jquery.json-2.4.min.js b/html5/verto/demo/js/jquery.json-2.4.min.js
new file mode 100644 (file)
index 0000000..87050c9
--- /dev/null
@@ -0,0 +1,23 @@
+/*! jQuery JSON plugin 2.4.0 | code.google.com/p/jquery-json */
+(function($){'use strict';var escape=/["\\\x00-\x1f\x7f-\x9f]/g,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},hasOwn=Object.prototype.hasOwnProperty;$.toJSON=typeof JSON==='object'&&JSON.stringify?JSON.stringify:function(o){if(o===null){return'null';}
+var pairs,k,name,val,type=$.type(o);if(type==='undefined'){return undefined;}
+if(type==='number'||type==='boolean'){return String(o);}
+if(type==='string'){return $.quoteString(o);}
+if(typeof o.toJSON==='function'){return $.toJSON(o.toJSON());}
+if(type==='date'){var month=o.getUTCMonth()+1,day=o.getUTCDate(),year=o.getUTCFullYear(),hours=o.getUTCHours(),minutes=o.getUTCMinutes(),seconds=o.getUTCSeconds(),milli=o.getUTCMilliseconds();if(month<10){month='0'+month;}
+if(day<10){day='0'+day;}
+if(hours<10){hours='0'+hours;}
+if(minutes<10){minutes='0'+minutes;}
+if(seconds<10){seconds='0'+seconds;}
+if(milli<100){milli='0'+milli;}
+if(milli<10){milli='0'+milli;}
+return'"'+year+'-'+month+'-'+day+'T'+
+hours+':'+minutes+':'+seconds+'.'+milli+'Z"';}
+pairs=[];if($.isArray(o)){for(k=0;k<o.length;k++){pairs.push($.toJSON(o[k])||'null');}
+return'['+pairs.join(',')+']';}
+if(typeof o==='object'){for(k in o){if(hasOwn.call(o,k)){type=typeof k;if(type==='number'){name='"'+k+'"';}else if(type==='string'){name=$.quoteString(k);}else{continue;}
+type=typeof o[k];if(type!=='function'&&type!=='undefined'){val=$.toJSON(o[k]);pairs.push(name+':'+val);}}}
+return'{'+pairs.join(',')+'}';}};$.evalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){return eval('('+str+')');};$.secureEvalJSON=typeof JSON==='object'&&JSON.parse?JSON.parse:function(str){var filtered=str.replace(/\\["\\\/bfnrtu]/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,'');if(/^[\],:{}\s]*$/.test(filtered)){return eval('('+str+')');}
+throw new SyntaxError('Error parsing JSON, source is not valid.');};$.quoteString=function(str){if(str.match(escape)){return'"'+str.replace(escape,function(a){var c=meta[a];if(typeof c==='string'){return c;}
+c=a.charCodeAt();return'\\u00'+Math.floor(c/16).toString(16)+(c%16).toString(16);})+'"';}
+return'"'+str+'"';};}(jQuery));
\ No newline at end of file
diff --git a/html5/verto/demo/js/jquery.mobile-1.3.2.min.js b/html5/verto/demo/js/jquery.mobile-1.3.2.min.js
new file mode 100644 (file)
index 0000000..e06e590
--- /dev/null
@@ -0,0 +1,9 @@
+/*! jQuery Mobile 1.3.2 | Git HEAD hash: 528cf0e <> 2013-07-19T22:17:57Z | (c) 2010, 2013 jQuery Foundation, Inc. | jquery.org/license */
+!function(a,b,c){"function"==typeof define&&define.amd?define(["jquery"],function(d){return c(d,a,b),d.mobile}):c(a.jQuery,a,b)}(this,document,function(a,b,c,d){!function(a){a.mobile={}}(a),function(a,b,d){var e={};a.mobile=a.extend(a.mobile,{version:"1.3.2",ns:"",subPageUrlKey:"ui-page",activePageClass:"ui-page-active",activeBtnClass:"ui-btn-active",focusClass:"ui-focus",ajaxEnabled:!0,hashListeningEnabled:!0,linkBindingEnabled:!0,defaultPageTransition:"fade",maxTransitionWidth:!1,minScrollBack:250,touchOverflowEnabled:!1,defaultDialogTransition:"pop",pageLoadErrorMessage:"Error Loading Page",pageLoadErrorMessageTheme:"e",phonegapNavigationEnabled:!1,autoInitializePage:!0,pushStateEnabled:!0,ignoreContentEnabled:!1,orientationChangeEnabled:!0,buttonMarkup:{hoverDelay:200},window:a(b),document:a(c),keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91},behaviors:{},silentScroll:function(c){"number"!==a.type(c)&&(c=a.mobile.defaultHomeScroll),a.event.special.scrollstart.enabled=!1,setTimeout(function(){b.scrollTo(0,c),a.mobile.document.trigger("silentscroll",{x:0,y:c})},20),setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},nsNormalizeDict:e,nsNormalize:function(b){return b?e[b]||(e[b]=a.camelCase(a.mobile.ns+b)):void 0},getInheritedTheme:function(a,b){for(var c,d,e=a[0],f="",g=/ui-(bar|body|overlay)-([a-z])\b/;e&&(c=e.className||"",!(c&&(d=g.exec(c))&&(f=d[2])));)e=e.parentNode;return f||b||"a"},closestPageData:function(a){return a.closest(':jqmData(role="page"), :jqmData(role="dialog")').data("mobile-page")},enhanceable:function(a){return this.haveParents(a,"enhance")},hijackable:function(a){return this.haveParents(a,"ajax")},haveParents:function(b,c){if(!a.mobile.ignoreContentEnabled)return b;for(var d,e,f,g=b.length,h=a(),i=0;g>i;i++){for(e=b.eq(i),f=!1,d=b[i];d;){var j=d.getAttribute?d.getAttribute("data-"+a.mobile.ns+c):"";if("false"===j){f=!0;break}d=d.parentNode}f||(h=h.add(e))}return h},getScreenHeight:function(){return b.innerHeight||a.mobile.window.height()}},a.mobile),a.fn.jqmData=function(b,c){var e;return"undefined"!=typeof b&&(b&&(b=a.mobile.nsNormalize(b)),e=arguments.length<2||c===d?this.data(b):this.data(b,c)),e},a.jqmData=function(b,c,d){var e;return"undefined"!=typeof c&&(e=a.data(b,c?a.mobile.nsNormalize(c):c,d)),e},a.fn.jqmRemoveData=function(b){return this.removeData(a.mobile.nsNormalize(b))},a.jqmRemoveData=function(b,c){return a.removeData(b,a.mobile.nsNormalize(c))},a.fn.removeWithDependents=function(){a.removeWithDependents(this)},a.removeWithDependents=function(b){var c=a(b);(c.jqmData("dependents")||a()).remove(),c.remove()},a.fn.addDependents=function(b){a.addDependents(a(this),b)},a.addDependents=function(b,c){var d=a(b).jqmData("dependents")||a();a(b).jqmData("dependents",a.merge(d,c))},a.fn.getEncodedText=function(){return a("<div/>").text(a(this).text()).html()},a.fn.jqmEnhanceable=function(){return a.mobile.enhanceable(this)},a.fn.jqmHijackable=function(){return a.mobile.hijackable(this)};var f=a.find,g=/:jqmData\(([^)]*)\)/g;a.find=function(b,c,d,e){return b=b.replace(g,"[data-"+(a.mobile.ns||"")+"$1]"),f.call(this,b,c,d,e)},a.extend(a.find,f),a.find.matches=function(b,c){return a.find(b,null,null,c)},a.find.matchesSelector=function(b,c){return a.find(c,null,null,[b]).length>0}}(a,this),function(a,b){var c=0,d=Array.prototype.slice,e=a.cleanData;a.cleanData=function(b){for(var c,d=0;null!=(c=b[d]);d++)try{a(c).triggerHandler("remove")}catch(f){}e(b)},a.widget=function(b,c,d){var e,f,g,h,i=b.split(".")[0];b=b.split(".")[1],e=i+"-"+b,d||(d=c,c=a.Widget),a.expr[":"][e.toLowerCase()]=function(b){return!!a.data(b,e)},a[i]=a[i]||{},f=a[i][b],g=a[i][b]=function(a,b){return this._createWidget?(arguments.length&&this._createWidget(a,b),void 0):new g(a,b)},a.extend(g,f,{version:d.version,_proto:a.extend({},d),_childConstructors:[]}),h=new c,h.options=a.widget.extend({},h.options),a.each(d,function(b,e){a.isFunction(e)&&(d[b]=function(){var a=function(){return c.prototype[b].apply(this,arguments)},d=function(a){return c.prototype[b].apply(this,a)};return function(){var b,c=this._super,f=this._superApply;return this._super=a,this._superApply=d,b=e.apply(this,arguments),this._super=c,this._superApply=f,b}}())}),g.prototype=a.widget.extend(h,{widgetEventPrefix:f?h.widgetEventPrefix:b},d,{constructor:g,namespace:i,widgetName:b,widgetFullName:e}),f?(a.each(f._childConstructors,function(b,c){var d=c.prototype;a.widget(d.namespace+"."+d.widgetName,g,c._proto)}),delete f._childConstructors):c._childConstructors.push(g),a.widget.bridge(b,g)},a.widget.extend=function(c){for(var e,f,g=d.call(arguments,1),h=0,i=g.length;i>h;h++)for(e in g[h])f=g[h][e],g[h].hasOwnProperty(e)&&f!==b&&(c[e]=a.isPlainObject(f)?a.isPlainObject(c[e])?a.widget.extend({},c[e],f):a.widget.extend({},f):f);return c},a.widget.bridge=function(c,e){var f=e.prototype.widgetFullName||c;a.fn[c]=function(g){var h="string"==typeof g,i=d.call(arguments,1),j=this;return g=!h&&i.length?a.widget.extend.apply(null,[g].concat(i)):g,h?this.each(function(){var d,e=a.data(this,f);return e?a.isFunction(e[g])&&"_"!==g.charAt(0)?(d=e[g].apply(e,i),d!==e&&d!==b?(j=d&&d.jquery?j.pushStack(d.get()):d,!1):void 0):a.error("no such method '"+g+"' for "+c+" widget instance"):a.error("cannot call methods on "+c+" prior to initialization; "+"attempted to call method '"+g+"'")}):this.each(function(){var b=a.data(this,f);b?b.option(g||{})._init():a.data(this,f,new e(g,this))}),j}},a.Widget=function(){},a.Widget._childConstructors=[],a.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{disabled:!1,create:null},_createWidget:function(b,d){d=a(d||this.defaultElement||this)[0],this.element=a(d),this.uuid=c++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=a.widget.extend({},this.options,this._getCreateOptions(),b),this.bindings=a(),this.hoverable=a(),this.focusable=a(),d!==this&&(a.data(d,this.widgetFullName,this),this._on(!0,this.element,{remove:function(a){a.target===d&&this.destroy()}}),this.document=a(d.style?d.ownerDocument:d.document||d),this.window=a(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:a.noop,_getCreateEventData:a.noop,_create:a.noop,_init:a.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(a.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:a.noop,widget:function(){return this.element},option:function(c,d){var e,f,g,h=c;if(0===arguments.length)return a.widget.extend({},this.options);if("string"==typeof c)if(h={},e=c.split("."),c=e.shift(),e.length){for(f=h[c]=a.widget.extend({},this.options[c]),g=0;g<e.length-1;g++)f[e[g]]=f[e[g]]||{},f=f[e[g]];if(c=e.pop(),d===b)return f[c]===b?null:f[c];f[c]=d}else{if(d===b)return this.options[c]===b?null:this.options[c];h[c]=d}return this._setOptions(h),this},_setOptions:function(a){var b;for(b in a)this._setOption(b,a[b]);return this},_setOption:function(a,b){return this.options[a]=b,"disabled"===a&&(this.widget().toggleClass(this.widgetFullName+"-disabled ui-state-disabled",!!b).attr("aria-disabled",b),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")),this},enable:function(){return this._setOption("disabled",!1)},disable:function(){return this._setOption("disabled",!0)},_on:function(b,c,d){var e,f=this;"boolean"!=typeof b&&(d=c,c=b,b=!1),d?(c=e=a(c),this.bindings=this.bindings.add(c)):(d=c,c=this.element,e=this.widget()),a.each(d,function(d,g){function h(){return b||f.options.disabled!==!0&&!a(this).hasClass("ui-state-disabled")?("string"==typeof g?f[g]:g).apply(f,arguments):void 0}"string"!=typeof g&&(h.guid=g.guid=g.guid||h.guid||a.guid++);var i=d.match(/^(\w+)\s*(.*)$/),j=i[1]+f.eventNamespace,k=i[2];k?e.delegate(k,j,h):c.bind(j,h)})},_off:function(a,b){b=(b||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,a.unbind(b).undelegate(b)},_delay:function(a,b){function c(){return("string"==typeof a?d[a]:a).apply(d,arguments)}var d=this;return setTimeout(c,b||0)},_hoverable:function(b){this.hoverable=this.hoverable.add(b),this._on(b,{mouseenter:function(b){a(b.currentTarget).addClass("ui-state-hover")},mouseleave:function(b){a(b.currentTarget).removeClass("ui-state-hover")}})},_focusable:function(b){this.focusable=this.focusable.add(b),this._on(b,{focusin:function(b){a(b.currentTarget).addClass("ui-state-focus")},focusout:function(b){a(b.currentTarget).removeClass("ui-state-focus")}})},_trigger:function(b,c,d){var e,f,g=this.options[b];if(d=d||{},c=a.Event(c),c.type=(b===this.widgetEventPrefix?b:this.widgetEventPrefix+b).toLowerCase(),c.target=this.element[0],f=c.originalEvent)for(e in f)e in c||(c[e]=f[e]);return this.element.trigger(c,d),!(a.isFunction(g)&&g.apply(this.element[0],[c].concat(d))===!1||c.isDefaultPrevented())}},a.each({show:"fadeIn",hide:"fadeOut"},function(b,c){a.Widget.prototype["_"+b]=function(d,e,f){"string"==typeof e&&(e={effect:e});var g,h=e?e===!0||"number"==typeof e?c:e.effect||c:b;e=e||{},"number"==typeof e&&(e={duration:e}),g=!a.isEmptyObject(e),e.complete=f,e.delay&&d.delay(e.delay),g&&a.effects&&a.effects.effect[h]?d[b](e):h!==b&&d[h]?d[h](e.duration,e.easing,f):d.queue(function(c){a(this)[b](),f&&f.call(d[0]),c()})}})}(a),function(a,b){a.widget("mobile.widget",{_createWidget:function(){a.Widget.prototype._createWidget.apply(this,arguments),this._trigger("init")},_getCreateOptions:function(){var c=this.element,d={};return a.each(this.options,function(a){var e=c.jqmData(a.replace(/[A-Z]/g,function(a){return"-"+a.toLowerCase()}));e!==b&&(d[a]=e)}),d},enhanceWithin:function(b,c){this.enhance(a(this.options.initSelector,a(b)),c)},enhance:function(b,c){var d,e,f=a(b);f=a.mobile.enhanceable(f),c&&f.length&&(d=a.mobile.closestPageData(f),e=d&&d.keepNativeSelector()||"",f=f.not(e)),f[this.widgetName]()},raise:function(a){throw"Widget ["+this.widgetName+"]: "+a}})}(a),function(a){a.extend(a.mobile,{loadingMessageTextVisible:d,loadingMessageTheme:d,loadingMessage:d,showPageLoadingMsg:function(b,c,d){a.mobile.loading("show",b,c,d)},hidePageLoadingMsg:function(){a.mobile.loading("hide")},loading:function(){this.loaderWidget.loader.apply(this.loaderWidget,arguments)}});var b="ui-loader",c=a("html"),e=a.mobile.window;a.widget("mobile.loader",{options:{theme:"a",textVisible:!1,html:"",text:"loading"},defaultHtml:"<div class='"+b+"'>"+"<span class='ui-icon ui-icon-loading'></span>"+"<h1></h1>"+"</div>",fakeFixLoader:function(){var b=a("."+a.mobile.activeBtnClass).first();this.element.css({top:a.support.scrollTop&&e.scrollTop()+e.height()/2||b.length&&b.offset().top||100})},checkLoaderPosition:function(){var b=this.element.offset(),c=e.scrollTop(),d=a.mobile.getScreenHeight();(b.top<c||b.top-c>d)&&(this.element.addClass("ui-loader-fakefix"),this.fakeFixLoader(),e.unbind("scroll",this.checkLoaderPosition).bind("scroll",a.proxy(this.fakeFixLoader,this)))},resetHtml:function(){this.element.html(a(this.defaultHtml).html())},show:function(f,g,h){var i,j,k;this.resetHtml(),"object"===a.type(f)?(k=a.extend({},this.options,f),f=k.theme||a.mobile.loadingMessageTheme):(k=this.options,f=f||a.mobile.loadingMessageTheme||k.theme),j=g||a.mobile.loadingMessage||k.text,c.addClass("ui-loading"),(a.mobile.loadingMessage!==!1||k.html)&&(i=a.mobile.loadingMessageTextVisible!==d?a.mobile.loadingMessageTextVisible:k.textVisible,this.element.attr("class",b+" ui-corner-all ui-body-"+f+" ui-loader-"+(i||g||f.text?"verbose":"default")+(k.textonly||h?" ui-loader-textonly":"")),k.html?this.element.html(k.html):this.element.find("h1").text(j),this.element.appendTo(a.mobile.pageContainer),this.checkLoaderPosition(),e.bind("scroll",a.proxy(this.checkLoaderPosition,this)))},hide:function(){c.removeClass("ui-loading"),a.mobile.loadingMessage&&this.element.removeClass("ui-loader-fakefix"),a.mobile.window.unbind("scroll",this.fakeFixLoader),a.mobile.window.unbind("scroll",this.checkLoaderPosition)}}),e.bind("pagecontainercreate",function(){a.mobile.loaderWidget=a.mobile.loaderWidget||a(a.mobile.loader.prototype.defaultHtml).loader()})}(a,this),function(a,b,d){function e(a){return a=a||location.href,"#"+a.replace(/^[^#]*#?(.*)$/,"$1")}var f,g="hashchange",h=c,i=a.event.special,j=h.documentMode,k="on"+g in b&&(j===d||j>7);a.fn[g]=function(a){return a?this.bind(g,a):this.trigger(g)},a.fn[g].delay=50,i[g]=a.extend(i[g],{setup:function(){return k?!1:(a(f.start),void 0)},teardown:function(){return k?!1:(a(f.stop),void 0)}}),f=function(){function c(){var d=e(),h=n(j);d!==j?(m(j=d,h),a(b).trigger(g)):h!==j&&(location.href=location.href.replace(/#.*/,"")+h),f=setTimeout(c,a.fn[g].delay)}var f,i={},j=e(),l=function(a){return a},m=l,n=l;return i.start=function(){f||c()},i.stop=function(){f&&clearTimeout(f),f=d},b.attachEvent&&!b.addEventListener&&!k&&function(){var b,d;i.start=function(){b||(d=a.fn[g].src,d=d&&d+e(),b=a('<iframe tabindex="-1" title="empty"/>').hide().one("load",function(){d||m(e()),c()}).attr("src",d||"javascript:0").insertAfter("body")[0].contentWindow,h.onpropertychange=function(){try{"title"===event.propertyName&&(b.document.title=h.title)}catch(a){}})},i.stop=l,n=function(){return e(b.location.href)},m=function(c,d){var e=b.document,f=a.fn[g].domain;c!==d&&(e.title=h.title,e.open(),f&&e.write('<script>document.domain="'+f+'"</script>'),e.close(),b.location.hash=c)}}(),i}()}(a,this),function(a){b.matchMedia=b.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='&shy;<style media="'+a+'"> #mq-test-1 { width: 42px; }</style>',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(c),a.mobile.media=function(a){return b.matchMedia(a).matches}}(a),function(a){var b={touch:"ontouchend"in c};a.mobile.support=a.mobile.support||{},a.extend(a.support,b),a.extend(a.mobile.support,b)}(a),function(a){a.extend(a.support,{orientation:"orientation"in b&&"onorientationchange"in b})}(a),function(a,d){function e(a){var b=a.charAt(0).toUpperCase()+a.substr(1),c=(a+" "+n.join(b+" ")+b).split(" ");for(var e in c)if(m[c[e]]!==d)return!0}function f(a,b,d){for(var e,f=c.createElement("div"),g=function(a){return a.charAt(0).toUpperCase()+a.substr(1)},h=function(a){return""===a?"":"-"+a.charAt(0).toLowerCase()+a.substr(1)+"-"},i=function(c){var d=h(c)+a+": "+b+";",i=g(c),j=i+(""===i?a:g(a));f.setAttribute("style",d),f.style[j]&&(e=!0)},j=d?d:n,k=0;k<j.length;k++)i(j[k]);return!!e}function g(){var e="transform-3d",f=a.mobile.media("(-"+n.join("-"+e+"),(-")+"-"+e+"),("+e+")");if(f)return!!f;var g=c.createElement("div"),h={MozTransform:"-moz-transform",transform:"transform"};l.append(g);for(var i in h)g.style[i]!==d&&(g.style[i]="translate3d( 100px, 1px, 1px )",f=b.getComputedStyle(g).getPropertyValue(h[i]));return!!f&&"none"!==f}function h(){var b,c,d=location.protocol+"//"+location.host+location.pathname+"ui-dir/",e=a("head base"),f=null,g="";return e.length?g=e.attr("href"):e=f=a("<base>",{href:d}).appendTo("head"),b=a("<a href='testurl' />").prependTo(l),c=b[0].href,e[0].href=g||location.pathname,f&&f.remove(),0===c.indexOf(d)}function i(){var a,d=c.createElement("x"),e=c.documentElement,f=b.getComputedStyle;return"pointerEvents"in d.style?(d.style.pointerEvents="auto",d.style.pointerEvents="x",e.appendChild(d),a=f&&"auto"===f(d,"").pointerEvents,e.removeChild(d),!!a):!1}function j(){var a=c.createElement("div");return"undefined"!=typeof a.getBoundingClientRect}function k(){var a=b,c=navigator.userAgent,d=navigator.platform,e=c.match(/AppleWebKit\/([0-9]+)/),f=!!e&&e[1],g=c.match(/Fennec\/([0-9]+)/),h=!!g&&g[1],i=c.match(/Opera Mobi\/([0-9]+)/),j=!!i&&i[1];return(d.indexOf("iPhone")>-1||d.indexOf("iPad")>-1||d.indexOf("iPod")>-1)&&f&&534>f||a.operamini&&"[object OperaMini]"==={}.toString.call(a.operamini)||i&&7458>j||c.indexOf("Android")>-1&&f&&533>f||h&&6>h||"palmGetResource"in b&&f&&534>f||c.indexOf("MeeGo")>-1&&c.indexOf("NokiaBrowser/8.5.0")>-1?!1:!0}var l=a("<body>").prependTo("html"),m=l[0].style,n=["Webkit","Moz","O"],o="palmGetResource"in b,p=b.opera,q=b.operamini&&"[object OperaMini]"==={}.toString.call(b.operamini),r=b.blackberry&&!e("-webkit-transform");a.extend(a.mobile,{browser:{}}),a.mobile.browser.oldIE=function(){var a=3,b=c.createElement("div"),d=b.all||[];do b.innerHTML="<!--[if gt IE "+ ++a+"]><br><![endif]-->";while(d[0]);return a>4?a:!a}(),a.extend(a.support,{cssTransitions:"WebKitTransitionEvent"in b||f("transition","height 100ms linear",["Webkit","Moz",""])&&!a.mobile.browser.oldIE&&!p,pushState:"pushState"in history&&"replaceState"in history&&!(b.navigator.userAgent.indexOf("Firefox")>=0&&b.top!==b)&&-1===b.navigator.userAgent.search(/CriOS/),mediaquery:a.mobile.media("only all"),cssPseudoElement:!!e("content"),touchOverflow:!!e("overflowScrolling"),cssTransform3d:g(),boxShadow:!!e("boxShadow")&&!r,fixedPosition:k(),scrollTop:("pageXOffset"in b||"scrollTop"in c.documentElement||"scrollTop"in l[0])&&!o&&!q,dynamicBaseTag:h(),cssPointerEvents:i(),boundingRect:j()}),l.remove();var s=function(){var a=b.navigator.userAgent;return a.indexOf("Nokia")>-1&&(a.indexOf("Symbian/3")>-1||a.indexOf("Series60/5")>-1)&&a.indexOf("AppleWebKit")>-1&&a.match(/(BrowserNG|NokiaBrowser)\/7\.[0-3]/)}();a.mobile.gradeA=function(){return(a.support.mediaquery||a.mobile.browser.oldIE&&a.mobile.browser.oldIE>=7)&&(a.support.boundingRect||null!==a.fn.jquery.match(/1\.[0-7+]\.[0-9+]?/))},a.mobile.ajaxBlacklist=b.blackberry&&!b.WebKitPoint||q||s,s&&a(function(){a("head link[rel='stylesheet']").attr("rel","alternate stylesheet").attr("rel","stylesheet")}),a.support.boxShadow||a("html").addClass("ui-mobile-nosupport-boxshadow")}(a),function(a,b){var c,d=a.mobile.window;a.event.special.navigate=c={bound:!1,pushStateEnabled:!0,originalEventName:b,isPushStateEnabled:function(){return a.support.pushState&&a.mobile.pushStateEnabled===!0&&this.isHashChangeEnabled()},isHashChangeEnabled:function(){return a.mobile.hashListeningEnabled===!0},popstate:function(b){var c=new a.Event("navigate"),e=new a.Event("beforenavigate"),f=b.originalEvent.state||{};location.href,d.trigger(e),e.isDefaultPrevented()||(b.historyState&&a.extend(f,b.historyState),c.originalEvent=b,setTimeout(function(){d.trigger(c,{state:f})},0))},hashchange:function(b){var c=new a.Event("navigate"),e=new a.Event("beforenavigate");d.trigger(e),e.isDefaultPrevented()||(c.originalEvent=b,d.trigger(c,{state:b.hashchangeState||{}}))},setup:function(){c.bound||(c.bound=!0,c.isPushStateEnabled()?(c.originalEventName="popstate",d.bind("popstate.navigate",c.popstate)):c.isHashChangeEnabled()&&(c.originalEventName="hashchange",d.bind("hashchange.navigate",c.hashchange)))}}}(a),function(a,c){var d,e,f="&ui-state=dialog";a.mobile.path=d={uiStateKey:"&ui-state",urlParseRE:/^\s*(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,getLocation:function(a){var b=a?this.parseUrl(a):location,c=this.parseUrl(a||location.href).hash;return c="#"===c?"":c,b.protocol+"//"+b.host+b.pathname+b.search+c},parseLocation:function(){return this.parseUrl(this.getLocation())},parseUrl:function(b){if("object"===a.type(b))return b;var c=d.urlParseRE.exec(b||"")||[];return{href:c[0]||"",hrefNoHash:c[1]||"",hrefNoSearch:c[2]||"",domain:c[3]||"",protocol:c[4]||"",doubleSlash:c[5]||"",authority:c[6]||"",username:c[8]||"",password:c[9]||"",host:c[10]||"",hostname:c[11]||"",port:c[12]||"",pathname:c[13]||"",directory:c[14]||"",filename:c[15]||"",search:c[16]||"",hash:c[17]||""}},makePathAbsolute:function(a,b){if(a&&"/"===a.charAt(0))return a;a=a||"",b=b?b.replace(/^\/|(\/[^\/]*|[^\/]+)$/g,""):"";for(var c=b?b.split("/"):[],d=a.split("/"),e=0;e<d.length;e++){var f=d[e];switch(f){case".":break;case"..":c.length&&c.pop();break;default:c.push(f)}}return"/"+c.join("/")},isSameDomain:function(a,b){return d.parseUrl(a).domain===d.parseUrl(b).domain},isRelativeUrl:function(a){return""===d.parseUrl(a).protocol},isAbsoluteUrl:function(a){return""!==d.parseUrl(a).protocol},makeUrlAbsolute:function(a,b){if(!d.isRelativeUrl(a))return a;b===c&&(b=this.documentBase);var e=d.parseUrl(a),f=d.parseUrl(b),g=e.protocol||f.protocol,h=e.protocol?e.doubleSlash:e.doubleSlash||f.doubleSlash,i=e.authority||f.authority,j=""!==e.pathname,k=d.makePathAbsolute(e.pathname||f.filename,f.pathname),l=e.search||!j&&f.search||"",m=e.hash;return g+h+i+k+l+m},addSearchParams:function(b,c){var e=d.parseUrl(b),f="object"==typeof c?a.param(c):c,g=e.search||"?";return e.hrefNoSearch+g+("?"!==g.charAt(g.length-1)?"&":"")+f+(e.hash||"")},convertUrlToDataUrl:function(a){var c=d.parseUrl(a);return d.isEmbeddedPage(c)?c.hash.split(f)[0].replace(/^#/,"").replace(/\?.*$/,""):d.isSameDomain(c,this.documentBase)?c.hrefNoHash.replace(this.documentBase.domain,"").split(f)[0]:b.decodeURIComponent(a)},get:function(a){return a===c&&(a=d.parseLocation().hash),d.stripHash(a).replace(/[^\/]*\.[^\/*]+$/,"")},set:function(a){location.hash=a},isPath:function(a){return/\//.test(a)},clean:function(a){return a.replace(this.documentBase.domain,"")},stripHash:function(a){return a.replace(/^#/,"")},stripQueryParams:function(a){return a.replace(/\?.*$/,"")},cleanHash:function(a){return d.stripHash(a.replace(/\?.*$/,"").replace(f,""))},isHashValid:function(a){return/^#[^#]+$/.test(a)},isExternal:function(a){var b=d.parseUrl(a);return b.protocol&&b.domain!==this.documentUrl.domain?!0:!1},hasProtocol:function(a){return/^(:?\w+:)/.test(a)},isEmbeddedPage:function(a){var b=d.parseUrl(a);return""!==b.protocol?!this.isPath(b.hash)&&b.hash&&(b.hrefNoHash===this.documentUrl.hrefNoHash||this.documentBaseDiffers&&b.hrefNoHash===this.documentBase.hrefNoHash):/^#/.test(b.href)},squash:function(a,b){var c,e,f,g,h=this.isPath(a),i=this.parseUrl(a),j=i.hash,k="";return b=b||(d.isPath(a)?d.getLocation():d.getDocumentUrl()),e=h?d.stripHash(a):a,e=d.isPath(i.hash)?d.stripHash(i.hash):e,g=e.indexOf(this.uiStateKey),g>-1&&(k=e.slice(g),e=e.slice(0,g)),c=d.makeUrlAbsolute(e,b),f=this.parseUrl(c).search,h?((d.isPath(j)||0===j.replace("#","").indexOf(this.uiStateKey))&&(j=""),k&&-1===j.indexOf(this.uiStateKey)&&(j+=k),-1===j.indexOf("#")&&""!==j&&(j="#"+j),c=d.parseUrl(c),c=c.protocol+"//"+c.host+c.pathname+f+j):c+=c.indexOf("#")>-1?k:"#"+k,c},isPreservableHash:function(a){return 0===a.replace("#","").indexOf(this.uiStateKey)}},d.documentUrl=d.parseLocation(),e=a("head").find("base"),d.documentBase=e.length?d.parseUrl(d.makeUrlAbsolute(e.attr("href"),d.documentUrl.href)):d.documentUrl,d.documentBaseDiffers=d.documentUrl.hrefNoHash!==d.documentBase.hrefNoHash,d.getDocumentUrl=function(b){return b?a.extend({},d.documentUrl):d.documentUrl.href},d.getDocumentBase=function(b){return b?a.extend({},d.documentBase):d.documentBase.href}}(a),function(a,b){a.mobile.path,a.mobile.History=function(a,b){this.stack=a||[],this.activeIndex=b||0},a.extend(a.mobile.History.prototype,{getActive:function(){return this.stack[this.activeIndex]},getLast:function(){return this.stack[this.previousIndex]},getNext:function(){return this.stack[this.activeIndex+1]},getPrev:function(){return this.stack[this.activeIndex-1]},add:function(a,b){b=b||{},this.getNext()&&this.clearForward(),b.hash&&-1===b.hash.indexOf("#")&&(b.hash="#"+b.hash),b.url=a,this.stack.push(b),this.activeIndex=this.stack.length-1},clearForward:function(){this.stack=this.stack.slice(0,this.activeIndex+1)},find:function(a,b,c){b=b||this.stack;var d,e,f,g=b.length;for(e=0;g>e;e++)if(d=b[e],(decodeURIComponent(a)===decodeURIComponent(d.url)||decodeURIComponent(a)===decodeURIComponent(d.hash))&&(f=e,c))return f;return f},closest:function(a){var c,d=this.activeIndex;return c=this.find(a,this.stack.slice(0,d)),c===b&&(c=this.find(a,this.stack.slice(d),!0),c=c===b?c:c+d),c},direct:function(c){var d=this.closest(c.url),e=this.activeIndex;d!==b&&(this.activeIndex=d,this.previousIndex=e),e>d?(c.present||c.back||a.noop)(this.getActive(),"back"):d>e?(c.present||c.forward||a.noop)(this.getActive(),"forward"):d===b&&c.missing&&c.missing(this.getActive())}})}(a),function(a){var d=a.mobile.path,e=location.href;a.mobile.Navigator=function(b){this.history=b,this.ignoreInitialHashChange=!0,a.mobile.window.bind({"popstate.history":a.proxy(this.popstate,this),"hashchange.history":a.proxy(this.hashchange,this)})},a.extend(a.mobile.Navigator.prototype,{squash:function(e,f){var g,h,i=d.isPath(e)?d.stripHash(e):e;return h=d.squash(e),g=a.extend({hash:i,url:h},f),b.history.replaceState(g,g.title||c.title,h),g},hash:function(a,b){var c,e,f;if(c=d.parseUrl(a),e=d.parseLocation(),e.pathname+e.search===c.pathname+c.search)f=c.hash?c.hash:c.pathname+c.search;else if(d.isPath(a)){var g=d.parseUrl(b);f=g.pathname+g.search+(d.isPreservableHash(g.hash)?g.hash.replace("#",""):"")}else f=a;return f},go:function(e,f,g){var h,i,j,k,l=a.event.special.navigate.isPushStateEnabled();i=d.squash(e),j=this.hash(e,i),g&&j!==d.stripHash(d.parseLocation().hash)&&(this.preventNextHashChange=g),this.preventHashAssignPopState=!0,b.location.hash=j,this.preventHashAssignPopState=!1,h=a.extend({url:i,hash:j,title:c.title},f),l&&(k=new a.Event("popstate"),k.originalEvent={type:"popstate",state:null},this.squash(e,h),g||(this.ignorePopState=!0,a.mobile.window.trigger(k))),this.history.add(h.url,h)},popstate:function(b){var c,f;if(a.event.special.navigate.isPushStateEnabled())return this.preventHashAssignPopState?(this.preventHashAssignPopState=!1,b.stopImmediatePropagation(),void 0):this.ignorePopState?(this.ignorePopState=!1,void 0):!b.originalEvent.state&&1===this.history.stack.length&&this.ignoreInitialHashChange&&(this.ignoreInitialHashChange=!1,location.href===e)?(b.preventDefault(),void 0):(c=d.parseLocation().hash,!b.originalEvent.state&&c?(f=this.squash(c),this.history.add(f.url,f),b.historyState=f,void 0):(this.history.direct({url:(b.originalEvent.state||{}).url||c,present:function(c,d){b.historyState=a.extend({},c),b.historyState.direction=d}}),void 0))},hashchange:function(b){var e,f;if(a.event.special.navigate.isHashChangeEnabled()&&!a.event.special.navigate.isPushStateEnabled()){if(this.preventNextHashChange)return this.preventNextHashChange=!1,b.stopImmediatePropagation(),void 0;e=this.history,f=d.parseLocation().hash,this.history.direct({url:f,present:function(c,d){b.hashchangeState=a.extend({},c),b.hashchangeState.direction=d},missing:function(){e.add(f,{hash:f,title:c.title})}})}}})}(a),function(a){a.mobile.navigate=function(b,c,d){a.mobile.navigate.navigator.go(b,c,d)},a.mobile.navigate.history=new a.mobile.History,a.mobile.navigate.navigator=new a.mobile.Navigator(a.mobile.navigate.history);var b=a.mobile.path.parseLocation();a.mobile.navigate.history.add(b.href,{hash:b.hash})}(a),function(a,b,c,d){function e(a){for(;a&&"undefined"!=typeof a.originalEvent;)a=a.originalEvent;return a}function f(b,c){var f,g,h,i,j,k,l,m,n,o=b.type;if(b=a.Event(b),b.type=c,f=b.originalEvent,g=a.event.props,o.search(/^(mouse|click)/)>-1&&(g=D),f)for(l=g.length,i;l;)i=g[--l],b[i]=f[i];if(o.search(/mouse(down|up)|click/)>-1&&!b.which&&(b.which=1),-1!==o.search(/^touch/)&&(h=e(f),o=h.touches,j=h.changedTouches,k=o&&o.length?o[0]:j&&j.length?j[0]:d))for(m=0,n=B.length;n>m;m++)i=B[m],b[i]=k[i];return b}function g(b){for(var c,d,e={};b;){c=a.data(b,y);for(d in c)c[d]&&(e[d]=e.hasVirtualBinding=!0);b=b.parentNode}return e}function h(b,c){for(var d;b;){if(d=a.data(b,y),d&&(!c||d[c]))return b;b=b.parentNode}return null}function i(){L=!1}function j(){L=!0}function k(){P=0,J.length=0,K=!1,j()}function l(){i()}function m(){n(),F=setTimeout(function(){F=0,k()},a.vmouse.resetTimerDuration)}function n(){F&&(clearTimeout(F),F=0)}function o(b,c,d){var e;return(d&&d[b]||!d&&h(c.target,b))&&(e=f(c,b),a(c.target).trigger(e)),e}function p(b){var c=a.data(b.target,z);if(!(K||P&&P===c)){var d=o("v"+b.type,b);d&&(d.isDefaultPrevented()&&b.preventDefault(),d.isPropagationStopped()&&b.stopPropagation(),d.isImmediatePropagationStopped()&&b.stopImmediatePropagation())}}function q(b){var c,d,f=e(b).touches;if(f&&1===f.length&&(c=b.target,d=g(c),d.hasVirtualBinding)){P=O++,a.data(c,z,P),n(),l(),I=!1;var h=e(b).touches[0];G=h.pageX,H=h.pageY,o("vmouseover",b,d),o("vmousedown",b,d)}}function r(a){L||(I||o("vmousecancel",a,g(a.target)),I=!0,m())}function s(b){if(!L){var c=e(b).touches[0],d=I,f=a.vmouse.moveDistanceThreshold,h=g(b.target);I=I||Math.abs(c.pageX-G)>f||Math.abs(c.pageY-H)>f,I&&!d&&o("vmousecancel",b,h),o("vmousemove",b,h),m()}}function t(a){if(!L){j();var b,c=g(a.target);if(o("vmouseup",a,c),!I){var d=o("vclick",a,c);d&&d.isDefaultPrevented()&&(b=e(a).changedTouches[0],J.push({touchID:P,x:b.clientX,y:b.clientY}),K=!0)}o("vmouseout",a,c),I=!1,m()}}function u(b){var c,d=a.data(b,y);if(d)for(c in d)if(d[c])return!0;return!1}function v(){}function w(b){var c=b.substr(1);return{setup:function(){u(this)||a.data(this,y,{});var d=a.data(this,y);d[b]=!0,E[b]=(E[b]||0)+1,1===E[b]&&N.bind(c,p),a(this).bind(c,v),M&&(E.touchstart=(E.touchstart||0)+1,1===E.touchstart&&N.bind("touchstart",q).bind("touchend",t).bind("touchmove",s).bind("scroll",r))},teardown:function(){--E[b],E[b]||N.unbind(c,p),M&&(--E.touchstart,E.touchstart||N.unbind("touchstart",q).unbind("touchmove",s).unbind("touchend",t).unbind("scroll",r));var d=a(this),e=a.data(this,y);e&&(e[b]=!1),d.unbind(c,v),u(this)||d.removeData(y)}}}var x,y="virtualMouseBindings",z="virtualTouchID",A="vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "),B="clientX clientY pageX pageY screenX screenY".split(" "),C=a.event.mouseHooks?a.event.mouseHooks.props:[],D=a.event.props.concat(C),E={},F=0,G=0,H=0,I=!1,J=[],K=!1,L=!1,M="addEventListener"in c,N=a(c),O=1,P=0;a.vmouse={moveDistanceThreshold:10,clickDistanceThreshold:10,resetTimerDuration:1500};for(var Q=0;Q<A.length;Q++)a.event.special[A[Q]]=w(A[Q]);M&&c.addEventListener("click",function(b){var c,d,e,f,g,h,i=J.length,j=b.target;if(i)for(c=b.clientX,d=b.clientY,x=a.vmouse.clickDistanceThreshold,e=j;e;){for(f=0;i>f;f++)if(g=J[f],h=0,e===j&&Math.abs(g.x-c)<x&&Math.abs(g.y-d)<x||a.data(e,z)===g.touchID)return b.preventDefault(),b.stopPropagation(),void 0;e=e.parentNode}},!0)}(a,b,c),function(a,b,d){function e(b,c,d){var e=d.type;d.type=c,a.event.dispatch.call(b,d),d.type=e}var f=a(c);a.each("touchstart touchmove touchend tap taphold swipe swipeleft swiperight scrollstart scrollstop".split(" "),function(b,c){a.fn[c]=function(a){return a?this.bind(c,a):this.trigger(c)},a.attrFn&&(a.attrFn[c]=!0)});var g=a.mobile.support.touch,h="touchmove scroll",i=g?"touchstart":"mousedown",j=g?"touchend":"mouseup",k=g?"touchmove":"mousemove";a.event.special.scrollstart={enabled:!0,setup:function(){function b(a,b){c=b,e(f,c?"scrollstart":"scrollstop",a)}var c,d,f=this,g=a(f);g.bind(h,function(e){a.event.special.scrollstart.enabled&&(c||b(e,!0),clearTimeout(d),d=setTimeout(function(){b(e,!1)},50))})}},a.event.special.tap={tapholdThreshold:750,setup:function(){var b=this,c=a(b);c.bind("vmousedown",function(d){function g(){clearTimeout(j)}function h(){g(),c.unbind("vclick",i).unbind("vmouseup",g),f.unbind("vmousecancel",h)}function i(a){h(),k===a.target&&e(b,"tap",a)
+}if(d.which&&1!==d.which)return!1;var j,k=d.target;d.originalEvent,c.bind("vmouseup",g).bind("vclick",i),f.bind("vmousecancel",h),j=setTimeout(function(){e(b,"taphold",a.Event("taphold",{target:k}))},a.event.special.tap.tapholdThreshold)})}},a.event.special.swipe={scrollSupressionThreshold:30,durationThreshold:1e3,horizontalDistanceThreshold:30,verticalDistanceThreshold:75,start:function(b){var c=b.originalEvent.touches?b.originalEvent.touches[0]:b;return{time:(new Date).getTime(),coords:[c.pageX,c.pageY],origin:a(b.target)}},stop:function(a){var b=a.originalEvent.touches?a.originalEvent.touches[0]:a;return{time:(new Date).getTime(),coords:[b.pageX,b.pageY]}},handleSwipe:function(b,c){c.time-b.time<a.event.special.swipe.durationThreshold&&Math.abs(b.coords[0]-c.coords[0])>a.event.special.swipe.horizontalDistanceThreshold&&Math.abs(b.coords[1]-c.coords[1])<a.event.special.swipe.verticalDistanceThreshold&&b.origin.trigger("swipe").trigger(b.coords[0]>c.coords[0]?"swipeleft":"swiperight")},setup:function(){var b=this,c=a(b);c.bind(i,function(b){function e(b){g&&(f=a.event.special.swipe.stop(b),Math.abs(g.coords[0]-f.coords[0])>a.event.special.swipe.scrollSupressionThreshold&&b.preventDefault())}var f,g=a.event.special.swipe.start(b);c.bind(k,e).one(j,function(){c.unbind(k,e),g&&f&&a.event.special.swipe.handleSwipe(g,f),g=f=d})})}},a.each({scrollstop:"scrollstart",taphold:"tap",swipeleft:"swipe",swiperight:"swipe"},function(b,c){a.event.special[b]={setup:function(){a(this).bind(c,a.noop)}}})}(a,this),function(a){a.event.special.throttledresize={setup:function(){a(this).bind("resize",f)},teardown:function(){a(this).unbind("resize",f)}};var b,c,d,e=250,f=function(){c=(new Date).getTime(),d=c-g,d>=e?(g=c,a(this).trigger("throttledresize")):(b&&clearTimeout(b),b=setTimeout(f,e-d))},g=0}(a),function(a,b){function d(){var a=e();a!==f&&(f=a,i.trigger(j))}var e,f,g,h,i=a(b),j="orientationchange",k={0:!0,180:!0};if(a.support.orientation){var l=b.innerWidth||i.width(),m=b.innerHeight||i.height(),n=50;g=l>m&&l-m>n,h=k[b.orientation],(g&&h||!g&&!h)&&(k={"-90":!0,90:!0})}a.event.special.orientationchange=a.extend({},a.event.special.orientationchange,{setup:function(){return a.support.orientation&&!a.event.special.orientationchange.disabled?!1:(f=e(),i.bind("throttledresize",d),void 0)},teardown:function(){return a.support.orientation&&!a.event.special.orientationchange.disabled?!1:(i.unbind("throttledresize",d),void 0)},add:function(a){var b=a.handler;a.handler=function(a){return a.orientation=e(),b.apply(this,arguments)}}}),a.event.special.orientationchange.orientation=e=function(){var d=!0,e=c.documentElement;return d=a.support.orientation?k[b.orientation]:e&&e.clientWidth/e.clientHeight<1.1,d?"portrait":"landscape"},a.fn[j]=function(a){return a?this.bind(j,a):this.trigger(j)},a.attrFn&&(a.attrFn[j]=!0)}(a,this),function(a){a.widget("mobile.page",a.mobile.widget,{options:{theme:"c",domCache:!1,keepNativeDefault:":jqmData(role='none'), :jqmData(role='nojs')"},_create:function(){return this._trigger("beforecreate")===!1?!1:(this.element.attr("tabindex","0").addClass("ui-page ui-body-"+this.options.theme),this._on(this.element,{pagebeforehide:"removeContainerBackground",pagebeforeshow:"_handlePageBeforeShow"}),void 0)},_handlePageBeforeShow:function(){this.setContainerBackground()},removeContainerBackground:function(){a.mobile.pageContainer.removeClass("ui-overlay-"+a.mobile.getInheritedTheme(this.element.parent()))},setContainerBackground:function(b){this.options.theme&&a.mobile.pageContainer.addClass("ui-overlay-"+(b||this.options.theme))},keepNativeSelector:function(){var b=this.options,c=b.keepNative&&a.trim(b.keepNative);return c&&b.keepNative!==b.keepNativeDefault?[b.keepNative,b.keepNativeDefault].join(", "):b.keepNativeDefault}})}(a),function(a,b,c){var d=function(d){return d===c&&(d=!0),function(c,e,f,g){var h=new a.Deferred,i=e?" reverse":"",j=a.mobile.urlHistory.getActive(),k=j.lastScroll||a.mobile.defaultHomeScroll,l=a.mobile.getScreenHeight(),m=a.mobile.maxTransitionWidth!==!1&&a.mobile.window.width()>a.mobile.maxTransitionWidth,n=!a.support.cssTransitions||m||!c||"none"===c||Math.max(a.mobile.window.scrollTop(),k)>a.mobile.getMaxScrollForTransition(),o=" ui-page-pre-in",p=function(){a.mobile.pageContainer.toggleClass("ui-mobile-viewport-transitioning viewport-"+c)},q=function(){a.event.special.scrollstart.enabled=!1,b.scrollTo(0,k),setTimeout(function(){a.event.special.scrollstart.enabled=!0},150)},r=function(){g.removeClass(a.mobile.activePageClass+" out in reverse "+c).height("")},s=function(){d?g.animationComplete(t):t(),g.height(l+a.mobile.window.scrollTop()).addClass(c+" out"+i)},t=function(){g&&d&&r(),u()},u=function(){f.css("z-index",-10),f.addClass(a.mobile.activePageClass+o),a.mobile.focusPage(f),f.height(l+k),q(),f.css("z-index",""),n||f.animationComplete(v),f.removeClass(o).addClass(c+" in"+i),n&&v()},v=function(){d||g&&r(),f.removeClass("out in reverse "+c).height(""),p(),a.mobile.window.scrollTop()!==k&&q(),h.resolve(c,e,f,g,!0)};return p(),g&&!n?s():t(),h.promise()}},e=d(),f=d(!1),g=function(){return 3*a.mobile.getScreenHeight()};a.mobile.defaultTransitionHandler=e,a.mobile.transitionHandlers={"default":a.mobile.defaultTransitionHandler,sequential:e,simultaneous:f},a.mobile.transitionFallbacks={},a.mobile._maybeDegradeTransition=function(b){return b&&!a.support.cssTransform3d&&a.mobile.transitionFallbacks[b]&&(b=a.mobile.transitionFallbacks[b]),b},a.mobile.getMaxScrollForTransition=a.mobile.getMaxScrollForTransition||g}(a,this),function(a,d){function e(b){!p||p.closest("."+a.mobile.activePageClass).length&&!b||p.removeClass(a.mobile.activeBtnClass),p=null}function f(){t=!1,s.length>0&&a.mobile.changePage.apply(null,s.pop())}function g(b,c,d,e){c&&c.data("mobile-page")._trigger("beforehide",null,{nextPage:b}),b.data("mobile-page")._trigger("beforeshow",null,{prevPage:c||a("")}),a.mobile.hidePageLoadingMsg(),d=a.mobile._maybeDegradeTransition(d);var f=a.mobile.transitionHandlers[d||"default"]||a.mobile.defaultTransitionHandler,g=f(d,e,b,c);return g.done(function(){c&&c.data("mobile-page")._trigger("hide",null,{nextPage:b}),b.data("mobile-page")._trigger("show",null,{prevPage:c||a("")})}),g}function h(b,c){c&&b.attr("data-"+a.mobile.ns+"role",c),b.page()}function i(){var b=a.mobile.activePage&&k(a.mobile.activePage);return b||x.hrefNoHash}function j(a){for(;a&&("string"!=typeof a.nodeName||"a"!==a.nodeName.toLowerCase());)a=a.parentNode;return a}function k(b){var c=a(b).closest(".ui-page").jqmData("url"),d=x.hrefNoHash;return c&&n.isPath(c)||(c=d),n.makeUrlAbsolute(c,d)}var l=a.mobile.window,m=(a("html"),a("head")),n=a.extend(a.mobile.path,{getFilePath:function(b){var c="&"+a.mobile.subPageUrlKey;return b&&b.split(c)[0].split(u)[0]},isFirstPageUrl:function(b){var c=n.parseUrl(n.makeUrlAbsolute(b,this.documentBase)),e=c.hrefNoHash===this.documentUrl.hrefNoHash||this.documentBaseDiffers&&c.hrefNoHash===this.documentBase.hrefNoHash,f=a.mobile.firstPage,g=f&&f[0]?f[0].id:d;return e&&(!c.hash||"#"===c.hash||g&&c.hash.replace(/^#/,"")===g)},isPermittedCrossDomainRequest:function(b,c){return a.mobile.allowCrossDomainPages&&"file:"===b.protocol&&-1!==c.search(/^https?:/)}}),o=null,p=null,q=a.Deferred(),r=a.mobile.navigate.history,s=[],t=!1,u="&ui-state=dialog",v=m.children("base"),w=n.documentUrl,x=n.documentBase,y=(n.documentBaseDiffers,a.mobile.getScreenHeight),z=a.support.dynamicBaseTag?{element:v.length?v:a("<base>",{href:x.hrefNoHash}).prependTo(m),set:function(a){a=n.parseUrl(a).hrefNoHash,z.element.attr("href",n.makeUrlAbsolute(a,x))},reset:function(){z.element.attr("href",x.hrefNoSearch)}}:d;a.mobile.getDocumentUrl=n.getDocumentUrl,a.mobile.getDocumentBase=n.getDocumentBase,a.mobile.back=function(){var a=b.navigator;this.phonegapNavigationEnabled&&a&&a.app&&a.app.backHistory?a.app.backHistory():b.history.back()},a.mobile.focusPage=function(a){var b=a.find("[autofocus]"),c=a.find(".ui-title:eq(0)");return b.length?(b.focus(),void 0):(c.length?c.focus():a.focus(),void 0)};var A,B,C=!0;A=function(){if(C){var b=a.mobile.urlHistory.getActive();if(b){var c=l.scrollTop();b.lastScroll=c<a.mobile.minScrollBack?a.mobile.defaultHomeScroll:c}}},B=function(){setTimeout(A,100)},l.bind(a.support.pushState?"popstate":"hashchange",function(){C=!1}),l.one(a.support.pushState?"popstate":"hashchange",function(){C=!0}),l.one("pagecontainercreate",function(){a.mobile.pageContainer.bind("pagechange",function(){C=!0,l.unbind("scrollstop",B),l.bind("scrollstop",B)})}),l.bind("scrollstop",B),a.mobile._maybeDegradeTransition=a.mobile._maybeDegradeTransition||function(a){return a},a.mobile.resetActivePageHeight=function(b){var c=a("."+a.mobile.activePageClass),d=parseFloat(c.css("padding-top")),e=parseFloat(c.css("padding-bottom")),f=parseFloat(c.css("border-top-width")),g=parseFloat(c.css("border-bottom-width"));b="number"==typeof b?b:y(),c.css("min-height",b-d-e-f-g)},a.fn.animationComplete=function(b){return a.support.cssTransitions?a(this).one("webkitAnimationEnd animationend",b):(setTimeout(b,0),a(this))},a.mobile.path=n,a.mobile.base=z,a.mobile.urlHistory=r,a.mobile.dialogHashKey=u,a.mobile.allowCrossDomainPages=!1,a.mobile._bindPageRemove=function(){var b=a(this);!b.data("mobile-page").options.domCache&&b.is(":jqmData(external-page='true')")&&b.bind("pagehide.remove",function(){var b=a(this),c=new a.Event("pageremove");b.trigger(c),c.isDefaultPrevented()||b.removeWithDependents()})},a.mobile.loadPage=function(b,c){var e=a.Deferred(),f=a.extend({},a.mobile.loadPage.defaults,c),g=null,j=null,k=n.makeUrlAbsolute(b,i());f.data&&"get"===f.type&&(k=n.addSearchParams(k,f.data),f.data=d),f.data&&"post"===f.type&&(f.reloadPage=!0);var l=n.getFilePath(k),m=n.convertUrlToDataUrl(k);if(f.pageContainer=f.pageContainer||a.mobile.pageContainer,g=f.pageContainer.children("[data-"+a.mobile.ns+"url='"+m+"']"),0===g.length&&m&&!n.isPath(m)&&(g=f.pageContainer.children("#"+m).attr("data-"+a.mobile.ns+"url",m).jqmData("url",m)),0===g.length)if(a.mobile.firstPage&&n.isFirstPageUrl(l))a.mobile.firstPage.parent().length&&(g=a(a.mobile.firstPage));else if(n.isEmbeddedPage(l))return e.reject(k,c),e.promise();if(g.length){if(!f.reloadPage)return h(g,f.role),e.resolve(k,c,g),z&&!c.prefetch&&z.set(b),e.promise();j=g}var o=f.pageContainer,p=new a.Event("pagebeforeload"),q={url:b,absUrl:k,dataUrl:m,deferred:e,options:f};if(o.trigger(p,q),p.isDefaultPrevented())return e.promise();if(f.showLoadMsg)var r=setTimeout(function(){a.mobile.showPageLoadingMsg()},f.loadMsgDelay),s=function(){clearTimeout(r),a.mobile.hidePageLoadingMsg()};return!z||"undefined"!=typeof c&&"undefined"!=typeof c.prefetch||z.reset(),a.mobile.allowCrossDomainPages||n.isSameDomain(w,k)?a.ajax({url:l,type:f.type,data:f.data,contentType:f.contentType,dataType:"html",success:function(d,i,o){var p=a("<div></div>"),r=d.match(/<title[^>]*>([^<]*)/)&&RegExp.$1,t=new RegExp("(<[^>]+\\bdata-"+a.mobile.ns+"role=[\"']?page[\"']?[^>]*>)"),u=new RegExp("\\bdata-"+a.mobile.ns+"url=[\"']?([^\"'>]*)[\"']?");if(t.test(d)&&RegExp.$1&&u.test(RegExp.$1)&&RegExp.$1&&(b=l=n.getFilePath(a("<div>"+RegExp.$1+"</div>").text())),!z||"undefined"!=typeof c&&"undefined"!=typeof c.prefetch||z.set(l),p.get(0).innerHTML=d,g=p.find(":jqmData(role='page'), :jqmData(role='dialog')").first(),g.length||(g=a("<div data-"+a.mobile.ns+"role='page'>"+(d.split(/<\/?body[^>]*>/gim)[1]||"")+"</div>")),r&&!g.jqmData("title")&&(~r.indexOf("&")&&(r=a("<div>"+r+"</div>").text()),g.jqmData("title",r)),!a.support.dynamicBaseTag){var v=n.get(l);g.find("[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]").each(function(){var b=a(this).is("[href]")?"href":a(this).is("[src]")?"src":"action",c=a(this).attr(b);c=c.replace(location.protocol+"//"+location.host+location.pathname,""),/^(\w+:|#|\/)/.test(c)||a(this).attr(b,v+c)})}g.attr("data-"+a.mobile.ns+"url",n.convertUrlToDataUrl(l)).attr("data-"+a.mobile.ns+"external-page",!0).appendTo(f.pageContainer),g.one("pagecreate",a.mobile._bindPageRemove),h(g,f.role),k.indexOf("&"+a.mobile.subPageUrlKey)>-1&&(g=f.pageContainer.children("[data-"+a.mobile.ns+"url='"+m+"']")),f.showLoadMsg&&s(),q.xhr=o,q.textStatus=i,q.page=g,f.pageContainer.trigger("pageload",q),e.resolve(k,c,g,j)},error:function(b,d,g){z&&z.set(n.get()),q.xhr=b,q.textStatus=d,q.errorThrown=g;var h=new a.Event("pageloadfailed");f.pageContainer.trigger(h,q),h.isDefaultPrevented()||(f.showLoadMsg&&(s(),a.mobile.showPageLoadingMsg(a.mobile.pageLoadErrorMessageTheme,a.mobile.pageLoadErrorMessage,!0),setTimeout(a.mobile.hidePageLoadingMsg,1500)),e.reject(k,c))}}):e.reject(k,c),e.promise()},a.mobile.loadPage.defaults={type:"get",data:d,reloadPage:!1,role:d,showLoadMsg:!1,pageContainer:d,loadMsgDelay:50},a.mobile.changePage=function(b,j){if(t)return s.unshift(arguments),void 0;var k,l=a.extend({},a.mobile.changePage.defaults,j);l.pageContainer=l.pageContainer||a.mobile.pageContainer,l.fromPage=l.fromPage||a.mobile.activePage,k="string"==typeof b;var m=l.pageContainer,o=new a.Event("pagebeforechange"),p={toPage:b,options:l};if(p.absUrl=k?n.makeUrlAbsolute(b,i()):b.data("absUrl"),m.trigger(o,p),!o.isDefaultPrevented()){if(b=p.toPage,k="string"==typeof b,t=!0,k)return l.target=b,a.mobile.loadPage(b,l).done(function(b,c,d,e){t=!1,c.duplicateCachedPage=e,d.data("absUrl",p.absUrl),a.mobile.changePage(d,c)}).fail(function(){e(!0),f(),l.pageContainer.trigger("pagechangefailed",p)}),void 0;b[0]!==a.mobile.firstPage[0]||l.dataUrl||(l.dataUrl=w.hrefNoHash);var q=l.fromPage,v=l.dataUrl&&n.convertUrlToDataUrl(l.dataUrl)||b.jqmData("url"),x=v,y=(n.getFilePath(v),r.getActive()),z=0===r.activeIndex,A=0,B=c.title,C="dialog"===l.role||"dialog"===b.jqmData("role");if(q&&q[0]===b[0]&&!l.allowSamePageTransition)return t=!1,m.trigger("pagechange",p),l.fromHashChange&&r.direct({url:v}),void 0;h(b,l.role),l.fromHashChange&&(A="back"===j.direction?-1:1);try{c.activeElement&&"body"!==c.activeElement.nodeName.toLowerCase()?a(c.activeElement).blur():a("input:focus, textarea:focus, select:focus").blur()}catch(D){}var E=!1;C&&y&&(y.url&&y.url.indexOf(u)>-1&&a.mobile.activePage&&!a.mobile.activePage.is(".ui-dialog")&&r.activeIndex>0&&(l.changeHash=!1,E=!0),v=y.url||"",v+=!E&&v.indexOf("#")>-1?u:"#"+u,0===r.activeIndex&&v===r.initialDst&&(v+=u));var F=y?b.jqmData("title")||b.children(":jqmData(role='header')").find(".ui-title").text():B;if(F&&B===c.title&&(B=F),b.jqmData("title")||b.jqmData("title",B),l.transition=l.transition||(A&&!z?y.transition:d)||(C?a.mobile.defaultDialogTransition:a.mobile.defaultPageTransition),!A&&E&&(r.getActive().pageUrl=x),v&&!l.fromHashChange){var G;!n.isPath(v)&&v.indexOf("#")<0&&(v="#"+v),G={transition:l.transition,title:B,pageUrl:x,role:l.role},l.changeHash!==!1&&a.mobile.hashListeningEnabled?a.mobile.navigate(v,G,!0):b[0]!==a.mobile.firstPage[0]&&a.mobile.navigate.history.add(v,G)}c.title=B,a.mobile.activePage=b,l.reverse=l.reverse||0>A,g(b,q,l.transition,l.reverse).done(function(c,d,g,h,i){e(),l.duplicateCachedPage&&l.duplicateCachedPage.remove(),i||a.mobile.focusPage(b),f(),m.trigger("pagechange",p)})}},a.mobile.changePage.defaults={transition:d,reverse:!1,changeHash:!0,fromHashChange:!1,role:d,duplicateCachedPage:d,pageContainer:d,showLoadMsg:!0,dataUrl:d,fromPage:d,allowSamePageTransition:!1},a.mobile.navreadyDeferred=a.Deferred(),a.mobile._registerInternalEvents=function(){var c=function(b,c){var d,e,f,g,h=!0;return!a.mobile.ajaxEnabled||b.is(":jqmData(ajax='false')")||!b.jqmHijackable().length||b.attr("target")?!1:(d=b.attr("action"),g=(b.attr("method")||"get").toLowerCase(),d||(d=k(b),"get"===g&&(d=n.parseUrl(d).hrefNoSearch),d===x.hrefNoHash&&(d=w.hrefNoSearch)),d=n.makeUrlAbsolute(d,k(b)),n.isExternal(d)&&!n.isPermittedCrossDomainRequest(w,d)?!1:(c||(e=b.serializeArray(),o&&o[0].form===b[0]&&(f=o.attr("name"),f&&(a.each(e,function(a,b){return b.name===f?(f="",!1):void 0}),f&&e.push({name:f,value:o.attr("value")}))),h={url:d,options:{type:g,data:a.param(e),transition:b.jqmData("transition"),reverse:"reverse"===b.jqmData("direction"),reloadPage:!0}}),h))};a.mobile.document.delegate("form","submit",function(b){var d=c(a(this));d&&(a.mobile.changePage(d.url,d.options),b.preventDefault())}),a.mobile.document.bind("vclick",function(b){var d,f,g=b.target,h=!1;if(!(b.which>1)&&a.mobile.linkBindingEnabled){if(o=a(g),a.data(g,"mobile-button")){if(!c(a(g).closest("form"),!0))return;g.parentNode&&(g=g.parentNode)}else{if(g=j(g),!g||"#"===n.parseUrl(g.getAttribute("href")||"#").hash)return;if(!a(g).jqmHijackable().length)return}~g.className.indexOf("ui-link-inherit")?g.parentNode&&(f=a.data(g.parentNode,"buttonElements")):f=a.data(g,"buttonElements"),f?g=f.outer:h=!0,d=a(g),h&&(d=d.closest(".ui-btn")),d.length>0&&!d.hasClass("ui-disabled")&&(e(!0),p=d,p.addClass(a.mobile.activeBtnClass))}}),a.mobile.document.bind("click",function(c){if(a.mobile.linkBindingEnabled&&!c.isDefaultPrevented()){var f,g=j(c.target),h=a(g);if(g&&!(c.which>1)&&h.jqmHijackable().length){if(f=function(){b.setTimeout(function(){e(!0)},200)},h.is(":jqmData(rel='back')"))return a.mobile.back(),!1;var i=k(h),l=n.makeUrlAbsolute(h.attr("href")||"#",i);if(!a.mobile.ajaxEnabled&&!n.isEmbeddedPage(l))return f(),void 0;if(-1!==l.search("#")){if(l=l.replace(/[^#]*#/,""),!l)return c.preventDefault(),void 0;l=n.isPath(l)?n.makeUrlAbsolute(l,i):n.makeUrlAbsolute("#"+l,w.hrefNoHash)}var m=h.is("[rel='external']")||h.is(":jqmData(ajax='false')")||h.is("[target]"),o=m||n.isExternal(l)&&!n.isPermittedCrossDomainRequest(w,l);if(o)return f(),void 0;var p=h.jqmData("transition"),q="reverse"===h.jqmData("direction")||h.jqmData("back"),r=h.attr("data-"+a.mobile.ns+"rel")||d;a.mobile.changePage(l,{transition:p,reverse:q,role:r,link:h}),c.preventDefault()}}}),a.mobile.document.delegate(".ui-page","pageshow.prefetch",function(){var b=[];a(this).find("a:jqmData(prefetch)").each(function(){var c=a(this),d=c.attr("href");d&&-1===a.inArray(d,b)&&(b.push(d),a.mobile.loadPage(d,{role:c.attr("data-"+a.mobile.ns+"rel"),prefetch:!0}))})}),a.mobile._handleHashChange=function(c,e){var f=n.stripHash(c),g=0===a.mobile.urlHistory.stack.length?"none":d,h={changeHash:!1,fromHashChange:!0,reverse:"back"===e.direction};if(a.extend(h,e,{transition:(r.getLast()||{}).transition||g}),r.activeIndex>0&&f.indexOf(u)>-1&&r.initialDst!==f){if(a.mobile.activePage&&!a.mobile.activePage.is(".ui-dialog"))return"back"===e.direction?a.mobile.back():b.history.forward(),void 0;f=e.pageUrl;var i=a.mobile.urlHistory.getActive();a.extend(h,{role:i.role,transition:i.transition,reverse:"back"===e.direction})}f?(f=n.isPath(f)?f:n.makeUrlAbsolute("#"+f,x),f===n.makeUrlAbsolute("#"+r.initialDst,x)&&r.stack.length&&r.stack[0].url!==r.initialDst.replace(u,"")&&(f=a.mobile.firstPage),a.mobile.changePage(f,h)):a.mobile.changePage(a.mobile.firstPage,h)},l.bind("navigate",function(b,c){var d;b.originalEvent&&b.originalEvent.isDefaultPrevented()||(d=a.event.special.navigate.originalEventName.indexOf("hashchange")>-1?c.state.hash:c.state.url,d||(d=a.mobile.path.parseLocation().hash),d&&"#"!==d&&0!==d.indexOf("#"+a.mobile.path.uiStateKey)||(d=location.href),a.mobile._handleHashChange(d,c.state))}),a.mobile.document.bind("pageshow",a.mobile.resetActivePageHeight),a.mobile.window.bind("throttledresize",a.mobile.resetActivePageHeight)},a(function(){q.resolve()}),a.when(q,a.mobile.navreadyDeferred).done(function(){a.mobile._registerInternalEvents()})}(a),function(a){a.mobile.transitionFallbacks.flip="fade"}(a,this),function(a){a.mobile.transitionFallbacks.flow="fade"}(a,this),function(a){a.mobile.transitionFallbacks.pop="fade"}(a,this),function(a){a.mobile.transitionHandlers.slide=a.mobile.transitionHandlers.simultaneous,a.mobile.transitionFallbacks.slide="fade"}(a,this),function(a){a.mobile.transitionFallbacks.slidedown="fade"}(a,this),function(a){a.mobile.transitionFallbacks.slidefade="fade"}(a,this),function(a){a.mobile.transitionFallbacks.slideup="fade"}(a,this),function(a){a.mobile.transitionFallbacks.turn="fade"}(a,this),function(a){a.mobile.page.prototype.options.degradeInputs={color:!1,date:!1,datetime:!1,"datetime-local":!1,email:!1,month:!1,number:!1,range:"number",search:"text",tel:!1,time:!1,url:!1,week:!1},a.mobile.document.bind("pagecreate create",function(b){var c,d=a.mobile.closestPageData(a(b.target));d&&(c=d.options,a(b.target).find("input").not(d.keepNativeSelector()).each(function(){var b=a(this),d=this.getAttribute("type"),e=c.degradeInputs[d]||"text";if(c.degradeInputs[d]){var f=a("<div>").html(b.clone()).html(),g=f.indexOf(" type=")>-1,h=g?/\s+type=["']?\w+['"]?/:/\/?>/,i=' type="'+e+'" data-'+a.mobile.ns+'type="'+d+'"'+(g?"":">");b.replaceWith(f.replace(h,i))}}))})}(a),function(a){a.widget("mobile.dialog",a.mobile.widget,{options:{closeBtn:"left",closeBtnText:"Close",overlayTheme:"a",corners:!0,initSelector:":jqmData(role='dialog')"},_handlePageBeforeShow:function(){this._isCloseable=!0,this.options.overlayTheme&&this.element.page("removeContainerBackground").page("setContainerBackground",this.options.overlayTheme)},_handlePageBeforeHide:function(){this._isCloseable=!1},_create:function(){var b=this.element,c=this.options.corners?" ui-corner-all":"",d=a("<div/>",{role:"dialog","class":"ui-dialog-contain ui-overlay-shadow"+c});b.addClass("ui-dialog ui-overlay-"+this.options.overlayTheme),b.wrapInner(d),b.bind("vclick submit",function(b){var c,d=a(b.target).closest("vclick"===b.type?"a":"form");d.length&&!d.jqmData("transition")&&(c=a.mobile.urlHistory.getActive()||{},d.attr("data-"+a.mobile.ns+"transition",c.transition||a.mobile.defaultDialogTransition).attr("data-"+a.mobile.ns+"direction","reverse"))}),this._on(b,{pagebeforeshow:"_handlePageBeforeShow",pagebeforehide:"_handlePageBeforeHide"}),a.extend(this,{_createComplete:!1}),this._setCloseBtn(this.options.closeBtn)},_setCloseBtn:function(b){var c,d,e=this;this._headerCloseButton&&(this._headerCloseButton.remove(),this._headerCloseButton=null),"none"!==b&&(d="left"===b?"left":"right",c=a("<a href='#' class='ui-btn-"+d+"' data-"+a.mobile.ns+"icon='delete' data-"+a.mobile.ns+"iconpos='notext'>"+this.options.closeBtnText+"</a>"),this.element.children().find(":jqmData(role='header')").first().prepend(c),this._createComplete&&a.fn.buttonMarkup&&c.buttonMarkup(),this._createComplete=!0,c.bind("click",function(){e.close()}),this._headerCloseButton=c)},_setOption:function(a,b){"closeBtn"===a&&this._setCloseBtn(b),this._super(a,b)},close:function(){var b,c,d=a.mobile.navigate.history;this._isCloseable&&(this._isCloseable=!1,a.mobile.hashListeningEnabled&&d.activeIndex>0?a.mobile.back():(b=Math.max(0,d.activeIndex-1),c=d.stack[b].pageUrl||d.stack[b].url,d.previousIndex=d.activeIndex,d.activeIndex=b,a.mobile.path.isPath(c)||(c=a.mobile.path.makeUrlAbsolute("#"+c)),a.mobile.changePage(c,{direction:"back",changeHash:!1,fromHashChange:!0})))}}),a.mobile.document.delegate(a.mobile.dialog.prototype.options.initSelector,"pagecreate",function(){a.mobile.dialog.prototype.enhance(this)})}(a,this),function(a){a.mobile.page.prototype.options.backBtnText="Back",a.mobile.page.prototype.options.addBackBtn=!1,a.mobile.page.prototype.options.backBtnTheme=null,a.mobile.page.prototype.options.headerTheme="a",a.mobile.page.prototype.options.footerTheme="a",a.mobile.page.prototype.options.contentTheme=null,a.mobile.document.bind("pagecreate",function(b){var c=a(b.target),d=c.data("mobile-page").options,e=c.jqmData("role"),f=d.theme;a(":jqmData(role='header'), :jqmData(role='footer'), :jqmData(role='content')",c).jqmEnhanceable().each(function(){var b,g,h,i,j=a(this),k=j.jqmData("role"),l=j.jqmData("theme"),m=l||d.contentTheme||"dialog"===e&&f;if(j.addClass("ui-"+k),"header"===k||"footer"===k){var n=l||("header"===k?d.headerTheme:d.footerTheme)||f;j.addClass("ui-bar-"+n).attr("role","header"===k?"banner":"contentinfo"),"header"===k&&(b=j.children("a, button"),g=b.hasClass("ui-btn-left"),h=b.hasClass("ui-btn-right"),g=g||b.eq(0).not(".ui-btn-right").addClass("ui-btn-left").length,h=h||b.eq(1).addClass("ui-btn-right").length),d.addBackBtn&&"header"===k&&a(".ui-page").length>1&&c.jqmData("url")!==a.mobile.path.stripHash(location.hash)&&!g&&(i=a("<a href='javascript:void(0);' class='ui-btn-left' data-"+a.mobile.ns+"rel='back' data-"+a.mobile.ns+"icon='arrow-l'>"+d.backBtnText+"</a>").attr("data-"+a.mobile.ns+"theme",d.backBtnTheme||n).prependTo(j)),j.children("h1, h2, h3, h4, h5, h6").addClass("ui-title").attr({role:"heading","aria-level":"1"})}else"content"===k&&(m&&j.addClass("ui-body-"+m),j.attr("role","main"))})})}(a),function(a,b){function d(a){for(var b;a&&(b="string"==typeof a.className&&a.className+" ",!(b&&b.indexOf("ui-btn ")>-1&&b.indexOf("ui-disabled ")<0));)a=a.parentNode;return a}function e(d,e,f,g,h){var i=a.data(d[0],"buttonElements");d.removeClass(e).addClass(f),i&&(i.bcls=a(c.createElement("div")).addClass(i.bcls+" "+f).removeClass(e).attr("class"),g!==b&&(i.hover=g),i.state=h)}var f=function(a,c){var d=a.getAttribute(c);return"true"===d?!0:"false"===d?!1:null===d?b:d};a.fn.buttonMarkup=function(d){var e,h=this,i="data-"+a.mobile.ns;d=d&&"object"===a.type(d)?d:{};for(var j=0;j<h.length;j++){var k,l,m,n,o,p,q=h.eq(j),r=q[0],s=a.extend({},a.fn.buttonMarkup.defaults,{icon:d.icon!==b?d.icon:f(r,i+"icon"),iconpos:d.iconpos!==b?d.iconpos:f(r,i+"iconpos"),theme:d.theme!==b?d.theme:f(r,i+"theme")||a.mobile.getInheritedTheme(q,"c"),inline:d.inline!==b?d.inline:f(r,i+"inline"),shadow:d.shadow!==b?d.shadow:f(r,i+"shadow"),corners:d.corners!==b?d.corners:f(r,i+"corners"),iconshadow:d.iconshadow!==b?d.iconshadow:f(r,i+"iconshadow"),mini:d.mini!==b?d.mini:f(r,i+"mini")},d),t="ui-btn-inner",u="ui-btn-text",v=!1,w="up";for(e in s)s[e]===b||null===s[e]?q.removeAttr(i+e):r.setAttribute(i+e,s[e]);for(p=a.data("INPUT"===r.tagName||"BUTTON"===r.tagName?r.parentNode:r,"buttonElements"),p?(r=p.outer,q=a(r),m=p.inner,n=p.text,a(p.icon).remove(),p.icon=null,v=p.hover,w=p.state):(m=c.createElement(s.wrapperEls),n=c.createElement(s.wrapperEls)),o=s.icon?c.createElement("span"):null,g&&!p&&g(),s.theme||(s.theme=a.mobile.getInheritedTheme(q,"c")),k="ui-btn ",k+=v?"ui-btn-hover-"+s.theme:"",k+=w?" ui-btn-"+w+"-"+s.theme:"",k+=s.shadow?" ui-shadow":"",k+=s.corners?" ui-btn-corner-all":"",s.mini!==b&&(k+=s.mini===!0?" ui-mini":" ui-fullsize"),s.inline!==b&&(k+=s.inline===!0?" ui-btn-inline":" ui-btn-block"),s.icon&&(s.icon="ui-icon-"+s.icon,s.iconpos=s.iconpos||"left",l="ui-icon "+s.icon,s.iconshadow&&(l+=" ui-icon-shadow")),s.iconpos&&(k+=" ui-btn-icon-"+s.iconpos,"notext"!==s.iconpos||q.attr("title")||q.attr("title",q.getEncodedText())),p&&q.removeClass(p.bcls||""),q.removeClass("ui-link").addClass(k),m.className=t,n.className=u,p||m.appendChild(n),o&&(o.className=l,p&&p.icon||(o.innerHTML="&#160;",m.appendChild(o)));r.firstChild&&!p;)n.appendChild(r.firstChild);p||r.appendChild(m),p={hover:v,state:w,bcls:k,outer:r,inner:m,text:n,icon:o},a.data(r,"buttonElements",p),a.data(m,"buttonElements",p),a.data(n,"buttonElements",p),o&&a.data(o,"buttonElements",p)}return this},a.fn.buttonMarkup.defaults={corners:!0,shadow:!0,iconshadow:!0,wrapperEls:"span"};var g=function(){var c,f,h=a.mobile.buttonMarkup.hoverDelay;a.mobile.document.bind({"vmousedown vmousecancel vmouseup vmouseover vmouseout focus blur scrollstart":function(g){var i,j=a(d(g.target)),k=g.originalEvent&&/^touch/.test(g.originalEvent.type),l=g.type;j.length&&(i=j.attr("data-"+a.mobile.ns+"theme"),"vmousedown"===l?k?c=setTimeout(function(){e(j,"ui-btn-up-"+i,"ui-btn-down-"+i,b,"down")},h):e(j,"ui-btn-up-"+i,"ui-btn-down-"+i,b,"down"):"vmousecancel"===l||"vmouseup"===l?e(j,"ui-btn-down-"+i,"ui-btn-up-"+i,b,"up"):"vmouseover"===l||"focus"===l?k?f=setTimeout(function(){e(j,"ui-btn-up-"+i,"ui-btn-hover-"+i,!0,"")},h):e(j,"ui-btn-up-"+i,"ui-btn-hover-"+i,!0,""):("vmouseout"===l||"blur"===l||"scrollstart"===l)&&(e(j,"ui-btn-hover-"+i+" ui-btn-down-"+i,"ui-btn-up-"+i,!1,"up"),c&&clearTimeout(c),f&&clearTimeout(f)))},"focusin focus":function(b){a(d(b.target)).addClass(a.mobile.focusClass)},"focusout blur":function(b){a(d(b.target)).removeClass(a.mobile.focusClass)}}),g=null};a.mobile.document.bind("pagecreate create",function(b){a(":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a",b.target).jqmEnhanceable().not("button, input, .ui-btn, :jqmData(role='none'), :jqmData(role='nojs')").buttonMarkup()})}(a),function(a,b){a.widget("mobile.collapsible",a.mobile.widget,{options:{expandCueText:" click to expand contents",collapseCueText:" click to collapse contents",collapsed:!0,heading:"h1,h2,h3,h4,h5,h6,legend",collapsedIcon:"plus",expandedIcon:"minus",iconpos:"left",theme:null,contentTheme:null,inset:!0,corners:!0,mini:!1,initSelector:":jqmData(role='collapsible')"},_create:function(){var c=this.element,d=this.options,e=c.addClass("ui-collapsible"),f=c.children(d.heading).first(),g=e.wrapInner("<div class='ui-collapsible-content'></div>").children(".ui-collapsible-content"),h=c.closest(":jqmData(role='collapsible-set')").addClass("ui-collapsible-set"),i="";f.is("legend")&&(f=a("<div role='heading'>"+f.html()+"</div>").insertBefore(f),f.next().remove()),h.length?(d.theme||(d.theme=h.jqmData("theme")||a.mobile.getInheritedTheme(h,"c")),d.contentTheme||(d.contentTheme=h.jqmData("content-theme")),d.collapsedIcon=c.jqmData("collapsed-icon")||h.jqmData("collapsed-icon")||d.collapsedIcon,d.expandedIcon=c.jqmData("expanded-icon")||h.jqmData("expanded-icon")||d.expandedIcon,d.iconpos=c.jqmData("iconpos")||h.jqmData("iconpos")||d.iconpos,d.inset=h.jqmData("inset")!==b?h.jqmData("inset"):!0,d.corners=!1,d.mini||(d.mini=h.jqmData("mini"))):d.theme||(d.theme=a.mobile.getInheritedTheme(c,"c")),d.inset&&(i+=" ui-collapsible-inset",d.corners&&(i+=" ui-corner-all")),d.contentTheme&&(i+=" ui-collapsible-themed-content",g.addClass("ui-body-"+d.contentTheme)),""!==i&&e.addClass(i),f.insertBefore(g).addClass("ui-collapsible-heading").append("<span class='ui-collapsible-heading-status'></span>").wrapInner("<a href='#' class='ui-collapsible-heading-toggle'></a>").find("a").first().buttonMarkup({shadow:!1,corners:!1,iconpos:d.iconpos,icon:d.collapsedIcon,mini:d.mini,theme:d.theme}),e.bind("expand collapse",function(b){if(!b.isDefaultPrevented()){var c=a(this),e="collapse"===b.type;b.preventDefault(),f.toggleClass("ui-collapsible-heading-collapsed",e).find(".ui-collapsible-heading-status").text(e?d.expandCueText:d.collapseCueText).end().find(".ui-icon").toggleClass("ui-icon-"+d.expandedIcon,!e).toggleClass("ui-icon-"+d.collapsedIcon,e||d.expandedIcon===d.collapsedIcon).end().find("a").first().removeClass(a.mobile.activeBtnClass),c.toggleClass("ui-collapsible-collapsed",e),g.toggleClass("ui-collapsible-content-collapsed",e).attr("aria-hidden",e),g.trigger("updatelayout")}}).trigger(d.collapsed?"collapse":"expand"),f.bind("tap",function(){f.find("a").first().addClass(a.mobile.activeBtnClass)}).bind("click",function(a){var b=f.is(".ui-collapsible-heading-collapsed")?"expand":"collapse";e.trigger(b),a.preventDefault(),a.stopPropagation()})}}),a.mobile.document.bind("pagecreate create",function(b){a.mobile.collapsible.prototype.enhanceWithin(b.target)})}(a),function(a){a.mobile.behaviors.addFirstLastClasses={_getVisibles:function(a,b){var c;return b?c=a.not(".ui-screen-hidden"):(c=a.filter(":visible"),0===c.length&&(c=a.not(".ui-screen-hidden"))),c},_addFirstLastClasses:function(a,b,c){a.removeClass("ui-first-child ui-last-child"),b.eq(0).addClass("ui-first-child").end().last().addClass("ui-last-child"),c||this.element.trigger("updatelayout")}}}(a),function(a,b){a.widget("mobile.collapsibleset",a.mobile.widget,a.extend({options:{initSelector:":jqmData(role='collapsible-set')"},_create:function(){var c=this.element.addClass("ui-collapsible-set"),d=this.options;d.theme||(d.theme=a.mobile.getInheritedTheme(c,"c")),d.contentTheme||(d.contentTheme=c.jqmData("content-theme")),d.corners||(d.corners=c.jqmData("corners")),c.jqmData("inset")!==b&&(d.inset=c.jqmData("inset")),d.inset=d.inset!==b?d.inset:!0,d.corners=d.corners!==b?d.corners:!0,d.corners&&d.inset&&c.addClass("ui-corner-all"),c.jqmData("collapsiblebound")||c.jqmData("collapsiblebound",!0).bind("expand",function(b){var c=a(b.target).closest(".ui-collapsible");
+c.parent().is(":jqmData(role='collapsible-set')")&&c.siblings(".ui-collapsible").trigger("collapse")})},_init:function(){var a=this.element,b=a.children(":jqmData(role='collapsible')"),c=b.filter(":jqmData(collapsed='false')");this._refresh("true"),c.trigger("expand")},_refresh:function(b){var c=this.element.children(":jqmData(role='collapsible')");a.mobile.collapsible.prototype.enhance(c.not(".ui-collapsible")),this._addFirstLastClasses(c,this._getVisibles(c,b),b)},refresh:function(){this._refresh(!1)}},a.mobile.behaviors.addFirstLastClasses)),a.mobile.document.bind("pagecreate create",function(b){a.mobile.collapsibleset.prototype.enhanceWithin(b.target)})}(a),function(a){a.fn.fieldcontain=function(){return this.addClass("ui-field-contain ui-body ui-br").contents().filter(function(){return 3===this.nodeType&&!/\S/.test(this.nodeValue)}).remove()},a(c).bind("pagecreate create",function(b){a(":jqmData(role='fieldcontain')",b.target).jqmEnhanceable().fieldcontain()})}(a),function(a){a.fn.grid=function(b){return this.each(function(){var c,d=a(this),e=a.extend({grid:null},b),f=d.children(),g={solo:1,a:2,b:3,c:4,d:5},h=e.grid;if(!h)if(f.length<=5)for(var i in g)g[i]===f.length&&(h=i);else h="a",d.addClass("ui-grid-duo");c=g[h],d.addClass("ui-grid-"+h),f.filter(":nth-child("+c+"n+1)").addClass("ui-block-a"),c>1&&f.filter(":nth-child("+c+"n+2)").addClass("ui-block-b"),c>2&&f.filter(":nth-child("+c+"n+3)").addClass("ui-block-c"),c>3&&f.filter(":nth-child("+c+"n+4)").addClass("ui-block-d"),c>4&&f.filter(":nth-child("+c+"n+5)").addClass("ui-block-e")})}}(a),function(a,b){a.widget("mobile.navbar",a.mobile.widget,{options:{iconpos:"top",grid:null,initSelector:":jqmData(role='navbar')"},_create:function(){var d=this.element,e=d.find("a"),f=e.filter(":jqmData(icon)").length?this.options.iconpos:b;d.addClass("ui-navbar ui-mini").attr("role","navigation").find("ul").jqmEnhanceable().grid({grid:this.options.grid}),e.buttonMarkup({corners:!1,shadow:!1,inline:!0,iconpos:f}),d.delegate("a","vclick",function(b){var d=a(b.target).is("a")?a(this):a(this).parent("a");if(!d.is(".ui-disabled, .ui-btn-active")){e.removeClass(a.mobile.activeBtnClass),a(this).addClass(a.mobile.activeBtnClass);var f=a(this);a(c).one("pagehide",function(){f.removeClass(a.mobile.activeBtnClass)})}}),d.closest(".ui-page").bind("pagebeforeshow",function(){e.filter(".ui-state-persist").addClass(a.mobile.activeBtnClass)})}}),a.mobile.document.bind("pagecreate create",function(b){a.mobile.navbar.prototype.enhanceWithin(b.target)})}(a),function(a){var b={};a.widget("mobile.listview",a.mobile.widget,a.extend({options:{theme:null,countTheme:"c",headerTheme:"b",dividerTheme:"b",icon:"arrow-r",splitIcon:"arrow-r",splitTheme:"b",corners:!0,shadow:!0,inset:!1,initSelector:":jqmData(role='listview')"},_create:function(){var a=this,b="";b+=a.options.inset?" ui-listview-inset":"",a.options.inset&&(b+=a.options.corners?" ui-corner-all":"",b+=a.options.shadow?" ui-shadow":""),a.element.addClass(function(a,c){return c+" ui-listview"+b}),a.refresh(!0)},_findFirstElementByTagName:function(a,b,c,d){var e={};for(e[c]=e[d]=!0;a;){if(e[a.nodeName])return a;a=a[b]}return null},_getChildrenByTagName:function(b,c,d){var e=[],f={};for(f[c]=f[d]=!0,b=b.firstChild;b;)f[b.nodeName]&&e.push(b),b=b.nextSibling;return a(e)},_addThumbClasses:function(b){var c,d,e=b.length;for(c=0;e>c;c++)d=a(this._findFirstElementByTagName(b[c].firstChild,"nextSibling","img","IMG")),d.length&&(d.addClass("ui-li-thumb"),a(this._findFirstElementByTagName(d[0].parentNode,"parentNode","li","LI")).addClass(d.is(".ui-li-icon")?"ui-li-has-icon":"ui-li-has-thumb"))},refresh:function(b){this.parentPage=this.element.closest(".ui-page"),this._createSubPages();var d,e,f,g,h,i,j,k,l,m,n,o,p=this.options,q=this.element,r=q.jqmData("dividertheme")||p.dividerTheme,s=q.jqmData("splittheme"),t=q.jqmData("spliticon"),u=q.jqmData("icon"),v=this._getChildrenByTagName(q[0],"li","LI"),w=!!a.nodeName(q[0],"ol"),x=!a.support.cssPseudoElement,y=q.attr("start"),z={};w&&x&&q.find(".ui-li-dec").remove(),w&&(y||0===y?x?j=parseInt(y,10):(k=parseInt(y,10)-1,q.css("counter-reset","listnumbering "+k)):x&&(j=1)),p.theme||(p.theme=a.mobile.getInheritedTheme(this.element,"c"));for(var A=0,B=v.length;B>A;A++){if(d=v.eq(A),e="ui-li",b||!d.hasClass("ui-li")){f=d.jqmData("theme")||p.theme,g=this._getChildrenByTagName(d[0],"a","A");var C="list-divider"===d.jqmData("role");g.length&&!C?(n=d.jqmData("icon"),d.buttonMarkup({wrapperEls:"div",shadow:!1,corners:!1,iconpos:"right",icon:g.length>1||n===!1?!1:n||u||p.icon,theme:f}),n!==!1&&1===g.length&&d.addClass("ui-li-has-arrow"),g.first().removeClass("ui-link").addClass("ui-link-inherit"),g.length>1&&(e+=" ui-li-has-alt",h=g.last(),i=s||h.jqmData("theme")||p.splitTheme,o=h.jqmData("icon"),h.appendTo(d).attr("title",a.trim(h.getEncodedText())).addClass("ui-li-link-alt").empty().buttonMarkup({shadow:!1,corners:!1,theme:f,icon:!1,iconpos:"notext"}).find(".ui-btn-inner").append(a(c.createElement("span")).buttonMarkup({shadow:!0,corners:!0,theme:i,iconpos:"notext",icon:o||n||t||p.splitIcon})))):C?(e+=" ui-li-divider ui-bar-"+(d.jqmData("theme")||r),d.attr("role","heading"),w&&(y||0===y?x?j=parseInt(y,10):(l=parseInt(y,10)-1,d.css("counter-reset","listnumbering "+l)):x&&(j=1))):e+=" ui-li-static ui-btn-up-"+f}w&&x&&e.indexOf("ui-li-divider")<0&&(m=e.indexOf("ui-li-static")>0?d:d.find(".ui-link-inherit"),m.addClass("ui-li-jsnumbering").prepend("<span class='ui-li-dec'>"+j++ +". </span>")),z[e]||(z[e]=[]),z[e].push(d[0])}for(e in z)a(z[e]).addClass(e).children(".ui-btn-inner").addClass(e);q.find("h1, h2, h3, h4, h5, h6").addClass("ui-li-heading").end().find("p, dl").addClass("ui-li-desc").end().find(".ui-li-aside").each(function(){var b=a(this);b.prependTo(b.parent())}).end().find(".ui-li-count").each(function(){a(this).closest("li").addClass("ui-li-has-count")}).addClass("ui-btn-up-"+(q.jqmData("counttheme")||this.options.countTheme)+" ui-btn-corner-all"),this._addThumbClasses(v),this._addThumbClasses(q.find(".ui-link-inherit")),this._addFirstLastClasses(v,this._getVisibles(v,b),b),this._trigger("afterrefresh")},_idStringEscape:function(a){return a.replace(/[^a-zA-Z0-9]/g,"-")},_createSubPages:function(){var c,d=this.element,e=d.closest(".ui-page"),f=e.jqmData("url"),g=f||e[0][a.expando],h=d.attr("id"),i=this.options,j="data-"+a.mobile.ns,k=this,l=e.find(":jqmData(role='footer')").jqmData("id");if("undefined"==typeof b[g]&&(b[g]=-1),h=h||++b[g],a(d.find("li>ul, li>ol").toArray().reverse()).each(function(b){var e,g,k=a(this),m=k.attr("id")||h+"-"+b,n=k.parent(),o=a(k.prevAll().toArray().reverse()),p=o.length?o:a("<span>"+a.trim(n.contents()[0].nodeValue)+"</span>"),q=p.first().getEncodedText(),r=(f||"")+"&"+a.mobile.subPageUrlKey+"="+m,s=k.jqmData("theme")||i.theme,t=k.jqmData("counttheme")||d.jqmData("counttheme")||i.countTheme;c=!0,e=k.detach().wrap("<div "+j+"role='page' "+j+"url='"+r+"' "+j+"theme='"+s+"' "+j+"count-theme='"+t+"'><div "+j+"role='content'></div></div>").parent().before("<div "+j+"role='header' "+j+"theme='"+i.headerTheme+"'><div class='ui-title'>"+q+"</div></div>").after(l?a("<div "+j+"role='footer' "+j+"id='"+l+"'>"):"").parent().appendTo(a.mobile.pageContainer),e.page(),g=n.find("a:first"),g.length||(g=a("<a/>").html(p||q).prependTo(n.empty())),g.attr("href","#"+r)}).listview(),c&&e.is(":jqmData(external-page='true')")&&e.data("mobile-page").options.domCache===!1){var m=function(b,c){var d,g=c.nextPage,h=new a.Event("pageremove");c.nextPage&&(d=g.jqmData("url"),0!==d.indexOf(f+"&"+a.mobile.subPageUrlKey)&&(k.childPages().remove(),e.trigger(h),h.isDefaultPrevented()||e.removeWithDependents()))};e.unbind("pagehide.remove").bind("pagehide.remove",m)}},childPages:function(){var b=this.parentPage.jqmData("url");return a(":jqmData(url^='"+b+"&"+a.mobile.subPageUrlKey+"')")}},a.mobile.behaviors.addFirstLastClasses)),a.mobile.document.bind("pagecreate create",function(b){a.mobile.listview.prototype.enhanceWithin(b.target)})}(a),function(a){var b=a("meta[name=viewport]"),c=b.attr("content"),d=c+",maximum-scale=1, user-scalable=no",e=c+",maximum-scale=10, user-scalable=yes",f=/(user-scalable[\s]*=[\s]*no)|(maximum-scale[\s]*=[\s]*1)[$,\s]/.test(c);a.mobile.zoom=a.extend({},{enabled:!f,locked:!1,disable:function(c){f||a.mobile.zoom.locked||(b.attr("content",d),a.mobile.zoom.enabled=!1,a.mobile.zoom.locked=c||!1)},enable:function(c){f||a.mobile.zoom.locked&&c!==!0||(b.attr("content",e),a.mobile.zoom.enabled=!0,a.mobile.zoom.locked=!1)},restore:function(){f||(b.attr("content",c),a.mobile.zoom.enabled=!0)}})}(a),function(a){a.widget("mobile.textinput",a.mobile.widget,{options:{theme:null,mini:!1,preventFocusZoom:/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1,initSelector:"input[type='text'], input[type='search'], :jqmData(type='search'), input[type='number'], :jqmData(type='number'), input[type='password'], input[type='email'], input[type='url'], input[type='tel'], textarea, input[type='time'], input[type='date'], input[type='month'], input[type='week'], input[type='datetime'], input[type='datetime-local'], input[type='color'], input:not([type]), input[type='file']",clearBtn:!1,clearSearchButtonText:null,clearBtnText:"clear text",disabled:!1},_create:function(){function b(){setTimeout(function(){d.toggleClass("ui-input-clear-hidden",!f.val())},0)}var c,d,e=this,f=this.element,g=this.options,h=g.theme||a.mobile.getInheritedTheme(this.element,"c"),i=" ui-body-"+h,j=g.mini?" ui-mini":"",k=f.is("[type='search'], :jqmData(type='search')"),l=g.clearSearchButtonText||g.clearBtnText,m=f.is("textarea, :jqmData(type='range')"),n=!!g.clearBtn&&!m,o=f.is("input")&&!f.is(":jqmData(type='range')");if(a("label[for='"+f.attr("id")+"']").addClass("ui-input-text"),c=f.addClass("ui-input-text ui-body-"+h),"undefined"==typeof f[0].autocorrect||a.support.touchOverflow||(f[0].setAttribute("autocorrect","off"),f[0].setAttribute("autocomplete","off")),k?c=f.wrap("<div class='ui-input-search ui-shadow-inset ui-btn-corner-all ui-btn-shadow ui-icon-searchfield"+i+j+"'></div>").parent():o&&(c=f.wrap("<div class='ui-input-text ui-shadow-inset ui-corner-all ui-btn-shadow"+i+j+"'></div>").parent()),n||k?(d=a("<a href='#' class='ui-input-clear' title='"+l+"'>"+l+"</a>").bind("click",function(a){f.val("").focus().trigger("change"),d.addClass("ui-input-clear-hidden"),a.preventDefault()}).appendTo(c).buttonMarkup({icon:"delete",iconpos:"notext",corners:!0,shadow:!0,mini:g.mini}),k||c.addClass("ui-input-has-clear"),b(),f.bind("paste cut keyup input focus change blur",b)):o||k||f.addClass("ui-corner-all ui-shadow-inset"+i+j),f.focus(function(){g.preventFocusZoom&&a.mobile.zoom.disable(!0),c.addClass(a.mobile.focusClass)}).blur(function(){c.removeClass(a.mobile.focusClass),g.preventFocusZoom&&a.mobile.zoom.enable(!0)}),f.is("textarea")){var p,q=15,r=100;this._keyup=function(){var a=f[0].scrollHeight,b=f[0].clientHeight;if(a>b){var c=parseFloat(f.css("padding-top")),d=parseFloat(f.css("padding-bottom")),e=c+d;f.height(a-e+q)}},f.on("keyup change input paste",function(){clearTimeout(p),p=setTimeout(e._keyup,r)}),this._on(!0,a.mobile.document,{pagechange:"_keyup"}),a.trim(f.val())&&this._on(!0,a.mobile.window,{load:"_keyup"})}f.attr("disabled")&&this.disable()},disable:function(){var a,b=this.element.is("[type='search'], :jqmData(type='search')"),c=this.element.is("input")&&!this.element.is(":jqmData(type='range')"),d=this.element.attr("disabled",!0)&&(c||b);return a=d?this.element.parent():this.element,a.addClass("ui-disabled"),this._setOption("disabled",!0)},enable:function(){var a,b=this.element.is("[type='search'], :jqmData(type='search')"),c=this.element.is("input")&&!this.element.is(":jqmData(type='range')"),d=this.element.attr("disabled",!1)&&(c||b);return a=d?this.element.parent():this.element,a.removeClass("ui-disabled"),this._setOption("disabled",!1)}}),a.mobile.document.bind("pagecreate create",function(b){a.mobile.textinput.prototype.enhanceWithin(b.target,!0)})}(a),function(a){a.mobile.listview.prototype.options.filter=!1,a.mobile.listview.prototype.options.filterPlaceholder="Filter items...",a.mobile.listview.prototype.options.filterTheme="c",a.mobile.listview.prototype.options.filterReveal=!1;var b=function(a,b){return-1===a.toString().toLowerCase().indexOf(b)};a.mobile.listview.prototype.options.filterCallback=b,a.mobile.document.delegate("ul, ol","listviewcreate",function(){var c=a(this),d=c.data("mobile-listview");if(d&&d.options.filter){d.options.filterReveal&&c.children().addClass("ui-screen-hidden");var e=a("<form>",{"class":"ui-listview-filter ui-bar-"+d.options.filterTheme,role:"search"}).submit(function(a){a.preventDefault(),g.blur()}),f=function(){var e,f=a(this),g=this.value.toLowerCase(),h=null,i=c.children(),j=f.jqmData("lastval")+"",k=!1,l="",m=d.options.filterCallback!==b;if(!j||j!==g){if(d._trigger("beforefilter","beforefilter",{input:this}),f.jqmData("lastval",g),m||g.length<j.length||0!==g.indexOf(j)?h=c.children():(h=c.children(":not(.ui-screen-hidden)"),!h.length&&d.options.filterReveal&&(h=c.children(".ui-screen-hidden"))),g){for(var n=h.length-1;n>=0;n--)e=a(h[n]),l=e.jqmData("filtertext")||e.text(),e.is("li:jqmData(role=list-divider)")?(e.toggleClass("ui-filter-hidequeue",!k),k=!1):d.options.filterCallback(l,g,e)?e.toggleClass("ui-filter-hidequeue",!0):k=!0;h.filter(":not(.ui-filter-hidequeue)").toggleClass("ui-screen-hidden",!1),h.filter(".ui-filter-hidequeue").toggleClass("ui-screen-hidden",!0).toggleClass("ui-filter-hidequeue",!1)}else h.toggleClass("ui-screen-hidden",!!d.options.filterReveal);d._addFirstLastClasses(i,d._getVisibles(i,!1),!1)}},g=a("<input>",{placeholder:d.options.filterPlaceholder}).attr("data-"+a.mobile.ns+"type","search").jqmData("lastval","").bind("keyup change input",f).appendTo(e).textinput();d.options.inset&&e.addClass("ui-listview-filter-inset"),e.bind("submit",function(){return!1}).insertBefore(c)}})}(a),function(a){a.mobile.listview.prototype.options.autodividers=!1,a.mobile.listview.prototype.options.autodividersSelector=function(b){var c=a.trim(b.text())||null;return c?c=c.slice(0,1).toUpperCase():null},a.mobile.document.delegate("ul,ol","listviewcreate",function(){var b=a(this),d=b.data("mobile-listview");if(d&&d.options.autodividers){var e=function(){b.find("li:jqmData(role='list-divider')").remove();for(var e,f,g=b.find("li"),h=null,i=0;i<g.length;i++){if(e=g[i],f=d.options.autodividersSelector(a(e)),f&&h!==f){var j=c.createElement("li");j.appendChild(c.createTextNode(f)),j.setAttribute("data-"+a.mobile.ns+"role","list-divider"),e.parentNode.insertBefore(j,e)}h=f}},f=function(){b.unbind("listviewafterrefresh",f),e(),d.refresh(),b.bind("listviewafterrefresh",f)};f()}})}(a),function(a){a(c).bind("pagecreate create",function(b){a(":jqmData(role='nojs')",b.target).addClass("ui-nojs")})}(a),function(a){a.mobile.behaviors.formReset={_handleFormReset:function(){this._on(this.element.closest("form"),{reset:function(){this._delay("_reset")}})}}}(a),function(a){a.widget("mobile.checkboxradio",a.mobile.widget,a.extend({options:{theme:null,mini:!1,initSelector:"input[type='checkbox'],input[type='radio']"},_create:function(){var b=this,d=this.element,e=this.options,f=function(a,b){return a.jqmData(b)||a.closest("form, fieldset").jqmData(b)},g=a(d).closest("label"),h=g.length?g:a(d).closest("form, fieldset, :jqmData(role='page'), :jqmData(role='dialog')").find("label").filter("[for='"+d[0].id+"']").first(),i=d[0].type,j=f(d,"mini")||e.mini,k=i+"-on",l=i+"-off",m=f(d,"iconpos"),n="ui-"+k,o="ui-"+l;if("checkbox"===i||"radio"===i){a.extend(this,{label:h,inputtype:i,checkedClass:n,uncheckedClass:o,checkedicon:k,uncheckedicon:l}),e.theme||(e.theme=a.mobile.getInheritedTheme(this.element,"c")),h.buttonMarkup({theme:e.theme,icon:l,shadow:!1,mini:j,iconpos:m});var p=c.createElement("div");p.className="ui-"+i,d.add(h).wrapAll(p),h.bind({vmouseover:function(b){a(this).parent().is(".ui-disabled")&&b.stopPropagation()},vclick:function(a){return d.is(":disabled")?(a.preventDefault(),void 0):(b._cacheVals(),d.prop("checked","radio"===i&&!0||!d.prop("checked")),d.triggerHandler("click"),b._getInputSet().not(d).prop("checked",!1),b._updateAll(),!1)}}),d.bind({vmousedown:function(){b._cacheVals()},vclick:function(){var c=a(this);c.is(":checked")?(c.prop("checked",!0),b._getInputSet().not(c).prop("checked",!1)):c.prop("checked",!1),b._updateAll()},focus:function(){h.addClass(a.mobile.focusClass)},blur:function(){h.removeClass(a.mobile.focusClass)}}),this._handleFormReset(),this.refresh()}},_cacheVals:function(){this._getInputSet().each(function(){a(this).jqmData("cacheVal",this.checked)})},_getInputSet:function(){return"checkbox"===this.inputtype?this.element:this.element.closest("form, :jqmData(role='page'), :jqmData(role='dialog')").find("input[name='"+this.element[0].name+"'][type='"+this.inputtype+"']")},_updateAll:function(){var b=this;this._getInputSet().each(function(){var c=a(this);(this.checked||"checkbox"===b.inputtype)&&c.trigger("change")}).checkboxradio("refresh")},_reset:function(){this.refresh()},refresh:function(){var b=this.element[0],c=" "+a.mobile.activeBtnClass,d=this.checkedClass+(this.element.parents(".ui-controlgroup-horizontal").length?c:""),e=this.label;b.checked?e.removeClass(this.uncheckedClass+c).addClass(d).buttonMarkup({icon:this.checkedicon}):e.removeClass(d).addClass(this.uncheckedClass).buttonMarkup({icon:this.uncheckedicon}),b.disabled?this.disable():this.enable()},disable:function(){this.element.prop("disabled",!0).parent().addClass("ui-disabled")},enable:function(){this.element.prop("disabled",!1).parent().removeClass("ui-disabled")}},a.mobile.behaviors.formReset)),a.mobile.document.bind("pagecreate create",function(b){a.mobile.checkboxradio.prototype.enhanceWithin(b.target,!0)})}(a),function(a){a.widget("mobile.button",a.mobile.widget,{options:{theme:null,icon:null,iconpos:null,corners:!0,shadow:!0,iconshadow:!0,inline:null,mini:null,initSelector:"button, [type='button'], [type='submit'], [type='reset']"},_create:function(){var b,c=this.element,d=function(a){var b,c={};for(b in a)null!==a[b]&&"initSelector"!==b&&(c[b]=a[b]);return c}(this.options),e="";return"A"===c[0].tagName?(c.hasClass("ui-btn")||c.buttonMarkup(),void 0):(this.options.theme||(this.options.theme=a.mobile.getInheritedTheme(this.element,"c")),~c[0].className.indexOf("ui-btn-left")&&(e="ui-btn-left"),~c[0].className.indexOf("ui-btn-right")&&(e="ui-btn-right"),("submit"===c.attr("type")||"reset"===c.attr("type"))&&(e?e+=" ui-submit":e="ui-submit"),a("label[for='"+c.attr("id")+"']").addClass("ui-submit"),this.button=a("<div></div>")[c.html()?"html":"text"](c.html()||c.val()).insertBefore(c).buttonMarkup(d).addClass(e).append(c.addClass("ui-btn-hidden")),b=this.button,c.bind({focus:function(){b.addClass(a.mobile.focusClass)},blur:function(){b.removeClass(a.mobile.focusClass)}}),this.refresh(),void 0)},_setOption:function(b,c){var d={};d[b]=c,"initSelector"!==b&&(this.button.buttonMarkup(d),this.element.attr("data-"+(a.mobile.ns||"")+b.replace(/([A-Z])/,"-$1").toLowerCase(),c)),this._super("_setOption",b,c)},enable:function(){return this.element.attr("disabled",!1),this.button.removeClass("ui-disabled").attr("aria-disabled",!1),this._setOption("disabled",!1)},disable:function(){return this.element.attr("disabled",!0),this.button.addClass("ui-disabled").attr("aria-disabled",!0),this._setOption("disabled",!0)},refresh:function(){var b=this.element;b.prop("disabled")?this.disable():this.enable(),a(this.button.data("buttonElements").text)[b.html()?"html":"text"](b.html()||b.val())}}),a.mobile.document.bind("pagecreate create",function(b){a.mobile.button.prototype.enhanceWithin(b.target,!0)})}(a),function(a,d){a.widget("mobile.slider",a.mobile.widget,a.extend({widgetEventPrefix:"slide",options:{theme:null,trackTheme:null,disabled:!1,initSelector:"input[type='range'], :jqmData(type='range'), :jqmData(role='slider')",mini:!1,highlight:!1},_create:function(){var e,f,g=this,h=this.element,i=a.mobile.getInheritedTheme(h,"c"),j=this.options.theme||i,k=this.options.trackTheme||i,l=h[0].nodeName.toLowerCase(),m=(this.isToggleSwitch="select"===l,h.parent().is(":jqmData(role='rangeslider')")),n=this.isToggleSwitch?"ui-slider-switch":"",o=h.attr("id"),p=a("[for='"+o+"']"),q=p.attr("id")||o+"-label",r=p.attr("id",q),s=this.isToggleSwitch?0:parseFloat(h.attr("min")),t=this.isToggleSwitch?h.find("option").length-1:parseFloat(h.attr("max")),u=b.parseFloat(h.attr("step")||1),v=this.options.mini||h.jqmData("mini")?" ui-mini":"",w=c.createElement("a"),x=a(w),y=c.createElement("div"),z=a(y),A=this.options.highlight&&!this.isToggleSwitch?function(){var b=c.createElement("div");return b.className="ui-slider-bg "+a.mobile.activeBtnClass+" ui-btn-corner-all",a(b).prependTo(z)}():!1;if(w.setAttribute("href","#"),y.setAttribute("role","application"),y.className=[this.isToggleSwitch?"ui-slider ":"ui-slider-track ",n," ui-btn-down-",k," ui-btn-corner-all",v].join(""),w.className="ui-slider-handle",y.appendChild(w),x.buttonMarkup({corners:!0,theme:j,shadow:!0}).attr({role:"slider","aria-valuemin":s,"aria-valuemax":t,"aria-valuenow":this._value(),"aria-valuetext":this._value(),title:this._value(),"aria-labelledby":q}),a.extend(this,{slider:z,handle:x,type:l,step:u,max:t,min:s,valuebg:A,isRangeslider:m,dragging:!1,beforeStart:null,userModified:!1,mouseMoved:!1}),this.isToggleSwitch){f=c.createElement("div"),f.className="ui-slider-inneroffset";for(var B=0,C=y.childNodes.length;C>B;B++)f.appendChild(y.childNodes[B]);y.appendChild(f),x.addClass("ui-slider-handle-snapping"),e=h.find("option");for(var D=0,E=e.length;E>D;D++){var F=D?"a":"b",G=D?" "+a.mobile.activeBtnClass:" ui-btn-down-"+k,H=(c.createElement("div"),c.createElement("span"));H.className=["ui-slider-label ui-slider-label-",F,G," ui-btn-corner-all"].join(""),H.setAttribute("role","img"),H.appendChild(c.createTextNode(e[D].innerHTML)),a(H).prependTo(z)}g._labels=a(".ui-slider-label",z)}r.addClass("ui-slider"),h.addClass(this.isToggleSwitch?"ui-slider-switch":"ui-slider-input"),this._on(h,{change:"_controlChange",keyup:"_controlKeyup",blur:"_controlBlur",vmouseup:"_controlVMouseUp"}),z.bind("vmousedown",a.proxy(this._sliderVMouseDown,this)).bind("vclick",!1),this._on(c,{vmousemove:"_preventDocumentDrag"}),this._on(z.add(c),{vmouseup:"_sliderVMouseUp"}),z.insertAfter(h),this.isToggleSwitch||m||(f=this.options.mini?"<div class='ui-slider ui-mini'>":"<div class='ui-slider'>",h.add(z).wrapAll(f)),this.isToggleSwitch&&this.handle.bind({focus:function(){z.addClass(a.mobile.focusClass)},blur:function(){z.removeClass(a.mobile.focusClass)}}),this._on(this.handle,{vmousedown:"_handleVMouseDown",keydown:"_handleKeydown",keyup:"_handleKeyup"}),this.handle.bind("vclick",!1),this._handleFormReset(),this.refresh(d,d,!0)},_controlChange:function(a){return this._trigger("controlchange",a)===!1?!1:(this.mouseMoved||this.refresh(this._value(),!0),void 0)},_controlKeyup:function(){this.refresh(this._value(),!0,!0)},_controlBlur:function(){this.refresh(this._value(),!0)},_controlVMouseUp:function(){this._checkedRefresh()},_handleVMouseDown:function(){this.handle.focus()},_handleKeydown:function(b){var c=this._value();if(!this.options.disabled){switch(b.keyCode){case a.mobile.keyCode.HOME:case a.mobile.keyCode.END:case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:b.preventDefault(),this._keySliding||(this._keySliding=!0,this.handle.addClass("ui-state-active"))}switch(b.keyCode){case a.mobile.keyCode.HOME:this.refresh(this.min);break;case a.mobile.keyCode.END:this.refresh(this.max);break;case a.mobile.keyCode.PAGE_UP:case a.mobile.keyCode.UP:case a.mobile.keyCode.RIGHT:this.refresh(c+this.step);break;case a.mobile.keyCode.PAGE_DOWN:case a.mobile.keyCode.DOWN:case a.mobile.keyCode.LEFT:this.refresh(c-this.step)}}},_handleKeyup:function(){this._keySliding&&(this._keySliding=!1,this.handle.removeClass("ui-state-active"))},_sliderVMouseDown:function(a){return this.options.disabled||1!==a.which&&0!==a.which&&a.which!==d?!1:this._trigger("beforestart",a)===!1?!1:(this.dragging=!0,this.userModified=!1,this.mouseMoved=!1,this.isToggleSwitch&&(this.beforeStart=this.element[0].selectedIndex),this.refresh(a),this._trigger("start"),!1)},_sliderVMouseUp:function(){return this.dragging?(this.dragging=!1,this.isToggleSwitch&&(this.handle.addClass("ui-slider-handle-snapping"),this.mouseMoved?this.userModified?this.refresh(0===this.beforeStart?1:0):this.refresh(this.beforeStart):this.refresh(0===this.beforeStart?1:0)),this.mouseMoved=!1,this._trigger("stop"),!1):void 0},_preventDocumentDrag:function(a){return this._trigger("drag",a)===!1?!1:this.dragging&&!this.options.disabled?(this.mouseMoved=!0,this.isToggleSwitch&&this.handle.removeClass("ui-slider-handle-snapping"),this.refresh(a),this.userModified=this.beforeStart!==this.element[0].selectedIndex,!1):void 0},_checkedRefresh:function(){this.value!==this._value()&&this.refresh(this._value())},_value:function(){return this.isToggleSwitch?this.element[0].selectedIndex:parseFloat(this.element.val())},_reset:function(){this.refresh(d,!1,!0)},refresh:function(b,d,e){var f,g,h,i,j=this,k=a.mobile.getInheritedTheme(this.element,"c"),l=this.options.theme||k,m=this.options.trackTheme||k;j.slider[0].className=[this.isToggleSwitch?"ui-slider ui-slider-switch":"ui-slider-track"," ui-btn-down-"+m," ui-btn-corner-all",this.options.mini?" ui-mini":""].join(""),(this.options.disabled||this.element.attr("disabled"))&&this.disable(),this.value=this._value(),this.options.highlight&&!this.isToggleSwitch&&0===this.slider.find(".ui-slider-bg").length&&(this.valuebg=function(){var b=c.createElement("div");return b.className="ui-slider-bg "+a.mobile.activeBtnClass+" ui-btn-corner-all",a(b).prependTo(j.slider)}()),this.handle.buttonMarkup({corners:!0,theme:l,shadow:!0});var n,o,p=this.element,q=!this.isToggleSwitch,r=q?[]:p.find("option"),s=q?parseFloat(p.attr("min")):0,t=q?parseFloat(p.attr("max")):r.length-1,u=q&&parseFloat(p.attr("step"))>0?parseFloat(p.attr("step")):1;if("object"==typeof b){if(h=b,i=8,f=this.slider.offset().left,g=this.slider.width(),n=g/((t-s)/u),!this.dragging||h.pageX<f-i||h.pageX>f+g+i)return;o=n>1?100*((h.pageX-f)/g):Math.round(100*((h.pageX-f)/g))}else null==b&&(b=q?parseFloat(p.val()||0):p[0].selectedIndex),o=100*((parseFloat(b)-s)/(t-s));if(!isNaN(o)){var v=o/100*(t-s)+s,w=(v-s)%u,x=v-w;2*Math.abs(w)>=u&&(x+=w>0?u:-u);var y=100/((t-s)/u);if(v=parseFloat(x.toFixed(5)),"undefined"==typeof n&&(n=g/((t-s)/u)),n>1&&q&&(o=(v-s)*y*(1/u)),0>o&&(o=0),o>100&&(o=100),s>v&&(v=s),v>t&&(v=t),this.handle.css("left",o+"%"),this.handle[0].setAttribute("aria-valuenow",q?v:r.eq(v).attr("value")),this.handle[0].setAttribute("aria-valuetext",q?v:r.eq(v).getEncodedText()),this.handle[0].setAttribute("title",q?v:r.eq(v).getEncodedText()),this.valuebg&&this.valuebg.css("width",o+"%"),this._labels){var z=100*(this.handle.width()/this.slider.width()),A=o&&z+(100-z)*o/100,B=100===o?0:Math.min(z+100-A,100);this._labels.each(function(){var b=a(this).is(".ui-slider-label-a");a(this).width((b?A:B)+"%")})}if(!e){var C=!1;if(q?(C=p.val()!==v,p.val(v)):(C=p[0].selectedIndex!==v,p[0].selectedIndex=v),this._trigger("beforechange",b)===!1)return!1;!d&&C&&p.trigger("change")}}},enable:function(){return this.element.attr("disabled",!1),this.slider.removeClass("ui-disabled").attr("aria-disabled",!1),this._setOption("disabled",!1)},disable:function(){return this.element.attr("disabled",!0),this.slider.addClass("ui-disabled").attr("aria-disabled",!0),this._setOption("disabled",!0)}},a.mobile.behaviors.formReset)),a.mobile.document.bind("pagecreate create",function(b){a.mobile.slider.prototype.enhanceWithin(b.target,!0)})}(a),function(a){a.widget("mobile.rangeslider",a.mobile.widget,{options:{theme:null,trackTheme:null,disabled:!1,initSelector:":jqmData(role='rangeslider')",mini:!1,highlight:!0},_create:function(){var b,c=this.element,d=this.options.mini?"ui-rangeslider ui-mini":"ui-rangeslider",e=c.find("input").first(),f=c.find("input").last(),g=c.find("label").first(),h=a.data(e.get(0),"mobileSlider").slider,i=a.data(f.get(0),"mobileSlider").slider,j=a.data(e.get(0),"mobileSlider").handle,k=a('<div class="ui-rangeslider-sliders" />').appendTo(c);c.find("label").length>1&&(b=c.find("label").last().hide()),e.addClass("ui-rangeslider-first"),f.addClass("ui-rangeslider-last"),c.addClass(d),h.appendTo(k),i.appendTo(k),g.prependTo(c),j.prependTo(i),a.extend(this,{_inputFirst:e,_inputLast:f,_sliderFirst:h,_sliderLast:i,_targetVal:null,_sliderTarget:!1,_sliders:k,_proxy:!1}),this.refresh(),this._on(this.element.find("input.ui-slider-input"),{slidebeforestart:"_slidebeforestart",slidestop:"_slidestop",slidedrag:"_slidedrag",slidebeforechange:"_change",blur:"_change",keyup:"_change"}),this._on({mousedown:"_change"}),this._on(this.element.closest("form"),{reset:"_handleReset"}),this._on(j,{vmousedown:"_dragFirstHandle"})},_handleReset:function(){var a=this;setTimeout(function(){a._updateHighlight()},0)},_dragFirstHandle:function(b){return a.data(this._inputFirst.get(0),"mobileSlider").dragging=!0,a.data(this._inputFirst.get(0),"mobileSlider").refresh(b),!1},_slidedrag:function(b){var c=a(b.target).is(this._inputFirst),d=c?this._inputLast:this._inputFirst;return this._sliderTarget=!1,"first"===this._proxy&&c||"last"===this._proxy&&!c?(a.data(d.get(0),"mobileSlider").dragging=!0,a.data(d.get(0),"mobileSlider").refresh(b),!1):void 0},_slidestop:function(b){var c=a(b.target).is(this._inputFirst);this._proxy=!1,this.element.find("input").trigger("vmouseup"),this._sliderFirst.css("z-index",c?1:"")},_slidebeforestart:function(b){this._sliderTarget=!1,a(b.originalEvent.target).hasClass("ui-slider-track")&&(this._sliderTarget=!0,this._targetVal=a(b.target).val())},_setOption:function(a){this._superApply(a),this.refresh()},refresh:function(){var a=this.element,b=this.options;a.find("input").slider({theme:b.theme,trackTheme:b.trackTheme,disabled:b.disabled,mini:b.mini,highlight:b.highlight}).slider("refresh"),this._updateHighlight()},_change:function(b){if("keyup"===b.type)return this._updateHighlight(),!1;var c=this,d=parseFloat(this._inputFirst.val(),10),e=parseFloat(this._inputLast.val(),10),f=a(b.target).hasClass("ui-rangeslider-first"),g=f?this._inputFirst:this._inputLast,h=f?this._inputLast:this._inputFirst;if(this._inputFirst.val()>this._inputLast.val()&&"mousedown"===b.type&&!a(b.target).hasClass("ui-slider-handle"))g.blur();else if("mousedown"===b.type)return;return d>e&&!this._sliderTarget?(g.val(f?e:d).slider("refresh"),this._trigger("normalize")):d>e&&(g.val(this._targetVal).slider("refresh"),setTimeout(function(){h.val(f?d:e).slider("refresh"),a.data(h.get(0),"mobileSlider").handle.focus(),c._sliderFirst.css("z-index",f?"":1),c._trigger("normalize")},0),this._proxy=f?"first":"last"),d===e?(a.data(g.get(0),"mobileSlider").handle.css("z-index",1),a.data(h.get(0),"mobileSlider").handle.css("z-index",0)):(a.data(h.get(0),"mobileSlider").handle.css("z-index",""),a.data(g.get(0),"mobileSlider").handle.css("z-index","")),this._updateHighlight(),d>=e?!1:void 0},_updateHighlight:function(){var b=parseInt(a.data(this._inputFirst.get(0),"mobileSlider").handle.get(0).style.left,10),c=parseInt(a.data(this._inputLast.get(0),"mobileSlider").handle.get(0).style.left,10),d=c-b;this.element.find(".ui-slider-bg").css({"margin-left":b+"%",width:d+"%"})},_destroy:function(){this.element.removeClass("ui-rangeslider ui-mini").find("label").show(),this._inputFirst.after(this._sliderFirst),this._inputLast.after(this._sliderLast),this._sliders.remove(),this.element.find("input").removeClass("ui-rangeslider-first ui-rangeslider-last").slider("destroy")}}),a.widget("mobile.rangeslider",a.mobile.rangeslider,a.mobile.behaviors.formReset),a(c).bind("pagecreate create",function(b){a.mobile.rangeslider.prototype.enhanceWithin(b.target,!0)})}(a),function(a){a.widget("mobile.selectmenu",a.mobile.widget,a.extend({options:{theme:null,disabled:!1,icon:"arrow-d",iconpos:"right",inline:!1,corners:!0,shadow:!0,iconshadow:!0,overlayTheme:"a",dividerTheme:"b",hidePlaceholderMenuItems:!0,closeText:"Close",nativeMenu:!0,preventFocusZoom:/iPhone|iPad|iPod/.test(navigator.platform)&&navigator.userAgent.indexOf("AppleWebKit")>-1,initSelector:"select:not( :jqmData(role='slider') )",mini:!1},_button:function(){return a("<div/>")
+},_setDisabled:function(a){return this.element.attr("disabled",a),this.button.attr("aria-disabled",a),this._setOption("disabled",a)},_focusButton:function(){var a=this;setTimeout(function(){a.button.focus()},40)},_selectOptions:function(){return this.select.find("option")},_preExtension:function(){var b="";~this.element[0].className.indexOf("ui-btn-left")&&(b=" ui-btn-left"),~this.element[0].className.indexOf("ui-btn-right")&&(b=" ui-btn-right"),this.select=this.element.removeClass("ui-btn-left ui-btn-right").wrap("<div class='ui-select"+b+"'>"),this.selectID=this.select.attr("id"),this.label=a("label[for='"+this.selectID+"']").addClass("ui-select"),this.isMultiple=this.select[0].multiple,this.options.theme||(this.options.theme=a.mobile.getInheritedTheme(this.select,"c"))},_destroy:function(){var a=this.element.parents(".ui-select");a.length>0&&(a.is(".ui-btn-left, .ui-btn-right")&&this.element.addClass(a.is(".ui-btn-left")?"ui-btn-left":"ui-btn-right"),this.element.insertAfter(a),a.remove())},_create:function(){this._preExtension(),this._trigger("beforeCreate"),this.button=this._button();var c=this,d=this.options,e=d.inline||this.select.jqmData("inline"),f=d.mini||this.select.jqmData("mini"),g=d.icon?d.iconpos||this.select.jqmData("iconpos"):!1,h=(-1===this.select[0].selectedIndex?0:this.select[0].selectedIndex,this.button.insertBefore(this.select).buttonMarkup({theme:d.theme,icon:d.icon,iconpos:g,inline:e,corners:d.corners,shadow:d.shadow,iconshadow:d.iconshadow,mini:f}));this.setButtonText(),d.nativeMenu&&b.opera&&b.opera.version&&h.addClass("ui-select-nativeonly"),this.isMultiple&&(this.buttonCount=a("<span>").addClass("ui-li-count ui-btn-up-c ui-btn-corner-all").hide().appendTo(h.addClass("ui-li-has-count"))),(d.disabled||this.element.attr("disabled"))&&this.disable(),this.select.change(function(){c.refresh(),d.nativeMenu&&this.blur()}),this._handleFormReset(),this.build()},build:function(){var b=this;this.select.appendTo(b.button).bind("vmousedown",function(){b.button.addClass(a.mobile.activeBtnClass)}).bind("focus",function(){b.button.addClass(a.mobile.focusClass)}).bind("blur",function(){b.button.removeClass(a.mobile.focusClass)}).bind("focus vmouseover",function(){b.button.trigger("vmouseover")}).bind("vmousemove",function(){b.button.removeClass(a.mobile.activeBtnClass)}).bind("change blur vmouseout",function(){b.button.trigger("vmouseout").removeClass(a.mobile.activeBtnClass)}).bind("change blur",function(){b.button.removeClass("ui-btn-down-"+b.options.theme)}),b.button.bind("vmousedown",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.label.bind("click focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.select.bind("focus",function(){b.options.preventFocusZoom&&a.mobile.zoom.disable(!0)}),b.button.bind("mouseup",function(){b.options.preventFocusZoom&&setTimeout(function(){a.mobile.zoom.enable(!0)},0)}),b.select.bind("blur",function(){b.options.preventFocusZoom&&a.mobile.zoom.enable(!0)})},selected:function(){return this._selectOptions().filter(":selected")},selectedIndices:function(){var a=this;return this.selected().map(function(){return a._selectOptions().index(this)}).get()},setButtonText:function(){var b=this,d=this.selected(),e=this.placeholder,f=a(c.createElement("span"));this.button.find(".ui-btn-text").html(function(){return e=d.length?d.map(function(){return a(this).text()}).get().join(", "):b.placeholder,f.text(e).addClass(b.select.attr("class")).addClass(d.attr("class"))})},setButtonCount:function(){var a=this.selected();this.isMultiple&&this.buttonCount[a.length>1?"show":"hide"]().text(a.length)},_reset:function(){this.refresh()},refresh:function(){this.setButtonText(),this.setButtonCount()},open:a.noop,close:a.noop,disable:function(){this._setDisabled(!0),this.button.addClass("ui-disabled")},enable:function(){this._setDisabled(!1),this.button.removeClass("ui-disabled")}},a.mobile.behaviors.formReset)),a.mobile.document.bind("pagecreate create",function(b){a.mobile.selectmenu.prototype.enhanceWithin(b.target,!0)})}(a),function(a,d){function e(a,b,c,d){var e=d;return e=b>a?c+(a-b)/2:Math.min(Math.max(c,d-b/2),c+a-b)}function f(){var c=a.mobile.window;return{x:c.scrollLeft(),y:c.scrollTop(),cx:b.innerWidth||c.width(),cy:b.innerHeight||c.height()}}a.widget("mobile.popup",a.mobile.widget,{options:{theme:null,overlayTheme:null,shadow:!0,corners:!0,transition:"none",positionTo:"origin",tolerance:null,initSelector:":jqmData(role='popup')",closeLinkSelector:"a:jqmData(rel='back')",closeLinkEvents:"click.popup",navigateEvents:"navigate.popup",closeEvents:"navigate.popup pagebeforechange.popup",dismissible:!0,history:!a.mobile.browser.oldIE},_eatEventAndClose:function(a){return a.preventDefault(),a.stopImmediatePropagation(),this.options.dismissible&&this.close(),!1},_resizeScreen:function(){var a=this._ui.container.outerHeight(!0);this._ui.screen.removeAttr("style"),a>this._ui.screen.height()&&this._ui.screen.height(a)},_handleWindowKeyUp:function(b){return this._isOpen&&b.keyCode===a.mobile.keyCode.ESCAPE?this._eatEventAndClose(b):void 0},_expectResizeEvent:function(){var b=f();if(this._resizeData){if(b.x===this._resizeData.winCoords.x&&b.y===this._resizeData.winCoords.y&&b.cx===this._resizeData.winCoords.cx&&b.cy===this._resizeData.winCoords.cy)return!1;clearTimeout(this._resizeData.timeoutId)}return this._resizeData={timeoutId:setTimeout(a.proxy(this,"_resizeTimeout"),200),winCoords:b},!0},_resizeTimeout:function(){this._isOpen?this._expectResizeEvent()||(this._ui.container.hasClass("ui-popup-hidden")&&(this._ui.container.removeClass("ui-popup-hidden"),this.reposition({positionTo:"window"}),this._ignoreResizeEvents()),this._resizeScreen(),this._resizeData=null,this._orientationchangeInProgress=!1):(this._resizeData=null,this._orientationchangeInProgress=!1)},_ignoreResizeEvents:function(){var a=this;this._ignoreResizeTo&&clearTimeout(this._ignoreResizeTo),this._ignoreResizeTo=setTimeout(function(){a._ignoreResizeTo=0},1e3)},_handleWindowResize:function(){this._isOpen&&0===this._ignoreResizeTo&&(!this._expectResizeEvent()&&!this._orientationchangeInProgress||this._ui.container.hasClass("ui-popup-hidden")||this._ui.container.addClass("ui-popup-hidden").removeAttr("style"))},_handleWindowOrientationchange:function(){!this._orientationchangeInProgress&&this._isOpen&&0===this._ignoreResizeTo&&(this._expectResizeEvent(),this._orientationchangeInProgress=!0)},_handleDocumentFocusIn:function(b){var d,e=b.target,f=this._ui;if(this._isOpen){if(e!==f.container[0]){if(d=a(b.target),0===d.parents().filter(f.container[0]).length)return a(c.activeElement).one("focus",function(){d.blur()}),f.focusElement.focus(),b.preventDefault(),b.stopImmediatePropagation(),!1;f.focusElement[0]===f.container[0]&&(f.focusElement=d)}this._ignoreResizeEvents()}},_create:function(){var b={screen:a("<div class='ui-screen-hidden ui-popup-screen'></div>"),placeholder:a("<div style='display: none;'><!-- placeholder --></div>"),container:a("<div class='ui-popup-container ui-popup-hidden'></div>")},c=this.element.closest(".ui-page"),d=this.element.attr("id"),e=this.options;e.history=e.history&&a.mobile.ajaxEnabled&&a.mobile.hashListeningEnabled,0===c.length&&(c=a("body")),e.container=e.container||a.mobile.pageContainer||c,c.append(b.screen),b.container.insertAfter(b.screen),b.placeholder.insertAfter(this.element),d&&(b.screen.attr("id",d+"-screen"),b.container.attr("id",d+"-popup"),b.placeholder.html("<!-- placeholder for "+d+" -->")),b.container.append(this.element),b.focusElement=b.container,this.element.addClass("ui-popup"),a.extend(this,{_scrollTop:0,_page:c,_ui:b,_fallbackTransition:"",_currentTransition:!1,_prereqs:null,_isOpen:!1,_tolerance:null,_resizeData:null,_ignoreResizeTo:0,_orientationchangeInProgress:!1}),this._applyTheme(this.element,e.theme,"body"),this._applyTheme(this._ui.screen,e.overlayTheme,"overlay"),this._applyTransition(e.transition),this.element.toggleClass("ui-overlay-shadow",e.shadow).toggleClass("ui-corner-all",e.corners),this._setTolerance(e.tolerance),b.screen.bind("vclick",a.proxy(this,"_eatEventAndClose")),this._on(a.mobile.window,{orientationchange:a.proxy(this,"_handleWindowOrientationchange"),resize:a.proxy(this,"_handleWindowResize"),keyup:a.proxy(this,"_handleWindowKeyUp")}),this._on(a.mobile.document,{focusin:a.proxy(this,"_handleDocumentFocusIn")})},_applyTheme:function(a,b,c){for(var d,e=(a.attr("class")||"").split(" "),f=null,g=String(b);e.length>0;){if(f=e.pop(),d=new RegExp("^ui-"+c+"-([a-z])$").exec(f),d&&d.length>1){f=d[1];break}f=null}b!==f&&(a.removeClass("ui-"+c+"-"+f),null!==b&&"none"!==b&&a.addClass("ui-"+c+"-"+g))},_setTheme:function(a){this._applyTheme(this.element,a,"body")},_setOverlayTheme:function(a){this._applyTheme(this._ui.screen,a,"overlay"),this._isOpen&&this._ui.screen.addClass("in")},_setShadow:function(a){this.element.toggleClass("ui-overlay-shadow",a)},_setCorners:function(a){this.element.toggleClass("ui-corner-all",a)},_applyTransition:function(b){this._ui.container.removeClass(this._fallbackTransition),b&&"none"!==b&&(this._fallbackTransition=a.mobile._maybeDegradeTransition(b),"none"===this._fallbackTransition&&(this._fallbackTransition=""),this._ui.container.addClass(this._fallbackTransition))},_setTransition:function(a){this._currentTransition||this._applyTransition(a)},_setTolerance:function(b){var c={t:30,r:15,b:30,l:15};if(b!==d){var e=String(b).split(",");switch(a.each(e,function(a,b){e[a]=parseInt(b,10)}),e.length){case 1:isNaN(e[0])||(c.t=c.r=c.b=c.l=e[0]);break;case 2:isNaN(e[0])||(c.t=c.b=e[0]),isNaN(e[1])||(c.l=c.r=e[1]);break;case 4:isNaN(e[0])||(c.t=e[0]),isNaN(e[1])||(c.r=e[1]),isNaN(e[2])||(c.b=e[2]),isNaN(e[3])||(c.l=e[3])}}this._tolerance=c},_setOption:function(a,b){var c="_set"+a.charAt(0).toUpperCase()+a.slice(1);this[c]!==d&&this[c](b),this._super(a,b)},_placementCoords:function(a){var b,d,g=f(),h={x:this._tolerance.l,y:g.y+this._tolerance.t,cx:g.cx-this._tolerance.l-this._tolerance.r,cy:g.cy-this._tolerance.t-this._tolerance.b};this._ui.container.css("max-width",h.cx),b={cx:this._ui.container.outerWidth(!0),cy:this._ui.container.outerHeight(!0)},d={x:e(h.cx,b.cx,h.x,a.x),y:e(h.cy,b.cy,h.y,a.y)},d.y=Math.max(0,d.y);var i=c.documentElement,j=c.body,k=Math.max(i.clientHeight,j.scrollHeight,j.offsetHeight,i.scrollHeight,i.offsetHeight);return d.y-=Math.min(d.y,Math.max(0,d.y+b.cy-k)),{left:d.x,top:d.y}},_createPrereqs:function(b,c,d){var e,f=this;e={screen:a.Deferred(),container:a.Deferred()},e.screen.then(function(){e===f._prereqs&&b()}),e.container.then(function(){e===f._prereqs&&c()}),a.when(e.screen,e.container).done(function(){e===f._prereqs&&(f._prereqs=null,d())}),f._prereqs=e},_animate:function(b){return this._ui.screen.removeClass(b.classToRemove).addClass(b.screenClassToAdd),b.prereqs.screen.resolve(),b.transition&&"none"!==b.transition&&(b.applyTransition&&this._applyTransition(b.transition),this._fallbackTransition)?(this._ui.container.animationComplete(a.proxy(b.prereqs.container,"resolve")).addClass(b.containerClassToAdd).removeClass(b.classToRemove),void 0):(this._ui.container.removeClass(b.classToRemove),b.prereqs.container.resolve(),void 0)},_desiredCoords:function(b){var c,d=null,e=f(),g=b.x,h=b.y,i=b.positionTo;if(i&&"origin"!==i)if("window"===i)g=e.cx/2+e.x,h=e.cy/2+e.y;else{try{d=a(i)}catch(j){d=null}d&&(d.filter(":visible"),0===d.length&&(d=null))}return d&&(c=d.offset(),g=c.left+d.outerWidth()/2,h=c.top+d.outerHeight()/2),("number"!==a.type(g)||isNaN(g))&&(g=e.cx/2+e.x),("number"!==a.type(h)||isNaN(h))&&(h=e.cy/2+e.y),{x:g,y:h}},_reposition:function(a){a={x:a.x,y:a.y,positionTo:a.positionTo},this._trigger("beforeposition",d,a),this._ui.container.offset(this._placementCoords(this._desiredCoords(a)))},reposition:function(a){this._isOpen&&this._reposition(a)},_openPrereqsComplete:function(){this._ui.container.addClass("ui-popup-active"),this._isOpen=!0,this._resizeScreen(),this._ui.container.attr("tabindex","0").focus(),this._ignoreResizeEvents(),this._trigger("afteropen")},_open:function(b){var c=a.extend({},this.options,b),d=function(){var a=navigator.userAgent,b=a.match(/AppleWebKit\/([0-9\.]+)/),c=!!b&&b[1],d=a.match(/Android (\d+(?:\.\d+))/),e=!!d&&d[1],f=a.indexOf("Chrome")>-1;return null!==d&&"4.0"===e&&c&&c>534.13&&!f?!0:!1}();this._createPrereqs(a.noop,a.noop,a.proxy(this,"_openPrereqsComplete")),this._currentTransition=c.transition,this._applyTransition(c.transition),this.options.theme||this._setTheme(this._page.jqmData("theme")||a.mobile.getInheritedTheme(this._page,"c")),this._ui.screen.removeClass("ui-screen-hidden"),this._ui.container.removeClass("ui-popup-hidden"),this._reposition(c),this.options.overlayTheme&&d&&this.element.closest(".ui-page").addClass("ui-popup-open"),this._animate({additionalCondition:!0,transition:c.transition,classToRemove:"",screenClassToAdd:"in",containerClassToAdd:"in",applyTransition:!1,prereqs:this._prereqs})},_closePrereqScreen:function(){this._ui.screen.removeClass("out").addClass("ui-screen-hidden")},_closePrereqContainer:function(){this._ui.container.removeClass("reverse out").addClass("ui-popup-hidden").removeAttr("style")},_closePrereqsDone:function(){var b=this._ui.container;b.removeAttr("tabindex"),a.mobile.popup.active=d,a(":focus",b[0]).add(b[0]).blur(),this._trigger("afterclose")},_close:function(b){this._ui.container.removeClass("ui-popup-active"),this._page.removeClass("ui-popup-open"),this._isOpen=!1,this._createPrereqs(a.proxy(this,"_closePrereqScreen"),a.proxy(this,"_closePrereqContainer"),a.proxy(this,"_closePrereqsDone")),this._animate({additionalCondition:this._ui.screen.hasClass("in"),transition:b?"none":this._currentTransition,classToRemove:"in",screenClassToAdd:"out",containerClassToAdd:"reverse out",applyTransition:!0,prereqs:this._prereqs})},_unenhance:function(){this._setTheme("none"),this.element.detach().insertAfter(this._ui.placeholder).removeClass("ui-popup ui-overlay-shadow ui-corner-all"),this._ui.screen.remove(),this._ui.container.remove(),this._ui.placeholder.remove()},_destroy:function(){a.mobile.popup.active===this?(this.element.one("popupafterclose",a.proxy(this,"_unenhance")),this.close()):this._unenhance()},_closePopup:function(c,d){var e,f,g=this.options,h=!1;b.scrollTo(0,this._scrollTop),c&&"pagebeforechange"===c.type&&d&&(e="string"==typeof d.toPage?d.toPage:d.toPage.jqmData("url"),e=a.mobile.path.parseUrl(e),f=e.pathname+e.search+e.hash,this._myUrl!==a.mobile.path.makeUrlAbsolute(f)?h=!0:c.preventDefault()),g.container.unbind(g.closeEvents),this.element.undelegate(g.closeLinkSelector,g.closeLinkEvents),this._close(h)},_bindContainerClose:function(){this.options.container.one(this.options.closeEvents,a.proxy(this,"_closePopup"))},open:function(c){var d,e,f,g,h,i,j=this,k=this.options;if(!a.mobile.popup.active){if(a.mobile.popup.active=this,this._scrollTop=a.mobile.window.scrollTop(),!k.history)return j._open(c),j._bindContainerClose(),j.element.delegate(k.closeLinkSelector,k.closeLinkEvents,function(a){j.close(),a.preventDefault()}),void 0;if(i=a.mobile.urlHistory,e=a.mobile.dialogHashKey,f=a.mobile.activePage,g=f.is(".ui-dialog"),this._myUrl=d=i.getActive().url,h=d.indexOf(e)>-1&&!g&&i.activeIndex>0)return j._open(c),j._bindContainerClose(),void 0;-1!==d.indexOf(e)||g?d=a.mobile.path.parseLocation().hash+e:d+=d.indexOf("#")>-1?e:"#"+e,0===i.activeIndex&&d===i.initialDst&&(d+=e),a(b).one("beforenavigate",function(a){a.preventDefault(),j._open(c),j._bindContainerClose()}),this.urlAltered=!0,a.mobile.navigate(d,{role:"dialog"})}},close:function(){a.mobile.popup.active===this&&(this._scrollTop=a.mobile.window.scrollTop(),this.options.history&&this.urlAltered?(a.mobile.back(),this.urlAltered=!1):this._closePopup())}}),a.mobile.popup.handleLink=function(b){var c,d=b.closest(":jqmData(role='page')"),e=0===d.length?a("body"):d,f=a(a.mobile.path.parseUrl(b.attr("href")).hash,e[0]);f.data("mobile-popup")&&(c=b.offset(),f.popup("open",{x:c.left+b.outerWidth()/2,y:c.top+b.outerHeight()/2,transition:b.jqmData("transition"),positionTo:b.jqmData("position-to")})),setTimeout(function(){var c=b.parent().parent();c.hasClass("ui-li")&&(b=c.parent()),b.removeClass(a.mobile.activeBtnClass)},300)},a.mobile.document.bind("pagebeforechange",function(b,c){"popup"===c.options.role&&(a.mobile.popup.handleLink(c.options.link),b.preventDefault())}),a.mobile.document.bind("pagecreate create",function(b){a.mobile.popup.prototype.enhanceWithin(b.target,!0)})}(a),function(a,b){var d=function(d){var e,f,g,h=(d.select,d._destroy),i=d.selectID,j=i?i:(a.mobile.ns||"")+"uuid-"+d.uuid,k=j+"-listbox",l=j+"-dialog",m=d.label,n=d.select.closest(".ui-page"),o=d._selectOptions(),p=d.isMultiple=d.select[0].multiple,q=i+"-button",r=i+"-menu",s=a("<div data-"+a.mobile.ns+"role='dialog' id='"+l+"' data-"+a.mobile.ns+"theme='"+d.options.theme+"' data-"+a.mobile.ns+"overlay-theme='"+d.options.overlayTheme+"'>"+"<div data-"+a.mobile.ns+"role='header'>"+"<div class='ui-title'>"+m.getEncodedText()+"</div>"+"</div>"+"<div data-"+a.mobile.ns+"role='content'></div>"+"</div>"),t=a("<div id='"+k+"' class='ui-selectmenu'>").insertAfter(d.select).popup({theme:d.options.overlayTheme}),u=a("<ul>",{"class":"ui-selectmenu-list",id:r,role:"listbox","aria-labelledby":q}).attr("data-"+a.mobile.ns+"theme",d.options.theme).attr("data-"+a.mobile.ns+"divider-theme",d.options.dividerTheme).appendTo(t),v=a("<div>",{"class":"ui-header ui-bar-"+d.options.theme}).prependTo(t),w=a("<h1>",{"class":"ui-title"}).appendTo(v);d.isMultiple&&(g=a("<a>",{text:d.options.closeText,href:"#","class":"ui-btn-left"}).attr("data-"+a.mobile.ns+"iconpos","notext").attr("data-"+a.mobile.ns+"icon","delete").appendTo(v).buttonMarkup()),a.extend(d,{select:d.select,selectID:i,buttonId:q,menuId:r,popupID:k,dialogID:l,thisPage:n,menuPage:s,label:m,selectOptions:o,isMultiple:p,theme:d.options.theme,listbox:t,list:u,header:v,headerTitle:w,headerClose:g,menuPageContent:e,menuPageClose:f,placeholder:"",build:function(){var c=this,e=function(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g,"\\$1")};c.refresh(),c._origTabIndex===b&&(c._origTabIndex=null===c.select[0].getAttribute("tabindex")?!1:c.select.attr("tabindex")),c.select.attr("tabindex","-1").focus(function(){a(this).blur(),c.button.focus()}),c.button.bind("vclick keydown",function(b){c.options.disabled||c.isOpen||("vclick"===b.type||b.keyCode&&(b.keyCode===a.mobile.keyCode.ENTER||b.keyCode===a.mobile.keyCode.SPACE))&&(c._decideFormat(),"overlay"===c.menuType?c.button.attr("href","#"+e(c.popupID)).attr("data-"+(a.mobile.ns||"")+"rel","popup"):c.button.attr("href","#"+e(c.dialogID)).attr("data-"+(a.mobile.ns||"")+"rel","dialog"),c.isOpen=!0)}),c.list.attr("role","listbox").bind("focusin",function(b){a(b.target).attr("tabindex","0").trigger("vmouseover")}).bind("focusout",function(b){a(b.target).attr("tabindex","-1").trigger("vmouseout")}).delegate("li:not(.ui-disabled, .ui-li-divider)","click",function(b){var e=c.select[0].selectedIndex,f=c.list.find("li:not(.ui-li-divider)").index(this),g=c._selectOptions().eq(f)[0];g.selected=c.isMultiple?!g.selected:!0,c.isMultiple&&a(this).find(".ui-icon").toggleClass("ui-icon-checkbox-on",g.selected).toggleClass("ui-icon-checkbox-off",!g.selected),(c.isMultiple||e!==f)&&c.select.trigger("change"),c.isMultiple?c.list.find("li:not(.ui-li-divider)").eq(f).addClass("ui-btn-down-"+d.options.theme).find("a").first().focus():c.close(),b.preventDefault()}).keydown(function(b){var c,e,f=a(b.target),g=f.closest("li");switch(b.keyCode){case 38:return c=g.prev().not(".ui-selectmenu-placeholder"),c.is(".ui-li-divider")&&(c=c.prev()),c.length&&(f.blur().attr("tabindex","-1"),c.addClass("ui-btn-down-"+d.options.theme).find("a").first().focus()),!1;case 40:return e=g.next(),e.is(".ui-li-divider")&&(e=e.next()),e.length&&(f.blur().attr("tabindex","-1"),e.addClass("ui-btn-down-"+d.options.theme).find("a").first().focus()),!1;case 13:case 32:return f.trigger("click"),!1}}),c.menuPage.bind("pagehide",function(){a.mobile._bindPageRemove.call(c.thisPage)}),c.listbox.bind("popupafterclose",function(){c.close()}),c.isMultiple&&c.headerClose.click(function(){return"overlay"===c.menuType?(c.close(),!1):void 0}),c.thisPage.addDependents(this.menuPage)},_isRebuildRequired:function(){var a=this.list.find("li"),b=this._selectOptions();return b.text()!==a.text()},selected:function(){return this._selectOptions().filter(":selected:not( :jqmData(placeholder='true') )")},refresh:function(b){var c,d=this;this.element,this.isMultiple,(b||this._isRebuildRequired())&&d._buildList(),c=this.selectedIndices(),d.setButtonText(),d.setButtonCount(),d.list.find("li:not(.ui-li-divider)").removeClass(a.mobile.activeBtnClass).attr("aria-selected",!1).each(function(b){if(a.inArray(b,c)>-1){var e=a(this);e.attr("aria-selected",!0),d.isMultiple?e.find(".ui-icon").removeClass("ui-icon-checkbox-off").addClass("ui-icon-checkbox-on"):e.is(".ui-selectmenu-placeholder")?e.next().addClass(a.mobile.activeBtnClass):e.addClass(a.mobile.activeBtnClass)}})},close:function(){if(!this.options.disabled&&this.isOpen){var a=this;"page"===a.menuType?(a.menuPage.dialog("close"),a.list.appendTo(a.listbox)):a.listbox.popup("close"),a._focusButton(),a.isOpen=!1}},open:function(){this.button.click()},_decideFormat:function(){function b(){var b=c.list.find("."+a.mobile.activeBtnClass+" a");0===b.length&&(b=c.list.find("li.ui-btn:not( :jqmData(placeholder='true') ) a")),b.first().focus().closest("li").addClass("ui-btn-down-"+d.options.theme)}var c=this,e=a.mobile.window,f=c.list.parent(),g=f.outerHeight(),h=(f.outerWidth(),a("."+a.mobile.activePageClass),e.scrollTop()),i=c.button.offset().top,j=e.height();e.width(),g>j-80||!a.support.scrollTop?(c.menuPage.appendTo(a.mobile.pageContainer).page(),c.menuPageContent=s.find(".ui-content"),c.menuPageClose=s.find(".ui-header a"),c.thisPage.unbind("pagehide.remove"),0===h&&i>j&&c.thisPage.one("pagehide",function(){a(this).jqmData("lastScroll",i)}),c.menuPage.one("pageshow",function(){b()}).one("pagehide",function(){c.close()}),c.menuType="page",c.menuPageContent.append(c.list),c.menuPage.find("div .ui-title").text(c.label.text())):(c.menuType="overlay",c.listbox.one("popupafteropen",b))},_buildList:function(){var b=this,d=this.options,e=this.placeholder,f=!0,g=b.isMultiple?"checkbox-off":"false";b.list.empty().filter(".ui-listview").listview("destroy");for(var h,i=b.select.find("option"),j=i.length,k=this.select[0],l="data-"+a.mobile.ns,m=l+"option-index",n=l+"icon",o=l+"role",p=l+"placeholder",q=c.createDocumentFragment(),r=!1,s=0;j>s;s++,r=!1){var t=i[s],u=a(t),v=t.parentNode,w=u.text(),x=c.createElement("a"),y=[];if(x.setAttribute("href","#"),x.appendChild(c.createTextNode(w)),v!==k&&"optgroup"===v.nodeName.toLowerCase()){var z=v.getAttribute("label");if(z!==h){var A=c.createElement("li");A.setAttribute(o,"list-divider"),A.setAttribute("role","option"),A.setAttribute("tabindex","-1"),A.appendChild(c.createTextNode(z)),q.appendChild(A),h=z}}!f||t.getAttribute("value")&&0!==w.length&&!u.jqmData("placeholder")||(f=!1,r=!0,null===t.getAttribute(p)&&(this._removePlaceholderAttr=!0),t.setAttribute(p,!0),d.hidePlaceholderMenuItems&&y.push("ui-selectmenu-placeholder"),e!==w&&(e=b.placeholder=w));var B=c.createElement("li");t.disabled&&(y.push("ui-disabled"),B.setAttribute("aria-disabled",!0)),B.setAttribute(m,s),B.setAttribute(n,g),r&&B.setAttribute(p,!0),B.className=y.join(" "),B.setAttribute("role","option"),x.setAttribute("tabindex","-1"),B.appendChild(x),q.appendChild(B)}b.list[0].appendChild(q),this.isMultiple||e.length?this.headerTitle.text(this.placeholder):this.header.hide(),b.list.listview()},_button:function(){return a("<a>",{href:"#",role:"button",id:this.buttonId,"aria-haspopup":"true","aria-owns":this.menuId})},_destroy:function(){this.close(),this._origTabIndex!==b&&(this._origTabIndex!==!1?this.select.attr("tabindex",this._origTabIndex):this.select.removeAttr("tabindex")),this._removePlaceholderAttr&&this._selectOptions().removeAttr("data-"+a.mobile.ns+"placeholder"),this.listbox.remove(),this.menuPage.remove(),h.apply(this,arguments)}})};a.mobile.document.bind("selectmenubeforecreate",function(b){var c=a(b.target).data("mobile-selectmenu");c.options.nativeMenu||0!==c.element.parents(":jqmData(role='popup')").length||d(c)})}(a),function(a,b){a.widget("mobile.controlgroup",a.mobile.widget,a.extend({options:{shadow:!1,corners:!0,excludeInvisible:!0,type:"vertical",mini:!1,initSelector:":jqmData(role='controlgroup')"},_create:function(){var c=this.element,d={inner:a("<div class='ui-controlgroup-controls'></div>"),legend:a("<div role='heading' class='ui-controlgroup-label'></div>")},e=c.children("legend"),f=this;c.wrapInner(d.inner),e.length&&d.legend.append(e).insertBefore(c.children(0)),c.addClass("ui-corner-all ui-controlgroup"),a.extend(this,{_initialRefresh:!0}),a.each(this.options,function(a,c){f.options[a]=b,f._setOption(a,c,!0)})},_init:function(){this.refresh()},_setOption:function(c,d){var e="_set"+c.charAt(0).toUpperCase()+c.slice(1);this[e]!==b&&this[e](d),this._super(c,d),this.element.attr("data-"+(a.mobile.ns||"")+c.replace(/([A-Z])/,"-$1").toLowerCase(),d)},_setType:function(a){this.element.removeClass("ui-controlgroup-horizontal ui-controlgroup-vertical").addClass("ui-controlgroup-"+a),this.refresh()},_setCorners:function(a){this.element.toggleClass("ui-corner-all",a)},_setShadow:function(a){this.element.toggleClass("ui-shadow",a)},_setMini:function(a){this.element.toggleClass("ui-mini",a)},container:function(){return this.element.children(".ui-controlgroup-controls")},refresh:function(){var b=this.element.find(".ui-btn").not(".ui-slider-handle"),c=this._initialRefresh;a.mobile.checkboxradio&&this.element.find(":mobile-checkboxradio").checkboxradio("refresh"),this._addFirstLastClasses(b,this.options.excludeInvisible?this._getVisibles(b,c):b,c),this._initialRefresh=!1}},a.mobile.behaviors.addFirstLastClasses)),a(function(){a.mobile.document.bind("pagecreate create",function(b){a.mobile.controlgroup.prototype.enhanceWithin(b.target,!0)})})}(a),function(a){a(c).bind("pagecreate create",function(b){a(b.target).find("a").jqmEnhanceable().filter(":jqmData(rel='popup')[href][href!='']").each(function(){var b=this,d=a(this).attr("href"),e=d.substring(1);b.setAttribute("aria-haspopup",!0),b.setAttribute("aria-owns",e),b.setAttribute("aria-expanded",!1),a(c).on("popupafteropen",d,function(){b.setAttribute("aria-expanded",!0)}).on("popupafterclose",d,function(){b.setAttribute("aria-expanded",!1)})}).end().not(".ui-btn, .ui-link-inherit, :jqmData(role='none'), :jqmData(role='nojs')").addClass("ui-link")})}(a),function(a,b){a.widget("mobile.fixedtoolbar",a.mobile.widget,{options:{visibleOnPageShow:!0,disablePageZoom:!0,transition:"slide",fullscreen:!1,tapToggle:!0,tapToggleBlacklist:"a, button, input, select, textarea, .ui-header-fixed, .ui-footer-fixed, .ui-popup, .ui-panel, .ui-panel-dismiss-open",hideDuringFocus:"input, textarea, select",updatePagePadding:!0,trackPersistentToolbars:!0,supportBlacklist:function(){return!a.support.fixedPosition},initSelector:":jqmData(position='fixed')"},_create:function(){var b=this,c=b.options,d=b.element,e=d.is(":jqmData(role='header')")?"header":"footer",f=d.closest(".ui-page");return c.supportBlacklist()?(b.destroy(),void 0):(d.addClass("ui-"+e+"-fixed"),c.fullscreen?(d.addClass("ui-"+e+"-fullscreen"),f.addClass("ui-page-"+e+"-fullscreen")):f.addClass("ui-page-"+e+"-fixed"),a.extend(this,{_thisPage:null}),b._addTransitionClass(),b._bindPageEvents(),b._bindToggleHandlers(),void 0)},_addTransitionClass:function(){var a=this.options.transition;a&&"none"!==a&&("slide"===a&&(a=this.element.is(".ui-header")?"slidedown":"slideup"),this.element.addClass(a))},_bindPageEvents:function(){this._thisPage=this.element.closest(".ui-page"),this._on(this._thisPage,{pagebeforeshow:"_handlePageBeforeShow",webkitAnimationStart:"_handleAnimationStart",animationstart:"_handleAnimationStart",updatelayout:"_handleAnimationStart",pageshow:"_handlePageShow",pagebeforehide:"_handlePageBeforeHide"})},_handlePageBeforeShow:function(){var b=this.options;b.disablePageZoom&&a.mobile.zoom.disable(!0),b.visibleOnPageShow||this.hide(!0)},_handleAnimationStart:function(){this.options.updatePagePadding&&this.updatePagePadding(this._thisPage)},_handlePageShow:function(){this.updatePagePadding(this._thisPage),this.options.updatePagePadding&&this._on(a.mobile.window,{throttledresize:"updatePagePadding"})},_handlePageBeforeHide:function(b,c){var d=this.options;if(d.disablePageZoom&&a.mobile.zoom.enable(!0),d.updatePagePadding&&this._off(a.mobile.window,"throttledresize"),d.trackPersistentToolbars){var e=a(".ui-footer-fixed:jqmData(id)",this._thisPage),f=a(".ui-header-fixed:jqmData(id)",this._thisPage),g=e.length&&c.nextPage&&a(".ui-footer-fixed:jqmData(id='"+e.jqmData("id")+"')",c.nextPage)||a(),h=f.length&&c.nextPage&&a(".ui-header-fixed:jqmData(id='"+f.jqmData("id")+"')",c.nextPage)||a();(g.length||h.length)&&(g.add(h).appendTo(a.mobile.pageContainer),c.nextPage.one("pageshow",function(){h.prependTo(this),g.appendTo(this)}))}},_visible:!0,updatePagePadding:function(c){var d=this.element,e=d.is(".ui-header"),f=parseFloat(d.css(e?"top":"bottom"));this.options.fullscreen||(c=c&&c.type===b&&c||this._thisPage||d.closest(".ui-page"),a(c).css("padding-"+(e?"top":"bottom"),d.outerHeight()+f))},_useTransition:function(b){var c=a.mobile.window,d=this.element,e=c.scrollTop(),f=d.height(),g=d.closest(".ui-page").height(),h=a.mobile.getScreenHeight(),i=d.is(":jqmData(role='header')")?"header":"footer";return!b&&(this.options.transition&&"none"!==this.options.transition&&("header"===i&&!this.options.fullscreen&&e>f||"footer"===i&&!this.options.fullscreen&&g-f>e+h)||this.options.fullscreen)},show:function(a){var b="ui-fixed-hidden",c=this.element;this._useTransition(a)?c.removeClass("out "+b).addClass("in").animationComplete(function(){c.removeClass("in")}):c.removeClass(b),this._visible=!0},hide:function(a){var b="ui-fixed-hidden",c=this.element,d="out"+("slide"===this.options.transition?" reverse":"");this._useTransition(a)?c.addClass(d).removeClass("in").animationComplete(function(){c.addClass(b).removeClass(d)}):c.addClass(b).removeClass(d),this._visible=!1},toggle:function(){this[this._visible?"hide":"show"]()},_bindToggleHandlers:function(){var b,c,d=this,e=d.options,f=d.element,g=!0;f.closest(".ui-page").bind("vclick",function(b){e.tapToggle&&!a(b.target).closest(e.tapToggleBlacklist).length&&d.toggle()}).bind("focusin focusout",function(f){screen.width<1025&&a(f.target).is(e.hideDuringFocus)&&!a(f.target).closest(".ui-header-fixed, .ui-footer-fixed").length&&("focusout"!==f.type||g?"focusin"===f.type&&g&&(clearTimeout(b),g=!1,c=setTimeout(function(){d.hide()},0)):(g=!0,clearTimeout(c),b=setTimeout(function(){d.show()},0)))})},_destroy:function(){var a=this.element,b=a.is(".ui-header");a.closest(".ui-page").css("padding-"+(b?"top":"bottom"),""),a.removeClass("ui-header-fixed ui-footer-fixed ui-header-fullscreen ui-footer-fullscreen in out fade slidedown slideup ui-fixed-hidden"),a.closest(".ui-page").removeClass("ui-page-header-fixed ui-page-footer-fixed ui-page-header-fullscreen ui-page-footer-fullscreen")}}),a.mobile.document.bind("pagecreate create",function(b){a(b.target).jqmData("fullscreen")&&a(a.mobile.fixedtoolbar.prototype.options.initSelector,b.target).not(":jqmData(fullscreen)").jqmData("fullscreen",!0),a.mobile.fixedtoolbar.prototype.enhanceWithin(b.target)})}(a),function(a){a.widget("mobile.fixedtoolbar",a.mobile.fixedtoolbar,{_create:function(){this._super(),this._workarounds()},_workarounds:function(){var a=navigator.userAgent,b=navigator.platform,c=a.match(/AppleWebKit\/([0-9]+)/),d=!!c&&c[1],e=null,f=this;if(b.indexOf("iPhone")>-1||b.indexOf("iPad")>-1||b.indexOf("iPod")>-1)e="ios";else{if(!(a.indexOf("Android")>-1))return;e="android"}if("ios"===e)f._bindScrollWorkaround();else{if(!("android"===e&&d&&534>d))return;f._bindScrollWorkaround(),f._bindListThumbWorkaround()}},_viewportOffset:function(){var b=this.element,c=b.is(".ui-header"),d=Math.abs(b.offset().top-a.mobile.window.scrollTop());
+return c||(d=Math.round(d-a.mobile.window.height()+b.outerHeight())-60),d},_bindScrollWorkaround:function(){var b=this;this._on(a.mobile.window,{scrollstop:function(){var a=b._viewportOffset();a>2&&b._visible&&b._triggerRedraw()}})},_bindListThumbWorkaround:function(){this.element.closest(".ui-page").addClass("ui-android-2x-fixed")},_triggerRedraw:function(){var b=parseFloat(a(".ui-page-active").css("padding-bottom"));a(".ui-page-active").css("padding-bottom",b+1+"px"),setTimeout(function(){a(".ui-page-active").css("padding-bottom",b+"px")},0)},destroy:function(){this._super(),this.element.closest(".ui-page-active").removeClass("ui-android-2x-fix")}})}(a),function(a,d){a.widget("mobile.panel",a.mobile.widget,{options:{classes:{panel:"ui-panel",panelOpen:"ui-panel-open",panelClosed:"ui-panel-closed",panelFixed:"ui-panel-fixed",panelInner:"ui-panel-inner",modal:"ui-panel-dismiss",modalOpen:"ui-panel-dismiss-open",pagePanel:"ui-page-panel",pagePanelOpen:"ui-page-panel-open",contentWrap:"ui-panel-content-wrap",contentWrapOpen:"ui-panel-content-wrap-open",contentWrapClosed:"ui-panel-content-wrap-closed",contentFixedToolbar:"ui-panel-content-fixed-toolbar",contentFixedToolbarOpen:"ui-panel-content-fixed-toolbar-open",contentFixedToolbarClosed:"ui-panel-content-fixed-toolbar-closed",animate:"ui-panel-animate"},animate:!0,theme:"c",position:"left",dismissible:!0,display:"reveal",initSelector:":jqmData(role='panel')",swipeClose:!0,positionFixed:!1},_panelID:null,_closeLink:null,_page:null,_modal:null,_panelInner:null,_wrapper:null,_fixedToolbar:null,_create:function(){var b=this,c=b.element,d=c.closest(":jqmData(role='page')"),e=function(){var b=a.data(d[0],"mobilePage").options.theme,c="ui-body-"+b;return c},f=function(){var a=c.find("."+b.options.classes.panelInner);return 0===a.length&&(a=c.children().wrapAll('<div class="'+b.options.classes.panelInner+'" />').parent()),a},g=function(){var c=d.find("."+b.options.classes.contentWrap);return 0===c.length&&(c=d.children(".ui-header:not(:jqmData(position='fixed')), .ui-content:not(:jqmData(role='popup')), .ui-footer:not(:jqmData(position='fixed'))").wrapAll('<div class="'+b.options.classes.contentWrap+" "+e()+'" />').parent(),a.support.cssTransform3d&&b.options.animate&&c.addClass(b.options.classes.animate)),c},h=function(){var c=d.find("."+b.options.classes.contentFixedToolbar);return 0===c.length&&(c=d.find(".ui-header:jqmData(position='fixed'), .ui-footer:jqmData(position='fixed')").addClass(b.options.classes.contentFixedToolbar),a.support.cssTransform3d&&b.options.animate&&c.addClass(b.options.classes.animate)),c};a.extend(this,{_panelID:c.attr("id"),_closeLink:c.find(":jqmData(rel='close')"),_page:c.closest(":jqmData(role='page')"),_pageTheme:e(),_panelInner:f(),_wrapper:g(),_fixedToolbar:h()}),b._addPanelClasses(),b._wrapper.addClass(this.options.classes.contentWrapClosed),b._fixedToolbar.addClass(this.options.classes.contentFixedToolbarClosed),b._page.addClass(b.options.classes.pagePanel),a.support.cssTransform3d&&b.options.animate&&this.element.addClass(b.options.classes.animate),b._bindUpdateLayout(),b._bindCloseEvents(),b._bindLinkListeners(),b._bindPageEvents(),b.options.dismissible&&b._createModal(),b._bindSwipeEvents()},_createModal:function(){var b=this;b._modal=a("<div class='"+b.options.classes.modal+"' data-panelid='"+b._panelID+"'></div>").on("mousedown",function(){b.close()}).appendTo(this._page)},_getPosDisplayClasses:function(a){return a+"-position-"+this.options.position+" "+a+"-display-"+this.options.display},_getPanelClasses:function(){var a=this.options.classes.panel+" "+this._getPosDisplayClasses(this.options.classes.panel)+" "+this.options.classes.panelClosed;return this.options.theme&&(a+=" ui-body-"+this.options.theme),this.options.positionFixed&&(a+=" "+this.options.classes.panelFixed),a},_addPanelClasses:function(){this.element.addClass(this._getPanelClasses())},_bindCloseEvents:function(){var a=this;a._closeLink.on("click.panel",function(b){return b.preventDefault(),a.close(),!1}),a.element.on("click.panel","a:jqmData(ajax='false')",function(){a.close()})},_positionPanel:function(){var b=this,c=b._panelInner.outerHeight(),d=c>a.mobile.getScreenHeight();d||!b.options.positionFixed?(d&&(b._unfixPanel(),a.mobile.resetActivePageHeight(c)),b._scrollIntoView(c)):b._fixPanel()},_scrollIntoView:function(c){c<a(b).scrollTop()&&b.scrollTo(0,0)},_bindFixListener:function(){this._on(a(b),{throttledresize:"_positionPanel"})},_unbindFixListener:function(){this._off(a(b),"throttledresize")},_unfixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.removeClass(this.options.classes.panelFixed)},_fixPanel:function(){this.options.positionFixed&&a.support.fixedPosition&&this.element.addClass(this.options.classes.panelFixed)},_bindUpdateLayout:function(){var a=this;a.element.on("updatelayout",function(){a._open&&a._positionPanel()})},_bindLinkListeners:function(){var b=this;b._page.on("click.panel","a",function(c){if(this.href.split("#")[1]===b._panelID&&b._panelID!==d){c.preventDefault();var e,f=a(this);return f.hasClass("ui-link")||(e=f.parent().parent(),e.hasClass("ui-li")&&(f=e.parent()),f.addClass(a.mobile.activeBtnClass),b.element.one("panelopen panelclose",function(){f.removeClass(a.mobile.activeBtnClass)})),b.toggle(),!1}})},_bindSwipeEvents:function(){var a=this,b=a._modal?a.element.add(a._modal):a.element;a.options.swipeClose&&("left"===a.options.position?b.on("swipeleft.panel",function(){a.close()}):b.on("swiperight.panel",function(){a.close()}))},_bindPageEvents:function(){var a=this;a._page.on("panelbeforeopen",function(b){a._open&&b.target!==a.element[0]&&a.close()}).on("pagehide",function(){a._open&&a.close(!0)}).on("keyup.panel",function(b){27===b.keyCode&&a._open&&a.close()})},_open:!1,_contentWrapOpenClasses:null,_fixedToolbarOpenClasses:null,_modalOpenClasses:null,open:function(b){if(!this._open){var c=this,d=c.options,e=function(){c._page.off("panelclose"),c._page.jqmData("panel","open"),!b&&a.support.cssTransform3d&&d.animate?c.element.add(c._wrapper).on(c._transitionEndEvents,f):setTimeout(f,0),c.options.theme&&"overlay"!==c.options.display&&c._page.removeClass(c._pageTheme).addClass("ui-body-"+c.options.theme),c.element.removeClass(d.classes.panelClosed).addClass(d.classes.panelOpen),c._positionPanel(),c.options.theme&&"overlay"!==c.options.display&&c._wrapper.css("min-height",c._page.css("min-height")),c._contentWrapOpenClasses=c._getPosDisplayClasses(d.classes.contentWrap),c._wrapper.removeClass(d.classes.contentWrapClosed).addClass(c._contentWrapOpenClasses+" "+d.classes.contentWrapOpen),c._fixedToolbarOpenClasses=c._getPosDisplayClasses(d.classes.contentFixedToolbar),c._fixedToolbar.removeClass(d.classes.contentFixedToolbarClosed).addClass(c._fixedToolbarOpenClasses+" "+d.classes.contentFixedToolbarOpen),c._modalOpenClasses=c._getPosDisplayClasses(d.classes.modal)+" "+d.classes.modalOpen,c._modal&&c._modal.addClass(c._modalOpenClasses)},f=function(){c.element.add(c._wrapper).off(c._transitionEndEvents,f),c._page.addClass(d.classes.pagePanelOpen),c._bindFixListener(),c._trigger("open")};this.element.closest(".ui-page-active").length<0&&(b=!0),c._trigger("beforeopen"),"open"===c._page.jqmData("panel")?c._page.on("panelclose",function(){e()}):e(),c._open=!0}},close:function(b){if(this._open){var c=this.options,d=this,e=function(){!b&&a.support.cssTransform3d&&c.animate?d.element.add(d._wrapper).on(d._transitionEndEvents,f):setTimeout(f,0),d._page.removeClass(c.classes.pagePanelOpen),d.element.removeClass(c.classes.panelOpen),d._wrapper.removeClass(c.classes.contentWrapOpen),d._fixedToolbar.removeClass(c.classes.contentFixedToolbarOpen),d._modal&&d._modal.removeClass(d._modalOpenClasses)},f=function(){d.options.theme&&"overlay"!==d.options.display&&(d._page.removeClass("ui-body-"+d.options.theme).addClass(d._pageTheme),d._wrapper.css("min-height","")),d.element.add(d._wrapper).off(d._transitionEndEvents,f),d.element.addClass(c.classes.panelClosed),d._wrapper.removeClass(d._contentWrapOpenClasses).addClass(c.classes.contentWrapClosed),d._fixedToolbar.removeClass(d._fixedToolbarOpenClasses).addClass(c.classes.contentFixedToolbarClosed),d._fixPanel(),d._unbindFixListener(),a.mobile.resetActivePageHeight(),d._page.jqmRemoveData("panel"),d._trigger("close")};this.element.closest(".ui-page-active").length<0&&(b=!0),d._trigger("beforeclose"),e(),d._open=!1}},toggle:function(){this[this._open?"close":"open"]()},_transitionEndEvents:"webkitTransitionEnd oTransitionEnd otransitionend transitionend msTransitionEnd",_destroy:function(){var b=this.options.classes,c=this.options.theme,d=this.element.siblings("."+b.panel).length;d?this._open&&(this._wrapper.removeClass(b.contentWrapOpen),this._fixedToolbar.removeClass(b.contentFixedToolbarOpen),this._page.jqmRemoveData("panel"),this._page.removeClass(b.pagePanelOpen),c&&this._page.removeClass("ui-body-"+c).addClass(this._pageTheme)):(this._wrapper.children().unwrap(),this._page.find("a").unbind("panelopen panelclose"),this._page.removeClass(b.pagePanel),this._open&&(this._page.jqmRemoveData("panel"),this._page.removeClass(b.pagePanelOpen),c&&this._page.removeClass("ui-body-"+c).addClass(this._pageTheme),a.mobile.resetActivePageHeight())),this._panelInner.children().unwrap(),this.element.removeClass([this._getPanelClasses(),b.panelAnimate].join(" ")).off("swipeleft.panel swiperight.panel").off("panelbeforeopen").off("panelhide").off("keyup.panel").off("updatelayout"),this._closeLink.off("click.panel"),this._modal&&this._modal.remove(),this.element.off(this._transitionEndEvents).removeClass([b.panelUnfixed,b.panelClosed,b.panelOpen].join(" "))}}),a(c).bind("pagecreate create",function(b){a.mobile.panel.prototype.enhanceWithin(b.target)})}(a),function(a,b){a.widget("mobile.table",a.mobile.widget,{options:{classes:{table:"ui-table"},initSelector:":jqmData(role='table')"},_create:function(){var a=this;a.refresh(!0)},refresh:function(c){var d=this,e=this.element.find("thead tr");c&&this.element.addClass(this.options.classes.table),d.headers=this.element.find("tr:eq(0)").children(),d.allHeaders=d.headers.add(e.children()),e.each(function(){var f=0;a(this).children().each(function(){var g=parseInt(a(this).attr("colspan"),10),h=":nth-child("+(f+1)+")";if(a(this).jqmData("colstart",f+1),g)for(var i=0;g-1>i;i++)f++,h+=", :nth-child("+(f+1)+")";c===b&&a(this).jqmData("cells",""),a(this).jqmData("cells",d.element.find("tr").not(e.eq(0)).not(this).children(h)),f++})}),c===b&&this.element.trigger("refresh")}}),a.mobile.document.bind("pagecreate create",function(b){a.mobile.table.prototype.enhanceWithin(b.target)})}(a),function(a,b){a.mobile.table.prototype.options.mode="columntoggle",a.mobile.table.prototype.options.columnBtnTheme=null,a.mobile.table.prototype.options.columnPopupTheme=null,a.mobile.table.prototype.options.columnBtnText="Columns...",a.mobile.table.prototype.options.classes=a.extend(a.mobile.table.prototype.options.classes,{popup:"ui-table-columntoggle-popup",columnBtn:"ui-table-columntoggle-btn",priorityPrefix:"ui-table-priority-",columnToggleTable:"ui-table-columntoggle"}),a.mobile.document.delegate(":jqmData(role='table')","tablecreate refresh",function(c){var d,e,f,g,h=a(this),i=h.data("mobile-table"),j=c.type,k=i.options,l=a.mobile.ns,m=(h.attr("id")||k.classes.popup)+"-popup";"columntoggle"===k.mode&&("refresh"!==j&&(i.element.addClass(k.classes.columnToggleTable),d=a("<a href='#"+m+"' class='"+k.classes.columnBtn+"' data-"+l+"rel='popup' data-"+l+"mini='true'>"+k.columnBtnText+"</a>"),e=a("<div data-"+l+"role='popup' data-"+l+"role='fieldcontain' class='"+k.classes.popup+"' id='"+m+"'></div>"),f=a("<fieldset data-"+l+"role='controlgroup'></fieldset>")),i.headers.not("td").each(function(b){var c=a(this).jqmData("priority"),d=a(this).add(a(this).jqmData("cells"));c&&(d.addClass(k.classes.priorityPrefix+c),"refresh"!==j?a("<label><input type='checkbox' checked />"+a(this).text()+"</label>").appendTo(f).children(0).jqmData("cells",d).checkboxradio({theme:k.columnPopupTheme}):a("#"+m+" fieldset div:eq("+b+")").find("input").jqmData("cells",d))}),"refresh"!==j&&f.appendTo(e),g=f===b?a("#"+m+" fieldset"):f,"refresh"!==j&&(g.on("change","input",function(){this.checked?a(this).jqmData("cells").removeClass("ui-table-cell-hidden").addClass("ui-table-cell-visible"):a(this).jqmData("cells").removeClass("ui-table-cell-visible").addClass("ui-table-cell-hidden")}),d.insertBefore(h).buttonMarkup({theme:k.columnBtnTheme}),e.insertBefore(h).popup()),i.update=function(){g.find("input").each(function(){this.checked?(this.checked="table-cell"===a(this).jqmData("cells").eq(0).css("display"),"refresh"===j&&a(this).jqmData("cells").addClass("ui-table-cell-visible")):a(this).jqmData("cells").addClass("ui-table-cell-hidden"),a(this).checkboxradio("refresh")})},a.mobile.window.on("throttledresize",i.update),i.update())})}(a),function(a){a.mobile.table.prototype.options.mode="reflow",a.mobile.table.prototype.options.classes=a.extend(a.mobile.table.prototype.options.classes,{reflowTable:"ui-table-reflow",cellLabels:"ui-table-cell-label"}),a.mobile.document.delegate(":jqmData(role='table')","tablecreate refresh",function(b){var c=a(this),d=b.type,e=c.data("mobile-table"),f=e.options;if("reflow"===f.mode){"refresh"!==d&&e.element.addClass(f.classes.reflowTable);var g=a(e.allHeaders.get().reverse());g.each(function(){var b=a(this).jqmData("cells"),c=a(this).jqmData("colstart"),d=b.not(this).filter("thead th").length&&" ui-table-cell-label-top",e=a(this).text();if(""!==e)if(d){var g=parseInt(a(this).attr("colspan"),10),h="";g&&(h="td:nth-child("+g+"n + "+c+")"),b.filter(h).prepend("<b class='"+f.classes.cellLabels+d+"'>"+e+"</b>")}else b.prepend("<b class='"+f.classes.cellLabels+"'>"+e+"</b>")})}})}(a),function(a,b){function c(a){e=a.originalEvent,i=e.accelerationIncludingGravity,f=Math.abs(i.x),g=Math.abs(i.y),h=Math.abs(i.z),!b.orientation&&(f>7||(h>6&&8>g||8>h&&g>6)&&f>5)?j.enabled&&j.disable():j.enabled||j.enable()}a.mobile.iosorientationfixEnabled=!0;var d=navigator.userAgent;if(!(/iPhone|iPad|iPod/.test(navigator.platform)&&/OS [1-5]_[0-9_]* like Mac OS X/i.test(d)&&d.indexOf("AppleWebKit")>-1))return a.mobile.iosorientationfixEnabled=!1,void 0;var e,f,g,h,i,j=a.mobile.zoom;a.mobile.document.on("mobileinit",function(){a.mobile.iosorientationfixEnabled&&a.mobile.window.bind("orientationchange.iosorientationfix",j.enable).bind("devicemotion.iosorientationfix",c)})}(a,this),function(a,b){function d(){e.removeClass("ui-mobile-rendering")}var e=a("html"),f=(a("head"),a.mobile.window);a(b.document).trigger("mobileinit"),a.mobile.gradeA()&&(a.mobile.ajaxBlacklist&&(a.mobile.ajaxEnabled=!1),e.addClass("ui-mobile ui-mobile-rendering"),setTimeout(d,5e3),a.extend(a.mobile,{initializePage:function(){var b=a.mobile.path,e=a(":jqmData(role='page'), :jqmData(role='dialog')"),g=b.stripHash(b.stripQueryParams(b.parseLocation().hash)),h=c.getElementById(g);e.length||(e=a("body").wrapInner("<div data-"+a.mobile.ns+"role='page'></div>").children(0)),e.each(function(){var b=a(this);b.jqmData("url")||b.attr("data-"+a.mobile.ns+"url",b.attr("id")||location.pathname+location.search)}),a.mobile.firstPage=e.first(),a.mobile.pageContainer=a.mobile.firstPage.parent().addClass("ui-mobile-viewport"),a.mobile.navreadyDeferred.resolve(),f.trigger("pagecontainercreate"),a.mobile.showPageLoadingMsg(),d(),a.mobile.hashListeningEnabled&&a.mobile.path.isHashValid(location.hash)&&(a(h).is(':jqmData(role="page")')||a.mobile.path.isPath(g)||g===a.mobile.dialogHashKey)?a.event.special.navigate.isPushStateEnabled()?(a.mobile.navigate.history.stack=[],a.mobile.navigate(a.mobile.path.isPath(location.hash)?location.hash:location.href)):f.trigger("hashchange",[!0]):(a.mobile.path.isHashValid(location.hash)&&(a.mobile.urlHistory.initialDst=g.replace("#","")),a.event.special.navigate.isPushStateEnabled()&&a.mobile.navigate.navigator.squash(b.parseLocation().href),a.mobile.changePage(a.mobile.firstPage,{transition:"none",reverse:!0,changeHash:!1,fromHashChange:!0}))}}),a(function(){b.scrollTo(0,1),a.mobile.defaultHomeScroll=a.support.scrollTop&&1!==a.mobile.window.scrollTop()?1:0,a.mobile.autoInitializePage&&a.mobile.initializePage(),f.load(a.mobile.silentScroll),a.support.cssPointerEvents||a.mobile.document.delegate(".ui-disabled","vclick",function(a){a.preventDefault(),a.stopImmediatePropagation()})}))}(a,this)});
+/*
+//@ sourceMappingURL=jquery.mobile-1.3.2.min.map
+*/
\ No newline at end of file
diff --git a/html5/verto/demo/js/verto-min.js b/html5/verto/demo/js/verto-min.js
new file mode 100644 (file)
index 0000000..7b2bf2c
--- /dev/null
@@ -0,0 +1,196 @@
+
+(function($){function findLine(sdpLines,prefix,substr){return findLineInRange(sdpLines,0,-1,prefix,substr);}
+function findLineInRange(sdpLines,startLine,endLine,prefix,substr){var realEndLine=(endLine!=-1)?endLine:sdpLines.length;for(var i=startLine;i<realEndLine;++i){if(sdpLines[i].indexOf(prefix)===0){if(!substr||sdpLines[i].toLowerCase().indexOf(substr.toLowerCase())!==-1){return i;}}}
+return null;}
+function getCodecPayloadType(sdpLine){var pattern=new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+');var result=sdpLine.match(pattern);return(result&&result.length==2)?result[1]:null;}
+function setDefaultCodec(mLine,payload){var elements=mLine.split(' ');var newLine=[];var index=0;for(var i=0;i<elements.length;i++){if(index===3)
+newLine[index++]=payload;if(elements[i]!==payload)newLine[index++]=elements[i];}
+return newLine.join(' ');}
+$.FSRTC=function(options){this.options=$.extend({useVideo:null,useStereo:false,userData:null,videoParams:{},callbacks:{onICEComplete:function(){},onICE:function(){},onOfferSDP:function(){}}},options);this.mediaData={SDP:null,profile:{},candidateList:[]};this.constraints={optional:[{'DtlsSrtpKeyAgreement':'true'}],mandatory:{OfferToReceiveAudio:true,OfferToReceiveVideo:this.options.useVideo?true:false,}};if(self.options.useVideo){self.options.useVideo.style.display='none';}
+setCompat();checkCompat();};$.FSRTC.prototype.useVideo=function(obj){var self=this;if(obj){self.options.useVideo=obj;self.constraints.mandatory.OfferToReceiveVideo=true;}else{self.options.useVideo=null;self.constraints.mandatory.OfferToReceiveVideo=false;}
+if(self.options.useVideo){self.options.useVideo.style.display='none';}};$.FSRTC.prototype.useStereo=function(on){var self=this;self.options.useStereo=on;};$.FSRTC.prototype.stereoHack=function(sdp){var self=this;if(!self.options.useStereo){return sdp;}
+var sdpLines=sdp.split('\r\n');var opusIndex=findLine(sdpLines,'a=rtpmap','opus/48000'),opusPayload;if(opusIndex){opusPayload=getCodecPayloadType(sdpLines[opusIndex]);}
+var fmtpLineIndex=findLine(sdpLines,'a=fmtp:'+opusPayload.toString());if(fmtpLineIndex===null)return sdp;sdpLines[fmtpLineIndex]=sdpLines[fmtpLineIndex].concat('; stereo=1');sdp=sdpLines.join('\r\n');return sdp;};function setCompat(){$.FSRTC.moz=!!navigator.mozGetUserMedia;if(!navigator.getUserMedia){navigator.getUserMedia=navigator.mozGetUserMedia||navigator.webkitGetUserMedia||navigator.msGetUserMedia;}}
+function checkCompat(){if(!navigator.getUserMedia){alert('This application cannot function in this browser.');return false;}
+return true;}
+function onStreamError(self){console.log('There has been a problem retrieving the streams - did you allow access?');}
+function onStreamSuccess(self){console.log("Stream Success");}
+function onICE(self,candidate){self.mediaData.candidate=candidate;self.mediaData.candidateList.push(self.mediaData.candidate);doCallback(self,"onICE");}
+function doCallback(self,func,arg){if(func in self.options.callbacks){self.options.callbacks[func](self,arg);}}
+function onICEComplete(self,candidate){console.log("ICE Complete");doCallback(self,"onICEComplete");}
+function onChannelError(self,e){console.error("Channel Error",e);doCallback(self,"onError",e);}
+function onICESDP(self,sdp){self.mediaData.SDP=self.stereoHack(sdp.sdp);console.log("ICE SDP");doCallback(self,"onICESDP");}
+function onAnswerSDP(self,sdp){self.answer.SDP=self.stereoHack(sdp.sdp);console.log("ICE ANSWER SDP");doCallback(self,"onAnswerSDP",self.answer.SDP);}
+function onMessage(self,msg){console.log("Message");doCallback(self,"onICESDP",msg);}
+function onRemoteStream(self,stream){if(self.options.useVideo){self.options.useVideo.style.display='block';}
+var element=self.options.useAudio;console.log("REMOTE STREAM",stream,element);if(typeof element.srcObject!=='undefined'){element.srcObject=stream;}else if(typeof element.mozSrcObject!=='undefined'){element.mozSrcObject=stream;}else if(typeof element.src!=='undefined'){element.src=URL.createObjectURL(stream);}else{console.error('Error attaching stream to element.');}
+self.options.useAudio.play();self.remoteStream=stream;}
+function onOfferSDP(self,sdp){self.mediaData.SDP=self.stereoHack(sdp.sdp);console.log("Offer SDP");doCallback(self,"onOfferSDP");}
+$.FSRTC.prototype.answer=function(sdp,onSuccess,onError){this.peer.addAnswerSDP({type:"answer",sdp:sdp},onSuccess,onError);};$.FSRTC.prototype.stop=function(){var self=this;if(self.options.useVideo){self.options.useVideo.style.display='none';}
+if(self.localStream){self.localStream.stop();self.localStream=null;}
+if(self.peer){console.log("stopping peer");self.peer.stop();}};$.FSRTC.prototype.createAnswer=function(sdp){var self=this;self.type="answer";self.remoteSDP=sdp;console.debug("inbound sdp: ",sdp);function onSuccess(stream){self.localStream=stream;self.peer=RTCPeerConnection({type:self.type,attachStream:self.localStream,onICE:function(candidate){return onICE(self,candidate);},onICEComplete:function(){return onICEComplete(self);},onRemoteStream:function(stream){return onRemoteStream(self,stream);},onICESDP:function(sdp){return onICESDP(self,sdp);},onChannelError:function(e){return onChannelError(self,e);},constraints:self.constraints,offerSDP:{type:"offer",sdp:self.remoteSDP}});onStreamSuccess(self);}
+function onError(){onStreamError(self);}
+getUserMedia({constraints:{audio:true,video:this.options.useVideo?{mandatory:this.options.videoParams,optional:[]}:null},video:this.options.useVideo?true:false,onsuccess:onSuccess,onerror:onError});};$.FSRTC.prototype.call=function(profile){checkCompat();var self=this;self.type="offer";function onSuccess(stream){self.localStream=stream;self.peer=RTCPeerConnection({type:self.type,attachStream:self.localStream,onICE:function(candidate){return onICE(self,candidate);},onICEComplete:function(){return onICEComplete(self);},onRemoteStream:function(stream){return onRemoteStream(self,stream);},onOfferSDP:function(sdp){return onOfferSDP(self,sdp);},onICESDP:function(sdp){return onICESDP(self,sdp);},onChannelError:function(e){return onChannelError(self,e);},constraints:self.constraints});onStreamSuccess(self);}
+function onError(){onStreamError(self);}
+getUserMedia({constraints:{audio:true,video:this.options.useVideo?{mandatory:this.options.videoParams,optional:[]}:null},video:this.options.useVideo?true:false,onsuccess:onSuccess,onerror:onError});};window.moz=!!navigator.mozGetUserMedia;function RTCPeerConnection(options){var w=window,PeerConnection=w.mozRTCPeerConnection||w.webkitRTCPeerConnection,SessionDescription=w.mozRTCSessionDescription||w.RTCSessionDescription,IceCandidate=w.mozRTCIceCandidate||w.RTCIceCandidate;var STUN={url:!moz?'stun:stun.l.google.com:19302':'stun:23.21.150.121'};var TURN={url:'turn:homeo@turn.bistri.com:80',credential:'homeo'};var iceServers={iceServers:options.iceServers||[STUN]};if(!moz&&!options.iceServers){if(parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2])>=28)TURN={url:'turn:turn.bistri.com:80',credential:'homeo',username:'homeo'};iceServers.iceServers=[STUN];}
+var optional={optional:[]};if(!moz){optional.optional=[{DtlsSrtpKeyAgreement:true},{RtpDataChannels:options.onChannelMessage?true:false}];}
+var peer=new PeerConnection(iceServers,optional);openOffererChannel();var x=0;peer.onicecandidate=function(event){console.log("WTF ICE",event);if(event.candidate){options.onICE(event.candidate);}else{if(options.onICEComplete){options.onICEComplete();}
+if(options.type=="offer"){if(!moz&&!x&&options.onICESDP){options.onICESDP(peer.localDescription);}}else{if(!x&&options.onICESDP){options.onICESDP(peer.localDescription);}}}};if(options.attachStream)peer.addStream(options.attachStream);if(options.attachStreams&&options.attachStream.length){var streams=options.attachStreams;for(var i=0;i<streams.length;i++){peer.addStream(streams[i]);}}
+peer.onaddstream=function(event){var remoteMediaStream=event.stream;remoteMediaStream.onended=function(){if(options.onRemoteStreamEnded)options.onRemoteStreamEnded(remoteMediaStream);};if(options.onRemoteStream)options.onRemoteStream(remoteMediaStream);};var constraints=options.constraints||{optional:[],mandatory:{OfferToReceiveAudio:true,OfferToReceiveVideo:true}};function createOffer(){if(!options.onOfferSDP)return;peer.createOffer(function(sessionDescription){sessionDescription.sdp=serializeSdp(sessionDescription.sdp);peer.setLocalDescription(sessionDescription);options.onOfferSDP(sessionDescription);if(moz&&options.onICESDP){options.onICESDP(sessionDescription);}},onSdpError,constraints);}
+function createAnswer(){if(options.type!="answer")return;peer.setRemoteDescription(new SessionDescription(options.offerSDP),onSdpSuccess,onSdpError);peer.createAnswer(function(sessionDescription){sessionDescription.sdp=serializeSdp(sessionDescription.sdp);peer.setLocalDescription(sessionDescription);if(options.onAnswerSDP){options.onAnswerSDP(sessionDescription);}},onSdpError,constraints);}
+if((options.onChannelMessage&&!moz)||!options.onChannelMessage){createOffer();createAnswer();}
+function setBandwidth(sdp){sdp=sdp.replace(/b=AS([^\r\n]+\r\n)/g,'');sdp=sdp.replace(/a=mid:data\r\n/g,'a=mid:data\r\nb=AS:1638400\r\n');return sdp;}
+function getInteropSDP(sdp){var chars='ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),extractedChars='';function getChars(){extractedChars+=chars[parseInt(Math.random()*40)]||'';if(extractedChars.length<40)getChars();return extractedChars;}
+if(options.onAnswerSDP)sdp=sdp.replace(/(a=crypto:0 AES_CM_128_HMAC_SHA1_32)(.*?)(\r\n)/g,'');var inline=getChars()+'\r\n'+(extractedChars='');sdp=sdp.indexOf('a=crypto')==-1?sdp.replace(/c=IN/g,'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:'+inline+'c=IN'):sdp;return sdp;}
+function serializeSdp(sdp){return sdp;}
+var channel;function openOffererChannel(){if(!options.onChannelMessage||(moz&&!options.onOfferSDP))return;_openOffererChannel();if(!moz)return;navigator.mozGetUserMedia({audio:true,fake:true},function(stream){peer.addStream(stream);createOffer();},useless);}
+function _openOffererChannel(){channel=peer.createDataChannel(options.channel||'RTCDataChannel',moz?{}:{reliable:false});if(moz)channel.binaryType='blob';setChannelEvents();}
+function setChannelEvents(){channel.onmessage=function(event){if(options.onChannelMessage)options.onChannelMessage(event);};channel.onopen=function(){if(options.onChannelOpened)options.onChannelOpened(channel);};channel.onclose=function(event){if(options.onChannelClosed)options.onChannelClosed(event);console.warn('WebRTC DataChannel closed',event);};channel.onerror=function(event){if(options.onChannelError)options.onChannelError(event);console.error('WebRTC DataChannel error',event);};}
+if(options.onAnswerSDP&&moz&&options.onChannelMessage)openAnswererChannel();function openAnswererChannel(){peer.ondatachannel=function(event){channel=event.channel;channel.binaryType='blob';setChannelEvents();};if(!moz)return;navigator.mozGetUserMedia({audio:true,fake:true},function(stream){peer.addStream(stream);createAnswer();},useless);}
+function useless(){log('Error in fake:true');}
+function onSdpSuccess(){}
+function onSdpError(e){if(options.onChannelError){options.onChannelError(e);}
+console.error('sdp error:',e);}
+return{addAnswerSDP:function(sdp,cbSuccess,cbError){peer.setRemoteDescription(new SessionDescription(sdp),cbSuccess?cbSuccess:onSdpSuccess,cbError?cbError:onSdpError);},addICE:function(candidate){peer.addIceCandidate(new IceCandidate({sdpMLineIndex:candidate.sdpMLineIndex,candidate:candidate.candidate}));},peer:peer,channel:channel,sendData:function(message){if(channel){channel.send(message);}},stop:function(){peer.close();if(options.attachStream){options.attachStream.stop();}}};}
+var video_constraints={mandatory:{},optional:[]};function getUserMedia(options){var n=navigator,media;n.getMedia=n.webkitGetUserMedia||n.mozGetUserMedia;n.getMedia(options.constraints||{audio:true,video:video_constraints},streaming,options.onerror||function(e){console.error(e);});function streaming(stream){var video=options.video;if(video){video[moz?'mozSrcObject':'src']=moz?stream:window.webkitURL.createObjectURL(stream);}
+if(options.onsuccess){options.onsuccess(stream);}
+media=stream;}
+return media;}})(jQuery);(function($){$.JsonRpcClient=function(options){var self=this;this.options=$.extend({ajaxUrl:null,socketUrl:null,onmessage:null,login:null,passwd:null,sessid:null,getSocket:function(onmessage_cb){return self._getSocket(onmessage_cb);}},options);this.wsOnMessage=function(event){self._wsOnMessage(event);};};$.JsonRpcClient.prototype._ws_socket=null;$.JsonRpcClient.prototype._ws_callbacks={};$.JsonRpcClient.prototype._current_id=1;$.JsonRpcClient.prototype.call=function(method,params,success_cb,error_cb){if(!params){params={};}
+if(this.options.sessid){params.sessid=this.options.sessid;}
+var request={jsonrpc:'2.0',method:method,params:params,id:this._current_id++};if(!success_cb){success_cb=function(e){console.log("Success: ",e);};}
+if(!error_cb){error_cb=function(e){console.log("Error: ",e);};}
+var socket=this.options.getSocket(this.wsOnMessage);if(socket!==null){this._wsCall(socket,request,success_cb,error_cb);return;}
+if(this.options.ajaxUrl===null){throw"$.JsonRpcClient.call used with no websocket and no http endpoint.";}
+$.ajax({type:'POST',url:this.options.ajaxUrl,data:$.toJSON(request),dataType:'json',cache:false,success:function(data){if('error'in data)error_cb(data.error,this);success_cb(data.result,this);},error:function(jqXHR,textStatus,errorThrown){try{var response=$.parseJSON(jqXHR.responseText);if('console'in window)console.log(response);error_cb(response.error,this);}
+catch(err){error_cb({error:jqXHR.responseText},this);}}});};$.JsonRpcClient.prototype.notify=function(method,params){if(this.options.sessid){params.sessid=this.options.sessid;}
+var request={jsonrpc:'2.0',method:method,params:params};var socket=this.options.getSocket(this.wsOnMessage);if(socket!==null){this._wsCall(socket,request);return;}
+if(this.options.ajaxUrl===null){throw"$.JsonRpcClient.notify used with no websocket and no http endpoint.";}
+$.ajax({type:'POST',url:this.options.ajaxUrl,data:$.toJSON(request),dataType:'json',cache:false});};$.JsonRpcClient.prototype.batch=function(callback,all_done_cb,error_cb){var batch=new $.JsonRpcClient._batchObject(this,all_done_cb,error_cb);callback(batch);batch._execute();};$.JsonRpcClient.prototype.socketReady=function(){if(this._ws_socket===null||this._ws_socket.readyState>1){return false;}
+return true;}
+$.JsonRpcClient.prototype.closeSocket=function(){if(self.socketReady()){this._ws_socket.onclose=function(w){console.log("Closing Socket")}
+this._ws_socket.close();}}
+$.JsonRpcClient.prototype.loginData=function(params){self.options.login=params.login;self.options.passwd=params.passwd;}
+$.JsonRpcClient.prototype.connectSocket=function(onmessage_cb){var self=this;if(!self.socketReady()){self.authing=false;this._ws_socket=new WebSocket(this.options.socketUrl);if(this._ws_socket){this._ws_socket.onmessage=onmessage_cb;this._ws_socket.onclose=function(w){if(!self.ws_sleep){self.ws_sleep=2;}
+self.ws_cnt=0;if(self.options.onWSClose){self.options.onWSClose(self);}
+console.error("Websocket Lost sleep: "+self.ws_sleep+"sec");setTimeout(function(){console.log("Attempting Reconnection....");self.connectSocket(onmessage_cb);},self.ws_sleep*1000);if(++self.ws_cnt>=150){self.ws_sleep=30;}}
+this._ws_socket.onopen=function(){this.ws_sleep=2;this.ws_cnt=0;if(self.options.onWSConnect){self.options.onWSConnect(self);}
+var req;while(req=$.JsonRpcClient.q.pop()){self._ws_socket.send(req);}}}}
+return this._ws_socket?true:false;}
+$.JsonRpcClient.prototype._getSocket=function(onmessage_cb){if(this.options.socketUrl===null||!("WebSocket"in window))return null;this.connectSocket(onmessage_cb);return this._ws_socket;};$.JsonRpcClient.q=[];$.JsonRpcClient.prototype._wsCall=function(socket,request,success_cb,error_cb){var request_json=$.toJSON(request);if(socket.readyState<1){self=this;$.JsonRpcClient.q.push(request_json);}
+else{socket.send(request_json);}
+if('id'in request&&typeof success_cb!=='undefined'){this._ws_callbacks[request.id]={request:request_json,request_obj:request,success_cb:success_cb,error_cb:error_cb};}};$.JsonRpcClient.prototype._wsOnMessage=function(event){var response;try{response=$.parseJSON(event.data);if(typeof response==='object'&&'jsonrpc'in response&&response.jsonrpc==='2.0'){if('result'in response&&this._ws_callbacks[response.id]){var success_cb=this._ws_callbacks[response.id].success_cb;delete this._ws_callbacks[response.id];success_cb(response.result,this);return;}
+else if('error'in response&&this._ws_callbacks[response.id]){var error_cb=this._ws_callbacks[response.id].error_cb;var orig_req=this._ws_callbacks[response.id].request;if(!self.authing&&response.error.code==-32000&&self.options.login&&self.options.passwd){self.authing=true;this.call("login",{login:self.options.login,passwd:self.options.passwd},this._ws_callbacks[response.id].request_obj.method=="login"?function(e){self.authing=false;console.log("logged in");delete self._ws_callbacks[response.id];if(self.options.onWSLogin){self.options.onWSLogin(true,self);}}:function(e){self.authing=false;console.log("logged in, resending request id: "+response.id);var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send(orig_req);}
+if(self.options.onWSLogin){self.options.onWSLogin(true,self);}},function(e){console.log("error logging in, request id:",response.id);delete self._ws_callbacks[response.id];error_cb(response.error,this);if(self.options.onWSLogin){self.options.onWSLogin(false,self);}});return;}
+delete this._ws_callbacks[response.id];error_cb(response.error,this);return;}}}
+catch(err){console.log("ERROR: "+err);return;}
+if(typeof this.options.onmessage==='function'){event.eventData=response;if(!event.eventData){event.eventData={};}
+var reply=this.options.onmessage(event);if(reply&&typeof reply==="object"&&event.eventData.id){var msg={jsonrpc:"2.0",id:event.eventData.id,result:reply};var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send($.toJSON(msg));}}}};$.JsonRpcClient._batchObject=function(jsonrpcclient,all_done_cb,error_cb){this._requests=[];this.jsonrpcclient=jsonrpcclient;this.all_done_cb=all_done_cb;this.error_cb=typeof error_cb==='function'?error_cb:function(){};};$.JsonRpcClient._batchObject.prototype.call=function(method,params,success_cb,error_cb){if(!params){params={};}
+if(this.options.sessid){params.sessid=this.options.sessid;}
+if(!success_cb){success_cb=function(e){console.log("Success: ",e);};}
+if(!error_cb){error_cb=function(e){console.log("Error: ",e);};}
+this._requests.push({request:{jsonrpc:'2.0',method:method,params:params,id:this.jsonrpcclient._current_id++},success_cb:success_cb,error_cb:error_cb});};$.JsonRpcClient._batchObject.prototype.notify=function(method,params){if(this.options.sessid){params.sessid=this.options.sessid;}
+this._requests.push({request:{jsonrpc:'2.0',method:method,params:params}});};$.JsonRpcClient._batchObject.prototype._execute=function(){var self=this;if(this._requests.length===0)return;var batch_request=[];var handlers={};var socket=self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage);if(socket!==null){for(var i=0;i<this._requests.length;i++){var call=this._requests[i];var success_cb=('success_cb'in call)?call.success_cb:undefined;var error_cb=('error_cb'in call)?call.error_cb:undefined;self.jsonrpcclient._wsCall(socket,call.request,success_cb,error_cb);}
+if(typeof all_done_cb==='function')all_done_cb(result);return;}
+for(var i=0;i<this._requests.length;i++){var call=this._requests[i];batch_request.push(call.request);if('id'in call.request){handlers[call.request.id]={success_cb:call.success_cb,error_cb:call.error_cb};}}
+var success_cb=function(data){self._batchCb(data,handlers,self.all_done_cb);};if(self.jsonrpcclient.options.ajaxUrl===null){throw"$.JsonRpcClient.batch used with no websocket and no http endpoint.";}
+$.ajax({url:self.jsonrpcclient.options.ajaxUrl,data:$.toJSON(batch_request),dataType:'json',cache:false,type:'POST',error:function(jqXHR,textStatus,errorThrown){self.error_cb(jqXHR,textStatus,errorThrown);},success:success_cb});};$.JsonRpcClient._batchObject.prototype._batchCb=function(result,handlers,all_done_cb){for(var i=0;i<result.length;i++){var response=result[i];if('error'in response){if(response.id===null||!(response.id in handlers)){if('console'in window)console.log(response);}
+else handlers[response.id].error_cb(response.error,this);}
+else{if(!(response.id in handlers)&&'console'in window)console.log(response);else handlers[response.id].success_cb(response.result,this);}}
+if(typeof all_done_cb==='function')all_done_cb(result);};})(jQuery);(function($){var generateGUID=(typeof(window.crypto)!=='undefined'&&typeof(window.crypto.getRandomValues)!=='undefined')?function(){var buf=new Uint16Array(8);window.crypto.getRandomValues(buf);var S4=function(num){var ret=num.toString(16);while(ret.length<4){ret="0"+ret;}
+return ret;};return(S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));}:function(){return'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,function(c){var r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);return v.toString(16);});};$.verto=function(options,callbacks){var verto=this;$.verto.saved.push(verto);verto.options=$.extend({login:null,passwd:null,socketUrl:null,tag:null,videoParams:{},ringSleep:6000},options);verto.sessid=$.cookie('verto_session_uuid')||generateGUID();$.cookie('verto_session_uuid',verto.sessid,{expires:1});verto.dialogs={};verto.callbacks=callbacks||{};verto.eventSUBS={};verto.rpcClient=new $.JsonRpcClient({login:verto.options.login,passwd:verto.options.passwd,socketUrl:verto.options.socketUrl,sessid:verto.sessid,onmessage:function(e){return verto.handleMessage(e.eventData);},onWSConnect:function(o){o.call('login',{});},onWSLogin:function(success){if(verto.callbacks.onWSLogin){verto.callbacks.onWSLogin(verto,success);}},onWSClose:function(success){if(verto.callbacks.onWSClose){verto.callbacks.onWSClose(verto,success);}
+verto.purge();}});if(verto.options.ringFile&&verto.options.tag){verto.ringer=$("#"+verto.options.tag);}
+verto.rpcClient.call('login',{});};$.verto.prototype.loginData=function(params){verto.options.login=params.login;verto.options.passwd=params.passwd;verto.rpcClient.loginData(params);};$.verto.prototype.logout=function(msg){var verto=this;verto.rpcClient.closeSocket();verto.purge();};$.verto.prototype.login=function(msg){var verto=this;verto.logout();verto.rpcClient.call('login',{});};$.verto.prototype.message=function(msg){var verto=this;var err=0;if(!msg.to){console.error("Missing To");err++;}
+if(!msg.body){console.error("Missing Body");err++;}
+if(err){return false;}
+verto.sendMethod("verto.info",{msg:msg});return true;};$.verto.prototype.processReply=function(method,success,e){var verto=this;var i;console.log("Response: "+method,success,e);switch(method){case"verto.subscribe":for(i in e.unauthorizedChannels){drop_bad(verto,e.unauthorizedChannels[i]);}
+for(i in e.subscribedChannels){mark_ready(verto,e.subscribedChannels[i]);}
+break;case"verto.unsubscribe":break;}};$.verto.prototype.sendMethod=function(method,params){var verto=this;verto.rpcClient.call(method,params,function(e){verto.processReply(method,true,e);},function(e){verto.processReply(method,false,e);});};function do_sub(verto,channel,obj){}
+function drop_bad(verto,channel){console.error("drop unauthorized channel: "+channel);delete verto.eventSUBS[channel];}
+function mark_ready(verto,channel){for(var j in verto.eventSUBS[channel]){verto.eventSUBS[channel][j].ready=true;console.log("subscribed to channel: "+channel);if(verto.eventSUBS[channel][j].readyHandler){verto.eventSUBS[channel][j].readyHandler(verto,channel);}}}
+var SERNO=1;function do_subscribe(verto,channel,subChannels,sparams){var params=sparams||{};var local=params.local;var obj={eventChannel:channel,userData:params.userData,handler:params.handler,ready:false,readyHandler:params.readyHandler,serno:SERNO++};var isnew=false;if(!verto.eventSUBS[channel]){verto.eventSUBS[channel]=[];subChannels.push(channel);isnew=true;}
+verto.eventSUBS[channel].push(obj);if(local){obj.ready=true;obj.local=true;}
+if(!isnew&&verto.eventSUBS[channel][0].ready){obj.ready=true;if(obj.readyHandler){obj.readyHandler(verto,channel);}}
+return{serno:obj.serno,eventChannel:channel};}
+$.verto.prototype.subscribe=function(channel,sparams){var verto=this;var r=[];var subChannels=[];var params=sparams||{};if(typeof(channel)==="string"){r.push(do_subscribe(verto,channel,subChannels,params));}else{for(var i in channel){r.push(do_subscribe(verto,channel,subChannels,params));}}
+if(subChannels.length){verto.sendMethod("verto.subscribe",{eventChannel:subChannels.length==1?subChannels[0]:subChannels,subParams:params.subParams});}
+return r;};$.verto.prototype.unsubscribe=function(handle){var verto=this;var i;if(!handle){for(i in verto.eventSUBS){if(verto.eventSUBS[i]){verto.unsubscribe(verto.eventSUBS[i]);}}}else{var unsubChannels={};var sendChannels=[];var channel;if(typeof(handle)=="string"){delete verto.eventSUBS[handle];unsubChannels[handle]++;}else{for(i in handle){if(typeof(handle[i])=="string"){channel=handle[i];delete verto.eventSUBS[channel];unsubChannels[channel]++;}else{var repl=[];channel=handle[i].eventChannel;for(var j in verto.eventSUBS[channel]){if(verto.eventSUBS[channel][j].serno==handle[i].serno){}else{repl.push(verto.eventSUBS[channel][j]);}}
+verto.eventSUBS[channel]=repl;if(verto.eventSUBS[channel].length===0){delete verto.eventSUBS[channel];unsubChannels[channel]++;}}}}
+for(var u in unsubChannels){console.log("Sending Unsubscribe for: ",u);sendChannels.push(u);}
+if(sendChannels.length){verto.sendMethod("verto.unsubscribe",{eventChannel:sendChannels.length==1?sendChannels[0]:sendChannels});}}};$.verto.prototype.broadcast=function(channel,params){var verto=this;var msg={eventChannel:channel,data:{}};for(var i in params){msg.data[i]=params[i];}
+verto.sendMethod("verto.broadcast",msg);};$.verto.prototype.purge=function(callID){var verto=this;var x=0;var i;for(i in verto.dialogs){if(!x){console.log("purging dialogs");}
+x++;verto.dialogs[i].setState($.verto.enum.state.purge);}
+for(i in verto.eventSUBS){if(verto.eventSUBS[i]){console.log("purging subscription: "+i);delete verto.eventSUBS[i];}}};$.verto.prototype.hangup=function(callID){var verto=this;if(callID){var dialog=verto.dialogs[callID];if(dialog){dialog.hangup();}}else{for(var i in verto.dialogs){verto.dialogs[i].hangup();}}};$.verto.prototype.newCall=function(args,callbacks){var verto=this;if(!verto.rpcClient.socketReady()){console.error("Not Connected...");return;}
+var dialog=new $.verto.dialog($.verto.enum.direction.outbound,this,args);dialog.invite();if(callbacks){dialog.callbacks=callbacks;}
+return dialog;};$.verto.prototype.handleMessage=function(data){var verto=this;if(data.params.callID){var dialog=verto.dialogs[data.params.callID];if(dialog){switch(data.method){case'verto.bye':dialog.hangup();break;case'verto.answer':dialog.handleAnswer(data.params.sdp);break;case'verto.media':dialog.handleMedia(data.params.sdp);break;case'verto.display':dialog.handleDisplay(data.params);break;case'verto.info':dialog.handleInfo(data.params);break;default:console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED",data.method);break;}}else{switch(data.method){case'verto.attach':data.params.attach=true;if(data.params.sdp&&data.params.sdp.indexOf("m=video")>0){data.params.useVideo=true;}
+if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;}
+dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);break;case'verto.invite':if(data.params.sdp&&data.params.sdp.indexOf("m=video")>0){data.params.wantVideo=true;}
+if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;}
+dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);break;default:console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED");break;}}
+return{method:data.method};}else{switch(data.method){case'verto.event':var list=null;var key=null;if(data.params){key=data.params.eventChannel;}
+if(key){list=verto.eventSUBS[key];if(!list){list=verto.eventSUBS[key.split(".")[0]];}}
+if(!list&&key&&verto.dialogs[key]){verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent,data.params);}else if(!list){if(!key){key="UNDEFINED";}
+console.error("UNSUBBED or invalid EVENT "+key+" IGNORED");}else{for(var i in list){var sub=list[i];if(!sub||!sub.ready){console.error("invalid EVENT for "+key+" IGNORED");}else if(sub.handler){sub.handler(verto,data.params,sub.userData);}else if(verto.callbacks.onEvent){verto.callbacks.onEvent(verto,data.params,sub.userData);}else{console.log("EVENT:",data.params);}}}
+break;case"verto.info":if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.info,data.params.msg);}
+console.error(data);console.debug("MESSAGE from: "+data.params.msg.from,data.params.msg.body);break;default:console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED",data.method);break;}}};var del_array=function(array,name){var r=[];var len=array.length;for(var i=0;i<len;i++){if(array[i]!=name){r.push(array[i]);}}
+return r;};var hashArray=function(){var vha=this;var hash={};var array=[];vha.reorder=function(a){array=a;var h=hash;hash={};var len=array.length;for(var i=0;i<len;i++){var key=array[i];if(h[key]){hash[key]=h[key];delete h[key];}}
+h=undefined;};vha.clear=function(){hash=undefined;array=undefined;hash={};array=[];};vha.add=function(name,val,insertAt){var redraw=false;if(!hash[name]){if(insertAt===undefined||insertAt<0||insertAt>=array.length){array.push(name);}else{var x=0;var n=[];var len=array.length;for(var i=0;i<len;i++){if(x++==insertAt){n.push(name);}
+n.push(array[i]);}
+array=undefined;array=n;n=undefined;redraw=true;}}
+hash[name]=val;return redraw;};vha.del=function(name){var r=false;if(hash[name]){array=del_array(array,name);delete hash[name];r=true;}else{console.error("can't del nonexistant key "+name);}
+return r;};vha.get=function(name){return hash[name];};vha.order=function(){return array;};vha.hash=function(){return hash;};vha.indexOf=function(name){var len=array.length;for(var i=0;i<len;i++){if(array[i]==name){return i;}}};vha.arrayLen=function(){return array.length;};vha.asArray=function(){var r=[];var len=array.length;for(var i=0;i<len;i++){var key=array[i];r.push(hash[key]);}
+return r;};vha.each=function(cb){var len=array.length;for(var i=0;i<len;i++){cb(array[i],hash[array[i]]);}};vha.dump=function(html){var str="";vha.each(function(name,val){str+="name: "+name+" val: "+JSON.stringify(val)+(html?"<br>":"\n");});return str;};};$.verto.liveArray=function(verto,context,name,config){var la=this;var lastSerno=0;var binding=null;var user_obj=config.userObj;var local=false;hashArray.call(la);la._add=la.add;la._del=la.del;la._reorder=la.reorder;la._clear=la.clear;la.context=context;la.name=name;la.user_obj=user_obj;la.verto=verto;la.broadcast=function(channel,obj){verto.broadcast(channel,obj);};la.errs=0;la.clear=function(){la._clear();lastSerno=0;if(la.onChange){la.onChange(la,{action:"clear"});}};la.checkSerno=function(serno){if(serno<0){return true;}
+if(lastSerno>0&&serno!=(lastSerno+1)){if(la.onErr){la.onErr(la,{lastSerno:lastSerno,serno:serno});}
+la.errs++;console.debug(la.errs);if(la.errs<3){la.bootstrap(la.user_obj);}
+return false;}else{lastSerno=serno;return true;}};la.reorder=function(serno,a){if(la.checkSerno(serno)){la._reorder(a);if(la.onChange){la.onChange(la,{serno:serno,action:"reorder"});}}};la.init=function(serno,val,key,index){if(key===null||key===undefined){key=serno;}
+if(la.checkSerno(serno)){if(la.onChange){la.onChange(la,{serno:serno,action:"init",index:index,key:key,data:val});}}};la.bootObj=function(serno,val){if(la.checkSerno(serno)){for(var i in val){la._add(val[i][0],val[i][1]);}
+if(la.onChange){la.onChange(la,{serno:serno,action:"bootObj",data:val,redraw:true});}}};la.add=function(serno,val,key,index){if(key===null||key===undefined){key=serno;}
+if(la.checkSerno(serno)){var redraw=la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"add",index:index,key:key,data:val,redraw:redraw});}}};la.modify=function(serno,val,key,index){if(key===null||key===undefined){key=serno;}
+if(la.checkSerno(serno)){la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"modify",key:key,data:val,index:index});}}};la.del=function(serno,key,index){if(key===null||key===undefined){key=serno;}
+if(la.checkSerno(serno)){if(index===null||index<0||index===undefined){index=la.indexOf(key);}
+var ok=la._del(key);if(ok&&la.onChange){la.onChange(la,{serno:serno,action:"del",key:key,index:index});}}};var eventHandler=function(v,e,la){var packet=e.data;if(packet.name!=la.name){return;}
+console.error("READ:",packet);switch(packet.action){case"init":la.init(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"bootObj":la.bootObj(packet.wireSerno,packet.data);break;case"add":la.add(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"modify":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.modify(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);}
+break;case"del":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.del(packet.wireSerno,packet.hashKey,packet.arrIndex);}
+break;case"clear":la.clear();break;case"reorder":la.reorder(packet.wireSerno,packet.order);break;default:if(la.checkSerno(packet.wireSerno)){if(la.onChange){la.onChange(la,{serno:packet.wireSerno,action:packet.action,data:packet.data});}}
+break;}};if(la.context){binding=la.verto.subscribe(la.context,{handler:eventHandler,userData:la,subParams:config.subParams});}
+la.destroy=function(){la._clear();la.verto.unsubscribe(binding);};la.bootstrap=function(obj){var self=la;self.clear();self.broadcast(self.context,{liveArray:{command:"bootstrap",context:self.context,name:self.name,obj:obj}});};la.changepage=function(obj){var self=la;self.clear();self.broadcast(self.context,{liveArray:{command:"changepage",context:la.context,name:la.name,obj:obj}});};la.heartbeat=function(obj){var self=la;var callback=function(){self.heartbeat.call(self,obj);};self.broadcast(self.context,{liveArray:{command:"heartbeat",context:self.context,name:self.name,obj:obj}});self.hb_pid=setTimeout(callback,30000);};la.bootstrap(la.user_obj);};$.verto.liveTable=function(verto,context,name,jq,config){var dt;var la=new $.verto.liveArray(verto,context,name,{subParams:config.subParams});var lt=this;lt.liveArray=la;lt.dataTable=dt;lt.verto=verto;lt.destroy=function(){if(dt){dt.fnDestroy();}
+if(la){la.destroy();}
+dt=null;la=null;};la.onErr=function(obj,args){console.error("Error: ",obj,args);};la.onChange=function(obj,args){var index=0;var iserr=0;if(!dt){if(!config.aoColumns){if(args.action!="init"){return;}
+config.aoColumns=[];for(var i in args.data){config.aoColumns.push({"sTitle":args.data[i]});}}
+dt=jq.dataTable(config);}
+if(dt&&(args.action=="del"||args.action=="modify")){index=args.index;if(index===undefined&&args.key){index=la.indexOf(args.key);}
+if(index===undefined){console.error("INVALID PACKET Missing INDEX\n",args);return;}}
+try{switch(args.action){case"bootObj":if(!args.data){console.error("missing data");return;}
+dt.fnClearTable();dt.fnAddData(obj.asArray());dt.fnAdjustColumnSizing();break;case"add":if(!args.data){console.error("missing data");return;}
+if(args.redraw>-1){dt.fnClearTable();dt.fnAddData(obj.asArray());}else{dt.fnAddData(args.data);}
+dt.fnAdjustColumnSizing();break;case"modify":if(!args.data){return;}
+console.debug(args,index);dt.fnUpdate(args.data,index);dt.fnAdjustColumnSizing();break;case"del":dt.fnDeleteRow(index);dt.fnAdjustColumnSizing();break;case"clear":dt.fnClearTable();break;case"reorder":dt.fnClearTable();dt.fnAddData(obj.asArray());break;case"hide":jq.hide();break;case"show":jq.show();break;}}catch(err){console.error("ERROR: "+err);iserr++;}
+if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}
+if(config.onChange){config.onChange(obj,args);}};la.onChange(la,{action:"init"});};$.verto.dialog=function(direction,verto,params){var dialog=this;dialog.params=$.extend({useVideo:verto.options.useVideo,useStereo:verto.options.useStereo,tag:verto.options.tag},params);dialog.verto=verto;dialog.direction=direction;dialog.lastState=null;dialog.state=dialog.lastState=$.verto.enum.state.new;dialog.callbacks=verto.callbacks;dialog.answered=false;dialog.attach=params.attach||false;if(dialog.params.callID){dialog.callID=dialog.params.callID;}else{dialog.callID=dialog.params.callID=generateGUID();}
+if(dialog.params.tag){dialog.audioStream=document.getElementById(dialog.params.tag);if(dialog.params.useVideo){dialog.videoStream=dialog.audioStream;}}
+dialog.verto.dialogs[dialog.callID]=dialog;var RTCcallbacks={};if(dialog.direction==$.verto.enum.direction.inbound){dialog.params.remote_caller_id_name=dialog.params.caller_id_name;dialog.params.remote_caller_id_number=dialog.params.caller_id_number;if(!dialog.params.remote_caller_id_name){dialog.params.remote_caller_id_name="Nobody";}
+if(!dialog.params.remote_caller_id_number){dialog.params.remote_caller_id_number="UNKNOWN";}
+RTCcallbacks.onMessage=function(rtc,msg){console.debug(msg);};RTCcallbacks.onAnswerSDP=function(rtc,sdp){console.error("answer sdp",sdp);};}else{dialog.params.remote_caller_id_name="Outbound Call";dialog.params.remote_caller_id_number=dialog.params.destination_number;}
+RTCcallbacks.onICESDP=function(rtc){if(rtc.type=="offer"){console.log("offer",rtc.mediaData.SDP);dialog.setState($.verto.enum.state.requesting);dialog.sendMethod("verto.invite",{sdp:rtc.mediaData.SDP});}else{dialog.setState($.verto.enum.state.answering);dialog.sendMethod(dialog.attach?"verto.attach":"verto.answer",{sdp:dialog.rtc.mediaData.SDP});}};RTCcallbacks.onICE=function(rtc){if(rtc.type=="offer"){console.log("offer",rtc.mediaData.candidate);return;}};RTCcallbacks.onError=function(e){console.error("ERROR:",e);dialog.hangup();};dialog.rtc=new $.FSRTC({callbacks:RTCcallbacks,useVideo:dialog.videoStream,useAudio:dialog.audioStream,useStereo:dialog.params.useStereo,videoParams:verto.options.videoParams,});dialog.rtc.verto=dialog.verto;if(dialog.direction==$.verto.enum.direction.inbound){if(dialog.attach){dialog.answer();}else{dialog.ring();}}};$.verto.dialog.prototype.invite=function(){var dialog=this;dialog.rtc.call();};$.verto.dialog.prototype.sendMethod=function(method,obj){var dialog=this;obj.dialogParams={};for(var i in dialog.params){if(i=="sdp"&&method!="verto.invite"&&method!="verto.attach"){continue;}
+obj.dialogParams[i]=dialog.params[i];}
+dialog.verto.rpcClient.call(method,obj,function(e){dialog.processReply(method,true,e);},function(e){dialog.processReply(method,false,e);});};function checkStateChange(oldS,newS){if(newS==$.verto.enum.state.purge||$.verto.enum.states[oldS.name][newS.name]){return true;}
+return false;}
+$.verto.dialog.prototype.setState=function(state){var dialog=this;if(dialog.state==$.verto.enum.state.ringing){dialog.stopRinging();}
+if(dialog.state==state||!checkStateChange(dialog.state,state)){console.error("Dialog "+dialog.callID+": INVALID state change from "+dialog.state.name+" to "+state.name);dialog.hangup();return false;}
+console.error("Dialog "+dialog.callID+": state change from "+dialog.state.name+" to "+state.name);dialog.lastState=dialog.state;dialog.state=state;if(dialog.callbacks.onDialogState){dialog.callbacks.onDialogState(this);}
+switch(dialog.state){case $.verto.enum.state.purge:dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.hangup:if(dialog.lastState.val>$.verto.enum.state.requesting.val&&dialog.lastState.val<$.verto.enum.state.hangup.val){dialog.sendMethod("verto.bye",{});}
+dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.destroy:delete verto.dialogs[dialog.callID];dialog.rtc.stop();break;}
+return true;};$.verto.dialog.prototype.processReply=function(method,success,e){var dialog=this;console.log("Response: "+method+" State:"+dialog.state.name,success,e);switch(method){case"verto.answer":case"verto.attach":if(success){dialog.setState($.verto.enum.state.active);}else{dialog.hangup();}
+break;case"verto.invite":if(success){dialog.setState($.verto.enum.state.trying);}else{dialog.setState($.verto.enum.state.destroy);}
+break;case"verto.bye":dialog.hangup();break;case"verto.modify":if(e.holdState){if(e.holdState=="held"){if(dialog.state!=$.verto.enum.state.held){dialog.setState($.verto.enum.state.held);}}else if(e.holdState=="active"){if(dialog.state!=$.verto.enum.state.active){dialog.setState($.verto.enum.state.active);}}}
+if(success){}
+break;default:break;}};$.verto.dialog.prototype.hangup=function(sdp){var dialog=this;if(dialog.state.val>$.verto.enum.state.new.val&&dialog.state.val<$.verto.enum.state.hangup.val){dialog.setState($.verto.enum.state.hangup);}else if(dialog.state.val<$.verto.enum.state.destroy){dialog.setState($.verto.enum.state.destroy);}};$.verto.dialog.prototype.stopRinging=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.stop();}};$.verto.dialog.prototype.indicateRing=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.attr("src",dialog.verto.options.ringFile)[0].play();setTimeout(function(){dialog.stopRinging();if(dialog.state==$.verto.enum.state.ringing){dialog.indicateRing();}},dialog.verto.options.ringSleep);}};$.verto.dialog.prototype.ring=function(){var dialog=this;dialog.setState($.verto.enum.state.ringing);dialog.indicateRing();};$.verto.dialog.prototype.useVideo=function(on){var dialog=this;dialog.params.useVideo=on;if(on){dialog.videoStream=dialog.audioStream;}else{dialog.videoStream=null;}
+dialog.rtc.useVideo(dialog.videoStream);};$.verto.dialog.prototype.useStereo=function(on){var dialog=this;dialog.params.useStereo=on;dialog.rtc.useStereo(on);};$.verto.dialog.prototype.dtmf=function(digits){var dialog=this;if(digits){dialog.sendMethod("verto.info",{dtmf:digits});}};$.verto.dialog.prototype.transfer=function(dest,params){var dialog=this;if(dest){cur_call.sendMethod("verto.modify",{action:"transfer",destination:dest,params:params});}};$.verto.dialog.prototype.hold=function(params){var dialog=this;cur_call.sendMethod("verto.modify",{action:"hold",params:params});};$.verto.dialog.prototype.unhold=function(params){var dialog=this;cur_call.sendMethod("verto.modify",{action:"unhold",params:params});};$.verto.dialog.prototype.toggleHold=function(params){var dialog=this;cur_call.sendMethod("verto.modify",{action:"toggleHold",params:params});};$.verto.dialog.prototype.message=function(msg){var dialog=this;var err=0;if(!msg.to){console.error("Missing To");err++;}
+if(!msg.body){console.error("Missing Body");err++;}
+if(err){return false;}
+dialog.sendMethod("verto.info",{msg:msg});return true;};$.verto.dialog.prototype.answer=function(params){var dialog=this;if(!dialog.answered){if(params){if(params.useVideo){dialog.useVideo(true);}}
+dialog.rtc.createAnswer(dialog.params.sdp);dialog.answered=true;}};$.verto.dialog.prototype.handleAnswer=function(sdp){var dialog=this;if(dialog.state.val>=$.verto.enum.state.active.val){return;}
+if(dialog.state.val>=$.verto.enum.state.early.val){dialog.setState($.verto.enum.state.active);}else{dialog.rtc.answer(sdp,function(){dialog.setState($.verto.enum.state.active);},function(e){console.error(e);dialog.hangup();});console.log("ANSWER SDP",sdp);}};$.verto.dialog.prototype.cidString=function(enc){var dialog=this;var party=dialog.params.remote_caller_id_name+(enc?" &lt;":" <")+dialog.params.remote_caller_id_number+(enc?"&gt;":">");return party;};$.verto.dialog.prototype.sendMessage=function(msg,params){var dialog=this;if(dialog.callbacks.onMessage){dialog.callbacks.onMessage(dialog.verto,dialog,msg,params);}};$.verto.dialog.prototype.handleInfo=function(params){var dialog=this;dialog.sendMessage($.verto.enum.message.info,params.msg);};$.verto.dialog.prototype.handleDisplay=function(params){var dialog=this;if(params.display_name){dialog.params.remote_caller_id_name=params.display_name;}
+if(params.display_number){dialog.params.remote_caller_id_number=params.display_number;}
+dialog.sendMessage($.verto.enum.message.display,{});};$.verto.dialog.prototype.handleMedia=function(sdp){var dialog=this;if(dialog.state.val>=$.verto.enum.state.early.val){return;}
+dialog.rtc.answer(sdp,function(){dialog.setState($.verto.enum.state.early);},function(e){console.error(e);dialog.hangup();});console.log("EARLY SDP",sdp);};$.verto.ENUM=function(s){var i=0,o={};s.split(" ").map(function(x){o[x]={name:x,val:i++};});return Object.freeze(o);};$.verto.enum={};$.verto.enum.states=Object.freeze({new:{requesting:1,ringing:1,destroy:1,answering:1},requesting:{trying:1,hangup:1},trying:{active:1,early:1,hangup:1},ringing:{answering:1,hangup:1},answering:{active:1,hangup:1},active:{hangup:1,held:1},held:{hangup:1,active:1},early:{hangup:1,active:1},hangup:{destroy:1},destroy:{},purge:{destroy:1}});$.verto.enum.state=$.verto.ENUM("new requesting trying ringing answering early active held hangup destroy purge");$.verto.enum.direction=$.verto.ENUM("inbound outbound");$.verto.enum.message=$.verto.ENUM("display info pvtEvent");$.verto.enum=Object.freeze($.verto.enum);$.verto.saved=[];$(window).bind('beforeunload',function(){for(var i in $.verto.saved){var verto=$.verto.saved[i];if(verto){verto.logout();verto.purge();}}
+return $.verto.warnOnUnload;});})(jQuery);
\ No newline at end of file
diff --git a/html5/verto/demo/sounds/bell_ring2.mp3 b/html5/verto/demo/sounds/bell_ring2.mp3
new file mode 100644 (file)
index 0000000..d0a423b
Binary files /dev/null and b/html5/verto/demo/sounds/bell_ring2.mp3 differ
diff --git a/html5/verto/demo/sounds/bell_ring2.wav b/html5/verto/demo/sounds/bell_ring2.wav
new file mode 100644 (file)
index 0000000..e550143
Binary files /dev/null and b/html5/verto/demo/sounds/bell_ring2.wav differ
diff --git a/html5/verto/demo/verto.html b/html5/verto/demo/verto.html
new file mode 100644 (file)
index 0000000..16a7aeb
--- /dev/null
@@ -0,0 +1,261 @@
+<!DOCTYPE html>
+<html>
+  <head>
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <link rel="stylesheet" href="css/jquery.mobile-1.3.2.min.css" />
+  <link rel="stylesheet" type="text/css" href="css/jsontable.css" />
+  <link rel="shortcut icon" href="favicon.ico" />
+    <meta charset="utf-8" />
+    <title>FreeSWITCH Verto Demo</title>
+
+    <style type="text/css">
+      .pageheader {
+      font-size: 22px;
+      font-weight: normal;
+      height: 27px;
+      }
+    </style>
+
+  </head>
+  <body>
+    <div data-role="page" id="page-login" align="center">
+      <div data-role="header" class="page-header">
+       FreeSWITCH Verto Demo
+      </div>
+      <br>
+      <a target="_CC2104" href="https://www.cluecon.com"><img border="0" width="300" src="img/cc_banner2014.gif"></a>
+
+      <div data-role="fieldcontain">
+       <label for="name">Login</label>
+       <input type="text" size="20" id="login"/>
+      </div>
+
+      <div data-role="fieldcontain">
+       <label for="name">Password</label>
+       <input type="password" size="20" id="passwd"/>
+      </div>
+
+      <div data-role="fieldcontain">
+       <label for="name">CID Name</label>  
+       <input type="text" size="30" id="name"/>
+      </div>
+
+      <div data-role="fieldcontain">
+       <label for="name">CID Number</label>  
+       <input type="text" size="20" id="cid"/>
+      </div>
+
+      <div data-role="fieldcontain">
+       <label for="name">Hostname</label>
+       <input type="text" size="20" id="hostName"/>
+      </div>
+
+      <div data-role="fieldcontain">
+       <label for="name">Websocket URL</label>
+       <input type="text" size="20" id="wsURL"/>
+      </div>
+
+      <br><br>
+      <button data-inline="true" id="loginbtn">Log In</button>      
+      
+    </div>
+
+    <div data-role="page" id="page-incall" align="center">
+      <div data-role="header" id="calltitle" class="pageheader">
+       Verto IN CALL
+      </div>
+
+      <br>
+      <a target="_CC2104" href="https://www.cluecon.com"><img border="0" width="300" src="img/cc_banner2014.gif"></a>
+      <br><br>
+
+      <div id="conf">
+       <div style="color:black;font-family: verdana" align="center" id="mcount"></div>
+       <table cellspacing="0" cellpadding="0" border="0" align="center" id="example" class="jsDataTable">
+       </table>
+      </div>
+
+      <div id="display" style="font-weight:bold;font-size:18px"></div>
+      <br>
+      <div data-role="fieldcontain" id="xferdiv">
+       <input data-mini="true" type="text" id="xferto"><br>
+      <button data-inline="true" id="cancelxferbtn">Cancel Transfer</button>
+      <button data-inline="true" class="startxferbtn">Complete Transfer</button>
+      </div>
+
+      <div id=keypad>
+       <button class="dtmf" data-inline="true">1</button>
+       <button class="dtmf" data-inline="true">2</button>
+       <button class="dtmf" data-inline="true">3</button>
+       <br>
+       <button class="dtmf" data-inline="true">4</button>
+       <button class="dtmf" data-inline="true">5</button>
+       <button class="dtmf" data-inline="true">6</button>
+       <br>    
+       <button class="dtmf" data-inline="true">7</button>
+       <button class="dtmf" data-inline="true">8</button>
+       <button class="dtmf" data-inline="true">9</button>
+       <br>
+       <button class="dtmf" data-inline="true">*</button>
+       <button class="dtmf" data-inline="true">0</button>
+       <button class="dtmf" data-inline="true">#</button>
+      </div>
+
+      <br>
+      <button data-inline="true" id="hold">HOLD</button>
+      <button data-inline="true" id="hupbtn">End Call</button>
+      <button data-inline="true" class="startxferbtn">Transfer</button>
+
+      <div id="media"> 
+       <video width=800 id="webcam" autoplay="autoplay" hidden="true"></video>
+      </div>
+      <br><br>
+    </div>
+    
+    <div data-role="page" id="page-main" align="center">
+      <div data-role="header" class="pageheader">
+       FreeSWITCH Verto Demo
+      </div>
+      <br>
+      <a target="_CC2104" href="https://www.cluecon.com"><img border="0" width="300" src="img/cc_banner2014.gif"></a>
+      
+      <div id="offline">
+       <h2>LOGGING IN</h2>
+       <img src="images/login.gif"></img>
+        <div id="errordisplay" style="font-weight:bold;font-size:18px;color:#ae0000"></div>
+      </div>
+
+      <div id="online" align="center">
+       <div id="text"></div>
+       <div data-role="fieldcontain">
+         <input type="text" id="ext"/><br>
+         <div id="dialpad">
+           <button class="dialbtn" data-inline="true">1</button>
+           <button class="dialbtn" data-inline="true">2</button>
+           <button class="dialbtn" data-inline="true">3</button>
+           <br>
+           <button class="dialbtn" data-inline="true">4</button>
+           <button class="dialbtn" data-inline="true">5</button>
+           <button class="dialbtn" data-inline="true">6</button>
+           <br>        
+           <button class="dialbtn" data-inline="true">7</button>
+           <button class="dialbtn" data-inline="true">8</button>
+           <button class="dialbtn" data-inline="true">9</button>
+           <br>
+           <button class="dialbtn" data-inline="true">*</button>
+           <button class="dialbtn" data-inline="true">0</button>
+           <button class="dialbtn" data-inline="true">#</button>
+         </div>
+
+         <button data-inline="true" id="clearbtn">Clear</button>
+         <button data-inline="true" id="callbtn">Call</button>
+         <br><br>
+         <button data-inline="true"id="logoutbtn">Log Out</button>
+       </div>
+       <br>
+       <label><input id="use_vid" type="checkbox" value="foo" > Use Video</label>
+       <label><input id="use_stereo" type="checkbox" value="foo" > Stereo Audio</label>
+       <br>
+<!--
+       <b>TEXT</b><br>To: <input type="text" size="20" id="textto"/> MSG: <input type="text" size="40" id="textmsg"/>
+       <button id="vtxtbtn">Send</button>
+-->
+      </div>
+
+
+
+<table width=500 style="font-size:11pt;font-face:arial">
+<tr><td align=center colspan=2><b>FreeSWITCH VERTO WebRTC Demo Directory<Br><br></td></tr>
+<tr><td width=100><b>Dial</b></td><td><b>Desc</b></td></tr>
+<tr><td align=left colspan=2><hr></td></tr>
+
+<tr><td>3d1</td><td> 3D sound demo #1</td></tr>
+<tr><td>3d2</td><td> 3D sound demo #2</td></tr>
+
+<tr><td>stereo1</td><td> Stereo sound demo #1</td></tr>
+<tr><td>stereo2</td><td> Stereo sound demo #2</td></tr>
+<tr><td>stereo3</td><td> Stereo sound demo #3</td></tr>
+<tr><td>3500</td><td>Local 48k Stereo Conference</td></tr>
+<tr><td>&nbsp;</td></tr>
+<tr><td>cluecon</td><td> ClueCon Hotline</td></tr>
+<tr><td>&lt;number&gt;</td><td>Call a US/Canda Number</td></tr>
+
+<tr><td>vuc</td><td>VoIP Users Conference</td></tr>
+<tr><td>888</td><td>FreeSWITCH Community Conference</td></tr>
+
+<tr><td>3300</td><td>Local 48k Conference</td></tr>
+<tr><td>5000</td><td>Try the Demo IVR</td></tr>
+<tr><td>9664</td><td>Listen to Hold Music</td></tr>
+<tr><td>9386</td><td>Funny Prompts</td></tr>
+<tr><td>9198</td><td>Tetris (tone generator)</td></tr>
+<tr><td colspan=2><Br>
+<center>
+<br><br><br>
+</td></tr>
+</td></tr>
+</table>
+
+
+
+
+    </div><!-- /page -->
+
+    <div data-role="page" id="dialog-logout" data-close-btn="none">
+      <div data-role="header">
+        <h2>Logged Out</h2>
+      </div>
+      <div data-role="content">
+        <p>You have been logged out or disconnected from the server.</p>
+
+       <button onclick="$('#dialog-logout').dialog('close')">OK</button>
+      </div>
+    </div>
+
+    <div data-role="page" id="dialog-login-error" data-close-btn="none">
+      <div data-role="header">
+        <h2>Login Error</h2>
+      </div>
+      <div data-role="content">
+        <p>Error logging in</p>
+
+       <button onclick="$('#dialog-login-error').dialog('close')">OK</button>
+      </div>
+    </div>
+
+    <div data-role="page" id="dialog-hold" data-close-btn="none">
+      <div data-role="header">
+        <h2>Call On hold</h2>
+      </div>
+      <div data-role="content">
+        <p>The call is on hold</p>
+
+       <button onclick="$('#dialog-hold').dialog('close');cur_call.toggleHold();">Resume Call</button>
+      </div>      
+    </div>
+
+    <div data-role="page" id="dialog-incoming-call" data-close-btn="none">
+      <div data-role="header">
+        <h2>Incoming Call</h2>
+      </div>
+      <div data-role="content">
+        <div id="dialog-incoming-call-txt"><p>Incoming Call</p></div>
+       <button id="ansbtn">Answer</button> 
+       <div id="vansdiv"><button id="vansbtn">Answer Video</button></div>
+       <button id="declinebtn">Decline</button>
+      </div>
+      
+    </div>
+
+
+    <script type="text/javascript" src="js/jquery-2.0.3.min.js"></script> 
+    <script type="text/javascript" src="js/jquery.mobile-1.3.2.min.js"></script> 
+    <script type="text/javascript" src="js/jquery.json-2.4.min.js"></script>  
+    <script type="text/javascript" src="js/jquery.cookie.js"></script>
+    <script type="text/javascript" src="js/jquery.dataTables.js"></script>
+    <script type="text/javascript" src="js/verto-min.js"></script>
+    
+    <script type="text/javascript" src="verto.js"></script>
+
+  </body>
+</html>
+
diff --git a/html5/verto/demo/verto.js b/html5/verto/demo/verto.js
new file mode 100644 (file)
index 0000000..fee1eff
--- /dev/null
@@ -0,0 +1,434 @@
+'use strict';
+var cur_call = null;
+var la = null;
+var $display = $("#display");
+var verto;
+var ringing = false;
+
+function display(msg) {
+    $("#calltitle").html(msg);
+}
+
+function clearLa() {
+    if (la) {
+        la.destroy();
+        la = null;
+    }
+
+    $("#conf").hide();
+}
+
+function goto_dialog(where) {
+    $.mobile.changePage("#dialog-" + where, {
+        role: "dialog"
+    });
+}
+
+function goto_page(where) {
+    $.mobile.changePage("#page-" + where);
+}
+
+var first_login = false;
+var online_visible = false;
+function online(on) {
+    if (on) {
+        $("#online").show();
+        $("#offline").hide();
+        first_login = true;
+    } else {
+        if (first_login && online_visible) {
+            goto_dialog("logout");
+        }
+
+        $("#online").hide();
+        $("#offline").show();
+    }
+
+    online_visible = on;
+}
+
+function check_vid() {
+    var use_vid = $("#use_vid").is(':checked');
+    return use_vid;
+}
+
+var callbacks = {
+
+    onMessage: function(verto, dialog, msg, data) {
+
+        switch (msg) {
+        case $.verto.enum.message.pvtEvent:
+            console.error("pvtEvent", data.pvtData.action);
+            if (data.pvtData) {
+                switch (data.pvtData.action) {
+                case "conference-liveArray-part":
+                    clearLa();
+                    break;
+                case "conference-liveArray-join":
+
+                    $(".jsDataTable").width(check_vid() ? "650px" : "550px");
+
+                    la = new $.verto.liveTable(verto, data.pvtData.laChannel, data.pvtData.laName, $('#example'), {
+                        subParams: {
+                            callID: dialog.callID
+                        },
+
+                        "onChange": function(obj, args) {
+                            //var len = obj.asArray().length;
+                            $("#mcount").text("Conference Members: " + " (" + obj.arrayLen() + " Total)");
+                        },
+
+                        "aaData": [],
+                        "aoColumns": [{
+                            "sTitle": "ID"
+                        },
+                        {
+                            "sTitle": "Number"
+                        },
+                        {
+                            "sTitle": "Name"
+                        },
+                        {
+                            "sTitle": "Codec"
+                        },
+                        {
+                            "sTitle": "Status",
+                            "sWidth": check_vid() ? "300px" : "150px"
+                        }],
+                        "bAutoWidth": true,
+                        "bDestroy": true,
+                        "bSort": false,
+                        "bInfo": false,
+                        "bFilter": false,
+                        "bLengthChange": false,
+                        "bPaginate": false,
+                        "iDisplayLength": 1000,
+
+                        "oLanguage": {
+                            "sEmptyTable": "The Conference is Empty....."
+                        }
+                    });
+
+                    $("#conf").show();
+
+                    break;
+                }
+            }
+            break;
+        case $.verto.enum.message.info:
+            $("#text").html("Message from: <b>" + data.from + "</b>:<br>" + "<pre>" + data.body + "</pre>");
+            break;
+        case $.verto.enum.message.display:
+            var party = dialog.params.remote_caller_id_name + "<" + dialog.params.remote_caller_id_number + ">";
+            display("Talking to: " + dialog.cidString());
+            break;
+        default:
+            break;
+        }
+    },
+
+    onDialogState: function(d) {
+        cur_call = d;
+
+        switch (d.state) {
+        case $.verto.enum.state.ringing:
+            display("Call From: " + d.cidString());
+
+            $("#ansbtn").click(function() {
+               ringing = false;
+                cur_call.answer({
+                   useStereo: $("#use_stereo").is(':checked')
+               });
+                $('#dialog-incoming-call').dialog('close');
+            });
+
+            $("#declinebtn").click(function() {
+               ringing = false;
+                cur_call.hangup();
+                $('#dialog-incoming-call').dialog('close');
+            });
+           
+           ringing = true;
+
+            goto_dialog("incoming-call");
+            $("#dialog-incoming-call-txt").text("Incoming call from: " + d.cidString());
+
+            if (d.params.wantVideo) {
+                $("#vansbtn").click(function() {
+                   ringing = false;
+                    $("#use_vid").prop("checked", true);
+                    cur_call.answer({
+                        useVideo: true,
+                       useStereo: $("#use_stereo").is(':checked')
+                    });
+                });
+                // the buttons in this jquery mobile wont hide .. gotta wrap them in a div as a workaround
+                $("#vansdiv").show();
+            } else {
+                $("#vansdiv").hide();
+            }
+
+            break;
+
+        case $.verto.enum.state.active:
+            display("Talking to: " + d.cidString());
+            goto_page("incall");
+            break;
+        case $.verto.enum.state.hangup:
+        case $.verto.enum.state.destroy:
+            clearLa();
+            goto_page("main");
+            cur_call = null;
+            break;
+        case $.verto.enum.state.held:
+            break;
+        default:
+            display("");
+            break;
+        }
+    },
+    onWSLogin: function(v, success) {
+        display("");
+
+        if (success) {
+            online(true);
+
+            verto.subscribe("presence", {
+                handler: function(v, e) {
+                    console.error("PRESENCE:", e);
+                }
+            });
+            if (!window.location.hash) {
+                goto_page("main");
+            }
+        } else {
+            goto_page("login");
+            goto_dialog("login-error");
+        }
+
+    },
+    onWSClose: function(v, success) {
+        if ($('#online').is(':visible')) {
+            display("");
+            online(false);
+        }
+        var today = new Date();
+        $("#errordisplay").html("Connection Error.<br>Last Attempt: " + today);
+        goto_page("main");
+    },
+
+    onEvent: function(v, e) {
+        console.debug("w00t", e);
+    },
+};
+
+$("#hold").click(function(e) {
+    cur_call.toggleHold();
+    goto_dialog("hold");
+});
+
+$("#cancelxferbtn").click(function(e) {
+    $("#xferto").val("");
+    $("#xferdiv").hide();
+});
+
+$(".startxferbtn").click(function(e) {
+    if ($('#xferdiv').is(':visible')) {
+        var xfer = $("#xferto").val();
+        if (xfer) {
+            cur_call.transfer(xfer);
+        }
+        $("#xferto").val("");
+        $("#xferdiv").hide();
+    } else {
+        $("#xferdiv").show();
+    }
+});
+
+$("#clearbtn").click(function(e) {
+    $("#ext").val("");
+});
+
+$(".dialbtn").click(function(e) {
+    $("#ext").val($("#ext").val() + e.currentTarget.textContent);
+});
+
+$(".dtmf").click(function(e) {
+    if ($('#xferdiv').is(':visible')) {
+        $("#xferto").val($("#xferto").val() + e.currentTarget.textContent);
+    } else {
+        cur_call.dtmf(e.currentTarget.textContent);
+    }
+
+});
+
+$("#hupbtn").click(function() {
+    verto.hangup();
+    cur_call = null;
+});
+
+$("#webcam").click(function() {
+    check_vid();
+});
+
+$("#callbtn").click(function() {
+    $('#ext').trigger('change');
+
+    if (cur_call) {
+        return;
+    }
+
+    cur_call = verto.newCall({
+        destination_number: $("#ext").val(),
+        caller_id_name: $("#name").val(),
+        caller_id_number: $("#cid").val(),
+        useVideo: check_vid(),
+        useStereo: $("#use_stereo").is(':checked')
+    });
+});
+
+function pop(id, cname, dft) {
+    var tmp = $.cookie(cname) || dft;
+    $.cookie(cname, tmp, {
+        expires: 365
+    });
+    $(id).val(tmp).change(function() {
+        $.cookie(cname, $(id).val(), {
+            expires: 365
+        });
+    });
+}
+
+
+
+function init() {
+    pop("#ext", "verto_demo_ext", "3500");
+    pop("#name", "verto_demo_name", "FreeSWITCH User");
+    pop("#cid", "verto_demo_cid", "1008");
+    pop("#textto", "verto_demo_textto", "1000");
+
+    pop("#login", "verto_demo_login", "1008");
+    pop("#passwd", "verto_demo_passwd", "1234");
+
+    pop("#hostName", "verto_demo_hostname", window.location.hostname);
+    pop("#wsURL", "verto_demo_wsurl", "wss://" + window.location.hostname + ":8082");
+
+    var tmp = $.cookie("verto_demo_vid_checked") || "false";
+    $.cookie("verto_demo_vid_checked", tmp, {
+        expires: 365
+    });
+
+    $("#use_vid").prop("checked", tmp === "true").change(function(e) {
+        tmp = $("#use_vid").is(':checked');
+        $.cookie("verto_demo_vid_checked", tmp ? "true" : "false", {
+            expires: 365
+        });
+    });
+
+    tmp = $.cookie("verto_demo_stereo_checked") || "false";
+    $.cookie("verto_demo_stereo_checked", tmp, {
+        expires: 365
+    });
+
+    $("#use_stereo").prop("checked", tmp === "true").change(function(e) {
+        tmp = $("#use_stereo").is(':checked');
+        $.cookie("verto_demo_stereo_checked", tmp ? "true" : "false", {
+            expires: 365
+        });
+    });
+
+    verto = new $.verto({
+        login: $("#login").val() + "@" + $("#hostName").val(),
+        passwd: $("#passwd").val(),
+        socketUrl: $("#wsURL").val(),
+        tag: "webcam",
+        ringFile: "sounds/bell_ring2.wav",
+        videoParams: {
+            "minWidth": "1280",
+            "minHeight": "720"
+        }
+    },
+    callbacks);
+
+    $("#login").change(function(e) {
+        $("#cid").val(e.currentTarget.value);
+        $.cookie("verto_demo_cid", e.currentTarget.value, {
+            expires: 365
+        });
+    });
+
+    $("#vtxtbtn").click(function() {
+        verto.message({
+            to: $("#textto").val(),
+            body: $("#textmsg").val()
+        });
+        $("#textmsg").val("");
+    });
+
+    $("#logoutbtn").click(function() {
+        verto.logout();
+        goto_page("login");
+        online(false);
+    });
+
+    $("#loginbtn").click(function() {
+        online(false);
+        verto.loginData({
+            login: $("#login").val() + "@" + $("#hostName").val(),
+            passwd: $("#passwd").val()
+        });
+        verto.login();
+        goto_page("main");
+    });
+
+    $("#xferdiv").hide();
+    $("#webcam").hide();
+
+    online(false);
+}
+
+$(document).ready(function() {
+    init();
+    $("#page-incall").on("pagebeforechange", function(event) {});
+});
+
+$(document).bind("pagebeforechange", function(e, data) {
+    if (typeof(data.toPage) !== "string") {
+        return;
+    }
+
+    switch (window.location.hash) {
+
+    case "#page-incall":
+
+        console.error(e, data);
+        setTimeout(function() {
+            if (!cur_call) {
+                goto_page("main");
+            }
+        },
+        10000);
+        break;
+
+    case "#page-main":
+
+        console.error(e, data);
+        setTimeout(function() {
+            if (cur_call && !ringing) {
+                goto_page("incall");
+            }
+        },
+        2000);
+        break;
+
+    case "#page-login":
+
+        setTimeout(function() {
+            if (online_visible) {
+                goto_page("main");
+            }
+        },
+        1000);
+        break;
+    }
+});
diff --git a/html5/verto/js/Makefile b/html5/verto/js/Makefile
new file mode 100644 (file)
index 0000000..9ee3be8
--- /dev/null
@@ -0,0 +1,15 @@
+JSFILES=src/jquery.FSRTC.js src/jquery.jsonrpcclient.js src/jquery.verto.js
+
+all: jsmin verto-min.js
+
+jsmin: jsmin.c
+       $(CC) $< -o $@
+
+verto-min.js: jsmin $(JSFILES)
+       cat $(JSFILES) | ./jsmin > $@
+
+clean:
+       rm -f verto-min.js jsmin *~
+
+install-demo: all
+       cp verto-min.js ../demo/js
diff --git a/html5/verto/js/README b/html5/verto/js/README
new file mode 100644 (file)
index 0000000..f5fc3a4
--- /dev/null
@@ -0,0 +1,10 @@
+This file needs to say more.
+Documentation for the api needs to be developed with jsdoc-toolkit http://pulkitgoyal.in/documenting-jquery-plugins-jsdoc-toolkit/
+
+Dependancies for DEMO
+jquery-2.0.3.min.js
+jquery-2.0.3.min.map
+jquery.cookie.js
+jquery.dataTables.js
+jquery.json-2.4.min.js
+jquery.mobile-1.3.2.min.js
diff --git a/html5/verto/js/jsmin.c b/html5/verto/js/jsmin.c
new file mode 100644 (file)
index 0000000..3ab004b
--- /dev/null
@@ -0,0 +1,306 @@
+/* jsmin.c
+   2013-03-29
+
+Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+The Software shall be used for Good, not Evil.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+static int   theA;
+static int   theB;
+static int   theLookahead = EOF;
+static int   theX = EOF;
+static int   theY = EOF;
+
+
+static void
+error(char* s)
+{
+    fputs("JSMIN Error: ", stderr);
+    fputs(s, stderr);
+    fputc('\n', stderr);
+    exit(1);
+}
+
+/* isAlphanum -- return true if the character is a letter, digit, underscore,
+        dollar sign, or non-ASCII character.
+*/
+
+static int
+isAlphanum(int c)
+{
+    return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
+        (c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
+        c > 126);
+}
+
+
+/* get -- return the next character from stdin. Watch out for lookahead. If
+        the character is a control character, translate it to a space or
+        linefeed.
+*/
+
+static int
+get()
+{
+    int c = theLookahead;
+    theLookahead = EOF;
+    if (c == EOF) {
+        c = getc(stdin);
+    }
+    if (c >= ' ' || c == '\n' || c == EOF) {
+        return c;
+    }
+    if (c == '\r') {
+        return '\n';
+    }
+    return ' ';
+}
+
+
+/* peek -- get the next character without getting it.
+*/
+
+static int
+peek()
+{
+    theLookahead = get();
+    return theLookahead;
+}
+
+
+/* next -- get the next character, excluding comments. peek() is used to see
+        if a '/' is followed by a '/' or '*'.
+*/
+
+static int
+next()
+{
+    int c = get();
+    if  (c == '/') {
+        switch (peek()) {
+        case '/':
+            for (;;) {
+                c = get();
+                if (c <= '\n') {
+                    break;
+                }
+            }
+            break;
+        case '*':
+            get();
+            while (c != ' ') {
+                switch (get()) {
+                case '*':
+                    if (peek() == '/') {
+                        get();
+                        c = ' ';
+                    }
+                    break;
+                case EOF:
+                    error("Unterminated comment.");
+                }
+            }
+            break;
+        }
+    }
+    theY = theX;
+    theX = c;
+    return c;
+}
+
+
+/* action -- do something! What you do is determined by the argument:
+        1   Output A. Copy B to A. Get the next B.
+        2   Copy B to A. Get the next B. (Delete A).
+        3   Get the next B. (Delete B).
+   action treats a string as a single character. Wow!
+   action recognizes a regular expression if it is preceded by ( or , or =.
+*/
+
+static void
+action(int d)
+{
+    switch (d) {
+    case 1:
+        putc(theA, stdout);
+        if (
+            (theY == '\n' || theY == ' ') &&
+            (theA == '+' || theA == '-' || theA == '*' || theA == '/') &&
+            (theB == '+' || theB == '-' || theB == '*' || theB == '/')
+        ) {
+            putc(theY, stdout);
+        }
+    case 2:
+        theA = theB;
+        if (theA == '\'' || theA == '"' || theA == '`') {
+            for (;;) {
+                putc(theA, stdout);
+                theA = get();
+                if (theA == theB) {
+                    break;
+                }
+                if (theA == '\\') {
+                    putc(theA, stdout);
+                    theA = get();
+                }
+                if (theA == EOF) {
+                    error("Unterminated string literal.");
+                }
+            }
+        }
+    case 3:
+        theB = next();
+        if (theB == '/' && (
+            theA == '(' || theA == ',' || theA == '=' || theA == ':' ||
+            theA == '[' || theA == '!' || theA == '&' || theA == '|' ||
+            theA == '?' || theA == '+' || theA == '-' || theA == '~' ||
+            theA == '*' || theA == '/' || theA == '{' || theA == '\n'
+        )) {
+            putc(theA, stdout);
+            if (theA == '/' || theA == '*') {
+                putc(' ', stdout);
+            }
+            putc(theB, stdout);
+            for (;;) {
+                theA = get();
+                if (theA == '[') {
+                    for (;;) {
+                        putc(theA, stdout);
+                        theA = get();
+                        if (theA == ']') {
+                            break;
+                        }
+                        if (theA == '\\') {
+                            putc(theA, stdout);
+                            theA = get();
+                        }
+                        if (theA == EOF) {
+                            error("Unterminated set in Regular Expression literal.");
+                        }
+                    }
+                } else if (theA == '/') {
+                    switch (peek()) {
+                    case '/':
+                    case '*':
+                        error("Unterminated set in Regular Expression literal.");
+                    }
+                    break;
+                } else if (theA =='\\') {
+                    putc(theA, stdout);
+                    theA = get();
+                }
+                if (theA == EOF) {
+                    error("Unterminated Regular Expression literal.");
+                }
+                putc(theA, stdout);
+            }
+            theB = next();
+        }
+    }
+}
+
+
+/* jsmin -- Copy the input to the output, deleting the characters which are
+        insignificant to JavaScript. Comments will be removed. Tabs will be
+        replaced with spaces. Carriage returns will be replaced with linefeeds.
+        Most spaces and linefeeds will be removed.
+*/
+
+static void
+jsmin()
+{
+    if (peek() == 0xEF) {
+        get();
+        get();
+        get();
+    }
+    theA = '\n';
+    action(3);
+    while (theA != EOF) {
+        switch (theA) {
+        case ' ':
+            action(isAlphanum(theB) ? 1 : 2);
+            break;
+        case '\n':
+            switch (theB) {
+            case '{':
+            case '[':
+            case '(':
+            case '+':
+            case '-':
+            case '!':
+            case '~':
+                action(1);
+                break;
+            case ' ':
+                action(3);
+                break;
+            default:
+                action(isAlphanum(theB) ? 1 : 2);
+            }
+            break;
+        default:
+            switch (theB) {
+            case ' ':
+                action(isAlphanum(theA) ? 1 : 3);
+                break;
+            case '\n':
+                switch (theA) {
+                case '}':
+                case ']':
+                case ')':
+                case '+':
+                case '-':
+                case '"':
+                case '\'':
+                case '`':
+                    action(1);
+                    break;
+                default:
+                    action(isAlphanum(theA) ? 1 : 3);
+                }
+                break;
+            default:
+                action(1);
+                break;
+            }
+        }
+    }
+}
+
+
+/* main -- Output any command line arguments as comments
+        and then minify the input.
+*/
+extern int
+main(int argc, char* argv[])
+{
+    int i;
+    for (i = 1; i < argc; i += 1) {
+        fprintf(stdout, "// %s\n", argv[i]);
+    }
+    jsmin();
+    return 0;
+}
diff --git a/html5/verto/js/src/jquery.FSRTC.js b/html5/verto/js/src/jquery.FSRTC.js
new file mode 100644 (file)
index 0000000..28f9306
--- /dev/null
@@ -0,0 +1,758 @@
+/*
+ * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
+ * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * jquery.FSRTC.js - WebRTC Glue code
+ *
+ */
+
+(function($) {
+
+    // Find the line in sdpLines that starts with |prefix|, and, if specified,
+    // contains |substr| (case-insensitive search).
+    function findLine(sdpLines, prefix, substr) {
+        return findLineInRange(sdpLines, 0, -1, prefix, substr);
+    }
+
+    // Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix|
+    // and, if specified, contains |substr| (case-insensitive search).
+    function findLineInRange(sdpLines, startLine, endLine, prefix, substr) {
+        var realEndLine = (endLine != -1) ? endLine : sdpLines.length;
+        for (var i = startLine; i < realEndLine; ++i) {
+            if (sdpLines[i].indexOf(prefix) === 0) {
+                if (!substr || sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) {
+                    return i;
+                }
+            }
+        }
+        return null;
+    }
+
+    // Gets the codec payload type from an a=rtpmap:X line.
+    function getCodecPayloadType(sdpLine) {
+        var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+');
+        var result = sdpLine.match(pattern);
+        return (result && result.length == 2) ? result[1] : null;
+    }
+
+    // Returns a new m= line with the specified codec as the first one.
+    function setDefaultCodec(mLine, payload) {
+        var elements = mLine.split(' ');
+        var newLine = [];
+        var index = 0;
+        for (var i = 0; i < elements.length; i++) {
+            if (index === 3) // Format of media starts from the fourth.
+            newLine[index++] = payload; // Put target payload to the first.
+            if (elements[i] !== payload) newLine[index++] = elements[i];
+        }
+        return newLine.join(' ');
+    }
+
+    $.FSRTC = function(options) {
+        this.options = $.extend({
+            useVideo: null,
+            useStereo: false,
+            userData: null,
+            videoParams: {},
+            callbacks: {
+                onICEComplete: function() {},
+                onICE: function() {},
+                onOfferSDP: function() {}
+            }
+        },
+        options);
+
+        this.mediaData = {
+            SDP: null,
+            profile: {},
+            candidateList: []
+        };
+
+        this.constraints = {
+            optional: [{
+                'DtlsSrtpKeyAgreement': 'true'
+            }],
+            mandatory: {
+                OfferToReceiveAudio: true,
+                OfferToReceiveVideo: this.options.useVideo ? true : false,
+            }
+        };
+
+        if (self.options.useVideo) {
+            self.options.useVideo.style.display = 'none';
+        }
+
+        setCompat();
+        checkCompat();
+    };
+
+    $.FSRTC.prototype.useVideo = function(obj) {
+        var self = this;
+
+        if (obj) {
+            self.options.useVideo = obj;
+            self.constraints.mandatory.OfferToReceiveVideo = true;
+        } else {
+            self.options.useVideo = null;
+            self.constraints.mandatory.OfferToReceiveVideo = false;
+        }
+
+        if (self.options.useVideo) {
+            self.options.useVideo.style.display = 'none';
+        }
+    };
+
+    $.FSRTC.prototype.useStereo = function(on) {
+        var self = this;
+        self.options.useStereo = on;
+    };
+
+    // Sets Opus in stereo if stereo is enabled, by adding the stereo=1 fmtp param.
+    $.FSRTC.prototype.stereoHack = function(sdp) {
+        var self = this;
+
+        if (!self.options.useStereo) {
+            return sdp;
+        }
+
+        var sdpLines = sdp.split('\r\n');
+
+        // Find opus payload.
+        var opusIndex = findLine(sdpLines, 'a=rtpmap', 'opus/48000'),
+        opusPayload;
+        if (opusIndex) {
+            opusPayload = getCodecPayloadType(sdpLines[opusIndex]);
+        }
+
+        // Find the payload in fmtp line.
+        var fmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + opusPayload.toString());
+        if (fmtpLineIndex === null) return sdp;
+
+        // Append stereo=1 to fmtp line.
+        sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat('; stereo=1');
+
+        sdp = sdpLines.join('\r\n');
+        return sdp;
+    };
+
+    function setCompat() {
+        $.FSRTC.moz = !!navigator.mozGetUserMedia;
+        //navigator.getUserMedia || (navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia);
+       if (!navigator.getUserMedia) {
+           navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia || navigator.msGetUserMedia;
+       }
+    }
+
+    function checkCompat() {
+        if (!navigator.getUserMedia) {
+            alert('This application cannot function in this browser.');
+            return false;
+        }
+        return true;
+    }
+
+    function onStreamError(self) {
+        console.log('There has been a problem retrieving the streams - did you allow access?');
+
+    }
+
+    function onStreamSuccess(self) {
+        console.log("Stream Success");
+    }
+
+    function onICE(self, candidate) {
+        self.mediaData.candidate = candidate;
+        self.mediaData.candidateList.push(self.mediaData.candidate);
+
+        doCallback(self, "onICE");
+    }
+
+    function doCallback(self, func, arg) {
+        if (func in self.options.callbacks) {
+            self.options.callbacks[func](self, arg);
+        }
+    }
+
+    function onICEComplete(self, candidate) {
+        console.log("ICE Complete");
+        doCallback(self, "onICEComplete");
+    }
+
+    function onChannelError(self, e) {
+        console.error("Channel Error", e);
+        doCallback(self, "onError", e);
+    }
+
+    function onICESDP(self, sdp) {
+        self.mediaData.SDP = self.stereoHack(sdp.sdp);
+        console.log("ICE SDP");
+        doCallback(self, "onICESDP");
+    }
+
+    function onAnswerSDP(self, sdp) {
+        self.answer.SDP = self.stereoHack(sdp.sdp);
+        console.log("ICE ANSWER SDP");
+        doCallback(self, "onAnswerSDP", self.answer.SDP);
+    }
+
+    function onMessage(self, msg) {
+        console.log("Message");
+        doCallback(self, "onICESDP", msg);
+    }
+
+    function onRemoteStream(self, stream) {
+        if (self.options.useVideo) {
+            self.options.useVideo.style.display = 'block';
+        }
+
+        var element = self.options.useAudio;
+        console.log("REMOTE STREAM", stream, element);
+
+        if (typeof element.srcObject !== 'undefined') {
+            element.srcObject = stream;
+        } else if (typeof element.mozSrcObject !== 'undefined') {
+            element.mozSrcObject = stream;
+        } else if (typeof element.src !== 'undefined') {
+            element.src = URL.createObjectURL(stream);
+        } else {
+            console.error('Error attaching stream to element.');
+        }
+
+        self.options.useAudio.play();
+        self.remoteStream = stream;
+    }
+
+    function onOfferSDP(self, sdp) {
+        self.mediaData.SDP = self.stereoHack(sdp.sdp);
+        console.log("Offer SDP");
+        doCallback(self, "onOfferSDP");
+    }
+
+    $.FSRTC.prototype.answer = function(sdp, onSuccess, onError) {
+        this.peer.addAnswerSDP({
+            type: "answer",
+            sdp: sdp
+        },
+        onSuccess, onError);
+    };
+
+    $.FSRTC.prototype.stop = function() {
+        var self = this;
+
+        if (self.options.useVideo) {
+            self.options.useVideo.style.display = 'none';
+        }
+
+        if (self.localStream) {
+            self.localStream.stop();
+            self.localStream = null;
+        }
+
+        if (self.peer) {
+            console.log("stopping peer");
+            self.peer.stop();
+        }
+    };
+
+    $.FSRTC.prototype.createAnswer = function(sdp) {
+        var self = this;
+        self.type = "answer";
+        self.remoteSDP = sdp;
+        console.debug("inbound sdp: ", sdp);
+
+        function onSuccess(stream) {
+            self.localStream = stream;
+
+            self.peer = RTCPeerConnection({
+                type: self.type,
+                attachStream: self.localStream,
+                onICE: function(candidate) {
+                    return onICE(self, candidate);
+                },
+                onICEComplete: function() {
+                    return onICEComplete(self);
+                },
+                onRemoteStream: function(stream) {
+                    return onRemoteStream(self, stream);
+                },
+                onICESDP: function(sdp) {
+                    return onICESDP(self, sdp);
+                },
+                onChannelError: function(e) {
+                    return onChannelError(self, e);
+                },
+                constraints: self.constraints,
+                offerSDP: {
+                    type: "offer",
+                    sdp: self.remoteSDP
+                }
+            });
+
+            onStreamSuccess(self);
+        }
+
+        function onError() {
+            onStreamError(self);
+        }
+
+        getUserMedia({
+            constraints: {
+                audio: true,
+                video: this.options.useVideo ? {
+                    mandatory: this.options.videoParams,
+                    optional: []
+                } : null
+            },
+            video: this.options.useVideo ? true : false,
+            onsuccess: onSuccess,
+            onerror: onError
+        });
+
+    };
+
+    $.FSRTC.prototype.call = function(profile) {
+        checkCompat();
+
+        var self = this;
+
+        self.type = "offer";
+
+        function onSuccess(stream) {
+            self.localStream = stream;
+
+            self.peer = RTCPeerConnection({
+                type: self.type,
+                attachStream: self.localStream,
+                onICE: function(candidate) {
+                    return onICE(self, candidate);
+                },
+                onICEComplete: function() {
+                    return onICEComplete(self);
+                },
+                onRemoteStream: function(stream) {
+                    return onRemoteStream(self, stream);
+                },
+                onOfferSDP: function(sdp) {
+                    return onOfferSDP(self, sdp);
+                },
+                onICESDP: function(sdp) {
+                    return onICESDP(self, sdp);
+                },
+                onChannelError: function(e) {
+                    return onChannelError(self, e);
+                },
+                constraints: self.constraints
+            });
+
+            onStreamSuccess(self);
+        }
+
+        function onError() {
+            onStreamError(self);
+        }
+
+        getUserMedia({
+            constraints: {
+                audio: true,
+                video: this.options.useVideo ? {
+                    mandatory: this.options.videoParams,
+                    optional: []
+                } : null
+            },
+            video: this.options.useVideo ? true : false,
+            onsuccess: onSuccess,
+            onerror: onError
+        });
+
+        /*
+       navigator.getUserMedia({
+            video: this.options.useVideo,
+            audio: true
+       }, onSuccess, onError);
+*/
+
+    };
+
+    // DERIVED from RTCPeerConnection-v1.5
+    // 2013, @muazkh - github.com/muaz-khan
+    // MIT License - https://www.webrtc-experiment.com/licence/
+    // Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/RTCPeerConnection
+    window.moz = !!navigator.mozGetUserMedia;
+
+    function RTCPeerConnection(options) {
+
+        var w = window,
+        PeerConnection = w.mozRTCPeerConnection || w.webkitRTCPeerConnection,
+        SessionDescription = w.mozRTCSessionDescription || w.RTCSessionDescription,
+        IceCandidate = w.mozRTCIceCandidate || w.RTCIceCandidate;
+
+        var STUN = {
+            url: !moz ? 'stun:stun.l.google.com:19302' : 'stun:23.21.150.121'
+        };
+
+        var TURN = {
+            url: 'turn:homeo@turn.bistri.com:80',
+            credential: 'homeo'
+        };
+
+        var iceServers = {
+            iceServers: options.iceServers || [STUN]
+        };
+
+        if (!moz && !options.iceServers) {
+            if (parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2]) >= 28) TURN = {
+                url: 'turn:turn.bistri.com:80',
+                credential: 'homeo',
+                username: 'homeo'
+            };
+
+            iceServers.iceServers = [STUN];
+        }
+
+        var optional = {
+            optional: []
+        };
+
+        if (!moz) {
+            optional.optional = [{
+                DtlsSrtpKeyAgreement: true
+            },
+            {
+                RtpDataChannels: options.onChannelMessage ? true : false
+            }];
+        }
+
+        var peer = new PeerConnection(iceServers, optional);
+
+        openOffererChannel();
+        var x = 0;
+
+        peer.onicecandidate = function(event) {
+            console.log("WTF ICE", event);
+
+            if (event.candidate) {
+                options.onICE(event.candidate);
+            } else {
+                if (options.onICEComplete) {
+                    options.onICEComplete();
+                }
+
+                if (options.type == "offer") {
+                    if (!moz && !x && options.onICESDP) {
+                        options.onICESDP(peer.localDescription);
+                        //x = 1;
+                        /*
+                         x = 1;
+                         peer.createOffer(function(sessionDescription) {
+                         sessionDescription.sdp = serializeSdp(sessionDescription.sdp);
+                         peer.setLocalDescription(sessionDescription);
+                         if (options.onICESDP) {
+                         options.onICESDP(sessionDescription);
+                         }
+                         }, onSdpError, constraints);
+                       */
+                    }
+                } else {
+                    if (!x && options.onICESDP) {
+                        options.onICESDP(peer.localDescription);
+                        //x = 1;
+                        /*
+                         x = 1;
+                         peer.createAnswer(function(sessionDescription) {
+                         sessionDescription.sdp = serializeSdp(sessionDescription.sdp);
+                         peer.setLocalDescription(sessionDescription);
+                         if (options.onICESDP) {
+                         options.onICESDP(sessionDescription);
+                         }
+                         }, onSdpError, constraints);
+                       */
+                    }
+                }
+            }
+        };
+
+        // attachStream = MediaStream;
+        if (options.attachStream) peer.addStream(options.attachStream);
+
+        // attachStreams[0] = audio-stream;
+        // attachStreams[1] = video-stream;
+        // attachStreams[2] = screen-capturing-stream;
+        if (options.attachStreams && options.attachStream.length) {
+            var streams = options.attachStreams;
+            for (var i = 0; i < streams.length; i++) {
+                peer.addStream(streams[i]);
+            }
+        }
+
+        peer.onaddstream = function(event) {
+            var remoteMediaStream = event.stream;
+
+            // onRemoteStreamEnded(MediaStream)
+            remoteMediaStream.onended = function() {
+                if (options.onRemoteStreamEnded) options.onRemoteStreamEnded(remoteMediaStream);
+            };
+
+            // onRemoteStream(MediaStream)
+            if (options.onRemoteStream) options.onRemoteStream(remoteMediaStream);
+
+            //console.debug('on:add:stream', remoteMediaStream);
+        };
+
+        var constraints = options.constraints || {
+            optional: [],
+            mandatory: {
+                OfferToReceiveAudio: true,
+                OfferToReceiveVideo: true
+            }
+        };
+
+        // onOfferSDP(RTCSessionDescription)
+        function createOffer() {
+            if (!options.onOfferSDP) return;
+
+            peer.createOffer(function(sessionDescription) {
+                sessionDescription.sdp = serializeSdp(sessionDescription.sdp);
+                peer.setLocalDescription(sessionDescription);
+                options.onOfferSDP(sessionDescription);
+                if (moz && options.onICESDP) {
+                    options.onICESDP(sessionDescription);
+                }
+            },
+            onSdpError, constraints);
+        }
+
+        // onAnswerSDP(RTCSessionDescription)
+        function createAnswer() {
+            if (options.type != "answer") return;
+
+            //options.offerSDP.sdp = addStereo(options.offerSDP.sdp);
+            peer.setRemoteDescription(new SessionDescription(options.offerSDP), onSdpSuccess, onSdpError);
+            peer.createAnswer(function(sessionDescription) {
+                sessionDescription.sdp = serializeSdp(sessionDescription.sdp);
+                peer.setLocalDescription(sessionDescription);
+                if (options.onAnswerSDP) {
+                    options.onAnswerSDP(sessionDescription);
+                }
+            },
+            onSdpError, constraints);
+        }
+
+        // if Mozilla Firefox & DataChannel; offer/answer will be created later
+        if ((options.onChannelMessage && !moz) || !options.onChannelMessage) {
+            createOffer();
+            createAnswer();
+        }
+
+        // DataChannel Bandwidth
+        function setBandwidth(sdp) {
+            // remove existing bandwidth lines
+            sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, '');
+            sdp = sdp.replace(/a=mid:data\r\n/g, 'a=mid:data\r\nb=AS:1638400\r\n');
+
+            return sdp;
+        }
+
+        // old: FF<>Chrome interoperability management
+        function getInteropSDP(sdp) {
+            var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''),
+            extractedChars = '';
+
+            function getChars() {
+                extractedChars += chars[parseInt(Math.random() * 40)] || '';
+                if (extractedChars.length < 40) getChars();
+
+                return extractedChars;
+            }
+
+            // usually audio-only streaming failure occurs out of audio-specific crypto line
+            // a=crypto:1 AES_CM_128_HMAC_SHA1_32 --------- kAttributeCryptoVoice
+            if (options.onAnswerSDP) sdp = sdp.replace(/(a=crypto:0 AES_CM_128_HMAC_SHA1_32)(.*?)(\r\n)/g, '');
+
+            // video-specific crypto line i.e. SHA1_80
+            // a=crypto:1 AES_CM_128_HMAC_SHA1_80 --------- kAttributeCryptoVideo
+            var inline = getChars() + '\r\n' + (extractedChars = '');
+            sdp = sdp.indexOf('a=crypto') == -1 ? sdp.replace(/c=IN/g, 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:' + inline + 'c=IN') : sdp;
+
+            return sdp;
+        }
+
+        function serializeSdp(sdp) {
+            //if (!moz) sdp = setBandwidth(sdp);
+            //sdp = getInteropSDP(sdp);
+            //console.debug(sdp);
+            return sdp;
+        }
+
+        // DataChannel management
+        var channel;
+
+        function openOffererChannel() {
+            if (!options.onChannelMessage || (moz && !options.onOfferSDP)) return;
+
+            _openOffererChannel();
+
+            if (!moz) return;
+            navigator.mozGetUserMedia({
+                audio: true,
+                fake: true
+            },
+            function(stream) {
+                peer.addStream(stream);
+                createOffer();
+            },
+            useless);
+        }
+
+        function _openOffererChannel() {
+            channel = peer.createDataChannel(options.channel || 'RTCDataChannel', moz ? {} : {
+                reliable: false
+            });
+
+            if (moz) channel.binaryType = 'blob';
+
+            setChannelEvents();
+        }
+
+        function setChannelEvents() {
+            channel.onmessage = function(event) {
+                if (options.onChannelMessage) options.onChannelMessage(event);
+            };
+
+            channel.onopen = function() {
+                if (options.onChannelOpened) options.onChannelOpened(channel);
+            };
+            channel.onclose = function(event) {
+                if (options.onChannelClosed) options.onChannelClosed(event);
+
+                console.warn('WebRTC DataChannel closed', event);
+            };
+            channel.onerror = function(event) {
+                if (options.onChannelError) options.onChannelError(event);
+
+                console.error('WebRTC DataChannel error', event);
+            };
+        }
+
+        if (options.onAnswerSDP && moz && options.onChannelMessage) openAnswererChannel();
+
+        function openAnswererChannel() {
+            peer.ondatachannel = function(event) {
+                channel = event.channel;
+                channel.binaryType = 'blob';
+                setChannelEvents();
+            };
+
+            if (!moz) return;
+            navigator.mozGetUserMedia({
+                audio: true,
+                fake: true
+            },
+            function(stream) {
+                peer.addStream(stream);
+                createAnswer();
+            },
+            useless);
+        }
+
+        // fake:true is also available on chrome under a flag!
+        function useless() {
+            log('Error in fake:true');
+        }
+
+        function onSdpSuccess() {}
+
+        function onSdpError(e) {
+            if (options.onChannelError) {
+                options.onChannelError(e);
+            }
+            console.error('sdp error:', e);
+        }
+
+        return {
+            addAnswerSDP: function(sdp, cbSuccess, cbError) {
+
+                peer.setRemoteDescription(new SessionDescription(sdp), cbSuccess ? cbSuccess : onSdpSuccess, cbError ? cbError : onSdpError);
+            },
+            addICE: function(candidate) {
+                peer.addIceCandidate(new IceCandidate({
+                    sdpMLineIndex: candidate.sdpMLineIndex,
+                    candidate: candidate.candidate
+                }));
+            },
+
+            peer: peer,
+            channel: channel,
+            sendData: function(message) {
+                if (channel) {
+                   channel.send(message);
+               }
+            },
+
+            stop: function() {
+                peer.close();
+                if (options.attachStream) {
+                    options.attachStream.stop();
+                }
+            }
+
+        };
+    }
+
+    // getUserMedia
+    var video_constraints = {
+        mandatory: {},
+        optional: []
+    };
+
+    function getUserMedia(options) {
+        var n = navigator,
+        media;
+        n.getMedia = n.webkitGetUserMedia || n.mozGetUserMedia;
+        n.getMedia(options.constraints || {
+            audio: true,
+            video: video_constraints
+        },
+        streaming, options.onerror ||
+        function(e) {
+            console.error(e);
+        });
+
+        function streaming(stream) {
+            var video = options.video;
+            if (video) {
+                video[moz ? 'mozSrcObject' : 'src'] = moz ? stream : window.webkitURL.createObjectURL(stream);
+                //video.play();
+            }
+            if (options.onsuccess) {
+               options.onsuccess(stream);
+           }
+            media = stream;
+        }
+
+        return media;
+    }
+
+})(jQuery);
diff --git a/html5/verto/js/src/jquery.jsonrpcclient.js b/html5/verto/js/src/jquery.jsonrpcclient.js
new file mode 100644 (file)
index 0000000..c5ff8d7
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+ * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
+ * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is jquery.jsonrpclient.js modified for Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
+ *
+ * The Initial Developer of the Original Code is
+ * Textalk AB http://textalk.se/
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * jquery.jsonrpclient.js - JSON RPC client code
+ *
+ */
+/**
+ * This plugin requires jquery.json.js to be available, or at least the methods $.toJSON and
+ * $.parseJSON.
+ *
+ * The plan is to make use of websockets if they are available, but work just as well with only
+ * http if not.
+ *
+ * Usage example:
+ *
+ *   var foo = new $.JsonRpcClient({ ajaxUrl: '/backend/jsonrpc' });
+ *   foo.call(
+ *     'bar', [ 'A parameter', 'B parameter' ],
+ *     function(result) { alert('Foo bar answered: ' + result.my_answer); },
+ *     function(error)  { console.log('There was an error', error); }
+ *   );
+ *
+ * More examples are available in README.md
+ */
+(function($) {
+  /**
+   * @fn new
+   * @memberof $.JsonRpcClient
+   *
+   * @param options An object stating the backends:
+   *                ajaxUrl    A url (relative or absolute) to a http(s) backend.
+   *                socketUrl  A url (relative of absolute) to a ws(s) backend.
+   *                onmessage  A socket message handler for other messages (non-responses).
+   *                getSocket  A function returning a WebSocket or null.
+   *                           It must take an onmessage_cb and bind it to the onmessage event
+   *                           (or chain it before/after some other onmessage handler).
+   *                           Or, it could return null if no socket is available.
+   *                           The returned instance must have readyState <= 1, and if less than 1,
+   *                           react to onopen binding.
+   */
+  $.JsonRpcClient = function(options) {
+    var self = this;
+    this.options = $.extend({
+      ajaxUrl     : null,
+      socketUrl   : null, ///< The ws-url for default getSocket.
+      onmessage   : null, ///< Other onmessage-handler.
+      login       : null, /// auth login
+      passwd      : null, /// auth passwd
+      sessid : null,
+      getSocket   : function(onmessage_cb) { return self._getSocket(onmessage_cb); }
+    }, options);
+      
+    // Declare an instance version of the onmessage callback to wrap 'this'.
+    this.wsOnMessage = function(event) { self._wsOnMessage(event); };
+  };
+
+  /// Holding the WebSocket on default getsocket.
+  $.JsonRpcClient.prototype._ws_socket = null;
+
+  /// Object <id>: { success_cb: cb, error_cb: cb }
+  $.JsonRpcClient.prototype._ws_callbacks = {};
+
+  /// The next JSON-RPC request id.
+  $.JsonRpcClient.prototype._current_id = 1;
+
+  /**
+   * @fn call
+   * @memberof $.JsonRpcClient
+   *
+   * @param method     The method to run on JSON-RPC server.
+   * @param params     The params; an array or object.
+   * @param success_cb A callback for successful request.
+   * @param error_cb   A callback for error.
+   */
+  $.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) {
+    // Construct the JSON-RPC 2.0 request.
+
+    if (!params) {
+       params = {};
+    }
+
+    if (this.options.sessid) {
+       params.sessid = this.options.sessid;
+    }
+
+    var request = {
+      jsonrpc : '2.0',
+      method  : method,
+      params  : params,
+      id      : this._current_id++  // Increase the id counter to match request/response
+    };
+
+    if (!success_cb) {
+       success_cb = function(e){console.log("Success: ", e);};
+    }
+
+    if (!error_cb) {
+       error_cb = function(e){console.log("Error: ", e);};
+    }
+
+    // Try making a WebSocket call.
+    var socket = this.options.getSocket(this.wsOnMessage);
+    if (socket !== null) {
+      this._wsCall(socket, request, success_cb, error_cb);
+      return;
+    }
+
+    // No WebSocket, and no HTTP backend?  This won't work.
+    if (this.options.ajaxUrl === null) {
+      throw "$.JsonRpcClient.call used with no websocket and no http endpoint.";
+    }
+
+    $.ajax({
+      type     : 'POST',
+      url      : this.options.ajaxUrl,
+      data     : $.toJSON(request),
+      dataType : 'json',
+      cache    : false,
+
+      success  : function(data) {
+          if ('error' in data) error_cb(data.error, this);
+          success_cb(data.result, this);
+      },
+
+      // JSON-RPC Server could return non-200 on error
+      error    : function(jqXHR, textStatus, errorThrown) {
+        try {
+          var response = $.parseJSON(jqXHR.responseText);
+          if ('console' in window) console.log(response);
+            error_cb(response.error, this);
+        }
+        catch (err) {
+          // Perhaps the responseText wasn't really a jsonrpc-error.
+            error_cb({ error: jqXHR.responseText }, this);
+        }
+      }
+    });
+  };
+
+  /**
+   * Notify sends a command to the server that won't need a response.  In http, there is probably
+   * an empty response - that will be dropped, but in ws there should be no response at all.
+   *
+   * This is very similar to call, but has no id and no handling of callbacks.
+   *
+   * @fn notify
+   * @memberof $.JsonRpcClient
+   *
+   * @param method     The method to run on JSON-RPC server.
+   * @param params     The params; an array or object.
+   */
+  $.JsonRpcClient.prototype.notify = function(method, params) {
+    // Construct the JSON-RPC 2.0 request.
+
+    if (this.options.sessid) {
+       params.sessid = this.options.sessid;
+    }
+
+    var request = {
+      jsonrpc: '2.0',
+      method:  method,
+      params:  params
+    };
+
+    // Try making a WebSocket call.
+    var socket = this.options.getSocket(this.wsOnMessage);
+    if (socket !== null) {
+      this._wsCall(socket, request);
+      return;
+    }
+
+    // No WebSocket, and no HTTP backend?  This won't work.
+    if (this.options.ajaxUrl === null) {
+      throw "$.JsonRpcClient.notify used with no websocket and no http endpoint.";
+    }
+
+    $.ajax({
+      type     : 'POST',
+      url      : this.options.ajaxUrl,
+      data     : $.toJSON(request),
+      dataType : 'json',
+      cache    : false
+    });
+  };
+
+  /**
+   * Make a batch-call by using a callback.
+   *
+   * The callback will get an object "batch" as only argument.  On batch, you can call the methods
+   * "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be
+   * sent as a batch call then the callback is done.
+   *
+   * @fn batch
+   * @memberof $.JsonRpcClient
+   * 
+   * @param callback    The main function which will get a batch handler to run call and notify on.
+   * @param all_done_cb A callback function to call after all results have been handled.
+   * @param error_cb    A callback function to call if there is an error from the server.
+   *                    Note, that batch calls should always get an overall success, and the
+   *                    only error
+   */
+  $.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) {
+    var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb);
+    callback(batch);
+    batch._execute();
+  };
+
+  /**
+   * The default getSocket handler.
+   *
+   * @param onmessage_cb The callback to be bound to onmessage events on the socket.
+   *
+   * @fn _getSocket
+   * @memberof $.JsonRpcClient
+   */
+
+  $.JsonRpcClient.prototype.socketReady = function() {
+      if (this._ws_socket === null || this._ws_socket.readyState > 1) {
+         return false;
+      }
+
+      return true;
+  }
+
+  $.JsonRpcClient.prototype.closeSocket = function() {
+      if (self.socketReady()) {
+         this._ws_socket.onclose = function (w) {console.log("Closing Socket")}
+         this._ws_socket.close();
+      }
+  }
+   
+  $.JsonRpcClient.prototype.loginData = function(params) {
+      self.options.login = params.login;
+      self.options.passwd = params.passwd;
+  }
+    
+  $.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) {
+      var self = this;
+
+      if (!self.socketReady()) {
+         self.authing = false;
+         // No socket, or dying socket, let's get a new one.
+         this._ws_socket = new WebSocket(this.options.socketUrl);
+         
+         if (this._ws_socket) {
+             // Set up onmessage handler.
+             this._ws_socket.onmessage = onmessage_cb;
+             this._ws_socket.onclose = function (w) {
+                 if (!self.ws_sleep) {
+                     self.ws_sleep = 2;
+                 }
+
+                 self.ws_cnt = 0;
+                 
+                 if (self.options.onWSClose) {
+                     self.options.onWSClose(self);
+                 }
+
+                 console.error("Websocket Lost sleep: " + self.ws_sleep + "sec");
+
+                 setTimeout(function() {
+                     console.log("Attempting Reconnection....");
+                     self.connectSocket(onmessage_cb);
+                 }, self.ws_sleep * 1000);
+                 
+
+                 if (++self.ws_cnt >= 150) {
+                     self.ws_sleep = 30;
+                 }
+             }
+
+             // Set up sending of message for when the socket is open.
+             this._ws_socket.onopen = function() {
+                 this.ws_sleep = 2;      
+                 this.ws_cnt = 0;
+                 if (self.options.onWSConnect) {
+                     self.options.onWSConnect(self);
+                 }
+                 
+                 var req;
+                 // Send the requests.
+                 while (req = $.JsonRpcClient.q.pop()) {
+                     self._ws_socket.send(req);
+                 }
+             }
+         }
+      }      
+      
+      return this._ws_socket ? true : false;
+  }
+
+  $.JsonRpcClient.prototype._getSocket = function(onmessage_cb) {
+    // If there is no ws url set, we don't have a socket.
+    // Likewise, if there is no window.WebSocket.
+    if (this.options.socketUrl === null || !("WebSocket" in window)) return null;
+
+      this.connectSocket(onmessage_cb);
+
+    return this._ws_socket;
+  };
+
+  /**
+   * Queue to save messages delivered when websocket is not ready
+   */
+  $.JsonRpcClient.q = [];
+
+  /**
+   * Internal handler to dispatch a JRON-RPC request through a websocket.
+   *
+   * @fn _wsCall
+   * @memberof $.JsonRpcClient
+   */
+  $.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) {
+    var request_json = $.toJSON(request);
+
+    if (socket.readyState < 1) {
+       // The websocket is not open yet; we have to set sending of the message in onopen.
+       self = this; // In closure below, this is set to the WebSocket.  Use self instead.
+
+       $.JsonRpcClient.q.push(request_json);
+
+
+    }
+    else {
+      // We have a socket and it should be ready to send on.
+      socket.send(request_json);
+    }
+
+    // Setup callbacks.  If there is an id, this is a call and not a notify.
+    if ('id' in request && typeof success_cb !== 'undefined') {
+       this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb };
+    }
+  };
+
+  /**
+   * Internal handler for the websocket messages.  It determines if the message is a JSON-RPC
+   * response, and if so, tries to couple it with a given callback.  Otherwise, it falls back to
+   * given external onmessage-handler, if any.
+   *
+   * @param event The websocket onmessage-event.
+   */
+  $.JsonRpcClient.prototype._wsOnMessage = function(event) {
+    // Check if this could be a JSON RPC message.
+      var response;
+    try {
+       response = $.parseJSON(event.data);
+
+      /// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends.
+
+      if (typeof response === 'object'
+          && 'jsonrpc' in response
+          && response.jsonrpc === '2.0') {
+
+        /// @todo Handle bad response (without id).
+
+        // If this is an object with result, it is a response.
+        if ('result' in response && this._ws_callbacks[response.id]) {
+          // Get the success callback.
+          var success_cb = this._ws_callbacks[response.id].success_cb;
+
+/*
+         // set the sessid if present
+            if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) {
+             this.options.sessid = response.result.sessid;
+             if (this.options.sessid) {
+                 console.log("setting session UUID to: " + this.options.sessid);
+             }
+         }
+*/
+          // Delete the callback from the storage.
+          delete this._ws_callbacks[response.id];
+
+          // Run callback with result as parameter.
+            success_cb(response.result, this);
+          return;
+        }
+
+        // If this is an object with error, it is an error response.
+        else if ('error' in response && this._ws_callbacks[response.id]) {
+
+          // Get the error callback.
+          var error_cb = this._ws_callbacks[response.id].error_cb;
+         var orig_req = this._ws_callbacks[response.id].request;
+
+         // if this is an auth request, send the credentials and resend the failed request
+          if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) {
+             self.authing = true;
+
+             this.call("login", { login: self.options.login, passwd: self.options.passwd}, 
+                       this._ws_callbacks[response.id].request_obj.method == "login" 
+                       ?
+                       function(e) {
+                           self.authing = false;
+                           console.log("logged in");
+                           delete self._ws_callbacks[response.id];
+
+                           if (self.options.onWSLogin) {
+                               self.options.onWSLogin(true, self);
+                           }
+                       } 
+
+                       :
+
+                       function(e) {
+                           self.authing = false;
+                           console.log("logged in, resending request id: " + response.id);
+                           var socket = self.options.getSocket(self.wsOnMessage);
+                           if (socket !== null) {                          
+                               socket.send(orig_req);
+                           }
+                           if (self.options.onWSLogin) {
+                               self.options.onWSLogin(true, self);
+                           }
+                       }, 
+
+                       function(e) {
+                           console.log("error logging in, request id:", response.id);
+                           delete self._ws_callbacks[response.id];
+                           error_cb(response.error, this);
+                           if (self.options.onWSLogin) {
+                               self.options.onWSLogin(false, self);
+                           }
+                       }
+                       
+                      );
+             return;
+         }
+
+          // Delete the callback from the storage.
+          delete this._ws_callbacks[response.id];
+
+          // Run callback with the error object as parameter.
+            error_cb(response.error, this);
+
+          return;
+        }
+      }
+    }
+    catch (err) {
+      // Probably an error while parsing a non json-string as json.  All real JSON-RPC cases are
+      // handled above, and the fallback method is called below.
+       console.log("ERROR: "+ err);
+       return;
+    }
+
+    // This is not a JSON-RPC response.  Call the fallback message handler, if given.
+    if (typeof this.options.onmessage === 'function') {
+       event.eventData = response;
+       if (!event.eventData) {
+           event.eventData = {};
+       }
+       
+       var reply = this.options.onmessage(event);
+
+       if (reply && typeof reply === "object" && event.eventData.id) {
+           var msg = {
+               jsonrpc: "2.0",
+               id: event.eventData.id,
+               result: reply
+           };
+           
+           var socket = self.options.getSocket(self.wsOnMessage);
+           if (socket !== null) {                          
+               socket.send($.toJSON(msg));
+           }
+       }
+
+    }
+  };
+
+
+  /************************************************************************************************
+   * Batch object with methods
+   ************************************************************************************************/
+
+  /**
+   * Handling object for batch calls.
+   */
+  $.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) {
+    // Array of objects to hold the call and notify requests.  Each objects will have the request
+    // object, and unless it is a notify, success_cb and error_cb.
+    this._requests   = [];
+
+    this.jsonrpcclient = jsonrpcclient;
+    this.all_done_cb = all_done_cb;
+    this.error_cb    = typeof error_cb === 'function' ? error_cb : function() {};
+
+  };
+
+  /**
+   * @sa $.JsonRpcClient.prototype.call
+   */
+  $.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) {
+
+    if (!params) {
+       params = {};
+    }
+
+    if (this.options.sessid) {
+       params.sessid = this.options.sessid;
+    }
+
+    if (!success_cb) {
+       success_cb = function(e){console.log("Success: ", e);};
+    }
+
+    if (!error_cb) {
+       error_cb = function(e){console.log("Error: ", e);};
+    }
+
+    this._requests.push({
+      request    : {
+        jsonrpc : '2.0',
+        method  : method,
+        params  : params,
+        id      : this.jsonrpcclient._current_id++  // Use the client's id series.
+      },
+      success_cb : success_cb,
+      error_cb   : error_cb
+    });
+  };
+
+  /**
+   * @sa $.JsonRpcClient.prototype.notify
+   */
+  $.JsonRpcClient._batchObject.prototype.notify = function(method, params) {
+    if (this.options.sessid) {
+       params.sessid = this.options.sessid;
+    }
+
+    this._requests.push({
+      request    : {
+        jsonrpc : '2.0',
+        method  : method,
+        params  : params
+      }
+    });
+  };
+
+  /**
+   * Executes the batched up calls.
+   */
+  $.JsonRpcClient._batchObject.prototype._execute = function() {
+    var self = this;
+
+    if (this._requests.length === 0) return; // All done :P
+
+    // Collect all request data and sort handlers by request id.
+    var batch_request = [];
+    var handlers = {};
+
+    // If we have a WebSocket, just send the requests individually like normal calls.
+    var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage);
+    if (socket !== null) {
+      for (var i = 0; i < this._requests.length; i++) {
+        var call = this._requests[i];
+        var success_cb = ('success_cb' in call) ? call.success_cb : undefined;
+        var error_cb   = ('error_cb'   in call) ? call.error_cb   : undefined;
+        self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb);
+      }
+      if (typeof all_done_cb === 'function') all_done_cb(result);
+      return;
+    }
+
+    for (var i = 0; i < this._requests.length; i++) {
+      var call = this._requests[i];
+      batch_request.push(call.request);
+
+      // If the request has an id, it should handle returns (otherwise it's a notify).
+      if ('id' in call.request) {
+        handlers[call.request.id] = {
+          success_cb : call.success_cb,
+          error_cb   : call.error_cb
+        };
+      }
+    }
+
+    var success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); };
+
+    // No WebSocket, and no HTTP backend?  This won't work.
+    if (self.jsonrpcclient.options.ajaxUrl === null) {
+      throw "$.JsonRpcClient.batch used with no websocket and no http endpoint.";
+    }
+
+    // Send request
+    $.ajax({
+      url      : self.jsonrpcclient.options.ajaxUrl,
+      data     : $.toJSON(batch_request),
+      dataType : 'json',
+      cache    : false,
+      type     : 'POST',
+
+      // Batch-requests should always return 200
+      error    : function(jqXHR, textStatus, errorThrown) {
+        self.error_cb(jqXHR, textStatus, errorThrown);
+      },
+      success  : success_cb
+    });
+  };
+
+  /**
+   * Internal helper to match the result array from a batch call to their respective callbacks.
+   *
+   * @fn _batchCb
+   * @memberof $.JsonRpcClient
+   */
+  $.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) {
+    for (var i = 0; i < result.length; i++) {
+      var response = result[i];
+
+      // Handle error
+      if ('error' in response) {
+        if (response.id === null || !(response.id in handlers)) {
+          // An error on a notify?  Just log it to the console.
+          if ('console' in window) console.log(response);
+        }
+          else handlers[response.id].error_cb(response.error, this);
+      }
+      else {
+        // Here we should always have a correct id and no error.
+        if (!(response.id in handlers) && 'console' in window) console.log(response);
+          else handlers[response.id].success_cb(response.result, this);
+      }
+    }
+
+    if (typeof all_done_cb === 'function') all_done_cb(result);
+  };
+
+})(jQuery);
diff --git a/html5/verto/js/src/jquery.verto.js b/html5/verto/js/src/jquery.verto.js
new file mode 100644 (file)
index 0000000..54e24e4
--- /dev/null
@@ -0,0 +1,1661 @@
+/*
+ * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
+ * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthm@freeswitch.org>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthm@freeswitch.org>
+ *
+ * jquery.verto.js - Main interface
+ *
+ */
+
+(function($) {
+
+    var generateGUID = (typeof(window.crypto) !== 'undefined' && typeof(window.crypto.getRandomValues) !== 'undefined') ?
+    function() {
+        // If we have a cryptographically secure PRNG, use that
+        // http://stackoverflow.com/questions/6906916/collisions-when-generating-uuids-in-javascript
+        var buf = new Uint16Array(8);
+        window.crypto.getRandomValues(buf);
+        var S4 = function(num) {
+            var ret = num.toString(16);
+            while (ret.length < 4) {
+                ret = "0" + ret;
+            }
+            return ret;
+        };
+        return (S4(buf[0]) + S4(buf[1]) + "-" + S4(buf[2]) + "-" + S4(buf[3]) + "-" + S4(buf[4]) + "-" + S4(buf[5]) + S4(buf[6]) + S4(buf[7]));
+    }
+
+    :
+
+    function() {
+        // Otherwise, just use Math.random
+        // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
+        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+            var r = Math.random() * 16 | 0,
+            v = c == 'x' ? r : (r & 0x3 | 0x8);
+            return v.toString(16);
+        });
+    };
+
+    /// MASTER OBJ
+    $.verto = function(options, callbacks) {
+        var verto = this;
+
+        $.verto.saved.push(verto);
+
+        verto.options = $.extend({
+            login: null,
+            passwd: null,
+            socketUrl: null,
+            tag: null,
+            videoParams: {},
+            ringSleep: 6000
+        },
+        options);
+
+        verto.sessid = $.cookie('verto_session_uuid') || generateGUID();
+        $.cookie('verto_session_uuid', verto.sessid, {
+            expires: 1
+        });
+
+        verto.dialogs = {};
+
+        verto.callbacks = callbacks || {};
+
+        verto.eventSUBS = {};
+
+        verto.rpcClient = new $.JsonRpcClient({
+            login: verto.options.login,
+            passwd: verto.options.passwd,
+            socketUrl: verto.options.socketUrl,
+            sessid: verto.sessid,
+            onmessage: function(e) {
+                return verto.handleMessage(e.eventData);
+            },
+            onWSConnect: function(o) {
+                o.call('login', {});
+            },
+            onWSLogin: function(success) {
+                if (verto.callbacks.onWSLogin) {
+                    verto.callbacks.onWSLogin(verto, success);
+                }
+            },
+            onWSClose: function(success) {
+                if (verto.callbacks.onWSClose) {
+                    verto.callbacks.onWSClose(verto, success);
+                }
+                verto.purge();
+            }
+        });
+
+        if (verto.options.ringFile && verto.options.tag) {
+            verto.ringer = $("#" + verto.options.tag);
+        }
+
+        verto.rpcClient.call('login', {});
+
+    };
+
+    $.verto.prototype.loginData = function(params) {
+        verto.options.login = params.login;
+        verto.options.passwd = params.passwd;
+        verto.rpcClient.loginData(params);
+    };
+
+    $.verto.prototype.logout = function(msg) {
+        var verto = this;
+        verto.rpcClient.closeSocket();
+        verto.purge();
+    };
+
+    $.verto.prototype.login = function(msg) {
+        var verto = this;
+        verto.logout();
+        verto.rpcClient.call('login', {});
+    };
+
+    $.verto.prototype.message = function(msg) {
+        var verto = this;
+        var err = 0;
+
+        if (!msg.to) {
+            console.error("Missing To");
+            err++;
+        }
+
+        if (!msg.body) {
+            console.error("Missing Body");
+            err++;
+        }
+
+        if (err) {
+            return false;
+        }
+
+        verto.sendMethod("verto.info", {
+            msg: msg
+        });
+
+        return true;
+    };
+
+    $.verto.prototype.processReply = function(method, success, e) {
+        var verto = this;
+       var i;
+
+        console.log("Response: " + method, success, e);
+
+        switch (method) {
+        case "verto.subscribe":
+            for (i in e.unauthorizedChannels) {
+                drop_bad(verto, e.unauthorizedChannels[i]);
+            }
+            for (i in e.subscribedChannels) {
+                mark_ready(verto, e.subscribedChannels[i]);
+            }
+
+            break;
+        case "verto.unsubscribe":
+            //console.error(e);
+            break;
+        }
+    };
+
+    $.verto.prototype.sendMethod = function(method, params) {
+        var verto = this;
+
+        verto.rpcClient.call(method, params,
+
+        function(e) {
+            /* Success */
+            verto.processReply(method, true, e);
+        },
+
+        function(e) {
+            /* Error */
+            verto.processReply(method, false, e);
+        });
+    };
+
+    function do_sub(verto, channel, obj) {
+
+    }
+
+    function drop_bad(verto, channel) {
+        console.error("drop unauthorized channel: " + channel);
+        delete verto.eventSUBS[channel];
+    }
+
+    function mark_ready(verto, channel) {
+        for (var j in verto.eventSUBS[channel]) {
+            verto.eventSUBS[channel][j].ready = true;
+            console.log("subscribed to channel: " + channel);
+            if (verto.eventSUBS[channel][j].readyHandler) {
+                verto.eventSUBS[channel][j].readyHandler(verto, channel);
+            }
+        }
+    }
+
+    var SERNO = 1;
+
+    function do_subscribe(verto, channel, subChannels, sparams) {
+        var params = sparams || {};
+
+        var local = params.local;
+
+        var obj = {
+            eventChannel: channel,
+            userData: params.userData,
+            handler: params.handler,
+            ready: false,
+            readyHandler: params.readyHandler,
+            serno: SERNO++
+        };
+
+        var isnew = false;
+
+        if (!verto.eventSUBS[channel]) {
+            verto.eventSUBS[channel] = [];
+            subChannels.push(channel);
+            isnew = true;
+        }
+
+        verto.eventSUBS[channel].push(obj);
+
+        if (local) {
+            obj.ready = true;
+            obj.local = true;
+        }
+
+        if (!isnew && verto.eventSUBS[channel][0].ready) {
+            obj.ready = true;
+            if (obj.readyHandler) {
+                obj.readyHandler(verto, channel);
+            }
+        }
+
+        return {
+            serno: obj.serno,
+            eventChannel: channel
+        };
+
+    }
+
+    $.verto.prototype.subscribe = function(channel, sparams) {
+        var verto = this;
+        var r = [];
+        var subChannels = [];
+        var params = sparams || {};
+
+        if (typeof(channel) === "string") {
+            r.push(do_subscribe(verto, channel, subChannels, params));
+        } else {
+            for (var i in channel) {
+                r.push(do_subscribe(verto, channel, subChannels, params));
+            }
+        }
+
+        if (subChannels.length) {
+            verto.sendMethod("verto.subscribe", {
+                eventChannel: subChannels.length == 1 ? subChannels[0] : subChannels,
+                subParams: params.subParams
+            });
+        }
+
+        return r;
+    };
+
+    $.verto.prototype.unsubscribe = function(handle) {
+        var verto = this;
+       var i;
+
+        if (!handle) {
+            for (i in verto.eventSUBS) {
+                if (verto.eventSUBS[i]) {
+                    verto.unsubscribe(verto.eventSUBS[i]);
+                }
+            }
+        } else {
+            var unsubChannels = {};
+            var sendChannels = [];
+           var channel;
+
+            if (typeof(handle) == "string") {
+                delete verto.eventSUBS[handle];
+                unsubChannels[handle]++;
+            } else {
+                for (i in handle) {
+                    if (typeof(handle[i]) == "string") {
+                        channel = handle[i];
+                        delete verto.eventSUBS[channel];
+                        unsubChannels[channel]++;
+                    } else {
+                        var repl = [];
+                        channel = handle[i].eventChannel;
+
+                        for (var j in verto.eventSUBS[channel]) {
+                            if (verto.eventSUBS[channel][j].serno == handle[i].serno) {} else {
+                                repl.push(verto.eventSUBS[channel][j]);
+                            }
+                        }
+
+                        verto.eventSUBS[channel] = repl;
+
+                        if (verto.eventSUBS[channel].length === 0) {
+                            delete verto.eventSUBS[channel];
+                            unsubChannels[channel]++;
+                        }
+                    }
+                }
+            }
+
+            for (var u in unsubChannels) {
+                console.log("Sending Unsubscribe for: ", u);
+                sendChannels.push(u);
+            }
+
+            if (sendChannels.length) {
+                verto.sendMethod("verto.unsubscribe", {
+                    eventChannel: sendChannels.length == 1 ? sendChannels[0] : sendChannels
+                });
+            }
+        }
+    };
+
+    $.verto.prototype.broadcast = function(channel, params) {
+        var verto = this;
+        var msg = {
+            eventChannel: channel,
+            data: {}
+        };
+        for (var i in params) {
+            msg.data[i] = params[i];
+        }
+        verto.sendMethod("verto.broadcast", msg);
+    };
+
+    $.verto.prototype.purge = function(callID) {
+        var verto = this;
+        var x = 0;
+       var i;
+
+        for (i in verto.dialogs) {
+            if (!x) {
+                console.log("purging dialogs");
+            }
+           x++;
+            verto.dialogs[i].setState($.verto.enum.state.purge);
+        }
+
+        for (i in verto.eventSUBS) {
+            if (verto.eventSUBS[i]) {
+                console.log("purging subscription: " + i);
+                delete verto.eventSUBS[i];
+            }
+        }
+    };
+
+    $.verto.prototype.hangup = function(callID) {
+        var verto = this;
+        if (callID) {
+            var dialog = verto.dialogs[callID];
+
+            if (dialog) {
+                dialog.hangup();
+            }
+        } else {
+            for (var i in verto.dialogs) {
+                verto.dialogs[i].hangup();
+            }
+        }
+    };
+
+    $.verto.prototype.newCall = function(args, callbacks) {
+        var verto = this;
+
+        if (!verto.rpcClient.socketReady()) {
+            console.error("Not Connected...");
+            return;
+        }
+
+        var dialog = new $.verto.dialog($.verto.enum.direction.outbound, this, args);
+
+        dialog.invite();
+
+        if (callbacks) {
+            dialog.callbacks = callbacks;
+        }
+
+        return dialog;
+    };
+
+    $.verto.prototype.handleMessage = function(data) {
+        var verto = this;
+
+        if (data.params.callID) {
+            var dialog = verto.dialogs[data.params.callID];
+
+            if (dialog) {
+
+                switch (data.method) {
+                case 'verto.bye':
+                    dialog.hangup();
+                    break;
+                case 'verto.answer':
+                    dialog.handleAnswer(data.params.sdp);
+                    break;
+                case 'verto.media':
+                    dialog.handleMedia(data.params.sdp);
+                    break;
+                case 'verto.display':
+                    dialog.handleDisplay(data.params);
+                    break;
+                case 'verto.info':
+                    dialog.handleInfo(data.params);
+                    break;
+                default:
+                    console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", data.method);
+                    break;
+                }
+            } else {
+
+                switch (data.method) {
+                case 'verto.attach':
+                    data.params.attach = true;
+
+                    if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) {
+                        data.params.useVideo = true;
+                    }
+
+                    if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) {
+                        data.params.useStereo = true;
+                    }
+
+                   dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params);
+                   break;
+                case 'verto.invite':
+
+                    if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) {
+                        data.params.wantVideo = true;
+                    }
+
+                    if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) {
+                        data.params.useStereo = true;
+                    }
+
+                    dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params);
+                    break;
+                default:
+                    console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED");
+                    break;
+                }
+            }
+
+            return {
+                method: data.method
+            };
+        } else {
+            switch (data.method) {
+            case 'verto.event':
+                var list = null;
+                var key = null;
+
+                if (data.params) {
+                    key = data.params.eventChannel;
+                }
+
+                if (key) {
+                    list = verto.eventSUBS[key];
+
+                    if (!list) {
+                        list = verto.eventSUBS[key.split(".")[0]];
+                    }
+                }
+
+                if (!list && key && verto.dialogs[key]) {
+                    verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent, data.params);
+                } else if (!list) {
+                    if (!key) {
+                        key = "UNDEFINED";
+                    }
+                    console.error("UNSUBBED or invalid EVENT " + key + " IGNORED");
+                } else {
+                    for (var i in list) {
+                        var sub = list[i];
+
+                        if (!sub || !sub.ready) {
+                            console.error("invalid EVENT for " + key + " IGNORED");
+                        } else if (sub.handler) {
+                            sub.handler(verto, data.params, sub.userData);
+                        } else if (verto.callbacks.onEvent) {
+                            verto.callbacks.onEvent(verto, data.params, sub.userData);
+                        } else {
+                            console.log("EVENT:", data.params);
+                        }
+                    }
+                }
+
+                break;
+
+            case "verto.info":
+                if (verto.callbacks.onMessage) {
+                    verto.callbacks.onMessage(verto, null, $.verto.enum.message.info, data.params.msg);
+                }
+                console.error(data);
+                console.debug("MESSAGE from: " + data.params.msg.from, data.params.msg.body);
+
+                break;
+
+            default:
+                console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", data.method);
+                break;
+            }
+        }
+    };
+
+    var del_array = function(array, name) {
+        var r = [];
+        var len = array.length;
+
+        for (var i = 0; i < len; i++) {
+            if (array[i] != name) {
+                r.push(array[i]);
+            }
+        }
+
+        return r;
+    };
+
+    var hashArray = function() {
+        var vha = this;
+
+        var hash = {};
+        var array = [];
+
+        vha.reorder = function(a) {
+            array = a;
+            var h = hash;
+            hash = {};
+
+            var len = array.length;
+
+            for (var i = 0; i < len; i++) {
+                var key = array[i];
+                if (h[key]) {
+                    hash[key] = h[key];
+                    delete h[key];
+                }
+            }
+            h = undefined;
+        };
+
+        vha.clear = function() {
+            hash = undefined;
+            array = undefined;
+            hash = {};
+            array = [];
+        };
+
+        vha.add = function(name, val, insertAt) {
+            var redraw = false;
+
+            if (!hash[name]) {
+                if (insertAt === undefined || insertAt < 0 || insertAt >= array.length) {
+                    array.push(name);
+                } else {
+                    var x = 0;
+                    var n = [];
+                    var len = array.length;
+
+                    for (var i = 0; i < len; i++) {
+                        if (x++==insertAt) {
+                            n.push(name);
+                        }
+                        n.push(array[i]);
+                    }
+
+                    array = undefined;
+                    array = n;
+                    n = undefined;
+                    redraw = true;
+                }
+            }
+
+            hash[name] = val;
+
+            return redraw;
+        };
+
+        vha.del = function(name) {
+            var r = false;
+
+            if (hash[name]) {
+                array = del_array(array, name);
+                delete hash[name];
+                r = true;
+            } else {
+                console.error("can't del nonexistant key " + name);
+            }
+
+            return r;
+        };
+
+        vha.get = function(name) {
+            return hash[name];
+        };
+
+        vha.order = function() {
+            return array;
+        };
+
+        vha.hash = function() {
+            return hash;
+        };
+
+        vha.indexOf = function(name) {
+            var len = array.length;
+
+            for (var i = 0; i < len; i++) {
+                if (array[i] == name) {
+                    return i;
+                }
+            }
+        };
+
+        vha.arrayLen = function() {
+            return array.length;
+        };
+
+        vha.asArray = function() {
+            var r = [];
+
+            var len = array.length;
+
+            for (var i = 0; i < len; i++) {
+                var key = array[i];
+                r.push(hash[key]);
+            }
+
+            return r;
+        };
+
+        vha.each = function(cb) {
+            var len = array.length;
+
+            for (var i = 0; i < len; i++) {
+                cb(array[i], hash[array[i]]);
+            }
+        };
+
+        vha.dump = function(html) {
+            var str = "";
+
+            vha.each(function(name, val) {
+                str += "name: " + name + " val: " + JSON.stringify(val) + (html ? "<br>" : "\n");
+            });
+
+            return str;
+        };
+
+    };
+
+    $.verto.liveArray = function(verto, context, name, config) {
+        var la = this;
+        var lastSerno = 0;
+        var binding = null;
+        var user_obj = config.userObj;
+        var local = false;
+
+        // Inherit methods of hashArray
+        hashArray.call(la);
+
+        // Save the hashArray add, del, reorder, clear methods so we can make our own.
+        la._add = la.add;
+        la._del = la.del;
+        la._reorder = la.reorder;
+        la._clear = la.clear;
+
+        la.context = context;
+        la.name = name;
+        la.user_obj = user_obj;
+
+        la.verto = verto;
+        la.broadcast = function(channel, obj) {
+            verto.broadcast(channel, obj);
+        };
+        la.errs = 0;
+
+        la.clear = function() {
+            la._clear();
+            lastSerno = 0;
+
+            if (la.onChange) {
+                la.onChange(la, {
+                    action: "clear"
+                });
+            }
+        };
+
+        la.checkSerno = function(serno) {
+            if (serno < 0) {
+                return true;
+            }
+
+            if (lastSerno > 0 && serno != (lastSerno + 1)) {
+                if (la.onErr) {
+                    la.onErr(la, {
+                        lastSerno: lastSerno,
+                        serno: serno
+                    });
+                }
+                la.errs++;
+                console.debug(la.errs);
+                if (la.errs < 3) {
+                    la.bootstrap(la.user_obj);
+                }
+                return false;
+            } else {
+                lastSerno = serno;
+                return true;
+            }
+        };
+
+        la.reorder = function(serno, a) {
+            if (la.checkSerno(serno)) {
+                la._reorder(a);
+                if (la.onChange) {
+                    la.onChange(la, {
+                        serno: serno,
+                        action: "reorder"
+                    });
+                }
+            }
+        };
+
+        la.init = function(serno, val, key, index) {
+            if (key === null || key === undefined) {
+                key = serno;
+            }
+            if (la.checkSerno(serno)) {
+                if (la.onChange) {
+                    la.onChange(la, {
+                        serno: serno,
+                        action: "init",
+                        index: index,
+                        key: key,
+                        data: val
+                    });
+                }
+            }
+        };
+
+        la.bootObj = function(serno, val) {
+            if (la.checkSerno(serno)) {
+
+                //la.clear();
+                for (var i in val) {
+                    la._add(val[i][0], val[i][1]);
+                }
+
+                if (la.onChange) {
+                    la.onChange(la, {
+                        serno: serno,
+                        action: "bootObj",
+                        data: val,
+                        redraw: true
+                    });
+                }
+            }
+        };
+
+        // @param serno  La is the serial number for la particular request.
+        // @param key    If looking at it as a hash table, la represents the key in the hashArray object where you want to store the val object.
+        // @param index  If looking at it as an array, la represents the position in the array where you want to store the val object.
+        // @param val    La is the object you want to store at the key or index location in the hash table / array.
+        la.add = function(serno, val, key, index) {
+            if (key === null || key === undefined) {
+                key = serno;
+            }
+            if (la.checkSerno(serno)) {
+                var redraw = la._add(key, val, index);
+                if (la.onChange) {
+                    la.onChange(la, {
+                        serno: serno,
+                        action: "add",
+                        index: index,
+                        key: key,
+                        data: val,
+                        redraw: redraw
+                    });
+                }
+            }
+        };
+
+        la.modify = function(serno, val, key, index) {
+            if (key === null || key === undefined) {
+                key = serno;
+            }
+            if (la.checkSerno(serno)) {
+                la._add(key, val, index);
+                if (la.onChange) {
+                    la.onChange(la, {
+                        serno: serno,
+                        action: "modify",
+                        key: key,
+                        data: val,
+                        index: index
+                    });
+                }
+            }
+        };
+
+        la.del = function(serno, key, index) {
+            if (key === null || key === undefined) {
+                key = serno;
+            }
+            if (la.checkSerno(serno)) {
+                if (index === null || index < 0 || index === undefined) {
+                    index = la.indexOf(key);
+                }
+                var ok = la._del(key);
+
+                if (ok && la.onChange) {
+                    la.onChange(la, {
+                        serno: serno,
+                        action: "del",
+                        key: key,
+                        index: index
+                    });
+                }
+            }
+        };
+
+        var eventHandler = function(v, e, la) {
+            var packet = e.data;
+
+            if (packet.name != la.name) {
+                return;
+            }
+
+            console.error("READ:", packet);
+
+            switch (packet.action) {
+
+            case "init":
+                la.init(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex);
+                break;
+
+            case "bootObj":
+                la.bootObj(packet.wireSerno, packet.data);
+                break;
+            case "add":
+                la.add(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex);
+                break;
+
+            case "modify":
+                if (! (packet.arrIndex || packet.hashKey)) {
+                    console.error("Invalid Packet", packet);
+                } else {
+                    la.modify(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex);
+                }
+                break;
+            case "del":
+                if (! (packet.arrIndex || packet.hashKey)) {
+                    console.error("Invalid Packet", packet);
+                } else {
+                    la.del(packet.wireSerno, packet.hashKey, packet.arrIndex);
+                }
+                break;
+
+            case "clear":
+                la.clear();
+                break;
+
+            case "reorder":
+                la.reorder(packet.wireSerno, packet.order);
+                break;
+
+            default:
+                if (la.checkSerno(packet.wireSerno)) {
+                    if (la.onChange) {
+                        la.onChange(la, {
+                            serno: packet.wireSerno,
+                            action: packet.action,
+                            data: packet.data
+                        });
+                    }
+                }
+                break;
+            }
+        };
+
+        if (la.context) {
+            binding = la.verto.subscribe(la.context, {
+                handler: eventHandler,
+                userData: la,
+                subParams: config.subParams
+            });
+        }
+
+        la.destroy = function() {
+            la._clear();
+            la.verto.unsubscribe(binding);
+        };
+
+        la.bootstrap = function(obj) {
+            var self = la;
+
+            self.clear();
+            self.broadcast(self.context, {
+                liveArray: {
+                    command: "bootstrap",
+                    context: self.context,
+                    name: self.name,
+                    obj: obj
+                }
+            });
+
+            //self.heartbeat();
+        };
+
+        la.changepage = function(obj) {
+            var self = la;
+            self.clear();
+            self.broadcast(self.context, {
+                liveArray: {
+                    command: "changepage",
+                    context: la.context,
+                    name: la.name,
+                    obj: obj
+                }
+            });
+        };
+
+        la.heartbeat = function(obj) {
+            var self = la;
+
+            var callback = function() {
+                self.heartbeat.call(self, obj);
+            };
+            self.broadcast(self.context, {
+                liveArray: {
+                    command: "heartbeat",
+                    context: self.context,
+                    name: self.name,
+                    obj: obj
+                }
+            });
+            self.hb_pid = setTimeout(callback, 30000);
+        };
+
+        la.bootstrap(la.user_obj);
+    };
+
+    $.verto.liveTable = function(verto, context, name, jq, config) {
+        var dt;
+        var la = new $.verto.liveArray(verto, context, name, {
+            subParams: config.subParams
+        });
+        var lt = this;
+
+        lt.liveArray = la;
+        lt.dataTable = dt;
+        lt.verto = verto;
+
+        lt.destroy = function() {
+            if (dt) {
+                dt.fnDestroy();
+            }
+            if (la) {
+                la.destroy();
+            }
+
+            dt = null;
+            la = null;
+        };
+
+        la.onErr = function(obj, args) {
+            console.error("Error: ", obj, args);
+        };
+
+        la.onChange = function(obj, args) {
+            var index = 0;
+            var iserr = 0;
+
+            if (!dt) {
+                if (!config.aoColumns) {
+                    if (args.action != "init") {
+                        return;
+                    }
+
+                    config.aoColumns = [];
+
+                    for (var i in args.data) {
+                        config.aoColumns.push({
+                            "sTitle": args.data[i]
+                        });
+                    }
+                }
+
+                dt = jq.dataTable(config);
+            }
+
+            if (dt && (args.action == "del" || args.action == "modify")) {
+                index = args.index;
+
+                if (index === undefined && args.key) {
+                    index = la.indexOf(args.key);
+                }
+
+                if (index === undefined) {
+                    console.error("INVALID PACKET Missing INDEX\n", args);
+                    return;
+                }
+            }
+
+            try {
+                switch (args.action) {
+                case "bootObj":
+                    if (!args.data) {
+                        console.error("missing data");
+                        return;
+                    }
+                    dt.fnClearTable();
+                    dt.fnAddData(obj.asArray());
+                    dt.fnAdjustColumnSizing();
+                    break;
+                case "add":
+                    if (!args.data) {
+                        console.error("missing data");
+                        return;
+                    }
+                    if (args.redraw > -1) {
+                        // specific position, more costly
+                        dt.fnClearTable();
+                        dt.fnAddData(obj.asArray());
+                    } else {
+                        dt.fnAddData(args.data);
+                    }
+                    dt.fnAdjustColumnSizing();
+                    break;
+                case "modify":
+                    if (!args.data) {
+                        return;
+                    }
+                    console.debug(args, index);
+                    dt.fnUpdate(args.data, index);
+                    dt.fnAdjustColumnSizing();
+                    break;
+                case "del":
+                    dt.fnDeleteRow(index);
+                    dt.fnAdjustColumnSizing();
+                    break;
+                case "clear":
+                    dt.fnClearTable();
+                    break;
+                case "reorder":
+                    // specific position, more costly
+                    dt.fnClearTable();
+                    dt.fnAddData(obj.asArray());
+                    break;
+                case "hide":
+                    jq.hide();
+                    break;
+
+                case "show":
+                    jq.show();
+                    break;
+
+                }
+            } catch(err) {
+                console.error("ERROR: " + err);
+                iserr++;
+            }
+
+            if (iserr) {
+                obj.errs++;
+                if (obj.errs < 3) {
+                    obj.bootstrap(obj.user_obj);
+                }
+            } else {
+                obj.errs = 0;
+            }
+
+            if (config.onChange) {
+                config.onChange(obj, args);
+            }
+
+        };
+
+        la.onChange(la, {
+            action: "init"
+        });
+
+    };
+
+    $.verto.dialog = function(direction, verto, params) {
+        var dialog = this;
+
+        dialog.params = $.extend({
+            useVideo: verto.options.useVideo,
+            useStereo: verto.options.useStereo,
+            tag: verto.options.tag
+        },
+        params);
+
+        dialog.verto = verto;
+        dialog.direction = direction;
+        dialog.lastState = null;
+        dialog.state = dialog.lastState = $.verto.enum.state.new;
+        dialog.callbacks = verto.callbacks;
+        dialog.answered = false;
+        dialog.attach = params.attach || false;
+
+        if (dialog.params.callID) {
+            dialog.callID = dialog.params.callID;
+        } else {
+            dialog.callID = dialog.params.callID = generateGUID();
+        }
+
+        if (dialog.params.tag) {
+            dialog.audioStream = document.getElementById(dialog.params.tag);
+
+            if (dialog.params.useVideo) {
+                dialog.videoStream = dialog.audioStream;
+            }
+        } //else conjure one TBD
+
+        dialog.verto.dialogs[dialog.callID] = dialog;
+
+        var RTCcallbacks = {};
+
+        if (dialog.direction == $.verto.enum.direction.inbound) {
+
+            dialog.params.remote_caller_id_name = dialog.params.caller_id_name;
+            dialog.params.remote_caller_id_number = dialog.params.caller_id_number;
+
+            if (!dialog.params.remote_caller_id_name) {
+                dialog.params.remote_caller_id_name = "Nobody";
+            }
+
+            if (!dialog.params.remote_caller_id_number) {
+                dialog.params.remote_caller_id_number = "UNKNOWN";
+            }
+
+            RTCcallbacks.onMessage = function(rtc, msg) {
+                console.debug(msg);
+            };
+
+            RTCcallbacks.onAnswerSDP = function(rtc, sdp) {
+                console.error("answer sdp", sdp);
+            };
+        } else {
+            dialog.params.remote_caller_id_name = "Outbound Call";
+            dialog.params.remote_caller_id_number = dialog.params.destination_number;
+        }
+
+        RTCcallbacks.onICESDP = function(rtc) {
+
+            if (rtc.type == "offer") {
+                console.log("offer", rtc.mediaData.SDP);
+
+                dialog.setState($.verto.enum.state.requesting);
+
+                dialog.sendMethod("verto.invite", {
+                    sdp: rtc.mediaData.SDP
+                });
+            } else { //answer 
+                dialog.setState($.verto.enum.state.answering);
+
+                dialog.sendMethod(dialog.attach ? "verto.attach" : "verto.answer", {
+                    sdp: dialog.rtc.mediaData.SDP
+                });
+            }
+
+        };
+
+        RTCcallbacks.onICE = function(rtc) {
+            //console.log("cand", rtc.mediaData.candidate);
+            if (rtc.type == "offer") {
+                console.log("offer", rtc.mediaData.candidate);
+                return;
+            }
+
+        };
+
+        RTCcallbacks.onError = function(e) {
+            console.error("ERROR:", e);
+            dialog.hangup();
+        };
+
+        dialog.rtc = new $.FSRTC({
+            callbacks: RTCcallbacks,
+            useVideo: dialog.videoStream,
+            useAudio: dialog.audioStream,
+            useStereo: dialog.params.useStereo,
+            videoParams: verto.options.videoParams,
+        });
+
+        dialog.rtc.verto = dialog.verto;
+
+        if (dialog.direction == $.verto.enum.direction.inbound) {
+            if (dialog.attach) {
+                dialog.answer();
+            } else {
+                dialog.ring();
+            }
+        }
+    };
+
+    $.verto.dialog.prototype.invite = function() {
+        var dialog = this;
+        dialog.rtc.call();
+    };
+
+    $.verto.dialog.prototype.sendMethod = function(method, obj) {
+        var dialog = this;
+        obj.dialogParams = {};
+
+        for (var i in dialog.params) {
+            if (i == "sdp" && method != "verto.invite" && method != "verto.attach") {
+                continue;
+            }
+
+            obj.dialogParams[i] = dialog.params[i];
+        }
+
+        dialog.verto.rpcClient.call(method, obj,
+
+        function(e) {
+            /* Success */
+            dialog.processReply(method, true, e);
+        },
+
+        function(e) {
+            /* Error */
+            dialog.processReply(method, false, e);
+        });
+    };
+
+    function checkStateChange(oldS, newS) {
+
+        if (newS == $.verto.enum.state.purge || $.verto.enum.states[oldS.name][newS.name]) {
+            return true;
+        }
+
+        return false;
+    }
+
+    $.verto.dialog.prototype.setState = function(state) {
+        var dialog = this;
+
+        if (dialog.state == $.verto.enum.state.ringing) {
+            dialog.stopRinging();
+        }
+
+        if (dialog.state == state || !checkStateChange(dialog.state, state)) {
+            console.error("Dialog " + dialog.callID + ": INVALID state change from " + dialog.state.name + " to " + state.name);
+            dialog.hangup();
+            return false;
+        }
+
+        console.error("Dialog " + dialog.callID + ": state change from " + dialog.state.name + " to " + state.name);
+
+        dialog.lastState = dialog.state;
+        dialog.state = state;
+
+        if (dialog.callbacks.onDialogState) {
+            dialog.callbacks.onDialogState(this);
+        }
+
+        switch (dialog.state) {
+        case $.verto.enum.state.purge:
+            dialog.setState($.verto.enum.state.destroy);
+            break;
+        case $.verto.enum.state.hangup:
+
+            if (dialog.lastState.val > $.verto.enum.state.requesting.val && dialog.lastState.val < $.verto.enum.state.hangup.val) {
+                dialog.sendMethod("verto.bye", {});
+            }
+
+            dialog.setState($.verto.enum.state.destroy);
+            break;
+        case $.verto.enum.state.destroy:
+            delete verto.dialogs[dialog.callID];
+            dialog.rtc.stop();
+            break;
+        }
+
+        return true;
+    };
+
+    $.verto.dialog.prototype.processReply = function(method, success, e) {
+        var dialog = this;
+
+        console.log("Response: " + method + " State:" + dialog.state.name, success, e);
+
+        switch (method) {
+
+        case "verto.answer":
+        case "verto.attach":
+            if (success) {
+                dialog.setState($.verto.enum.state.active);
+            } else {
+                dialog.hangup();
+            }
+            break;
+        case "verto.invite":
+            if (success) {
+                dialog.setState($.verto.enum.state.trying);
+            } else {
+                dialog.setState($.verto.enum.state.destroy);
+            }
+            break;
+
+        case "verto.bye":
+            dialog.hangup();
+            break;
+
+        case "verto.modify":
+            if (e.holdState) {
+                if (e.holdState == "held") {
+                    if (dialog.state != $.verto.enum.state.held) {
+                        dialog.setState($.verto.enum.state.held);
+                    }
+                } else if (e.holdState == "active") {
+                    if (dialog.state != $.verto.enum.state.active) {
+                        dialog.setState($.verto.enum.state.active);
+                    }
+                }
+            }
+
+            if (success) {}
+
+            break;
+
+        default:
+            break;
+        }
+
+    };
+
+    $.verto.dialog.prototype.hangup = function(sdp) {
+        var dialog = this;
+
+        if (dialog.state.val > $.verto.enum.state.new.val && dialog.state.val < $.verto.enum.state.hangup.val) {
+            dialog.setState($.verto.enum.state.hangup);
+        } else if (dialog.state.val < $.verto.enum.state.destroy) {
+            dialog.setState($.verto.enum.state.destroy);
+        }
+    };
+
+    $.verto.dialog.prototype.stopRinging = function() {
+        var dialog = this;
+        if (dialog.verto.ringer) {
+            dialog.verto.ringer.stop();
+        }
+    };
+
+    $.verto.dialog.prototype.indicateRing = function() {
+        var dialog = this;
+
+        if (dialog.verto.ringer) {
+            dialog.verto.ringer.attr("src", dialog.verto.options.ringFile)[0].play();
+
+            setTimeout(function() {
+                dialog.stopRinging();
+                if (dialog.state == $.verto.enum.state.ringing) {
+                    dialog.indicateRing();
+                }
+            },
+            dialog.verto.options.ringSleep);
+        }
+    };
+
+    $.verto.dialog.prototype.ring = function() {
+        var dialog = this;
+
+        dialog.setState($.verto.enum.state.ringing);
+        dialog.indicateRing();
+    };
+
+    $.verto.dialog.prototype.useVideo = function(on) {
+        var dialog = this;
+
+        dialog.params.useVideo = on;
+
+        if (on) {
+            dialog.videoStream = dialog.audioStream;
+        } else {
+            dialog.videoStream = null;
+        }
+
+        dialog.rtc.useVideo(dialog.videoStream);
+
+    };
+
+    $.verto.dialog.prototype.useStereo = function(on) {
+        var dialog = this;
+
+        dialog.params.useStereo = on;
+        dialog.rtc.useStereo(on);
+    };
+
+    $.verto.dialog.prototype.dtmf = function(digits) {
+        var dialog = this;
+        if (digits) {
+            dialog.sendMethod("verto.info", {
+                dtmf: digits
+            });
+        }
+    };
+
+    $.verto.dialog.prototype.transfer = function(dest, params) {
+        var dialog = this;
+        if (dest) {
+            cur_call.sendMethod("verto.modify", {
+                action: "transfer",
+                destination: dest,
+                params: params
+            });
+        }
+    };
+
+    $.verto.dialog.prototype.hold = function(params) {
+        var dialog = this;
+
+        cur_call.sendMethod("verto.modify", {
+            action: "hold",
+            params: params
+        });
+    };
+
+    $.verto.dialog.prototype.unhold = function(params) {
+        var dialog = this;
+
+        cur_call.sendMethod("verto.modify", {
+            action: "unhold",
+            params: params
+        });
+    };
+
+    $.verto.dialog.prototype.toggleHold = function(params) {
+        var dialog = this;
+
+        cur_call.sendMethod("verto.modify", {
+            action: "toggleHold",
+            params: params
+        });
+    };
+
+    $.verto.dialog.prototype.message = function(msg) {
+        var dialog = this;
+        var err = 0;
+
+        if (!msg.to) {
+            console.error("Missing To");
+            err++;
+        }
+
+        if (!msg.body) {
+            console.error("Missing Body");
+            err++;
+        }
+
+        if (err) {
+            return false;
+        }
+
+        dialog.sendMethod("verto.info", {
+            msg: msg
+        });
+
+        return true;
+    };
+
+    $.verto.dialog.prototype.answer = function(params) {
+        var dialog = this;
+
+        if (!dialog.answered) {
+            if (params) {
+                if (params.useVideo) {
+                    dialog.useVideo(true);
+                }
+            }
+            dialog.rtc.createAnswer(dialog.params.sdp);
+            dialog.answered = true;
+        }
+    };
+
+    $.verto.dialog.prototype.handleAnswer = function(sdp) {
+        var dialog = this;
+
+        if (dialog.state.val >= $.verto.enum.state.active.val) {
+            return;
+        }
+
+        if (dialog.state.val >= $.verto.enum.state.early.val) {
+            dialog.setState($.verto.enum.state.active);
+        } else {
+            dialog.rtc.answer(sdp, function() {
+                dialog.setState($.verto.enum.state.active);
+            },
+            function(e) {
+                console.error(e);
+                dialog.hangup();
+            });
+            console.log("ANSWER SDP", sdp);
+        }
+    };
+
+    $.verto.dialog.prototype.cidString = function(enc) {
+        var dialog = this;
+        var party = dialog.params.remote_caller_id_name + (enc ? " &lt;" : " <") + dialog.params.remote_caller_id_number + (enc ? "&gt;" : ">");
+        return party;
+    };
+
+    $.verto.dialog.prototype.sendMessage = function(msg, params) {
+        var dialog = this;
+
+        if (dialog.callbacks.onMessage) {
+            dialog.callbacks.onMessage(dialog.verto, dialog, msg, params);
+        }
+    };
+
+    $.verto.dialog.prototype.handleInfo = function(params) {
+        var dialog = this;
+
+        dialog.sendMessage($.verto.enum.message.info, params.msg);
+    };
+
+    $.verto.dialog.prototype.handleDisplay = function(params) {
+        var dialog = this;
+
+        if (params.display_name) {
+            dialog.params.remote_caller_id_name = params.display_name;
+        }
+        if (params.display_number) {
+            dialog.params.remote_caller_id_number = params.display_number;
+        }
+
+        dialog.sendMessage($.verto.enum.message.display, {});
+    };
+
+    $.verto.dialog.prototype.handleMedia = function(sdp) {
+        var dialog = this;
+
+        if (dialog.state.val >= $.verto.enum.state.early.val) {
+            return;
+        }
+
+        dialog.rtc.answer(sdp, function() {
+            dialog.setState($.verto.enum.state.early);
+        },
+        function(e) {
+            console.error(e);
+            dialog.hangup();
+        });
+        console.log("EARLY SDP", sdp);
+    };
+
+    $.verto.ENUM = function(s) {
+        var i = 0,
+        o = {};
+        s.split(" ").map(function(x) {
+            o[x] = {
+                name: x,
+                val: i++
+            };
+        });
+        return Object.freeze(o);
+    };
+
+    $.verto.enum = {};
+
+    $.verto.enum.states = Object.freeze({
+        new: {
+            requesting: 1,
+            ringing: 1,
+            destroy: 1,
+            answering: 1
+        },
+        requesting: {
+            trying: 1,
+            hangup: 1
+        },
+        trying: {
+            active: 1,
+            early: 1,
+            hangup: 1
+        },
+        ringing: {
+            answering: 1,
+            hangup: 1
+        },
+        answering: {
+            active: 1,
+            hangup: 1
+        },
+        active: {
+            hangup: 1,
+            held: 1
+        },
+        held: {
+            hangup: 1,
+            active: 1
+        },
+        early: {
+            hangup: 1,
+            active: 1
+        },
+        hangup: {
+            destroy: 1
+        },
+        destroy: {},
+        purge: {
+            destroy: 1
+        }
+    });
+
+    $.verto.enum.state = $.verto.ENUM("new requesting trying ringing answering early active held hangup destroy purge");
+    $.verto.enum.direction = $.verto.ENUM("inbound outbound");
+    $.verto.enum.message = $.verto.ENUM("display info pvtEvent");
+
+    $.verto.enum = Object.freeze($.verto.enum);
+
+    $.verto.saved = [];
+
+    $(window).bind('beforeunload', function() {
+        for (var i in $.verto.saved) {
+            var verto = $.verto.saved[i];
+            if (verto) {
+                verto.logout();
+                verto.purge();
+            }
+        }
+        return $.verto.warnOnUnload;
+    });
+
+})(jQuery);