Google Analytics for WordPress by MonsterInsights - Version 5.2

Version Description

Release Date: December 9th, 2014

  • Features:
    • Added a brand new GA dashboard:
      • Added graphs showing the sessions and bounce rates.
      • Added reporting tables showing top pages, traffic sources and countries.
Download this release

Release Info

Developer joostdevalk
Plugin Icon 128x128 Google Analytics for WordPress by MonsterInsights
Version 5.2
Comparing to
See all releases

Code changes from version 5.1.4 to 5.2

Files changed (84) hide show
  1. admin/api-libs/class-api-libs.php +7 -0
  2. admin/api-libs/googleanalytics/class-api-googleanalytics.php +1 -49
  3. admin/api-libs/googleanalytics/class-googleanalytics-reporting.php +210 -0
  4. admin/class-admin-assets.php +101 -0
  5. admin/class-admin-dashboards-aggregate.php +0 -19
  6. admin/class-admin-dashboards.php +0 -16
  7. admin/class-admin-form.php +26 -0
  8. admin/class-admin-menu.php +6 -4
  9. admin/class-admin.php +106 -63
  10. admin/class-google-analytics.php +11 -6
  11. admin/dashboards/class-admin-dashboards-api-options.php +90 -0
  12. admin/dashboards/class-admin-dashboards-collector.php +432 -0
  13. admin/dashboards/class-admin-dashboards-data.php +66 -0
  14. admin/dashboards/class-admin-dashboards-display.php +140 -0
  15. admin/dashboards/class-admin-dashboards.php +217 -0
  16. admin/dashboards/drivers/class-admin-dashboards-driver-generate.php +121 -0
  17. admin/dashboards/drivers/class-admin-dashboards-driver.php +80 -0
  18. admin/dashboards/drivers/class-admin-dashboards-graph-generate.php +145 -0
  19. admin/dashboards/drivers/class-admin-dashboards-graph.php +27 -0
  20. admin/dashboards/drivers/class-admin-dashboards-table-generate.php +70 -0
  21. admin/dashboards/drivers/class-admin-dashboards-table.php +27 -0
  22. admin/dashboards/views/graph.php +20 -0
  23. admin/dashboards/views/table.php +22 -0
  24. admin/pages/dashboard.php +64 -2
  25. admin/pages/settings.php +1 -1
  26. {js → assets/css}/index.php +0 -0
  27. assets/css/yoast_ga_admin_dashboard.css +76 -0
  28. assets/css/yoast_ga_admin_dashboard.min.css +1 -0
  29. {css → assets/css}/yoast_ga_styles.css +1 -1
  30. assets/css/yoast_ga_styles.min.css +1 -0
  31. {css → assets/dependencies/chosen}/chosen.css +10 -11
  32. {js → assets/dependencies/chosen}/chosen.jquery.min.js +0 -0
  33. assets/dependencies/chosen/chosen.min.css +1 -0
  34. {img → assets/dependencies/chosen/img}/chosen-sprite.png +0 -0
  35. {img → assets/dependencies/chosen/img}/chosen-sprite@2x.png +0 -0
  36. assets/dependencies/chosen/index.php +4 -0
  37. assets/dependencies/datatables/css/jquery.dataTables.css +476 -0
  38. assets/dependencies/datatables/css/jquery.dataTables.min.css +1 -0
  39. assets/dependencies/datatables/css/jquery.dataTables_themeroller.css +330 -0
  40. assets/dependencies/datatables/images/Sorting icons.psd +0 -0
  41. assets/dependencies/datatables/images/back_disabled.png +0 -0
  42. assets/dependencies/datatables/images/back_enabled.png +0 -0
  43. assets/dependencies/datatables/images/back_enabled_hover.png +0 -0
  44. assets/dependencies/datatables/images/favicon.ico +0 -0
  45. assets/dependencies/datatables/images/forward_disabled.png +0 -0
  46. assets/dependencies/datatables/images/forward_enabled.png +0 -0
  47. assets/dependencies/datatables/images/forward_enabled_hover.png +0 -0
  48. assets/dependencies/datatables/images/sort_asc.png +0 -0
  49. assets/dependencies/datatables/images/sort_asc_disabled.png +0 -0
  50. assets/dependencies/datatables/images/sort_both.png +0 -0
  51. assets/dependencies/datatables/images/sort_desc.png +0 -0
  52. assets/dependencies/datatables/images/sort_desc_disabled.png +0 -0
  53. assets/dependencies/datatables/js/jquery.dataTables.js +14840 -0
  54. assets/dependencies/datatables/js/jquery.dataTables.min.js +157 -0
  55. assets/dependencies/index.php +4 -0
  56. assets/dependencies/qtip/index.php +4 -0
  57. {js → assets/dependencies/qtip}/jquery.qtip.min.js +0 -0
  58. assets/dependencies/rickshaw/d3.v3.min.js +5 -0
  59. assets/dependencies/rickshaw/index.php +4 -0
  60. assets/dependencies/rickshaw/rickshaw.min.css +1 -0
  61. assets/dependencies/rickshaw/rickshaw.min.js +3 -0
  62. {img → assets/img}/banner-ga-ecommerce.png +0 -0
  63. {img → assets/img}/banner-premium-ga.png +0 -0
  64. {img → assets/img}/banner-website-review.png +0 -0
  65. {img → assets/img}/eBook_261x130.png +0 -0
  66. {img → assets/img}/eComm_130x100.png +0 -0
  67. {img → assets/img}/ga-premium-banner.png +0 -0
  68. assets/img/index.php +4 -0
  69. {img → assets/img}/question-mark.png +0 -0
  70. assets/index.php +4 -0
  71. assets/js/index.php +4 -0
  72. {js → assets/js}/yoast_ga_admin.js +0 -0
  73. {js → assets/js}/yoast_ga_admin.min.js +0 -0
  74. assets/js/yoast_ga_admin_dashboard.js +476 -0
  75. assets/js/yoast_ga_admin_dashboard.min.js +1 -0
  76. css/chosen.min.css +0 -1
  77. css/yoast_ga_styles.min.css +0 -1
  78. frontend/class-frontend.php +2 -8
  79. googleanalytics.php +2 -2
  80. includes/class-autoload.php +32 -18
  81. includes/class-options.php +7 -2
  82. includes/class-utils.php +23 -0
  83. js/chosen-sprite@2x.png +0 -0
  84. readme.txt +10 -1
admin/api-libs/class-api-libs.php CHANGED
@@ -102,6 +102,13 @@ if ( ! class_exists( 'Yoast_Api_Libs' ) ) {
102
  return false;
103
  }
104
 
 
 
 
 
 
 
 
105
  public function get_instance( $name ) {
106
  if ( isset( self::$instances[$name] ) ) {
107
  return self::$instances[$name];
102
  return false;
103
  }
104
 
105
+ /**
106
+ * Get instance
107
+ *
108
+ * @param $name
109
+ *
110
+ * @return bool
111
+ */
112
  public function get_instance( $name ) {
113
  if ( isset( self::$instances[$name] ) ) {
114
  return self::$instances[$name];
admin/api-libs/googleanalytics/class-api-googleanalytics.php CHANGED
@@ -10,7 +10,7 @@ if ( ! class_exists( 'Yoast_Api_Googleanalytics' ) ) {
10
  * This class will be loaded when someone calls the API library with the Google analytics module
11
  */
12
  public function __construct() {
13
-
14
  }
15
 
16
  /**
@@ -28,54 +28,6 @@ if ( ! class_exists( 'Yoast_Api_Googleanalytics' ) ) {
28
  }
29
  }
30
 
31
- /**
32
- * Doing request to Google Analytics
33
- *
34
- * This method will do a request to google and get the response code and body from content
35
- *
36
- * @param string $target_url
37
- * @param string $scope
38
- * @param string $access_token
39
- * @param string secret
40
- *
41
- * @return array|null
42
- */
43
- public function do_request( $target_url, $scope, $access_token, $secret ) {
44
- $gdata = $this->get_gdata( $scope, $access_token, $secret );
45
- $response = $gdata->get( $target_url );
46
- $http_code = wp_remote_retrieve_response_code( $response );
47
- $response = wp_remote_retrieve_body( $response );
48
-
49
- if ( $http_code == 200 ) {
50
- return array(
51
- 'response' => array( 'code' => $http_code ),
52
- 'body' => $response,
53
- );
54
- }
55
- }
56
-
57
- /**
58
- * Getting WP_GData object
59
- *
60
- * If not available include class file and create an instance of WP_GDAta
61
- *
62
- * @param string $scope
63
- * @param null $token
64
- * @param null $secret
65
- *
66
- * @return WP_GData
67
- */
68
- protected function get_gdata( $scope, $token = null, $secret = null ) {
69
- $args = array(
70
- 'scope' => $scope,
71
- 'xoauth_displayname' => 'Google Analytics by Yoast',
72
- );
73
-
74
- $gdata = new WP_GData( $args, $token, $secret );
75
-
76
- return $gdata;
77
- }
78
-
79
  }
80
 
81
  }
10
  * This class will be loaded when someone calls the API library with the Google analytics module
11
  */
12
  public function __construct() {
13
+ $this->load_api_oauth_files();
14
  }
15
 
16
  /**
28
  }
29
  }
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  }
32
 
33
  }
admin/api-libs/googleanalytics/class-googleanalytics-reporting.php CHANGED
@@ -0,0 +1,210 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Yoast_Googleanalytics_Reporting {
4
+
5
+ /**
6
+ * Store this instance
7
+ *
8
+ * @var null
9
+ */
10
+ private static $instance = null;
11
+
12
+ /**
13
+ * Getting the instance object
14
+ *
15
+ * This method will return the instance of itself, if instance not exists, becauses of it's called for the first
16
+ * time, the instance will be created.
17
+ *
18
+ * @return null|Yoast_Google_Analytics
19
+ */
20
+ public static function instance() {
21
+ if ( is_null( self::$instance ) ) {
22
+ self::$instance = new self();
23
+ }
24
+
25
+ return self::$instance;
26
+ }
27
+
28
+ /**
29
+ * Doing request to Google Analytics
30
+ *
31
+ * This method will do a request to google and get the response code and body from content
32
+ *
33
+ * @param string $target_url
34
+ * @param string $scope
35
+ * @param string $access_token
36
+ * @param string secret
37
+ * @param string table,datelist
38
+ * @param int $start_date Unix timestamp
39
+ * @param int $end_date Unix timestamp
40
+ *
41
+ * @return array|null
42
+ */
43
+ public function do_api_request( $target_url, $scope, $access_token, $secret, $store_as, $start_date, $end_date ) {
44
+ $gdata = $this->get_gdata( $scope, $access_token, $secret );
45
+ $response = $gdata->get( $target_url );
46
+ $http_code = wp_remote_retrieve_response_code( $response );
47
+ $response = wp_remote_retrieve_body( $response );
48
+
49
+ if ( $http_code == 200 ) {
50
+ return array(
51
+ 'response' => array( 'code' => $http_code ),
52
+ 'body_raw' => $response,
53
+ 'body' => $this->parse_response( json_decode( $response ), $store_as, $start_date, $end_date ),
54
+ );
55
+ } else {
56
+ return array(
57
+ 'body_raw' => $response,
58
+ 'response' => $response,
59
+ 'http_code' => $http_code,
60
+ 'gdata' => $gdata,
61
+ );
62
+ }
63
+ }
64
+
65
+ /**
66
+ * Getting WP_GData object
67
+ *
68
+ * If not available include class file and create an instance of WP_GDAta
69
+ *
70
+ * @param string $scope
71
+ * @param null $token
72
+ * @param null $secret
73
+ *
74
+ * @return WP_GData
75
+ */
76
+ protected function get_gdata( $scope, $token = null, $secret = null ) {
77
+ $args = array(
78
+ 'scope' => $scope,
79
+ 'xoauth_displayname' => 'Google Analytics by Yoast',
80
+ );
81
+
82
+ $gdata = new WP_GData( $args, $token, $secret );
83
+
84
+ return $gdata;
85
+ }
86
+
87
+ /**
88
+ * Format a response
89
+ *
90
+ * @param $raw_data
91
+ * @param $store_as
92
+ * @param $start_date
93
+ * @param $end_date
94
+ *
95
+ * @return array
96
+ */
97
+ private function parse_response( $raw_data, $store_as, $start_date, $end_date ) {
98
+ $data = array();
99
+
100
+ if ( $store_as == 'datelist' ) {
101
+ $data_tmp = $this->date_range( strtotime( $start_date ), strtotime( $end_date ) );
102
+ $data = array_keys( $data_tmp );
103
+ }
104
+
105
+ if ( isset( $raw_data->rows ) && is_array( $raw_data->rows ) ) {
106
+ foreach ( $raw_data->rows as $key => $item ) {
107
+ if ( $store_as == 'datelist' ) {
108
+ $data[(int) $this->format_ga_date( $item[0] )] = $this->parse_row( $item );
109
+ } else {
110
+ $data[] = $this->parse_data_row( $item );
111
+ }
112
+ }
113
+ }
114
+
115
+ if ( $store_as == 'datelist' ) {
116
+ $data = $this->check_validity_data( $data );
117
+ }
118
+
119
+ return $data;
120
+ }
121
+
122
+ /**
123
+ * Check the key on valid unix timestamps and remove invalid keys
124
+ *
125
+ * @param array $data
126
+ *
127
+ * @return array
128
+ */
129
+ private function check_validity_data( $data = array() ) {
130
+ foreach( $data as $key => $value ){
131
+ if(strlen($key)<=5){
132
+ unset($data[$key]);
133
+ }
134
+ }
135
+
136
+ return $data;
137
+ }
138
+
139
+ /**
140
+ * Format the GA date value
141
+ *
142
+ * @param $date
143
+ *
144
+ * @return int
145
+ */
146
+ private function format_ga_date( $date ) {
147
+ $year = substr( $date, 0, 4 );
148
+ $month = substr( $date, 4, 2 );
149
+ $day = substr( $date, 6, 2 );
150
+
151
+ return strtotime( $year . '-' . $month . '-' . $day );
152
+ }
153
+
154
+ /**
155
+ * Parse a row and return an array with the correct data rows
156
+ *
157
+ * @param $item
158
+ *
159
+ * @return array
160
+ */
161
+ private function parse_row( $item ) {
162
+ if ( isset( $item[2] ) ) {
163
+ return array(
164
+ 'date' => (int) $this->format_ga_date( $item[0] ),
165
+ 'value' => (string) $item[1],
166
+ 'total' => (int) $item[2],
167
+ );
168
+ } else {
169
+ return (int) $item[1];
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Parse a row for the list storage type
175
+ *
176
+ * @param $item
177
+ *
178
+ * @return array
179
+ */
180
+ private function parse_data_row( $item ) {
181
+ return array(
182
+ 'name' => (string) $item[0],
183
+ 'value' => (int) $item[1],
184
+ );
185
+ }
186
+
187
+ /**
188
+ * Calculate the date range between 2 dates
189
+ *
190
+ * @param $first
191
+ * @param $last
192
+ * @param string $step
193
+ * @param string $format
194
+ *
195
+ * @return array
196
+ */
197
+ private function date_range( $first, $last, $step = '+1 day', $format = 'Y-m-d' ) {
198
+ $dates = array();
199
+ $current = $first;
200
+ $last = $last;
201
+
202
+ while ( $current <= $last ) {
203
+ $dates[] = date( $format, $current );
204
+ $current = strtotime( $step, $current );
205
+ }
206
+
207
+ return $dates;
208
+ }
209
+
210
+ }
admin/class-admin-assets.php ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * This class is for the backend
5
+ */
6
+ if ( ! class_exists( 'Yoast_GA_Admin_Assets' ) ) {
7
+
8
+ class Yoast_GA_Admin_Assets {
9
+
10
+ /**
11
+ * Add the scripts to the admin head
12
+ */
13
+ public static function enqueue_scripts() {
14
+ wp_enqueue_script( 'yoast_ga_admin', self::get_asset_path( 'assets/js/yoast_ga_admin' ) . self::file_ext( '.js' ) );
15
+
16
+ // Enqueue the qtip js file
17
+ wp_enqueue_script( 'jquery-qtip', self::get_asset_path( 'assets/dependencies/qtip/jquery.qtip.min.js' ) , array( 'jquery' ), '1.0.0-RC3', true );
18
+
19
+ // Enqueue the chosen js file
20
+ wp_enqueue_script( 'chosen_js', self::get_asset_path( 'assets/dependencies/chosen/chosen.jquery.min.js' ), array(), false, true );
21
+ }
22
+
23
+ /**
24
+ * Add the styles in the admin head
25
+ */
26
+ public static function enqueue_styles() {
27
+ wp_enqueue_style( 'yoast_ga_styles', self::get_asset_path( 'assets/css/yoast_ga_styles' ) . self::file_ext( '.css' ) );
28
+ }
29
+
30
+ /**
31
+ * Enqueues the settings page specific styles
32
+ */
33
+ public static function enqueue_settings_styles() {
34
+ // Enqueue the chosen css file
35
+ wp_enqueue_style( 'chosen_css', self::get_asset_path( 'assets/dependencies/chosen/chosen' ) . self::file_ext( '.css' ) );
36
+ }
37
+
38
+ /**
39
+ * Loading the assets for dashboard
40
+ */
41
+ public static function enqueue_dashboard_assets() {
42
+
43
+ //
44
+ wp_enqueue_script('ga-admin-dashboard', self::get_asset_path( 'assets/js/yoast_ga_admin_dashboard' ) . self::file_ext( '.js' ) );
45
+ wp_enqueue_style('ga-admin-dashboard-css', self::get_asset_path( 'assets/css/yoast_ga_admin_dashboard' ). self::file_ext( '.css' ) ) ;
46
+
47
+ // Enqueue the d3 js file
48
+ wp_enqueue_script( 'd3_js', self::get_asset_path( 'assets/dependencies/rickshaw/d3.v3.min.js' ), array(), false, true );
49
+
50
+ // Enqueue the ricksaw js file
51
+ wp_enqueue_script( 'rickshaw_js', self::get_asset_path( 'assets/dependencies/rickshaw/rickshaw.min.js' ), array(), false, true );
52
+
53
+ // Enqueue the rickshaw css
54
+ wp_enqueue_style( 'rickshaw_css', self::get_asset_path( 'assets/dependencies/rickshaw/rickshaw.min.css' ) );
55
+
56
+ // Enqueue the datatables js file
57
+ wp_enqueue_script( 'datatables_js', self::get_asset_path( 'assets/dependencies/datatables/js/jquery.dataTables.min.js' ), array(), false, true );
58
+
59
+ // Enqueue the datatables css
60
+ wp_enqueue_style( 'datatables_css', self::get_asset_path( 'assets/dependencies/datatables/css/jquery.dataTables.min.css' ) );
61
+
62
+ Yoast_GA_Dashboards::get_instance()->add_dashboard_js_translations();
63
+ }
64
+
65
+ /**
66
+ * Getting the full path to given $asset
67
+ *
68
+ * @param string $asset
69
+ *
70
+ * @return string
71
+ */
72
+ private static function get_asset_path( $asset ) {
73
+ static $plugin_directory;
74
+
75
+ if ( $plugin_directory == null ) {
76
+ $plugin_directory = plugin_dir_url( GAWP_FILE );
77
+ }
78
+
79
+ $return = $plugin_directory . $asset;
80
+
81
+ return $return;
82
+ }
83
+
84
+ /**
85
+ * Check whether we can include the minified version or not
86
+ *
87
+ * @param string $ext
88
+ *
89
+ * @return string
90
+ */
91
+ private static function file_ext( $ext ) {
92
+ if ( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) {
93
+ $ext = '.min' . $ext;
94
+ }
95
+
96
+ return $ext;
97
+ }
98
+
99
+ }
100
+
101
+ }
admin/class-admin-dashboards-aggregate.php DELETED
@@ -1,19 +0,0 @@
1
- <?php
2
-
3
- if ( ! class_exists( 'Yoast_GA_Dashboards_Aggregrate' ) ) {
4
-
5
- class Yoast_GA_Dashboards_Aggregrate extends Yoast_GA_Dashboards {
6
-
7
- private $api;
8
-
9
- /**
10
- * Construct on the dashboards class for GA
11
- */
12
- public function __construct(){
13
-
14
- $this->api = Yoast_Api_Libs::load_api_libraries( array( 'oauth' ) );
15
- }
16
-
17
- }
18
-
19
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/class-admin-dashboards.php DELETED
@@ -1,16 +0,0 @@
1
- <?php
2
-
3
- if ( ! class_exists( 'Yoast_GA_Dashboards' ) ) {
4
-
5
- class Yoast_GA_Dashboards extends Yoast_GA_Admin {
6
-
7
- /**
8
- * Construct on the dashboards class for GA
9
- */
10
- public function __construct(){
11
-
12
- }
13
-
14
- }
15
-
16
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/class-admin-form.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * This class is for the backend
5
+ */
6
+ if ( ! class_exists( 'Yoast_GA_Admin_Form' ) ) {
7
+
8
+ class Yoast_GA_Admin_Form {
9
+
10
+ /**
11
+ * Show a question mark with help
12
+ *
13
+ * @param string $id
14
+ * @param string $description
15
+ *
16
+ * @return string
17
+ */
18
+ public static function show_help( $id, $description ) {
19
+ $help = '<img src="' . plugins_url( 'assets/img/question-mark.png', GAWP_FILE ) . '" class="alignleft yoast_help" id="' . esc_attr( $id . 'help' ) . '" alt="' . esc_attr( $description ) . '" />';
20
+
21
+ return $help;
22
+ }
23
+
24
+ }
25
+
26
+ }
admin/class-admin-menu.php CHANGED
@@ -122,10 +122,12 @@ if ( ! class_exists( 'Yoast_GA_Admin_Menu' ) ) {
122
  * @param boolean $is_not_dashboard
123
  */
124
  private function add_assets( $page, $is_not_dashboard ) {
125
- add_action( 'admin_print_styles-' . $page, array( $this->target_object, 'enqueue_styles' ) );
126
- if ( $is_not_dashboard ) {
127
- add_action( 'admin_print_styles-' . $page, array( $this->target_object, 'enqueue_settings_styles' ) );
128
- add_action( 'admin_print_scripts-' . $page, array( $this->target_object, 'enqueue_scripts' ) );
 
 
129
  }
130
  }
131
 
122
  * @param boolean $is_not_dashboard
123
  */
124
  private function add_assets( $page, $is_not_dashboard ) {
125
+ add_action( 'admin_print_styles-' . $page, array( 'Yoast_GA_Admin_Assets', 'enqueue_styles' ) );
126
+
127
+ add_action( 'admin_print_styles-' . $page, array( 'Yoast_GA_Admin_Assets', 'enqueue_settings_styles' ) );
128
+ add_action( 'admin_print_scripts-' . $page, array( 'Yoast_GA_Admin_Assets', 'enqueue_scripts' ) );
129
+ if ( ! $is_not_dashboard ) {
130
+ Yoast_GA_Admin_Assets::enqueue_dashboard_assets();
131
  }
132
  }
133
 
admin/class-admin.php CHANGED
@@ -32,7 +32,6 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
32
 
33
  add_filter( 'plugin_action_links_' . plugin_basename( GAWP_FILE ), array( $this, 'add_action_links' ) );
34
 
35
- $this->api = Yoast_Api_Libs::load_api_libraries( array( 'oauth' ) );
36
  }
37
 
38
  /**
@@ -40,6 +39,7 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
40
  */
41
  public function init_settings() {
42
  $this->options = $this->get_options();
 
43
 
44
  if ( is_null( $this->get_tracking_code() ) ) {
45
  add_action( 'admin_notices', array( $this, 'config_warning' ) );
@@ -67,6 +67,10 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
67
  $this->show_notification( 'ga_notifications' );
68
 
69
  $this->connect_with_google_analytics();
 
 
 
 
70
  }
71
 
72
  /**
@@ -91,10 +95,14 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
91
  }
92
  }
93
 
 
 
 
 
94
  // Check checkboxes, on a uncheck they won't be posted to this function
95
  $defaults = $this->default_ga_values();
96
  foreach ( $defaults[$this->option_prefix] as $key => $value ) {
97
- if ( ! isset( $data[$key] ) ) {
98
  $this->options[$key] = $value;
99
  }
100
  }
@@ -119,6 +127,26 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
119
  exit;
120
  }
121
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  /**
123
  * Add a link to the settings page to the plugins list
124
  *
@@ -138,48 +166,6 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
138
  return $links;
139
  }
140
 
141
- /**
142
- * Check whether we can include the minified version or not
143
- *
144
- * @param string $ext
145
- *
146
- * @return string
147
- */
148
- private function file_ext( $ext ) {
149
- if ( ! defined( 'SCRIPT_DEBUG' ) || ! SCRIPT_DEBUG ) {
150
- $ext = '.min' . $ext;
151
- }
152
-
153
- return $ext;
154
- }
155
-
156
- /**
157
- * Add the scripts to the admin head
158
- */
159
- public function enqueue_scripts() {
160
- wp_enqueue_script( 'jquery-qtip', $this->plugin_url . 'js/jquery.qtip.min.js', array( 'jquery' ), '1.0.0-RC3', true );
161
-
162
- wp_enqueue_script( 'yoast_ga_admin', $this->plugin_url . 'js/yoast_ga_admin' . $this->file_ext( '.js' ) );
163
-
164
- // Eqneue the chosen js file
165
- wp_enqueue_script( 'chosen_js', plugins_url( 'js/chosen.jquery.min.js', GAWP_FILE ), array(), false, true );
166
- }
167
-
168
- /**
169
- * Add the styles in the admin head
170
- */
171
- public function enqueue_styles() {
172
- wp_enqueue_style( 'yoast_ga_styles', $this->plugin_url . 'css/yoast_ga_styles' . $this->file_ext( '.css' ) );
173
- }
174
-
175
- /**
176
- * Enqueues the settings page specific styles
177
- */
178
- public function enqueue_settings_styles() {
179
- // Enqueue the chosen css file
180
- wp_enqueue_style( 'chosen_css', $this->plugin_url . 'css/chosen' . $this->file_ext( '.css' ) );
181
- }
182
-
183
  /**
184
  * Adds some promo text for the premium plugin on the custom dimensions tab.
185
  */
@@ -226,11 +212,14 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
226
  add_action( 'yst_ga_custom_dimensions_tab-content', array( $this, 'premium_promo' ) );
227
  }
228
 
 
 
 
 
229
  if ( isset( $_GET['page'] ) ) {
230
  switch ( $_GET['page'] ) {
231
  case 'yst_ga_settings':
232
  require_once( $this->plugin_path . 'admin/pages/settings.php' );
233
-
234
  break;
235
  case 'yst_ga_extensions':
236
  require_once( $this->plugin_path . 'admin/pages/extensions.php' );
@@ -335,7 +324,7 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
335
  * @return string
336
  */
337
  private function show_help( $id, $description ) {
338
- $help = '<img src="' . plugins_url( 'img/question-mark.png', GAWP_FILE ) . '" class="alignleft yoast_help" id="' . esc_attr( $id . 'help' ) . '" alt="' . esc_attr( $description ) . '" />';
339
 
340
  return $help;
341
  }
@@ -372,23 +361,20 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
372
  $select .= '<select name="' . $name . '" id="yoast-ga-form-select-' . $this->form_namespace . '-' . $id . '">';
373
  }
374
  if ( count( $values ) >= 1 ) {
375
- foreach ( $values as $value ) {
376
- if( isset($value['parent_name']) ){
377
- $select .= '<optgroup label="' . $value['parent_name'] . '">';
378
- }
379
 
380
- if ( is_array( $this->options[$name] ) ) {
381
- if ( in_array( $value['id'], $this->options[$name] ) ) {
382
- $select .= '<option value="' . $value['id'] . '" selected="selected">' . stripslashes( $value['name'] ) . '</option>';
383
- } else {
384
- $select .= '<option value="' . $value['id'] . '">' . stripslashes( $value['name'] ) . '</option>';
 
 
385
  }
386
- } else {
387
- $select .= '<option value="' . $value['id'] . '" ' . selected( $this->options[$name], $value['id'], false ) . '>' . stripslashes( $value['name'] ) . '</option>';
388
- }
389
 
390
- if( isset($value['parent_name']) ){
391
  $select .= '</optgroup>';
 
 
 
392
  }
393
  }
394
  }
@@ -403,6 +389,47 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
403
  return $select;
404
  }
405
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  /**
407
  * Generate a textarea field
408
  *
@@ -473,6 +500,22 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
473
  }
474
  }
475
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
476
  /**
477
  * Get the user roles of this WordPress blog
478
  *
@@ -555,22 +598,22 @@ if ( ! class_exists( 'Yoast_GA_Admin' ) ) {
555
  $banners = array();
556
  $banners[] = array(
557
  'url' => 'https://yoast.com/hire-us/website-review/#utm_medium=banner&utm_source=gawp-config&utm_campaign=wpgaplugin',
558
- 'banner' => $this->plugin_url . 'img/banner-website-review.png',
559
  'title' => 'Get a website review by Yoast',
560
  );
561
  $banners[] = array(
562
  'url' => 'https://yoast.com/wordpress/plugins/google-analytics/#utm_medium=banner&utm_source=gawp-config&utm_campaign=wpgaplugin',
563
- 'banner' => $this->plugin_url . 'img/banner-premium-ga.png',
564
  'title' => 'Get the premium version of Google Analytics by Yoast!',
565
  );
566
  $banners[] = array(
567
  'url' => 'https://yoast.com/ebook-optimize-wordpress-site/#utm_medium=banner&utm_source=gawp-config&utm_campaign=wpgaplugin',
568
- 'banner' => $this->plugin_url . 'img/eBook_261x130.png',
569
  'title' => 'Get the Yoast ebook!',
570
  );
571
  $banners[] = array(
572
  'url' => 'https://yoast.com/wordpress/plugins/ga-ecommerce/#utm_medium=banner&utm_source=gawp-config&utm_campaign=wpgaplugin',
573
- 'banner' => $this->plugin_url . 'img/banner-ga-ecommerce.png',
574
  'title' => 'Get advanced eCommerce tracking for WooCommerce and Easy Digital Downloads!',
575
  );
576
 
32
 
33
  add_filter( 'plugin_action_links_' . plugin_basename( GAWP_FILE ), array( $this, 'add_action_links' ) );
34
 
 
35
  }
36
 
37
  /**
39
  */
40
  public function init_settings() {
41
  $this->options = $this->get_options();
42
+ $this->api = Yoast_Api_Libs::load_api_libraries( array( 'oauth', 'googleanalytics' ) );
43
 
44
  if ( is_null( $this->get_tracking_code() ) ) {
45
  add_action( 'admin_notices', array( $this, 'config_warning' ) );
67
  $this->show_notification( 'ga_notifications' );
68
 
69
  $this->connect_with_google_analytics();
70
+
71
+ // Load the Google Analytics Dashboards functionality
72
+ $dashboards = Yoast_GA_Dashboards::get_instance();
73
+ $dashboards->init_dashboards( $this->get_current_profile() );
74
  }
75
 
76
  /**
95
  }
96
  }
97
 
98
+ if ( ! empty( $this->options['analytics_profile'] ) ) {
99
+ $this->options['analytics_profile_code'] = $this->get_ua_code_from_profile( $this->options['analytics_profile'] );
100
+ }
101
+
102
  // Check checkboxes, on a uncheck they won't be posted to this function
103
  $defaults = $this->default_ga_values();
104
  foreach ( $defaults[$this->option_prefix] as $key => $value ) {
105
+ if ( ! isset( $data[$key] ) && ! isset( $this->options[$key] ) ) {
106
  $this->options[$key] = $value;
107
  }
108
  }
127
  exit;
128
  }
129
 
130
+ /**
131
+ * Transform the Profile ID into an helpful UA code
132
+ *
133
+ * @param $profile_id
134
+ *
135
+ * @return null
136
+ */
137
+ private function get_ua_code_from_profile( $profile_id ) {
138
+ $profiles = $this->get_profiles();
139
+ $ua_code = null;
140
+
141
+ foreach ( $profiles as $profile ) {
142
+ if ( isset( $profile['id'] ) && $profile['id'] == $profile_id ) {
143
+ $ua_code = $profile['ua_code'];
144
+ }
145
+ }
146
+
147
+ return $ua_code;
148
+ }
149
+
150
  /**
151
  * Add a link to the settings page to the plugins list
152
  *
166
  return $links;
167
  }
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  /**
170
  * Adds some promo text for the premium plugin on the custom dimensions tab.
171
  */
212
  add_action( 'yst_ga_custom_dimensions_tab-content', array( $this, 'premium_promo' ) );
213
  }
214
 
215
+ if ( ! has_action( 'yst_ga_custom_dimension_add-dashboards-tab' ) ) {
216
+ add_action( 'yst_ga_custom_dimension_add-dashboards-tab', array( $this, 'premium_promo' ) );
217
+ }
218
+
219
  if ( isset( $_GET['page'] ) ) {
220
  switch ( $_GET['page'] ) {
221
  case 'yst_ga_settings':
222
  require_once( $this->plugin_path . 'admin/pages/settings.php' );
 
223
  break;
224
  case 'yst_ga_extensions':
225
  require_once( $this->plugin_path . 'admin/pages/extensions.php' );
324
  * @return string
325
  */
326
  private function show_help( $id, $description ) {
327
+ $help = '<img src="' . plugins_url( 'assets/img/question-mark.png', GAWP_FILE ) . '" class="alignleft yoast_help" id="' . esc_attr( $id . 'help' ) . '" alt="' . esc_attr( $description ) . '" />';
328
 
329
  return $help;
330
  }
361
  $select .= '<select name="' . $name . '" id="yoast-ga-form-select-' . $this->form_namespace . '-' . $id . '">';
362
  }
363
  if ( count( $values ) >= 1 ) {
 
 
 
 
364
 
365
+ foreach ( $values as $optgroup => $value ) {
366
+
367
+ if( !empty($value['options'])) {
368
+ $select .= '<optgroup label="' . $optgroup . '">';
369
+
370
+ foreach($value['options'] AS $option) {
371
+ $select .= $this->option($name, $option);
372
  }
 
 
 
373
 
 
374
  $select .= '</optgroup>';
375
+
376
+ } else {
377
+ $select .= $this->option($name, $value);
378
  }
379
  }
380
  }
389
  return $select;
390
  }
391
 
392
+ /**
393
+ * Parsing a option string for select
394
+ *
395
+ * @param string $name
396
+ * @param string $value
397
+ *
398
+ * @return string
399
+ */
400
+ private function option($name, $value) {
401
+ if ( is_array( $this->options[$name] ) ) {
402
+ if ( in_array( $value['id'], $this->options[$name] ) ) {
403
+ return '<option value="' . $value['id'] . '" selected="selected">' . stripslashes( $value['name'] ) . '</option>';
404
+ } else {
405
+ return '<option value="' . $value['id'] . '">' . stripslashes( $value['name'] ) . '</option>';
406
+ }
407
+ } else {
408
+ return '<option value="' . $value['id'] . '" ' . selected( $this->options[$name], $value['id'], false ) . '>' . stripslashes( $value['name'] ) . '</option>';
409
+ }
410
+ }
411
+
412
+ /**
413
+ * Will parse the optgroups.
414
+ *
415
+ * @param array $values
416
+ *
417
+ * @return array
418
+ */
419
+ public function parse_optgroups($values) {
420
+
421
+ $optgroups = array();
422
+ foreach($values AS $key => $value) {
423
+ if(empty($value['parent_name'])) {
424
+ $current = $value;
425
+ } else {
426
+ $optgroups[$value['parent_name']]['options'][] = $current;
427
+ }
428
+ }
429
+
430
+ return $optgroups;
431
+ }
432
+
433
  /**
434
  * Generate a textarea field
435
  *
500
  }
501
  }
502
 
503
+ /**
504
+ * Get the current GA profile
505
+ *
506
+ * @return null
507
+ */
508
+ private function get_current_profile() {
509
+ $current_profile = null;
510
+ foreach ( $this->get_profiles() as $profile ) {
511
+ if ( ! empty( $profile['id'] ) && $profile['id'] == $this->options['analytics_profile'] ) {
512
+ $current_profile = $profile['profile_id'];
513
+ }
514
+ }
515
+
516
+ return $current_profile;
517
+ }
518
+
519
  /**
520
  * Get the user roles of this WordPress blog
521
  *
598
  $banners = array();
599
  $banners[] = array(
600
  'url' => 'https://yoast.com/hire-us/website-review/#utm_medium=banner&utm_source=gawp-config&utm_campaign=wpgaplugin',
601
+ 'banner' => $this->plugin_url . 'assets/img/banner-website-review.png',
602
  'title' => 'Get a website review by Yoast',
603
  );
604
  $banners[] = array(
605
  'url' => 'https://yoast.com/wordpress/plugins/google-analytics/#utm_medium=banner&utm_source=gawp-config&utm_campaign=wpgaplugin',
606
+ 'banner' => $this->plugin_url . 'assets/img/banner-premium-ga.png',
607
  'title' => 'Get the premium version of Google Analytics by Yoast!',
608
  );
609
  $banners[] = array(
610
  'url' => 'https://yoast.com/ebook-optimize-wordpress-site/#utm_medium=banner&utm_source=gawp-config&utm_campaign=wpgaplugin',
611
+ 'banner' => $this->plugin_url . 'assets/img/eBook_261x130.png',
612
  'title' => 'Get the Yoast ebook!',
613
  );
614
  $banners[] = array(
615
  'url' => 'https://yoast.com/wordpress/plugins/ga-ecommerce/#utm_medium=banner&utm_source=gawp-config&utm_campaign=wpgaplugin',
616
+ 'banner' => $this->plugin_url . 'assets/img/banner-ga-ecommerce.png',
617
  'title' => 'Get advanced eCommerce tracking for WooCommerce and Easy Digital Downloads!',
618
  );
619
 
admin/class-google-analytics.php CHANGED
@@ -275,9 +275,11 @@ if ( ! class_exists( 'Yoast_Google_Analytics', false ) ) {
275
  }
276
 
277
  foreach ( $ga_accounts as $key => $ga_account ) {
278
- $tmp_array = array(
279
- 'id' => $ga_account['ua'],
280
- 'name' => $ga_account['title'] . ' (' . $ga_account['ua'] . ')',
 
 
281
  );
282
 
283
  if ( isset( $this->options['ga_api_response_accounts'][$ga_account['ua']] ) ) {
@@ -326,6 +328,8 @@ if ( ! class_exists( 'Yoast_Google_Analytics', false ) ) {
326
  $ns = $entry->getNamespaces( true );
327
  $properties = $entry->children( $ns['dxp'] )->property;
328
 
 
 
329
  if ( isset ( $properties[$ua_key]->attributes()->value ) ) {
330
  $ua = (string) trim( $properties[$ua_key]->attributes()->value );
331
  }
@@ -336,8 +340,9 @@ if ( ! class_exists( 'Yoast_Google_Analytics', false ) ) {
336
 
337
  if ( ! empty( $ua ) && ! empty( $title ) ) {
338
  $return[] = array(
339
- 'ua' => $ua,
340
- 'title' => $title,
 
341
  );
342
  }
343
  }
@@ -364,7 +369,7 @@ if ( ! class_exists( 'Yoast_Google_Analytics', false ) ) {
364
  *
365
  * @return mixed
366
  */
367
- protected function get_options() {
368
  return get_option( $this->option_name );
369
  }
370
 
275
  }
276
 
277
  foreach ( $ga_accounts as $key => $ga_account ) {
278
+ $return[] = array(
279
+ 'id' => $ga_account['profile_id'],
280
+ 'profile_id' => $ga_account['profile_id'],
281
+ 'ua_code' => $ga_account['ua'],
282
+ 'name' => $ga_account['title'] . ' (' . $ga_account['ua'] . ')',
283
  );
284
 
285
  if ( isset( $this->options['ga_api_response_accounts'][$ga_account['ua']] ) ) {
328
  $ns = $entry->getNamespaces( true );
329
  $properties = $entry->children( $ns['dxp'] )->property;
330
 
331
+ $profile_id = (int) $properties[3]->attributes()->value; // ga:profileId
332
+
333
  if ( isset ( $properties[$ua_key]->attributes()->value ) ) {
334
  $ua = (string) trim( $properties[$ua_key]->attributes()->value );
335
  }
340
 
341
  if ( ! empty( $ua ) && ! empty( $title ) ) {
342
  $return[] = array(
343
+ 'ua' => $ua,
344
+ 'profile_id' => $profile_id,
345
+ 'title' => $title,
346
  );
347
  }
348
  }
369
  *
370
  * @return mixed
371
  */
372
+ public function get_options() {
373
  return get_option( $this->option_name );
374
  }
375
 
admin/dashboards/class-admin-dashboards-api-options.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Api_Options' ) ) {
4
+
5
+ class Yoast_GA_Dashboards_Api_Options {
6
+
7
+ /**
8
+ * Store this instance
9
+ *
10
+ * @var null
11
+ */
12
+ private static $instance = null;
13
+
14
+ /**
15
+ * Store the access token
16
+ *
17
+ * @var
18
+ */
19
+ private $access_token;
20
+
21
+ /**
22
+ * Store the options
23
+ *
24
+ * @var
25
+ */
26
+ private $options;
27
+
28
+ /**
29
+ * Construct on the dashboards class for GA
30
+ */
31
+ protected function __construct() {
32
+ $this->set_options();
33
+ }
34
+
35
+ /**
36
+ * Get the instance
37
+ *
38
+ * @return Yoast_GA_Dashboards
39
+ */
40
+ public static function get_instance() {
41
+ if ( is_null( self::$instance ) ) {
42
+ self::$instance = new self();
43
+ }
44
+
45
+ return self::$instance;
46
+ }
47
+
48
+ /**
49
+ * Set the API options
50
+ */
51
+ public function set_options() {
52
+ $this->options = Yoast_Google_Analytics::instance()->get_options();
53
+
54
+ $this->set_access_token();
55
+ }
56
+
57
+ /**
58
+ * Set the access token if we have one
59
+ */
60
+ private function set_access_token() {
61
+ if ( isset( $this->options['ga_oauth']['access_token']['oauth_token'] ) && isset( $this->options['ga_oauth']['access_token']['oauth_token_secret'] ) ) {
62
+ $this->access_token = $this->options['ga_oauth']['access_token'];
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Get the API options
68
+ *
69
+ * @return mixed
70
+ */
71
+ public function get_options() {
72
+ return $this->options;
73
+ }
74
+
75
+ /**
76
+ * Get the access token from the options API, false on fail
77
+ *
78
+ * @return bool
79
+ */
80
+ public function get_access_token() {
81
+ if ( ! empty( $this->access_token ) ) {
82
+ return $this->access_token;
83
+ } else {
84
+ return false;
85
+ }
86
+ }
87
+
88
+ }
89
+
90
+ }
admin/dashboards/class-admin-dashboards-collector.php ADDED
@@ -0,0 +1,432 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Collector' ) ) {
4
+
5
+ class Yoast_GA_Dashboards_Collector {
6
+
7
+ /**
8
+ * API storage
9
+ *
10
+ * @package
11
+ */
12
+ public $api;
13
+
14
+ /**
15
+ * Store the active metrics
16
+ *
17
+ * @var
18
+ */
19
+ public $active_metrics;
20
+
21
+ /**
22
+ * Store the dimensions
23
+ *
24
+ * @var array
25
+ */
26
+ private $dimensions = array();
27
+
28
+ /**
29
+ * Store the valid metrics, which should be
30
+ *
31
+ * @var array
32
+ */
33
+ private $valid_metrics = array();
34
+
35
+ /**
36
+ * Store the GA Profile ID
37
+ *
38
+ * @var
39
+ */
40
+ public $ga_profile_id;
41
+
42
+ /**
43
+ * The $_GET pages where the shutdown hook should be executed to aggregate data
44
+ *
45
+ * @var array
46
+ */
47
+ private $shutdown_get_pages = array( 'yst_ga_dashboard' );
48
+
49
+ /**
50
+ * The $_SERVER['SCRIPT_NAME'] pages where the shutdown hook should be executed to aggregate data
51
+ */
52
+ private $shutdown_pages = array( '/wp-admin/index.php' );
53
+
54
+ /**
55
+ * Construct on the dashboards class for GA
56
+ *
57
+ * @param $ga_profile_id
58
+ * @param $active_metrics
59
+ * @param $valid_metrics
60
+ */
61
+ public function __construct( $ga_profile_id, $active_metrics, $valid_metrics ) {
62
+ $this->ga_profile_id = $ga_profile_id;
63
+
64
+ $active_metrics = $this->filter_metrics_to_dimensions( $active_metrics );
65
+ $this->active_metrics = $active_metrics;
66
+
67
+ add_filter( 'ga_dashboards_dimensions', array( $this, 'filter_dimensions' ), 10, 1 );
68
+
69
+ $this->options = Yoast_GA_Dashboards_Api_Options::get_instance();
70
+
71
+ $this->init_shutdown_hook();
72
+ }
73
+
74
+ /**
75
+ * Fetch the data from Google Analytics and store it
76
+ */
77
+ public function aggregate_data() {
78
+ $this->close_connection();
79
+ $access_tokens = $this->options->get_access_token();
80
+
81
+ if ( $access_tokens != false && is_array( $access_tokens ) ) {
82
+ // Access tokens are set, continue
83
+
84
+ /**
85
+ * Implement the metric data first
86
+ */
87
+ if ( is_array( $this->active_metrics ) && count( $this->active_metrics ) >= 1 ) {
88
+ $this->aggregate_metrics( $access_tokens, $this->active_metrics );
89
+ }
90
+
91
+ /**
92
+ * Now implement the dimensions that are set
93
+ */
94
+ if ( is_array( $this->dimensions ) && count( $this->dimensions ) >= 1 ) {
95
+ $this->aggregate_dimensions( $access_tokens, $this->dimensions );
96
+ }
97
+ } else {
98
+ // Failure on authenticating, please reauthenticate
99
+ }
100
+ }
101
+
102
+ /**
103
+ * This hook runs on the shutdown to fetch data from GA
104
+ */
105
+ private function init_shutdown_hook() {
106
+ $this->api = Yoast_Api_Libs::load_api_libraries( array( 'oauth', 'googleanalytics' ) );
107
+
108
+ if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
109
+ if ( $this->run_shutdown_hook_get() || $this->run_shutdown_hook_page() ) {
110
+ add_action( 'shutdown', array( $this, 'aggregate_data' ), 10 );
111
+
112
+ return;
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Remove metrics and set them as a dimension if needed
119
+ *
120
+ * @param $metrics
121
+ *
122
+ * @return mixed
123
+ */
124
+ private function filter_metrics_to_dimensions( $metrics ) {
125
+ $filter_metrics = $this->get_filter_metrics();
126
+
127
+ foreach ( $metrics as $key => $metric_name ) {
128
+ if ( isset( $filter_metrics[$metric_name] ) ) {
129
+ // Add and set the dimension
130
+ $dimension = array( $filter_metrics[$metric_name] );
131
+ $this->dimensions = array_merge( $this->dimensions, $dimension );
132
+
133
+ // Remove it from the metrics after we've added it into dimensions
134
+ unset( $metrics[$key] );
135
+ }
136
+ }
137
+
138
+ return $metrics;
139
+ }
140
+
141
+ /**
142
+ * Get array with metrics which we need to filter as a dimension
143
+ *
144
+ * @return array
145
+ */
146
+ private function get_filter_metrics() {
147
+ return array(
148
+ 'source' => array(
149
+ 'metric' => 'sessions',
150
+ 'dimension' => 'source',
151
+ 'storage_name' => 'source',
152
+ ),
153
+ 'top_pageviews' => array(
154
+ 'metric' => 'pageViews',
155
+ 'dimension' => 'pagePath',
156
+ 'storage_name' => 'top_pageviews',
157
+ ),
158
+ 'top_countries' => array(
159
+ 'metric' => 'sessions',
160
+ 'dimension' => 'country',
161
+ 'storage_name' => 'top_countries',
162
+ ),
163
+ );
164
+ }
165
+
166
+ /**
167
+ * Filter function for adding dimensions
168
+ *
169
+ * @filter ga_dashboards_dimensions
170
+ *
171
+ * @param $dimensions
172
+ *
173
+ * @return array
174
+ */
175
+ public function filter_dimensions( $dimensions = array() ) {
176
+ if ( is_array( $dimensions ) && count( $dimensions ) >= 1 ) {
177
+ $dimensions = array_merge( $this->dimensions, $dimensions );
178
+ $this->dimensions = $dimensions;
179
+ }
180
+
181
+ return $this->dimensions;
182
+ }
183
+
184
+ /**
185
+ * Aggregate metrics from GA. This function should be called in the shutdown function.
186
+ *
187
+ * @param $access_tokens
188
+ * @param $metrics
189
+ */
190
+ private function aggregate_metrics( $access_tokens, $metrics ) {
191
+ foreach ( $metrics as $metric ) {
192
+ $this->execute_call( $access_tokens, $metric, date( 'Y-m-d', strtotime( '-6 weeks' ) ), date( 'Y-m-d' ) );
193
+ }
194
+ }
195
+
196
+ /**
197
+ * Aggregate dimensions from GA. This function should be called in the shutdown function.
198
+ *
199
+ * @param $access_tokens
200
+ * @param $dimensions
201
+ */
202
+ private function aggregate_dimensions( $access_tokens, $dimensions ) {
203
+ foreach ( $dimensions as $dimension ) {
204
+ if ( ( isset( $dimension['id'] ) || isset( $dimension['dimension'] ) ) && isset( $dimension['metric'] ) ) {
205
+ if ( isset( $dimension['id'] ) ) {
206
+ $this->execute_call( $access_tokens, $dimension['metric'], date( 'Y-m-d', strtotime( '-1 month' ) ), date( 'Y-m-d' ), 'ga:dimension' . $dimension['id'] );
207
+ } elseif ( isset( $dimension['dimension'] ) ) {
208
+ if ( isset( $dimension['storage_name'] ) ) {
209
+ $this->execute_call( $access_tokens, $dimension['metric'], date( 'Y-m-d', strtotime( '-1 month' ) ), date( 'Y-m-d' ), 'ga:' . $dimension['dimension'], $dimension['storage_name'] );
210
+ } else {
211
+ $this->execute_call( $access_tokens, $dimension['metric'], date( 'Y-m-d', strtotime( '-1 month' ) ), date( 'Y-m-d' ), 'ga:' . $dimension['dimension'] );
212
+ }
213
+ }
214
+ }
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Check if the shutdown hook should be ran on the GET var
220
+ *
221
+ * @return bool
222
+ */
223
+ private function run_shutdown_hook_get() {
224
+ if ( isset( $_GET['page'] ) && in_array( $_GET['page'], $this->shutdown_get_pages ) ) {
225
+ return true;
226
+ }
227
+
228
+ return false;
229
+ }
230
+
231
+ /**
232
+ * Check if the shutdown hook should be ran on this page
233
+ *
234
+ * @return bool
235
+ */
236
+ private function run_shutdown_hook_page() {
237
+ if ( isset( $_SERVER['SCRIPT_NAME'] ) && in_array( $_SERVER['SCRIPT_NAME'], $this->shutdown_pages ) ) {
238
+ return true;
239
+ }
240
+
241
+ return false;
242
+ }
243
+
244
+ /**
245
+ * Execute an API call to Google Analytics and store the data in the dashboards data class
246
+ *
247
+ * @param $access_tokens
248
+ * @param $metric
249
+ * @param $start_date 2014-10-16
250
+ * @param $end_date 2014-11-20
251
+ * @param $dimensions ga:date
252
+ * @param $storage_name string
253
+ *
254
+ * @return bool
255
+ */
256
+ private function execute_call( $access_tokens, $metric, $start_date, $end_date, $dimensions = 'ga:date', $storage_name = 'auto' ) {
257
+ $dimensions = $this->prepare_dimensions( $dimensions, $metric );
258
+ $params = $this->build_params_for_call( $start_date, $end_date, $dimensions, $metric );
259
+ $storage_type = $this->get_storage_type( $dimensions );
260
+
261
+ $response = Yoast_Googleanalytics_Reporting::instance()->do_api_request(
262
+ 'https://www.googleapis.com/analytics/v3/data/ga?' . $params,
263
+ 'https://www.googleapis.com/analytics/v3/data/ga',
264
+ $access_tokens['oauth_token'],
265
+ $access_tokens['oauth_token_secret'],
266
+ $storage_type,
267
+ $start_date,
268
+ $end_date
269
+ );
270
+
271
+ if ( strpos( 'ga:date', $dimensions ) !== false ) {
272
+ return $this->handle_response( $response, $metric, $dimensions, $start_date, $end_date, 'datelist', $storage_name );
273
+ } else {
274
+ return $this->handle_response( $response, $metric, $dimensions, $start_date, $end_date, 'table', $storage_name );
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Get the storage type from dimensions
280
+ *
281
+ * @param $dimensions
282
+ *
283
+ * @return string
284
+ */
285
+ private function get_storage_type( $dimensions ) {
286
+ if ( strpos( 'ga:date', $dimensions ) !== false ) {
287
+ return 'datelist';
288
+ } else {
289
+ return 'table';
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Prepare dimensions before adding them as a parameter in a call
295
+ *
296
+ * @param $dimensions
297
+ *
298
+ * @return string
299
+ */
300
+ private function prepare_dimensions( $dimensions, $metric ) {
301
+ $filter_metrics = $this->get_filter_metrics();
302
+
303
+ // Check if the dimensions param is an array, if so, glue it with implode to a comma separated string.
304
+ if ( is_array( $dimensions ) ) {
305
+ $dimensions = implode( ',', $dimensions );
306
+ }
307
+
308
+ if ( in_array( $metric, $this->valid_metrics ) ) {
309
+ $dimensions = 'ga:date,' . $dimensions;
310
+ } elseif ( isset( $filter_metrics[str_replace( 'ga:', '', $dimensions )] ) ) {
311
+ // Make sure we don't have a ga:date property here
312
+ $dimensions = str_replace( 'ga:date', '', $dimensions );
313
+ }
314
+
315
+ return $dimensions;
316
+ }
317
+
318
+ /**
319
+ * Build the params for a call to Google Analytics, return them prepared for a http query
320
+ *
321
+ * @param $start_date
322
+ * @param $end_date
323
+ * @param $dimensions
324
+ * @param $metric
325
+ *
326
+ * @return array|string
327
+ */
328
+ private function build_params_for_call( $start_date, $end_date, $dimensions, $metric ) {
329
+ $params = array(
330
+ 'ids' => 'ga:' . $this->ga_profile_id,
331
+ 'start-date' => $start_date,
332
+ 'end-date' => $end_date,
333
+ 'dimensions' => $dimensions,
334
+ 'metrics' => 'ga:' . $metric,
335
+ 'max-results' => 10000,
336
+ );
337
+
338
+ $params = $this->add_sort_direction( $params, $dimensions, $metric );
339
+ $params = http_build_query( $params );
340
+
341
+ return $params;
342
+ }
343
+
344
+ /**
345
+ * Add a sort direction if we need to (Especially on dimensions which are
346
+ * listed in $this->get_filter_metrics())
347
+ *
348
+ * @param $params
349
+ *
350
+ * @return mixed
351
+ */
352
+ private function add_sort_direction( $params, $dimensions, $metric ) {
353
+ $filter_dimensions = $this->get_filter_metrics();
354
+
355
+ foreach ( $filter_dimensions as $dimension ) {
356
+ if ( str_replace( 'ga:', '', $dimensions ) == $dimension['dimension'] && str_replace( 'ga:', '', $metric ) == $dimension['metric'] ) {
357
+ $params['sort'] = '-ga:' . $dimension['metric'];
358
+ }
359
+ }
360
+
361
+ return $params;
362
+ }
363
+
364
+ /**
365
+ * Handle the response from the Google Analytics api.
366
+ *
367
+ * @param $response
368
+ * @param $metric
369
+ * @param $dimensions
370
+ * @param $start_date
371
+ * @param $end_date
372
+ * @param $store_as
373
+ * @param $storage_name
374
+ *
375
+ * @return bool
376
+ */
377
+ private function handle_response( $response, $metric, $dimensions, $start_date, $end_date, $store_as = 'table', $storage_name = 'auto' ) {
378
+ if ( is_array( $response ) && isset( $response['response']['code'] ) && $response['response']['code'] == 200 ) {
379
+ // Success, store this data
380
+ $filter_metrics = $this->get_filter_metrics();
381
+ $extracted = str_replace( 'ga:', '', str_replace( 'ga:date,', '', $dimensions ) );
382
+
383
+ if ( isset( $filter_metrics[$extracted] ) ) {
384
+ $name = $extracted;
385
+
386
+ } else {
387
+ $name = $metric;
388
+ }
389
+
390
+ if ( $dimensions !== 'ga:date' && ! isset( $filter_metrics[$extracted] ) ) {
391
+ $name = str_replace( 'ga:date,', '', $dimensions );
392
+ }
393
+
394
+ // Overwrite the name if we have a defined one
395
+ if ( $storage_name != 'auto' ) {
396
+ $name = $storage_name;
397
+ }
398
+
399
+ return Yoast_GA_Dashboards_Data::set( $name, $response['body'], strtotime( $start_date ), strtotime( $end_date ), $store_as );
400
+ } else {
401
+ // Failure on API call try to log it
402
+ $this->log_error( print_r( $response['body_raw'], true ) );
403
+
404
+ return false;
405
+ }
406
+ }
407
+
408
+ /**
409
+ * Log an error while calling the Google Analytics API
410
+ *
411
+ * @param $error
412
+ */
413
+ private function log_error( $error ) {
414
+ if ( true == WP_DEBUG ) {
415
+ if ( function_exists( 'error_log' ) ) {
416
+ error_log( 'Yoast Google Analytics (Dashboard API): ' . $error );
417
+ }
418
+ }
419
+ }
420
+
421
+ /**
422
+ * Close the HTTP socket, to continue with the api calls to Google Analytics
423
+ */
424
+ private function close_connection() {
425
+ ob_end_flush();
426
+ header( 'Connection: close' );
427
+ flush();
428
+ }
429
+
430
+ }
431
+
432
+ }
admin/dashboards/class-admin-dashboards-data.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * This class is used to store and get the data of the dashboards. The data is aggregated by
5
+ * the class-admin-dashboards-collector.php and saved with Yoast_GA_Dashboards_Data::set().
6
+ *
7
+ * You can retrieve the data by using the function Yoast_GA_Dashboards_Data::get() in this
8
+ * class.
9
+ */
10
+
11
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Data' ) ) {
12
+
13
+ class Yoast_GA_Dashboards_Data {
14
+
15
+ /**
16
+ * The time to store a transient (in seconds)
17
+ *
18
+ * @var int
19
+ */
20
+ private static $store_transient_time = DAY_IN_SECONDS;
21
+
22
+ /**
23
+ * Get a data object
24
+ *
25
+ * @param $type String
26
+ *
27
+ * @return array
28
+ */
29
+ public static function get( $type ) {
30
+ $transient = get_transient( 'yst_ga_' . $type );
31
+
32
+ if ( false === $transient ) {
33
+ // Transient does not exist, abort
34
+ return array();
35
+ }
36
+
37
+ // @TODO loop through transient to get the correct date range
38
+
39
+ return $transient;
40
+ }
41
+
42
+ /**
43
+ * Save a data object
44
+ *
45
+ * @param $type
46
+ * @param $value
47
+ * @param $start_date
48
+ * @param $end_date
49
+ * @param $store_as
50
+ *
51
+ * @return bool
52
+ */
53
+ public static function set( $type, $value, $start_date, $end_date, $store_as ) {
54
+ $store = array(
55
+ 'store_as' => $store_as,
56
+ 'type' => $type,
57
+ 'start_date' => $start_date,
58
+ 'end_date' => $end_date,
59
+ 'value' => $value,
60
+ );
61
+
62
+ return set_transient( 'yst_ga_' . $type, $store, self::$store_transient_time );
63
+ }
64
+ }
65
+
66
+ }
admin/dashboards/class-admin-dashboards-display.php ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Display' ) ) {
4
+
5
+ class Yoast_GA_Dashboards_Display {
6
+
7
+ /**
8
+ * Property for holding instance of itself
9
+ *
10
+ * @var Yoast_GA_Dashboards_Display
11
+ */
12
+ protected static $instance;
13
+
14
+ /**
15
+ * Container for holding the setted dashboards
16
+ *
17
+ * @var array
18
+ */
19
+ protected $dashboards = array();
20
+
21
+ /**
22
+ * @var array The dashboard types which can be used
23
+ */
24
+ protected $dashboard_types = array( 'graph', 'table' );
25
+
26
+ /**
27
+ * @var array For each dashboard type there will be created a driver that will be stored in this property
28
+ */
29
+ protected $drivers = array();
30
+
31
+ /**
32
+ * For the use of singleton pattern. Create instance of itself and return his instance
33
+ *
34
+ * @return Yoast_GA_Dasboards_Graph
35
+ */
36
+ public static function get_instance() {
37
+
38
+ if ( is_null( self::$instance ) ) {
39
+ self::$instance = new self();
40
+ }
41
+
42
+ return self::$instance;
43
+ }
44
+
45
+ /**
46
+ * Protected constructor to prevent creating a new instance of the
47
+ * *Singleton* via the `new` operator from outside of this class.
48
+ */
49
+ protected function __construct() {
50
+ foreach ( $this->dashboard_types AS $dashboard_type ) {
51
+ if ( ! $this->driver_exists( $dashboard_type ) ) {
52
+ $this->create_driver( $dashboard_type );
53
+ }
54
+ }
55
+ }
56
+
57
+ /**
58
+ * Get the driver from property, this->drivers
59
+ *
60
+ * If driver doesn't exist, it will be created first
61
+ *
62
+ * @param string $dashboard_type - The name of the driver that will be returned
63
+ *
64
+ * @return object
65
+ */
66
+ private function driver( $dashboard_type ) {
67
+
68
+ if ( ! $this->driver_exists( $dashboard_type ) ) {
69
+ $this->create_driver( $dashboard_type );
70
+ }
71
+
72
+ return $this->drivers[$dashboard_type];
73
+ }
74
+
75
+ /**
76
+ * Adding dashboards to $this->dashboard en register them to the driver by $this->register
77
+ *
78
+ * @param array $dashboards
79
+ */
80
+ public function add_dashboards( $dashboards ) {
81
+ // Save all dashboards to property - for future use
82
+ $this->dashboards = array_merge( $this->dashboards, $dashboards );
83
+
84
+ $this->register( $dashboards );
85
+ }
86
+
87
+ /**
88
+ * Register dashboards to the drivers
89
+ *
90
+ * @param array $dashboards
91
+ */
92
+ private function register( $dashboards ) {
93
+ foreach ( $dashboards AS $dashboard_name => $dashboard_settings ) {
94
+ if ( ! empty( $dashboard_settings['type'] ) ) {
95
+ $this->driver( $dashboard_settings['type'] )->register( $dashboard_name, $dashboard_settings );
96
+ }
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Displaying the $dashboards on the screen. If $dashboards isn't given it will display all registered
102
+ * dashboards
103
+ *
104
+ * @param string $tab_to_show
105
+ */
106
+ public function display( $tab_to_show ) {
107
+
108
+ $dashboards_to_show = $this->dashboards;
109
+
110
+ foreach ( $dashboards_to_show AS $dashboard_name => $dashboard_settings ) {
111
+ if ( !empty($dashboard_settings['tab']) && $dashboard_settings['tab'] === $tab_to_show ) {
112
+ $this->driver( $dashboard_settings['type'] )->display( $dashboard_name );
113
+ }
114
+ }
115
+ }
116
+
117
+ /**
118
+ * Check if given $dashboard_type exists and if it's an object
119
+ *
120
+ * @param string $dashboard_type
121
+ *
122
+ * @return bool
123
+ */
124
+ protected function driver_exists( $dashboard_type ) {
125
+ return array_key_exists( $dashboard_type, $this->drivers ) && is_object( $this->drivers[$dashboard_type] );
126
+ }
127
+
128
+ /**
129
+ * Creates a driver based on given $dashboard_type
130
+ *
131
+ * @param $dashboard_type
132
+ */
133
+ protected function create_driver( $dashboard_type ) {
134
+ $driver_class = 'Yoast_GA_Dashboards_' . ucfirst( $dashboard_type );
135
+ $this->drivers[$dashboard_type] = new $driver_class();
136
+ }
137
+
138
+ }
139
+
140
+ }
admin/dashboards/class-admin-dashboards.php ADDED
@@ -0,0 +1,217 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards' ) ) {
4
+
5
+ class Yoast_GA_Dashboards {
6
+
7
+ /**
8
+ * Store the data aggregator
9
+ *
10
+ * @package
11
+ */
12
+ public $aggregator;
13
+
14
+ /**
15
+ * Store the Data instance
16
+ *
17
+ * @package
18
+ */
19
+ public $data;
20
+
21
+ /**
22
+ * Store the active metrics
23
+ *
24
+ * @var
25
+ */
26
+ public $active_metrics;
27
+
28
+ /**
29
+ * Store the valid metrics which are available in the Google API, more can be added
30
+ *
31
+ * @var array
32
+ *
33
+ * @link https://ga-dev-tools.appspot.com/explorer/
34
+ */
35
+ private $valid_metrics = array( 'sessions', 'bounces', 'users', 'newUsers', 'percentNewSessions', 'bounceRate', 'sessionDuration', 'avgSessionDuration', 'hits' );
36
+
37
+ /**
38
+ * Store this instance
39
+ *
40
+ * @var null
41
+ */
42
+ private static $instance = null;
43
+
44
+ /**
45
+ * Construct on the dashboards class for GA
46
+ */
47
+ protected function __construct() {
48
+ add_filter( 'ga_extend_dashboards', array( $this, 'extend_dashboards' ), 10, 1 );
49
+ }
50
+
51
+ /**
52
+ * Init the dashboards
53
+ *
54
+ * @param integer $ga_profile_id
55
+ */
56
+ public function init_dashboards( $ga_profile_id ) {
57
+
58
+ $dashboards = array(
59
+ 'sessions' => array(
60
+ 'title' => __( 'Sessions', 'google-analytics-for-wordpress' ),
61
+ 'help' => __( 'A session is a group of interactions that take place on your website within a given time frame. For example a single session can contain multiple screen or page views, events, social interactions, and ecommerce transactions. <a href="http://yoa.st/gasessions" target="_blank">[Learn more]</a>', 'google-analytics-for-wordpress' ),
62
+ 'type' => 'graph',
63
+ 'tab' => 'general',
64
+ ),
65
+ 'bounceRate' => array(
66
+ 'title' => __( 'Bounce rate', 'google-analytics-for-wordpress' ),
67
+ 'help' => __( 'Bounce Rate is the percentage of single-page sessions (i.e. sessions in which the person left your site from the entrance page without interacting with the page). <a href="http://yoa.st/gabounce" target="_blank">[Learn more]</a>', 'google-analytics-for-wordpress' ),
68
+ 'data-percent' => true,
69
+ 'type' => 'graph',
70
+ 'tab' => 'general',
71
+ ),
72
+ 'source' => array(
73
+ 'title' => __( 'Traffic sources', 'google-analytics-for-wordpress' ),
74
+ 'help' => __( 'Every referral to a web site has an origin, or (traffic) source. Possible sources include: “google” (the name of a search engine), “facebook.com” (the name of a referring site), “spring_newsletter” (the name of one of your newsletters), and “direct” (users that typed your URL directly into their browser, or who had bookmarked your site). <a href="http://yoa.st/gabnce" target="_blank">[Learn more]</a>', 'google-analytics-for-wordpress' ),
75
+ 'type' => 'table',
76
+ 'columns' => array(
77
+ __( 'Sessions', 'google-analytics-for-wordpress' )
78
+ ),
79
+ 'tab' => 'dimensions',
80
+ ),
81
+ 'top_pageviews' => array(
82
+ 'title' => __( 'Popular pages', 'google-analytics-for-wordpress' ),
83
+ 'help' => __( 'Pages by url.', 'google-analytics-for-wordpress' ),
84
+ 'type' => 'table',
85
+ 'columns' => array(
86
+ __( 'Sessions', 'google-analytics-for-wordpress' )
87
+ ),
88
+ 'tab' => 'dimensions',
89
+ ),
90
+ 'top_countries' => array(
91
+ 'title' => __( 'Countries', 'google-analytics-for-wordpress' ),
92
+ 'help' => __( 'The country or territory from which visits originated. <a href="http://yoa.st/gacountry" target="_blank">[Learn more]</a>', 'google-analytics-for-wordpress' ),
93
+ 'type' => 'table',
94
+ 'columns' => array(
95
+ __( 'Sessions', 'google-analytics-for-wordpress' )
96
+ ),
97
+ 'tab' => 'dimensions',
98
+ ),
99
+ );
100
+
101
+ $this->extend_dashboards( $dashboards );
102
+
103
+ // Register the active metrics
104
+ $register = array_keys( $dashboards );
105
+
106
+ $this->aggregator = new Yoast_GA_Dashboards_Collector( $ga_profile_id, $register, $this->valid_metrics );
107
+
108
+ $this->register( $register );
109
+ }
110
+
111
+ /**
112
+ * Adding dashboards for front-end
113
+ *
114
+ * By hook as filter: $dashboards = apply_filters( 'ga_extend_dashboards', $dashboards);
115
+ *
116
+ * @param $dashboards
117
+ *
118
+ * @return mixed
119
+ */
120
+ public function extend_dashboards( $dashboards ) {
121
+ // Initialize the dashboard graphs
122
+ Yoast_GA_Dashboards_Display::get_instance()->add_dashboards( $dashboards );
123
+
124
+ return $dashboards;
125
+ }
126
+
127
+ /**
128
+ * Get the instance
129
+ *
130
+ * @return Yoast_GA_Dashboards
131
+ */
132
+ public static function get_instance() {
133
+ if ( is_null( self::$instance ) ) {
134
+ self::$instance = new self();
135
+ }
136
+
137
+ return self::$instance;
138
+ }
139
+
140
+ /**
141
+ * Register the dashboard types
142
+ *
143
+ * @param $types array or singular string
144
+ *
145
+ * @return bool
146
+ */
147
+ public function register( $types ) {
148
+ if ( is_array( $types ) == false ) {
149
+ $types = array( $types );
150
+ }
151
+
152
+ if ( is_array( $types ) && count( $types ) >= 1 ) {
153
+ if ( $this->validate_dashboard_types( $types ) ) {
154
+ $this->active_metrics = $types;
155
+
156
+ return true;
157
+ }
158
+ }
159
+
160
+ return false;
161
+ }
162
+
163
+ /**
164
+ * Adding translations to ga-admin-dashboard
165
+ */
166
+ public function add_dashboard_js_translations() {
167
+ // Now we can localize the script with our data.
168
+ $translation_array = array(
169
+ // For datatables
170
+ 'sort_ascending' => __( ': activate to sort column ascending', 'google-analytics-for-wordpress' ),
171
+ 'sort_descending' => __( ': activate to sort column descending', 'google-analytics-for-wordpress' ),
172
+ 'empty_table' => __( 'No data available', 'google-analytics-for-wordpress' ),
173
+ 'info' => _x( 'Showing _START_ to _END_ of _TOTAL_ rows', '_START_, _END_ and _TOTAL_ will be replaced by JS (See: http://datatables.net/reference/option/language.info)', 'google-analytics-for-wordpress' ),
174
+ 'info_empty' => __( 'No rows to show', 'google-analytics-for-wordpress' ),
175
+ 'info_filtered' => _x( '(filtered from _MAX_ total rows)', '_MAX_ will be replaced by JS (See: http://datatables.net/reference/option/language.infoFiltered)', 'google-analytics-for-wordpress' ),
176
+ 'length_menu' => _x( 'Show _MENU_ rows', '_MAX_ will be replaced by JS', 'google-analytics-for-wordpress' ),
177
+ 'loading_records' => __( 'Loading...', 'google-analytics-for-wordpress' ),
178
+ 'pagination_first' => __( 'First', 'google-analytics-for-wordpress' ),
179
+ 'pagination_last' => __( 'Last', 'google-analytics-for-wordpress' ),
180
+ 'pagination_next' => __( 'Next', 'google-analytics-for-wordpress' ),
181
+ 'pagination_previous' => __( 'Previous', 'google-analytics-for-wordpress' ),
182
+ 'processing' => __( 'Processing...', 'google-analytics-for-wordpress' ),
183
+ 'search_placeholder' => __( 'Search', 'google-analytics-for-wordpress' ),
184
+ 'zero_records' => __( 'No matching records found', 'google-analytics-for-wordpress' ),
185
+
186
+ // For dimensions
187
+ 'dimensions' => __( 'Reports', 'google-analytics-for-wordpress' ),
188
+ 'custom_dimensions' => __( 'Custom dimension reports', 'google-analytics-for-wordpress' ),
189
+ );
190
+
191
+ wp_localize_script( 'ga-admin-dashboard', 'dashboard_translate', $translation_array );
192
+
193
+ }
194
+
195
+ /**
196
+ * Validate the registered types of dashboards
197
+ *
198
+ * @param $types
199
+ *
200
+ * @return bool
201
+ */
202
+ private function validate_dashboard_types( $types ) {
203
+ $valid = true;
204
+
205
+ if ( is_array( $types ) ) {
206
+ foreach ( $types as $check_type ) {
207
+ if ( ! in_array( $check_type, $this->valid_metrics ) ) {
208
+ $valid = false;
209
+ }
210
+ }
211
+ }
212
+
213
+ return $valid;
214
+ }
215
+ }
216
+
217
+ }
admin/dashboards/drivers/class-admin-dashboards-driver-generate.php ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Driver_Generate' ) ) {
4
+
5
+ abstract class Yoast_GA_Dashboards_Driver_Generate {
6
+
7
+ /**
8
+ * @var string - Which type of data should be loaded
9
+ */
10
+ protected $graph_type;
11
+
12
+ /**
13
+ * @var string - For which period should the data be shown
14
+ */
15
+ protected $period;
16
+
17
+ /**
18
+ * @var string - The end date
19
+ */
20
+ protected $end_date;
21
+
22
+ /**
23
+ * @var string - The start date
24
+ */
25
+ protected $start_date;
26
+
27
+ /**
28
+ * Construct will set all values and generate the date for response
29
+ */
30
+ public function __construct() {
31
+ $this->set_graph_type();
32
+ $this->set_period();
33
+ $this->set_end_date();
34
+ $this->set_start_date();
35
+ }
36
+
37
+ /**
38
+ * Getting graph_id from post and strip HTML-prefix graph- to get the type
39
+ */
40
+ protected function set_graph_type() {
41
+ $graph_id = filter_input( INPUT_GET, 'graph_id' );
42
+ $graph_type = str_replace( array( 'graph-', 'table-' ), '', $graph_id );
43
+ $this->graph_type = $graph_type;
44
+ }
45
+
46
+ /**
47
+ * Getting the period from post
48
+ */
49
+ protected function set_period() {
50
+ $this->period = filter_input( INPUT_GET, 'period' );
51
+ }
52
+
53
+ /**
54
+ * Setting the end date
55
+ */
56
+ protected function set_end_date() {
57
+ $this->end_date = time();
58
+ }
59
+
60
+ /**
61
+ * This method will set a start_date based on $this->period
62
+ *
63
+ * The values in dropdown, that will be mapped in strtotime
64
+ * See: http://php.net/manual/en/datetime.formats.relative.php
65
+ */
66
+ protected function set_start_date() {
67
+
68
+ switch ( $this->period ) {
69
+ case 'lastweek' :
70
+ $time = '-6 days';
71
+ break;
72
+ default:
73
+ case 'lastmonth' :
74
+ $time = '-1 month';
75
+ break;
76
+ }
77
+
78
+ $start_date = strtotime( $time, $this->end_date );
79
+
80
+ $this->start_date = $start_date;
81
+ }
82
+
83
+ /**
84
+ * Getting the saved Google data
85
+ *
86
+ * @return array
87
+ */
88
+ protected function get_google_data() {
89
+
90
+ $response = Yoast_GA_Dashboards_Data::get( $this->graph_type );
91
+
92
+ if ( array_key_exists( 'body', $response['value'] ) ) {
93
+ $return = $response['value']['body'];
94
+ } else {
95
+ $return = $response;
96
+ }
97
+
98
+ return $this->filter_google_data( $return );
99
+ }
100
+
101
+ /**
102
+ * Check if given timestamp is in given period
103
+ *
104
+ * @param integer $timestamp
105
+ *
106
+ * @return bool
107
+ */
108
+ protected function is_date_in_period( $timestamp ) {
109
+ return ( $timestamp >= $this->start_date && $timestamp <= $this->end_date );
110
+ }
111
+
112
+ /**
113
+ * Should always be available
114
+ *
115
+ * @return mixed
116
+ */
117
+ abstract public function get_json();
118
+
119
+ }
120
+
121
+ }
admin/dashboards/drivers/class-admin-dashboards-driver.php ADDED
@@ -0,0 +1,80 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Driver' ) ) {
4
+
5
+ abstract class Yoast_GA_Dashboards_Driver {
6
+
7
+ /**
8
+ * Container for holding set dashboards
9
+ *
10
+ * @var array
11
+ */
12
+ protected $dashboards = array();
13
+
14
+ /**
15
+ * This will initialize the AJAX request
16
+ */
17
+ public function __construct() {
18
+ $this->initialize_ajax();
19
+ }
20
+
21
+ /**
22
+ * Method which will be called by AJAX
23
+ *
24
+ * Will echo json for graph
25
+ */
26
+ public function get_ajax_data() {
27
+ check_ajax_referer( 'yoast-ga-dashboard-nonce', '_ajax_nonce' );
28
+
29
+ $generator = $this->get_dashboard_generate_object();
30
+ $json = $generator->get_json();
31
+
32
+ echo $json;
33
+ die();
34
+ }
35
+
36
+ /**
37
+ * Register a dashboard with settings.
38
+ *
39
+ * Dashboard can contain multiple dashboard-types. If so, $values shouldn't be passed and $dashboard argument
40
+ * should be key->value, key = dashboard and value should contain the values
41
+ *
42
+ * Given arguments will be marge with objects property dashboards
43
+ *
44
+ * @param mixed $dashboard
45
+ * @param mixed $values
46
+ */
47
+ public function register( $dashboard, $values = false ) {
48
+
49
+ if ( ! is_array( $dashboard ) ) {
50
+ $dashboard = array( $dashboard => $values );
51
+ }
52
+
53
+ $this->dashboards = array_merge( $this->dashboards, $dashboard );
54
+ }
55
+
56
+ /**
57
+ * Giving the dashboardname to show
58
+ *
59
+ * @param $dashboard
60
+ */
61
+ public function display( $dashboard ) {
62
+ $settings = $this->dashboards[ $dashboard ];
63
+ require dirname( GAWP_FILE ) . '/admin/dashboards/views/' . $this->dashboard_type . '.php';
64
+ }
65
+
66
+ /**
67
+ * Setting hook for doing ajax request
68
+ */
69
+ protected function initialize_ajax() {
70
+ add_action( $this->ajax_hook, array( $this, 'get_ajax_data' ) );
71
+ }
72
+
73
+ /**
74
+ * This method should always be available
75
+ * @return mixed
76
+ */
77
+ abstract protected function get_dashboard_generate_object();
78
+
79
+ }
80
+ }
admin/dashboards/drivers/class-admin-dashboards-graph-generate.php ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Graph_Generate' ) ) {
4
+
5
+ class Yoast_GA_Dashboards_Graph_Generate extends Yoast_GA_Dashboards_Driver_Generate {
6
+
7
+ /**
8
+ * The field that will be used for displaying on x-axis. Mostly it will be the j (day in month)
9
+ *
10
+ * See: http://nl3.php.net/manual/en/function.date.php under 'format'
11
+ *
12
+ * @var string
13
+ */
14
+ private $date_field = 'j';
15
+
16
+ /**
17
+ * @var array - Storage for $data
18
+ */
19
+ private $data = array();
20
+
21
+ /**
22
+ * Storage for mapping
23
+ *
24
+ * @var array
25
+ */
26
+ private $mapping = array(
27
+ 'x' => array(),
28
+ 'hover' => array(),
29
+ );
30
+
31
+ /**
32
+ * Construct will set all values and generate the date for response
33
+ */
34
+ public function __construct() {
35
+ parent::__construct();
36
+
37
+ $this->set_date_field();
38
+
39
+ $this->generate();
40
+ }
41
+
42
+ /**
43
+ * Putting $this->data and $this->mapping and give them back as a json encoded string
44
+ *
45
+ * @return string
46
+ */
47
+ public function get_json() {
48
+ $return = array(
49
+ 'data' => $this->data,
50
+ 'mapping' => $this->mapping,
51
+ );
52
+
53
+ return json_encode( $return );
54
+ }
55
+
56
+ /**
57
+ * Filtering the current data to eliminate all values which are not in given period
58
+ *
59
+ * @param integer $google_data
60
+ *
61
+ * @return integer
62
+ */
63
+ protected function filter_google_data( $google_data ) {
64
+
65
+ foreach ( $google_data['value'] AS $unix_timestamp => $value ) {
66
+ if ( $this->is_date_in_period( $unix_timestamp ) ) {
67
+ $return[$unix_timestamp] = $value;
68
+ }
69
+ }
70
+
71
+ return $return;
72
+ }
73
+
74
+ /**
75
+ * Which field should be taken from timestamp. Most cases J will be good
76
+ */
77
+ private function set_date_field() {
78
+ switch ( $this->period ) {
79
+ default:
80
+ case 'lastweek' :
81
+ case 'lastmonth' :
82
+ $date_field = 'j';
83
+ break;
84
+ }
85
+
86
+ $this->date_field = $date_field;
87
+ }
88
+
89
+ /**
90
+ * Generate the data for the frontend based on the $google_data
91
+ */
92
+ private function generate() {
93
+
94
+ $google_data = $this->get_google_data();
95
+
96
+ foreach ( $google_data AS $timestamp => $value ) {
97
+ $this->add_data( $value );
98
+ $this->add_x_mapping( $timestamp );
99
+ $this->add_hover_mapping( $timestamp, $value );
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Adding value to data property
105
+ *
106
+ * x is position on x-axis, always starting from 0
107
+ * y is the value of that point.
108
+ *
109
+ * @param integer $value
110
+ */
111
+ private function add_data( $value ) {
112
+ static $current_x = 0;
113
+
114
+ $this->data[] = array(
115
+ 'x' => $current_x,
116
+ 'y' => $value,
117
+ );
118
+
119
+ $current_x++;
120
+ }
121
+
122
+ /**
123
+ * Add date field to the x-mapping
124
+ *
125
+ * Key will be auto numbered by PHP, starting with 0, the key will always point to the the x in x-axis
126
+ * The value will be always the value that should be displayed.
127
+ *
128
+ * @param integer $timestamp
129
+ */
130
+ private function add_x_mapping( $timestamp ) {
131
+ $this->mapping['x'][] = date( $this->date_field . ' M', $timestamp );
132
+ }
133
+
134
+ /**
135
+ * Add date field to the hover-mapping
136
+ *
137
+ * @param integer $timestamp
138
+ * @param integer $value
139
+ */
140
+ private function add_hover_mapping( $timestamp, $value ) {
141
+ $this->mapping['hover'][] = date_i18n( 'l ' . $this->date_field . ' M', $timestamp ) . ': ' . $value;
142
+ }
143
+
144
+ }
145
+ }
admin/dashboards/drivers/class-admin-dashboards-graph.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Graph' ) ) {
4
+
5
+ class Yoast_GA_Dashboards_Graph extends Yoast_GA_Dashboards_Driver {
6
+
7
+ /**
8
+ * @var string The type of dashboard wherefore this object is created
9
+ */
10
+ protected $dashboard_type = 'graph';
11
+
12
+ /**
13
+ * @var string The hook for ajax, when this is called the hook will be executed
14
+ */
15
+ protected $ajax_hook = 'wp_ajax_yoast_dashboard_graphdata';
16
+
17
+ /**
18
+ * The object that handles the response and generates the content for dashboard
19
+ *
20
+ * @return Yoast_GA_Dashboards_Graph_Generate
21
+ */
22
+ protected function get_dashboard_generate_object() {
23
+ return new Yoast_GA_Dashboards_Graph_Generate();
24
+ }
25
+
26
+ }
27
+ }
admin/dashboards/drivers/class-admin-dashboards-table-generate.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Table_Generate' ) ) {
4
+
5
+ class Yoast_GA_Dashboards_Table_Generate extends Yoast_GA_Dashboards_Driver_Generate {
6
+
7
+ /**
8
+ * @var string - The ID of requested dimension
9
+ */
10
+ protected $dimension_id;
11
+
12
+ /**
13
+ * Construct will set all values and generate the date for response
14
+ */
15
+ public function __construct() {
16
+ parent::__construct();
17
+
18
+ $this->set_dimension_id();
19
+
20
+ $this->generate();
21
+ }
22
+
23
+ /**
24
+ * Putting $this->data and $this->mapping and give them back as a json encoded string
25
+ *
26
+ * @return string
27
+ */
28
+ public function get_json() {
29
+ $return = array(
30
+ 'data' => $this->data,
31
+ );
32
+
33
+ return json_encode( $return );
34
+ }
35
+
36
+ /**
37
+ * Filtering the current data to eliminate all values which are not in given period
38
+ *
39
+ * @param integer $google_data
40
+ *
41
+ * @return integer
42
+ */
43
+ protected function filter_google_data( $google_data ) {
44
+ return $google_data['value'];
45
+ }
46
+
47
+ /**
48
+ * Setting the dimension_id for current request. Based on dimension_id the graph_type will be set, this to
49
+ * handle the request correctly
50
+ */
51
+ private function set_dimension_id() {
52
+ $this->dimension_id = filter_input( INPUT_GET, 'dimension_id' );
53
+
54
+ if ( ! empty( $this->dimension_id ) ) {
55
+ $this->graph_type = 'ga:dimension' . $this->dimension_id;
56
+ } else {
57
+ $this->graph_type = $this->graph_type;
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Generate the data for the frontend based on the $google_data
63
+ */
64
+ private function generate() {
65
+ $google_data = $this->get_google_data();
66
+ $this->data = array_values( $google_data );
67
+ }
68
+
69
+ }
70
+ }
admin/dashboards/drivers/class-admin-dashboards-table.php ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Dashboards_Table' ) ) {
4
+
5
+ class Yoast_GA_Dashboards_Table extends Yoast_GA_Dashboards_Driver {
6
+
7
+ /**
8
+ * @var string The type of dashboard wherefore this object is created
9
+ */
10
+ protected $dashboard_type = 'table';
11
+
12
+ /**
13
+ * @var string The hook for ajax, when this is called the hook will be executed
14
+ */
15
+ protected $ajax_hook = 'wp_ajax_yoast_dashboard_tabledata';
16
+
17
+ /**
18
+ * The object that handles the response and generates the content for dashboard
19
+ *
20
+ * @return Yoast_GA_Dashboards_Table_Generate
21
+ */
22
+ protected function get_dashboard_generate_object() {
23
+ return new Yoast_GA_Dashboards_Table_Generate();
24
+ }
25
+
26
+ }
27
+ }
admin/dashboards/views/graph.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div id="graph-<?php echo $dashboard; ?>" class="yoast-dashboard yoast-graph" data-label="<?php echo $settings['title']; ?>" data-percent="<?php echo ! empty( $settings['data-percent'] ); ?>">
2
+ <h3>
3
+ <span class='alignleft'><?php echo $settings['title']; ?></span>
4
+ <?php
5
+ if ( ! empty( $settings['help'] ) ) {
6
+ echo Yoast_GA_Admin_Form::show_help( 'graph-' . $dashboard, $settings['help'] );
7
+ }
8
+ ?>
9
+ <span class='alignright period'><?php echo __( 'Last month', 'google-analytics-for-wordpress' ); ?></span>
10
+ </h3>
11
+
12
+ <?php if ( empty( $settings['hide_y_axis'] ) ) {
13
+ echo "<div class='yoast-graph-yaxis'></div >";
14
+ } ?>
15
+ <div class="yoast-graph-holder"></div>
16
+
17
+ <?php if ( empty( $settings['hide_x_axis'] ) ) {
18
+ echo "<div class='yoast-graph-xaxis'></div >";
19
+ } ?>
20
+ </div>
admin/dashboards/views/table.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class='yoast-dashboard yoast-data-table' id="table-<?php echo $dashboard; ?>" data-label="<?php echo $settings['title']; ?>" data-dimension="<?php echo (!empty($settings['custom-dimension-id'])) ? $settings['custom-dimension-id'] : ''; ?>">
2
+ <h3>
3
+ <span class='alignleft'><?php echo $settings['title']; ?></span>
4
+ <?php
5
+ if ( ! empty( $settings['help'] ) ) {
6
+ echo Yoast_GA_Admin_Form::show_help( 'graph-' . $dashboard, $settings['help'] );
7
+ }
8
+ ?>
9
+ <span class='alignright period'><?php echo __( 'Last month', 'google-analytics-for-wordpress' ); ?></span>
10
+ </h3>
11
+
12
+ <div>
13
+ <table class="widefat fixed stripe">
14
+ <thead>
15
+ <th><?php echo $settings['title']; ?></th>
16
+ <?php foreach($settings['columns'] As $columns) { ?>
17
+ <th><?php echo $columns; ?></th>
18
+ <?php } ?>
19
+ </thead>
20
+ </table>
21
+ </div>
22
+ </div>
admin/pages/dashboard.php CHANGED
@@ -5,10 +5,72 @@ echo $yoast_ga_admin->content_head();
5
  ?>
6
  <h2 id="yoast_ga_title"><?php echo __( 'Yoast Google Analytics: ', 'google-analytics-for-wordpress' ) . __( 'Dashboard', 'google-analytics-for-wordpress' ); ?></h2>
7
 
8
- <div id="ga-promote">
9
- <p><?php printf( __( 'This feature %1$swill be coming soon%2$s. For now, you can %3$sread our posts on Analytics%2$s, or of course, %4$slog into Google Analytics%2$s yourself.', 'google-analytics-for-wordpress' ), '<a href="https://yoast.com/google-analytics-5/#utm_medium=textlink&utm_source=gawp-config&utm_campaign=wpgaplugin">', '</a>', '<a href="https://yoast.com/cat/analytics/#utm_medium=textlink&utm_source=gawp-config&utm_campaign=wpgaplugin">', '<a href="http://www.google.com/analytics/">' ); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  </div>
11
 
 
 
 
 
 
 
 
 
12
  <?php
13
  echo $yoast_ga_admin->content_footer();
14
  ?>
5
  ?>
6
  <h2 id="yoast_ga_title"><?php echo __( 'Yoast Google Analytics: ', 'google-analytics-for-wordpress' ) . __( 'Dashboard', 'google-analytics-for-wordpress' ); ?></h2>
7
 
8
+ <h2 class="nav-tab-wrapper" id="ga-tabs">
9
+ <a class="nav-tab" id="general-tab" href="#top#general"><?php _e( 'Overview', 'google-analytics-for-wordpress' ); ?></a>
10
+ <a class="nav-tab" id="dimensions-tab" href="#top#dimensions"><?php _e( 'Reports', 'google-analytics-for-wordpress' ); ?></a>
11
+ <a class="nav-tab" id="customdimensions-tab" href="#top#customdimensions"><?php _e( 'Custom dimension reports', 'google-analytics-for-wordpress' ); ?></a>
12
+ </h2>
13
+
14
+ <script type="text/javascript">
15
+ var yoast_ga_dashboard_nonce = '<?php echo wp_create_nonce( 'yoast-ga-dashboard-nonce' ); ?>';
16
+
17
+ jQuery(function () {
18
+ jQuery.each(
19
+ jQuery('select[data-rel=toggle_dimensions]'),
20
+ function (num, element) {
21
+ dimension_switch(element);
22
+ }
23
+ );
24
+ });
25
+ </script>
26
+
27
+ <div class="tabwrapper">
28
+ <div id="general" class="wpseotab gatab active">
29
+ <div class="yoast-graphs">
30
+ <?php
31
+
32
+ if(Yoast_GA_Options::instance()->get_tracking_code() !== '') {
33
+ Yoast_GA_Dashboards_Display::get_instance()->display( 'general' );
34
+ } else {
35
+ echo sprintf(
36
+ __( 'You have not yet finished setting up Google Analytics for Wordpress by Yoast. Please %sadd your Analytics profile here%s to enable tracking.','google-analytics-for-wordpress'),
37
+ '<a href=" ' .admin_url( 'admin.php?page=yst_ga_settings#top#general' ) . '">',
38
+ '</a>'
39
+ );
40
+ }
41
+ ?>
42
+ </div>
43
+ </div>
44
+
45
+ <div id="dimensions" class="wpseotab gatab">
46
+ <?php
47
+ if(Yoast_GA_Options::instance()->get_tracking_code() !== '') {
48
+ ?>
49
+ <div class="ga-form ga-form-input">
50
+ <label class="ga-form ga-form-checkbox-label ga-form-label-left"><?php echo __( 'Select a dimension', 'google-analytics-for-wordpress' ); ?></label>
51
+ </div>
52
+ <select data-rel='toggle_dimensions' id="toggle_dimensions" style="width: 350px"></select>
53
+
54
+ <?php
55
+ Yoast_GA_Dashboards_Display::get_instance()->display( 'dimensions' );
56
+ } else {
57
+ echo sprintf(
58
+ __( 'You have not yet finished setting up Google Analytics for Wordpress by Yoast. Please %sadd your Analytics profile here%s to enable tracking.','google-analytics-for-wordpress'),
59
+ '<a href=" ' .admin_url( 'admin.php?page=yst_ga_settings#top#general' ) . '">',
60
+ '</a>'
61
+ );
62
+ }
63
+ ?>
64
  </div>
65
 
66
+ <div id="customdimensions" class="wpseotab gatab">
67
+ <?php
68
+ do_action('yst_ga_custom_dimension_add-dashboards-tab');
69
+ ?>
70
+ </div>
71
+ </div>
72
+
73
+
74
  <?php
75
  echo $yoast_ga_admin->content_footer();
76
  ?>
admin/pages/settings.php CHANGED
@@ -28,7 +28,7 @@ echo $yoast_ga_admin->create_form( 'settings' );
28
  echo '<h2>' . __( 'General settings', 'google-analytics-for-wordpress' ) . '</h2>';
29
  echo '<div id="ga-promote">';
30
 
31
- $profiles = $yoast_ga_admin->get_profiles();
32
  $ga_url = $_SERVER['PHP_SELF'];
33
  if ( isset( $_GET['page'] ) ) {
34
  $ga_url .= '?page=' . $_GET['page'];
28
  echo '<h2>' . __( 'General settings', 'google-analytics-for-wordpress' ) . '</h2>';
29
  echo '<div id="ga-promote">';
30
 
31
+ $profiles = $yoast_ga_admin->parse_optgroups( $yoast_ga_admin->get_profiles() );
32
  $ga_url = $_SERVER['PHP_SELF'];
33
  if ( isset( $_GET['page'] ) ) {
34
  $ga_url .= '?page=' . $_GET['page'];
{js → assets/css}/index.php RENAMED
File without changes
assets/css/yoast_ga_admin_dashboard.css ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .yoast-graphs {
2
+ display: inline-block;
3
+ clear: both;
4
+ position: relative;
5
+ }
6
+
7
+ .yoast-graph {
8
+ display: inline;
9
+ float: left;
10
+ width: 840px;
11
+ height: 375px;
12
+ margin: 5px;
13
+ }
14
+
15
+ .yoast-graph-holder,
16
+ .yoast-graph-yaxis {
17
+ height: 300px;
18
+ }
19
+
20
+ .yoast-graph-holder,
21
+ .yoast-graph-xaxis {
22
+ width: 780px;
23
+ }
24
+
25
+ .yoast-graph-holder,
26
+ .yoast-graph-yaxis,
27
+ .yoast-graph-xaxis {
28
+ float: left;
29
+ }
30
+
31
+ .yoast-graph-holder {
32
+ margin: 0 5px 0 0;
33
+ background: #fff;
34
+ }
35
+
36
+ .yoast-graph-xaxis {
37
+ height: 20px;
38
+ margin-left: 50px;
39
+ }
40
+
41
+ .yoast-graph-yaxis {
42
+ overflow: hidden;
43
+ width: 50px;
44
+ }
45
+
46
+ .x_label {
47
+ display: none;
48
+ }
49
+
50
+ .yoast-data-table {
51
+ margin: 25px 0 10px;
52
+ }
53
+
54
+ .yoast-dashboard h3 {
55
+ float: left;
56
+ clear: both;
57
+ width: 100%;
58
+ margin: 0 0 10px;
59
+ }
60
+
61
+ .yoast-dashboard .period {
62
+ color: #555;
63
+ font-size: 0.8em;
64
+ font-weight: normal;
65
+ font-style: italic;
66
+ }
67
+
68
+ .yoast-data-table table.dataTable thead .sorting,
69
+ .yoast-data-table table.dataTable thead .sorting_asc,
70
+ .yoast-data-table table.dataTable thead .sorting_desc {
71
+ border-color: #d3d3d3;
72
+ }
73
+
74
+ .yoast-data-table table.dataTable.no-footer {
75
+ border-bottom: none;
76
+ }
assets/css/yoast_ga_admin_dashboard.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .yoast-graphs{display:inline-block;clear:both;position:relative}.yoast-graph{display:inline;float:left;width:840px;height:375px;margin:5px}.yoast-graph-holder,.yoast-graph-yaxis{height:300px}.yoast-graph-holder,.yoast-graph-xaxis{width:780px}.yoast-graph-holder,.yoast-graph-xaxis,.yoast-graph-yaxis{float:left}.yoast-graph-holder{margin:0 5px 0 0;background:#fff}.yoast-graph-xaxis{height:20px;margin-left:50px}.yoast-graph-yaxis{overflow:hidden;width:50px}.x_label{display:none}.yoast-data-table{margin:25px 0 10px}.yoast-dashboard h3{float:left;clear:both;width:100%;margin:0 0 10px}.yoast-dashboard .period{color:#555;font-size:.8em;font-weight:400;font-style:italic}.yoast-data-table table.dataTable thead .sorting,.yoast-data-table table.dataTable thead .sorting_asc,.yoast-data-table table.dataTable thead .sorting_desc{border-color:#d3d3d3}.yoast-data-table table.dataTable.no-footer{border-bottom:none}
{css → assets/css}/yoast_ga_styles.css RENAMED
@@ -6,7 +6,7 @@ h2#yoast_ga_title {
6
  }
7
 
8
  .nav-tab-wrapper {
9
- margin-bottom: 0;
10
  }
11
 
12
  .gatab {
6
  }
7
 
8
  .nav-tab-wrapper {
9
+ margin-bottom: 20px;
10
  }
11
 
12
  .gatab {
assets/css/yoast_ga_styles.min.css ADDED
@@ -0,0 +1 @@
 
1
+ h2#yoast_ga_title{padding:9px 15px 4px 0;font-size:23px;font-weight:400;line-height:29px}.nav-tab-wrapper{margin-bottom:20px}.gatab{display:none}.gatab.active{display:block;padding:.5em .9em;border:1px solid #ddd;border-radius:0 3px 3px;background-color:#fff}.tabwrapper .gatab{padding:0;border:none;background:0 0}.tabwrapper .gatab h2{padding:9px 15px 4px 0;font-size:23px;font-weight:400}.ga-form-submit{margin-top:20px}.ga-form-label-left{float:left;width:250px;margin:0 0 0 5px;font-size:14px;font-weight:700;cursor:default}.ga-form-input{margin-top:10px}#yoast-ga-wrapper{display:table;width:auto;max-width:1150px}.yoast-ga-content{display:table-cell;min-width:850px;height:500px;margin:0;padding:0;vertical-align:top}.yoast-ga-banners{display:table-cell;width:261px;height:500px;margin:0;padding:20px;vertical-align:top}.ga-form-input{display:table;margin-bottom:20px}.ga-form-table{display:table-cell}.ga-form-description{display:block;float:right;max-width:325px;color:#999}p.ga-topdescription{max-width:600px}#ga-promote{max-width:600px;padding-left:10px;border:1px solid #ccc;background-color:#fff}#yoast-ga-form-settings input[type=text]{width:325px}#enter_ua{display:none;margin-top:10px;padding-top:10px}#yoast-ga-form-text-settings-ga_general-manual_ua_code_field{margin-top:-30px}select.ga-multiple{width:300px;height:150px!important}.wpseotab .extension{float:left;box-sizing:border-box;width:350px;height:230px;margin:10px 20px 10px 0;border:1px solid #ccc}.wpseotab .extension p{margin:0;padding:10px}.wpseotab .extension h3{box-sizing:border-box;height:110px;margin:0;padding:20px 10px 0 120px;border-bottom:1px solid #ccc;background:left 10px/130px 100px no-repeat #fff}.wpseotab .extension button.installed{border-color:#00a000;background-color:#00a000;cursor:default}.wpseotab .extension .button-primary.activate-link{border-color:#f06000;background-color:#f18500}.extension a{text-decoration:none}.ecommerce h3{background-image:url(../img/eComm_130x100.png)!important}.ga_premium h3{background-image:url(../img/ga-premium-banner.png)!important}#ga-debug-info h3{height:30px;margin-top:10px;padding-left:16px;font-size:14px}.yoast_help{margin:2px 5px 0}
{css → assets/dependencies/chosen}/chosen.css RENAMED
@@ -64,7 +64,7 @@
64
  right: 26px;
65
  width: 12px;
66
  height: 12px;
67
- background: url("../img/chosen-sprite.png") -42px 1px no-repeat;
68
  font-size: 1px;
69
  }
70
 
@@ -89,7 +89,7 @@
89
  display: block;
90
  width: 100%;
91
  height: 100%;
92
- background: url("../img/chosen-sprite.png") no-repeat 0 2px;
93
  }
94
 
95
  .chzn-container-single .chzn-search {
@@ -105,8 +105,8 @@
105
  padding: 4px 20px 4px 5px;
106
  border: 1px solid #aaa;
107
  outline: 0;
108
- background: #fff url("../img/chosen-sprite.png") no-repeat 100% -20px;
109
- background: url("../img/chosen-sprite.png") no-repeat 100% -20px, linear-gradient(#eee 1%, #fff 15%);
110
  font-family: sans-serif;
111
  font-size: 1em;
112
  }
@@ -203,7 +203,7 @@
203
  right: 3px;
204
  width: 12px;
205
  height: 12px;
206
- background: url("../img/chosen-sprite.png") -42px 1px no-repeat;
207
  font-size: 1px;
208
  }
209
 
@@ -305,11 +305,11 @@
305
  }
306
 
307
  .chzn-container .chzn-results-scroll-down span {
308
- background: url("../img/chosen-sprite.png") no-repeat -4px -3px;
309
  }
310
 
311
  .chzn-container .chzn-results-scroll-up span {
312
- background: url("../img/chosen-sprite.png") no-repeat -22px -3px;
313
  }
314
 
315
  /* @end */
@@ -426,9 +426,8 @@
426
 
427
  .chzn-rtl .chzn-search input {
428
  padding: 4px 5px 4px 20px;
429
- background: #fff url("../img/chosen-sprite.png") no-repeat -30px -20px;
430
- background: url("../img/chosen-sprite.png") no-repeat -30px -20px, linear-gradient(#eee 1%, #fff 15%);
431
-
432
  direction: rtl;
433
  }
434
 
@@ -451,7 +450,7 @@
451
  .chzn-container-multi .chzn-choices .search-choice .search-choice-close,
452
  .chzn-container .chzn-results-scroll-down span,
453
  .chzn-container .chzn-results-scroll-up span {
454
- background-image: url("../img/chosen-sprite@2x.png") !important;
455
  background-repeat: no-repeat !important;
456
  background-size: 52px 37px !important;
457
  }
64
  right: 26px;
65
  width: 12px;
66
  height: 12px;
67
+ background: url("img/chosen-sprite.png") -42px 1px no-repeat;
68
  font-size: 1px;
69
  }
70
 
89
  display: block;
90
  width: 100%;
91
  height: 100%;
92
+ background: url("img/chosen-sprite.png") no-repeat 0 2px;
93
  }
94
 
95
  .chzn-container-single .chzn-search {
105
  padding: 4px 20px 4px 5px;
106
  border: 1px solid #aaa;
107
  outline: 0;
108
+ background: #fff url("img/chosen-sprite.png") no-repeat 100% -20px;
109
+ background: url("img/chosen-sprite.png") no-repeat 100% -20px, linear-gradient(#eee 1%, #fff 15%);
110
  font-family: sans-serif;
111
  font-size: 1em;
112
  }
203
  right: 3px;
204
  width: 12px;
205
  height: 12px;
206
+ background: url("img/chosen-sprite.png") -42px 1px no-repeat;
207
  font-size: 1px;
208
  }
209
 
305
  }
306
 
307
  .chzn-container .chzn-results-scroll-down span {
308
+ background: url("img/chosen-sprite.png") no-repeat -4px -3px;
309
  }
310
 
311
  .chzn-container .chzn-results-scroll-up span {
312
+ background: url("img/chosen-sprite.png") no-repeat -22px -3px;
313
  }
314
 
315
  /* @end */
426
 
427
  .chzn-rtl .chzn-search input {
428
  padding: 4px 5px 4px 20px;
429
+ background: #fff url("img/chosen-sprite.png") no-repeat -30px -20px;
430
+ background: url("img/chosen-sprite.png") no-repeat -30px -20px, linear-gradient(#eee 1%, #fff 15%);
 
431
  direction: rtl;
432
  }
433
 
450
  .chzn-container-multi .chzn-choices .search-choice .search-choice-close,
451
  .chzn-container .chzn-results-scroll-down span,
452
  .chzn-container .chzn-results-scroll-up span {
453
+ background-image: url("img/chosen-sprite@2x.png") !important;
454
  background-repeat: no-repeat !important;
455
  background-size: 52px 37px !important;
456
  }
{js → assets/dependencies/chosen}/chosen.jquery.min.js RENAMED
File without changes
assets/dependencies/chosen/chosen.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .chzn-container{display:inline-block;zoom:1;position:relative;font-size:13px;*display:inline}.chzn-container .chzn-drop{position:absolute;z-index:1010;top:29px;left:0;border:1px solid #aaa;border-top:0;background:#fff;box-shadow:0 4px 5px rgba(0,0,0,.15)}.chzn-container-single .chzn-single{display:block;overflow:hidden;position:relative;height:23px;padding:0 0 0 8px;border:1px solid #aaa;border-radius:5px;color:#444;background-color:#fff;background-image:linear-gradient(#fff 20%,#f6f6f6 50%,#eee 52%,#f4f4f4 100%);background-clip:padding-box;box-shadow:0 0 3px #fff inset,0 1px 1px rgba(0,0,0,.1);line-height:24px;white-space:nowrap;text-decoration:none;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.chzn-container-single .chzn-default{color:#999}.chzn-container-single .chzn-single span{display:block;overflow:hidden;margin-right:26px;white-space:nowrap;text-overflow:ellipsis;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis}.chzn-container-single .chzn-single abbr{display:block;position:absolute;top:6px;right:26px;width:12px;height:12px;background:url(img/chosen-sprite.png) -42px 1px no-repeat;font-size:1px}.chzn-container-single .chzn-single abbr:hover,.chzn-container-single.chzn-disabled .chzn-single abbr:hover{background-position:-42px -10px}.chzn-container-single .chzn-single div{display:block;position:absolute;top:0;right:0;width:18px;height:100%}.chzn-container-single .chzn-single div b{display:block;width:100%;height:100%;background:url(img/chosen-sprite.png) no-repeat 0 2px}.chzn-container-single .chzn-search{position:relative;z-index:1010;margin:0;padding:3px 4px;white-space:nowrap}.chzn-container-single .chzn-search input{margin:1px 0;padding:4px 20px 4px 5px;border:1px solid #aaa;outline:0;background:#fff url(img/chosen-sprite.png) no-repeat 100% -20px;background:url(img/chosen-sprite.png) no-repeat 100% -20px,linear-gradient(#eee 1%,#fff 15%);font-family:sans-serif;font-size:1em}.chzn-container-single .chzn-drop{border-radius:0 0 4px 4px;background-clip:padding-box}.chzn-container-single-nosearch .chzn-search input{position:absolute;left:-9000px}.chzn-container-multi .chzn-choices{overflow:hidden;position:relative;height:auto!important;height:1%;margin:0;padding:0;border:1px solid #aaa;background-color:#fff;background-image:linear-gradient(#eee 1%,#fff 15%);cursor:text}.chzn-container-multi .chzn-choices li{float:left;list-style:none}.chzn-container-multi .chzn-choices .search-field{margin:0;padding:0;white-space:nowrap}.chzn-container-multi .chzn-choices .search-field input{height:15px;margin:1px 0;padding:5px;border:0!important;outline:0;color:#666;background:transparent!important;box-shadow:none;font-family:sans-serif;font-size:100%}.chzn-container-multi .chzn-choices .search-field .default{color:#999}.chzn-container-multi .chzn-choices .search-choice{position:relative;margin:3px 0 3px 5px;padding:3px 20px 3px 5px;border:1px solid #aaa;border-radius:3px;color:#333;background-color:#e4e4e4;background-image:linear-gradient(#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-clip:padding-box;box-shadow:0 0 2px #fff inset,0 1px 0 rgba(0,0,0,.05);line-height:13px;cursor:default;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0)}.chzn-container-multi .chzn-choices .search-choice.search-choice-disabled{padding-right:5px;border:1px solid #ccc;color:#666;background-color:#e4e4e4;background-image:linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0)}.chzn-container-multi .chzn-choices .search-choice-focus{background:#d4d4d4}.chzn-container-multi .chzn-choices .search-choice .search-choice-close{display:block;position:absolute;top:4px;right:3px;width:12px;height:12px;background:url(img/chosen-sprite.png) -42px 1px no-repeat;font-size:1px}.chzn-container-multi .chzn-choices .search-choice .search-choice-close:hover,.chzn-container-multi .chzn-choices .search-choice-focus .search-choice-close{background-position:-42px -10px}.chzn-container .chzn-results{overflow-x:hidden;overflow-y:auto;position:relative;max-height:240px;margin:0 4px 4px 0;padding:0 0 0 4px;-webkit-overflow-scrolling:touch}.chzn-container-multi .chzn-results{margin:-1px 0 0;padding:0}.chzn-container .chzn-results li{display:none;margin:0;padding:5px 6px;line-height:15px;list-style:none}.chzn-container .chzn-results .active-result{display:list-item;cursor:pointer}.chzn-container .chzn-results .highlighted{color:#fff;background-color:#3875d7;background-image:linear-gradient(#3875d7 20%,#2a62bc 90%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#3875d7', endColorstr='#2a62bc', GradientType=0)}.chzn-container .chzn-results li em{background:#feffde;font-style:normal}.chzn-container .chzn-results .highlighted em{background:0 0}.chzn-container .chzn-results .no-results{display:list-item;background:#f4f4f4}.chzn-container .chzn-results .group-result{color:#999;font-weight:700;cursor:default}.chzn-container .chzn-results .group-option{padding-left:15px}.chzn-container-multi .chzn-drop .result-selected{display:none}.chzn-container .chzn-results-scroll{position:absolute;z-index:1;width:321px;margin:0 4px;background:#fff;text-align:center}.chzn-container .chzn-results-scroll span{display:inline-block;width:9px;height:17px;text-indent:-5000px}.chzn-container .chzn-results-scroll-down{bottom:0}.chzn-container .chzn-results-scroll-down span{background:url(img/chosen-sprite.png) no-repeat -4px -3px}.chzn-container .chzn-results-scroll-up span{background:url(img/chosen-sprite.png) no-repeat -22px -3px}.chzn-container-active .chzn-single{border:1px solid #5897fb;box-shadow:0 0 5px rgba(0,0,0,.3)}.chzn-container-active .chzn-single-with-drop{border:1px solid #aaa;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:#eee;background-image:linear-gradient(#eee 20%,#fff 80%);box-shadow:0 1px 0 #fff inset;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0)}.chzn-container-active .chzn-single-with-drop div{border-left:none;background:0 0}.chzn-container-active .chzn-single-with-drop div b{background-position:-18px 2px}.chzn-container-active .chzn-choices{border:1px solid #5897fb;box-shadow:0 0 5px rgba(0,0,0,.3)}.chzn-container-active .chzn-choices .search-field input{color:#111!important}.chzn-disabled{opacity:.5!important;cursor:default}.chzn-disabled .chzn-choices .search-choice .search-choice-close,.chzn-disabled .chzn-single{cursor:default}.chzn-rtl{text-align:right}.chzn-rtl .chzn-single{overflow:visible;padding:0 8px 0 0}.chzn-rtl .chzn-single span{margin-right:0;margin-left:26px;direction:rtl}.chzn-rtl .chzn-single div{right:auto;left:3px}.chzn-rtl .chzn-single abbr{right:auto;left:26px}.chzn-rtl .chzn-choices .search-field input{direction:rtl}.chzn-rtl .chzn-choices li{float:right}.chzn-rtl .chzn-choices .search-choice{margin:3px 5px 3px 0;padding:3px 5px 3px 19px}.chzn-rtl .chzn-choices .search-choice .search-choice-close{right:auto;left:4px}.chzn-rtl.chzn-container-single .chzn-results{margin:0 0 4px 4px;padding:0 4px 0 0}.chzn-rtl .chzn-results .group-option{padding-right:15px;padding-left:0}.chzn-rtl.chzn-container-active .chzn-single-with-drop div{border-right:none}.chzn-rtl .chzn-search input{padding:4px 5px 4px 20px;background:#fff url(img/chosen-sprite.png) no-repeat -30px -20px;background:url(img/chosen-sprite.png) no-repeat -30px -20px,linear-gradient(#eee 1%,#fff 15%);direction:rtl}.chzn-container-single.chzn-rtl .chzn-single div b{background-position:6px 2px}.chzn-container-single.chzn-rtl .chzn-single-with-drop div b{background-position:-12px 2px}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-resolution:144dpi){.chzn-container .chzn-results-scroll-down span,.chzn-container .chzn-results-scroll-up span,.chzn-container-multi .chzn-choices .search-choice .search-choice-close,.chzn-container-single .chzn-search input,.chzn-container-single .chzn-single abbr,.chzn-container-single .chzn-single div b,.chzn-rtl .chzn-search input{background-image:url(img/chosen-sprite@2x.png)!important;background-repeat:no-repeat!important;background-size:52px 37px!important}}
{img → assets/dependencies/chosen/img}/chosen-sprite.png RENAMED
File without changes
{img → assets/dependencies/chosen/img}/chosen-sprite@2x.png RENAMED
File without changes
assets/dependencies/chosen/index.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ //Nothing to see here
3
+
4
+ header( 'HTTP/1.0 403 Forbidden' );
assets/dependencies/datatables/css/jquery.dataTables.css ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Table styles
3
+ */
4
+ table.dataTable {
5
+ width: 100%;
6
+ margin: 0 auto;
7
+ clear: both;
8
+ border-collapse: separate;
9
+ border-spacing: 0;
10
+ /*
11
+ * Header and footer styles
12
+ */
13
+ /*
14
+ * Body styles
15
+ */
16
+ }
17
+ table.dataTable thead th,
18
+ table.dataTable tfoot th {
19
+ font-weight: bold;
20
+ }
21
+ table.dataTable thead th,
22
+ table.dataTable thead td {
23
+ padding: 10px 18px;
24
+ border-bottom: 1px solid #111111;
25
+ }
26
+ table.dataTable thead th:active,
27
+ table.dataTable thead td:active {
28
+ outline: none;
29
+ }
30
+ table.dataTable tfoot th,
31
+ table.dataTable tfoot td {
32
+ padding: 10px 18px 6px 18px;
33
+ border-top: 1px solid #111111;
34
+ }
35
+ table.dataTable thead .sorting_asc,
36
+ table.dataTable thead .sorting_desc,
37
+ table.dataTable thead .sorting {
38
+ cursor: pointer;
39
+ *cursor: hand;
40
+ }
41
+ table.dataTable thead .sorting {
42
+ background: url("../images/sort_both.png") no-repeat center right;
43
+ }
44
+ table.dataTable thead .sorting_asc {
45
+ background: url("../images/sort_asc.png") no-repeat center right;
46
+ }
47
+ table.dataTable thead .sorting_desc {
48
+ background: url("../images/sort_desc.png") no-repeat center right;
49
+ }
50
+ table.dataTable thead .sorting_asc_disabled {
51
+ background: url("../images/sort_asc_disabled.png") no-repeat center right;
52
+ }
53
+ table.dataTable thead .sorting_desc_disabled {
54
+ background: url("../images/sort_desc_disabled.png") no-repeat center right;
55
+ }
56
+ table.dataTable tbody tr {
57
+ background-color: white;
58
+ }
59
+ table.dataTable tbody tr.selected {
60
+ background-color: #b0bed9;
61
+ }
62
+ table.dataTable tbody th,
63
+ table.dataTable tbody td {
64
+ padding: 8px 10px;
65
+ }
66
+ table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
67
+ border-top: 1px solid #dddddd;
68
+ }
69
+ table.dataTable.row-border tbody tr:first-child th,
70
+ table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
71
+ table.dataTable.display tbody tr:first-child td {
72
+ border-top: none;
73
+ }
74
+ table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
75
+ border-top: 1px solid #dddddd;
76
+ border-right: 1px solid #dddddd;
77
+ }
78
+ table.dataTable.cell-border tbody tr th:first-child,
79
+ table.dataTable.cell-border tbody tr td:first-child {
80
+ border-left: 1px solid #dddddd;
81
+ }
82
+ table.dataTable.cell-border tbody tr:first-child th,
83
+ table.dataTable.cell-border tbody tr:first-child td {
84
+ border-top: none;
85
+ }
86
+ table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
87
+ background-color: #f9f9f9;
88
+ }
89
+ table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
90
+ background-color: #abb9d3;
91
+ }
92
+ table.dataTable.hover tbody tr:hover,
93
+ table.dataTable.hover tbody tr.odd:hover,
94
+ table.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,
95
+ table.dataTable.display tbody tr.odd:hover,
96
+ table.dataTable.display tbody tr.even:hover {
97
+ background-color: whitesmoke;
98
+ }
99
+ table.dataTable.hover tbody tr:hover.selected,
100
+ table.dataTable.hover tbody tr.odd:hover.selected,
101
+ table.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,
102
+ table.dataTable.display tbody tr.odd:hover.selected,
103
+ table.dataTable.display tbody tr.even:hover.selected {
104
+ background-color: #a9b7d1;
105
+ }
106
+ table.dataTable.order-column tbody tr > .sorting_1,
107
+ table.dataTable.order-column tbody tr > .sorting_2,
108
+ table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
109
+ table.dataTable.display tbody tr > .sorting_2,
110
+ table.dataTable.display tbody tr > .sorting_3 {
111
+ background-color: #f9f9f9;
112
+ }
113
+ table.dataTable.order-column tbody tr.selected > .sorting_1,
114
+ table.dataTable.order-column tbody tr.selected > .sorting_2,
115
+ table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
116
+ table.dataTable.display tbody tr.selected > .sorting_2,
117
+ table.dataTable.display tbody tr.selected > .sorting_3 {
118
+ background-color: #acbad4;
119
+ }
120
+ table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
121
+ background-color: #f1f1f1;
122
+ }
123
+ table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
124
+ background-color: #f3f3f3;
125
+ }
126
+ table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
127
+ background-color: whitesmoke;
128
+ }
129
+ table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
130
+ background-color: #a6b3cd;
131
+ }
132
+ table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
133
+ background-color: #a7b5ce;
134
+ }
135
+ table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
136
+ background-color: #a9b6d0;
137
+ }
138
+ table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
139
+ background-color: #f9f9f9;
140
+ }
141
+ table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
142
+ background-color: #fbfbfb;
143
+ }
144
+ table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
145
+ background-color: #fdfdfd;
146
+ }
147
+ table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
148
+ background-color: #acbad4;
149
+ }
150
+ table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
151
+ background-color: #adbbd6;
152
+ }
153
+ table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
154
+ background-color: #afbdd8;
155
+ }
156
+ table.dataTable.display tbody tr:hover > .sorting_1,
157
+ table.dataTable.display tbody tr.odd:hover > .sorting_1,
158
+ table.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,
159
+ table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,
160
+ table.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {
161
+ background-color: #eaeaea;
162
+ }
163
+ table.dataTable.display tbody tr:hover > .sorting_2,
164
+ table.dataTable.display tbody tr.odd:hover > .sorting_2,
165
+ table.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,
166
+ table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,
167
+ table.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {
168
+ background-color: #ebebeb;
169
+ }
170
+ table.dataTable.display tbody tr:hover > .sorting_3,
171
+ table.dataTable.display tbody tr.odd:hover > .sorting_3,
172
+ table.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,
173
+ table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,
174
+ table.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {
175
+ background-color: #eeeeee;
176
+ }
177
+ table.dataTable.display tbody tr:hover.selected > .sorting_1,
178
+ table.dataTable.display tbody tr.odd:hover.selected > .sorting_1,
179
+ table.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,
180
+ table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,
181
+ table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {
182
+ background-color: #a1aec7;
183
+ }
184
+ table.dataTable.display tbody tr:hover.selected > .sorting_2,
185
+ table.dataTable.display tbody tr.odd:hover.selected > .sorting_2,
186
+ table.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,
187
+ table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,
188
+ table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {
189
+ background-color: #a2afc8;
190
+ }
191
+ table.dataTable.display tbody tr:hover.selected > .sorting_3,
192
+ table.dataTable.display tbody tr.odd:hover.selected > .sorting_3,
193
+ table.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,
194
+ table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,
195
+ table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {
196
+ background-color: #a4b2cb;
197
+ }
198
+ table.dataTable.no-footer {
199
+ border-bottom: 1px solid #111111;
200
+ }
201
+ table.dataTable.nowrap th, table.dataTable.nowrap td {
202
+ white-space: nowrap;
203
+ }
204
+ table.dataTable.compact thead th,
205
+ table.dataTable.compact thead td {
206
+ padding: 5px 9px;
207
+ }
208
+ table.dataTable.compact tfoot th,
209
+ table.dataTable.compact tfoot td {
210
+ padding: 5px 9px 3px 9px;
211
+ }
212
+ table.dataTable.compact tbody th,
213
+ table.dataTable.compact tbody td {
214
+ padding: 4px 5px;
215
+ }
216
+ table.dataTable th.dt-left,
217
+ table.dataTable td.dt-left {
218
+ text-align: left;
219
+ }
220
+ table.dataTable th.dt-center,
221
+ table.dataTable td.dt-center,
222
+ table.dataTable td.dataTables_empty {
223
+ text-align: center;
224
+ }
225
+ table.dataTable th.dt-right,
226
+ table.dataTable td.dt-right {
227
+ text-align: right;
228
+ }
229
+ table.dataTable th.dt-justify,
230
+ table.dataTable td.dt-justify {
231
+ text-align: justify;
232
+ }
233
+ table.dataTable th.dt-nowrap,
234
+ table.dataTable td.dt-nowrap {
235
+ white-space: nowrap;
236
+ }
237
+ table.dataTable thead th.dt-head-left,
238
+ table.dataTable thead td.dt-head-left,
239
+ table.dataTable tfoot th.dt-head-left,
240
+ table.dataTable tfoot td.dt-head-left {
241
+ text-align: left;
242
+ }
243
+ table.dataTable thead th.dt-head-center,
244
+ table.dataTable thead td.dt-head-center,
245
+ table.dataTable tfoot th.dt-head-center,
246
+ table.dataTable tfoot td.dt-head-center {
247
+ text-align: center;
248
+ }
249
+ table.dataTable thead th.dt-head-right,
250
+ table.dataTable thead td.dt-head-right,
251
+ table.dataTable tfoot th.dt-head-right,
252
+ table.dataTable tfoot td.dt-head-right {
253
+ text-align: right;
254
+ }
255
+ table.dataTable thead th.dt-head-justify,
256
+ table.dataTable thead td.dt-head-justify,
257
+ table.dataTable tfoot th.dt-head-justify,
258
+ table.dataTable tfoot td.dt-head-justify {
259
+ text-align: justify;
260
+ }
261
+ table.dataTable thead th.dt-head-nowrap,
262
+ table.dataTable thead td.dt-head-nowrap,
263
+ table.dataTable tfoot th.dt-head-nowrap,
264
+ table.dataTable tfoot td.dt-head-nowrap {
265
+ white-space: nowrap;
266
+ }
267
+ table.dataTable tbody th.dt-body-left,
268
+ table.dataTable tbody td.dt-body-left {
269
+ text-align: left;
270
+ }
271
+ table.dataTable tbody th.dt-body-center,
272
+ table.dataTable tbody td.dt-body-center {
273
+ text-align: center;
274
+ }
275
+ table.dataTable tbody th.dt-body-right,
276
+ table.dataTable tbody td.dt-body-right {
277
+ text-align: right;
278
+ }
279
+ table.dataTable tbody th.dt-body-justify,
280
+ table.dataTable tbody td.dt-body-justify {
281
+ text-align: justify;
282
+ }
283
+ table.dataTable tbody th.dt-body-nowrap,
284
+ table.dataTable tbody td.dt-body-nowrap {
285
+ white-space: nowrap;
286
+ }
287
+
288
+ table.dataTable,
289
+ table.dataTable th,
290
+ table.dataTable td {
291
+ -webkit-box-sizing: content-box;
292
+ -moz-box-sizing: content-box;
293
+ box-sizing: content-box;
294
+ }
295
+
296
+ /*
297
+ * Control feature layout
298
+ */
299
+ .dataTables_wrapper {
300
+ position: relative;
301
+ clear: both;
302
+ *zoom: 1;
303
+ zoom: 1;
304
+ }
305
+ .dataTables_wrapper .dataTables_length {
306
+ float: left;
307
+ }
308
+ .dataTables_wrapper .dataTables_filter {
309
+ float: right;
310
+ text-align: right;
311
+ }
312
+ .dataTables_wrapper .dataTables_filter input {
313
+ margin-left: 0.5em;
314
+ }
315
+ .dataTables_wrapper .dataTables_info {
316
+ clear: both;
317
+ float: left;
318
+ padding-top: 0.755em;
319
+ }
320
+ .dataTables_wrapper .dataTables_paginate {
321
+ float: right;
322
+ text-align: right;
323
+ padding-top: 0.25em;
324
+ }
325
+ .dataTables_wrapper .dataTables_paginate .paginate_button {
326
+ box-sizing: border-box;
327
+ display: inline-block;
328
+ min-width: 1.5em;
329
+ padding: 0.5em 1em;
330
+ margin-left: 2px;
331
+ text-align: center;
332
+ text-decoration: none !important;
333
+ cursor: pointer;
334
+ *cursor: hand;
335
+ color: #333333 !important;
336
+ border: 1px solid transparent;
337
+ }
338
+ .dataTables_wrapper .dataTables_paginate .paginate_button.current, .dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
339
+ color: #333333 !important;
340
+ border: 1px solid #cacaca;
341
+ background-color: white;
342
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, white), color-stop(100%, gainsboro));
343
+ /* Chrome,Safari4+ */
344
+ background: -webkit-linear-gradient(top, white 0%, gainsboro 100%);
345
+ /* Chrome10+,Safari5.1+ */
346
+ background: -moz-linear-gradient(top, white 0%, gainsboro 100%);
347
+ /* FF3.6+ */
348
+ background: -ms-linear-gradient(top, white 0%, gainsboro 100%);
349
+ /* IE10+ */
350
+ background: -o-linear-gradient(top, white 0%, gainsboro 100%);
351
+ /* Opera 11.10+ */
352
+ background: linear-gradient(to bottom, white 0%, gainsboro 100%);
353
+ /* W3C */
354
+ }
355
+ .dataTables_wrapper .dataTables_paginate .paginate_button.disabled, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover, .dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active {
356
+ cursor: default;
357
+ color: #666 !important;
358
+ border: 1px solid transparent;
359
+ background: transparent;
360
+ box-shadow: none;
361
+ }
362
+ .dataTables_wrapper .dataTables_paginate .paginate_button:hover {
363
+ color: white !important;
364
+ border: 1px solid #111111;
365
+ background-color: #585858;
366
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111111));
367
+ /* Chrome,Safari4+ */
368
+ background: -webkit-linear-gradient(top, #585858 0%, #111111 100%);
369
+ /* Chrome10+,Safari5.1+ */
370
+ background: -moz-linear-gradient(top, #585858 0%, #111111 100%);
371
+ /* FF3.6+ */
372
+ background: -ms-linear-gradient(top, #585858 0%, #111111 100%);
373
+ /* IE10+ */
374
+ background: -o-linear-gradient(top, #585858 0%, #111111 100%);
375
+ /* Opera 11.10+ */
376
+ background: linear-gradient(to bottom, #585858 0%, #111111 100%);
377
+ /* W3C */
378
+ }
379
+ .dataTables_wrapper .dataTables_paginate .paginate_button:active {
380
+ outline: none;
381
+ background-color: #2b2b2b;
382
+ background: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));
383
+ /* Chrome,Safari4+ */
384
+ background: -webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
385
+ /* Chrome10+,Safari5.1+ */
386
+ background: -moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
387
+ /* FF3.6+ */
388
+ background: -ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
389
+ /* IE10+ */
390
+ background: -o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);
391
+ /* Opera 11.10+ */
392
+ background: linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);
393
+ /* W3C */
394
+ box-shadow: inset 0 0 3px #111;
395
+ }
396
+ .dataTables_wrapper .dataTables_processing {
397
+ position: absolute;
398
+ top: 50%;
399
+ left: 50%;
400
+ width: 100%;
401
+ height: 40px;
402
+ margin-left: -50%;
403
+ margin-top: -25px;
404
+ padding-top: 20px;
405
+ text-align: center;
406
+ font-size: 1.2em;
407
+ background-color: white;
408
+ background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
409
+ /* Chrome,Safari4+ */
410
+ background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
411
+ /* Chrome10+,Safari5.1+ */
412
+ background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
413
+ /* FF3.6+ */
414
+ background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
415
+ /* IE10+ */
416
+ background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
417
+ /* Opera 11.10+ */
418
+ background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
419
+ /* W3C */
420
+ }
421
+ .dataTables_wrapper .dataTables_length,
422
+ .dataTables_wrapper .dataTables_filter,
423
+ .dataTables_wrapper .dataTables_info,
424
+ .dataTables_wrapper .dataTables_processing,
425
+ .dataTables_wrapper .dataTables_paginate {
426
+ color: #333333;
427
+ }
428
+ .dataTables_wrapper .dataTables_scroll {
429
+ clear: both;
430
+ }
431
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody {
432
+ *margin-top: -1px;
433
+ -webkit-overflow-scrolling: touch;
434
+ }
435
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th > div.dataTables_sizing,
436
+ .dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td > div.dataTables_sizing {
437
+ height: 0;
438
+ overflow: hidden;
439
+ margin: 0 !important;
440
+ padding: 0 !important;
441
+ }
442
+ .dataTables_wrapper.no-footer .dataTables_scrollBody {
443
+ border-bottom: 1px solid #111111;
444
+ }
445
+ .dataTables_wrapper.no-footer div.dataTables_scrollHead table,
446
+ .dataTables_wrapper.no-footer div.dataTables_scrollBody table {
447
+ border-bottom: none;
448
+ }
449
+ .dataTables_wrapper:after {
450
+ visibility: hidden;
451
+ display: block;
452
+ content: "";
453
+ clear: both;
454
+ height: 0;
455
+ }
456
+
457
+ @media screen and (max-width: 767px) {
458
+ .dataTables_wrapper .dataTables_info,
459
+ .dataTables_wrapper .dataTables_paginate {
460
+ float: none;
461
+ text-align: center;
462
+ }
463
+ .dataTables_wrapper .dataTables_paginate {
464
+ margin-top: 0.5em;
465
+ }
466
+ }
467
+ @media screen and (max-width: 640px) {
468
+ .dataTables_wrapper .dataTables_length,
469
+ .dataTables_wrapper .dataTables_filter {
470
+ float: none;
471
+ text-align: center;
472
+ }
473
+ .dataTables_wrapper .dataTables_filter {
474
+ margin-top: 0.5em;
475
+ }
476
+ }
assets/dependencies/datatables/css/jquery.dataTables.min.css ADDED
@@ -0,0 +1 @@
 
1
+ table.dataTable{width:100%;margin:0 auto;clear:both;border-collapse:separate;border-spacing:0}table.dataTable thead th,table.dataTable tfoot th{font-weight:bold}table.dataTable thead th,table.dataTable thead td{padding:10px 18px;border-bottom:1px solid #111}table.dataTable thead th:active,table.dataTable thead td:active{outline:none}table.dataTable tfoot th,table.dataTable tfoot td{padding:10px 18px 6px 18px;border-top:1px solid #111}table.dataTable thead .sorting_asc,table.dataTable thead .sorting_desc,table.dataTable thead .sorting{cursor:pointer;*cursor:hand}table.dataTable thead .sorting{background:url("../images/sort_both.png") no-repeat center right}table.dataTable thead .sorting_asc{background:url("../images/sort_asc.png") no-repeat center right}table.dataTable thead .sorting_desc{background:url("../images/sort_desc.png") no-repeat center right}table.dataTable thead .sorting_asc_disabled{background:url("../images/sort_asc_disabled.png") no-repeat center right}table.dataTable thead .sorting_desc_disabled{background:url("../images/sort_desc_disabled.png") no-repeat center right}table.dataTable tbody tr{background-color:#fff}table.dataTable tbody tr.selected{background-color:#b0bed9}table.dataTable tbody th,table.dataTable tbody td{padding:8px 10px}table.dataTable.row-border tbody th,table.dataTable.row-border tbody td,table.dataTable.display tbody th,table.dataTable.display tbody td{border-top:1px solid #ddd}table.dataTable.row-border tbody tr:first-child th,table.dataTable.row-border tbody tr:first-child td,table.dataTable.display tbody tr:first-child th,table.dataTable.display tbody tr:first-child td{border-top:none}table.dataTable.cell-border tbody th,table.dataTable.cell-border tbody td{border-top:1px solid #ddd;border-right:1px solid #ddd}table.dataTable.cell-border tbody tr th:first-child,table.dataTable.cell-border tbody tr td:first-child{border-left:1px solid #ddd}table.dataTable.cell-border tbody tr:first-child th,table.dataTable.cell-border tbody tr:first-child td{border-top:none}table.dataTable.stripe tbody tr.odd,table.dataTable.display tbody tr.odd{background-color:#f9f9f9}table.dataTable.stripe tbody tr.odd.selected,table.dataTable.display tbody tr.odd.selected{background-color:#abb9d3}table.dataTable.hover tbody tr:hover,table.dataTable.hover tbody tr.odd:hover,table.dataTable.hover tbody tr.even:hover,table.dataTable.display tbody tr:hover,table.dataTable.display tbody tr.odd:hover,table.dataTable.display tbody tr.even:hover{background-color:#f5f5f5}table.dataTable.hover tbody tr:hover.selected,table.dataTable.hover tbody tr.odd:hover.selected,table.dataTable.hover tbody tr.even:hover.selected,table.dataTable.display tbody tr:hover.selected,table.dataTable.display tbody tr.odd:hover.selected,table.dataTable.display tbody tr.even:hover.selected{background-color:#a9b7d1}table.dataTable.order-column tbody tr>.sorting_1,table.dataTable.order-column tbody tr>.sorting_2,table.dataTable.order-column tbody tr>.sorting_3,table.dataTable.display tbody tr>.sorting_1,table.dataTable.display tbody tr>.sorting_2,table.dataTable.display tbody tr>.sorting_3{background-color:#f9f9f9}table.dataTable.order-column tbody tr.selected>.sorting_1,table.dataTable.order-column tbody tr.selected>.sorting_2,table.dataTable.order-column tbody tr.selected>.sorting_3,table.dataTable.display tbody tr.selected>.sorting_1,table.dataTable.display tbody tr.selected>.sorting_2,table.dataTable.display tbody tr.selected>.sorting_3{background-color:#acbad4}table.dataTable.display tbody tr.odd>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd>.sorting_1{background-color:#f1f1f1}table.dataTable.display tbody tr.odd>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd>.sorting_2{background-color:#f3f3f3}table.dataTable.display tbody tr.odd>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd>.sorting_3{background-color:#f5f5f5}table.dataTable.display tbody tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_1{background-color:#a6b3cd}table.dataTable.display tbody tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_2{background-color:#a7b5ce}table.dataTable.display tbody tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.odd.selected>.sorting_3{background-color:#a9b6d0}table.dataTable.display tbody tr.even>.sorting_1,table.dataTable.order-column.stripe tbody tr.even>.sorting_1{background-color:#f9f9f9}table.dataTable.display tbody tr.even>.sorting_2,table.dataTable.order-column.stripe tbody tr.even>.sorting_2{background-color:#fbfbfb}table.dataTable.display tbody tr.even>.sorting_3,table.dataTable.order-column.stripe tbody tr.even>.sorting_3{background-color:#fdfdfd}table.dataTable.display tbody tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_1{background-color:#acbad4}table.dataTable.display tbody tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_2{background-color:#adbbd6}table.dataTable.display tbody tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody tr:hover>.sorting_1,table.dataTable.display tbody tr.odd:hover>.sorting_1,table.dataTable.display tbody tr.even:hover>.sorting_1,table.dataTable.order-column.hover tbody tr:hover>.sorting_1,table.dataTable.order-column.hover tbody tr.odd:hover>.sorting_1,table.dataTable.order-column.hover tbody tr.even:hover>.sorting_1{background-color:#eaeaea}table.dataTable.display tbody tr:hover>.sorting_2,table.dataTable.display tbody tr.odd:hover>.sorting_2,table.dataTable.display tbody tr.even:hover>.sorting_2,table.dataTable.order-column.hover tbody tr:hover>.sorting_2,table.dataTable.order-column.hover tbody tr.odd:hover>.sorting_2,table.dataTable.order-column.hover tbody tr.even:hover>.sorting_2{background-color:#ebebeb}table.dataTable.display tbody tr:hover>.sorting_3,table.dataTable.display tbody tr.odd:hover>.sorting_3,table.dataTable.display tbody tr.even:hover>.sorting_3,table.dataTable.order-column.hover tbody tr:hover>.sorting_3,table.dataTable.order-column.hover tbody tr.odd:hover>.sorting_3,table.dataTable.order-column.hover tbody tr.even:hover>.sorting_3{background-color:#eee}table.dataTable.display tbody tr:hover.selected>.sorting_1,table.dataTable.display tbody tr.odd:hover.selected>.sorting_1,table.dataTable.display tbody tr.even:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr.odd:hover.selected>.sorting_1,table.dataTable.order-column.hover tbody tr.even:hover.selected>.sorting_1{background-color:#a1aec7}table.dataTable.display tbody tr:hover.selected>.sorting_2,table.dataTable.display tbody tr.odd:hover.selected>.sorting_2,table.dataTable.display tbody tr.even:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr.odd:hover.selected>.sorting_2,table.dataTable.order-column.hover tbody tr.even:hover.selected>.sorting_2{background-color:#a2afc8}table.dataTable.display tbody tr:hover.selected>.sorting_3,table.dataTable.display tbody tr.odd:hover.selected>.sorting_3,table.dataTable.display tbody tr.even:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr.odd:hover.selected>.sorting_3,table.dataTable.order-column.hover tbody tr.even:hover.selected>.sorting_3{background-color:#a4b2cb}table.dataTable.no-footer{border-bottom:1px solid #111}table.dataTable.nowrap th,table.dataTable.nowrap td{white-space:nowrap}table.dataTable.compact thead th,table.dataTable.compact thead td{padding:5px 9px}table.dataTable.compact tfoot th,table.dataTable.compact tfoot td{padding:5px 9px 3px 9px}table.dataTable.compact tbody th,table.dataTable.compact tbody td{padding:4px 5px}table.dataTable th.dt-left,table.dataTable td.dt-left{text-align:left}table.dataTable th.dt-center,table.dataTable td.dt-center,table.dataTable td.dataTables_empty{text-align:center}table.dataTable th.dt-right,table.dataTable td.dt-right{text-align:right}table.dataTable th.dt-justify,table.dataTable td.dt-justify{text-align:justify}table.dataTable th.dt-nowrap,table.dataTable td.dt-nowrap{white-space:nowrap}table.dataTable thead th.dt-head-left,table.dataTable thead td.dt-head-left,table.dataTable tfoot th.dt-head-left,table.dataTable tfoot td.dt-head-left{text-align:left}table.dataTable thead th.dt-head-center,table.dataTable thead td.dt-head-center,table.dataTable tfoot th.dt-head-center,table.dataTable tfoot td.dt-head-center{text-align:center}table.dataTable thead th.dt-head-right,table.dataTable thead td.dt-head-right,table.dataTable tfoot th.dt-head-right,table.dataTable tfoot td.dt-head-right{text-align:right}table.dataTable thead th.dt-head-justify,table.dataTable thead td.dt-head-justify,table.dataTable tfoot th.dt-head-justify,table.dataTable tfoot td.dt-head-justify{text-align:justify}table.dataTable thead th.dt-head-nowrap,table.dataTable thead td.dt-head-nowrap,table.dataTable tfoot th.dt-head-nowrap,table.dataTable tfoot td.dt-head-nowrap{white-space:nowrap}table.dataTable tbody th.dt-body-left,table.dataTable tbody td.dt-body-left{text-align:left}table.dataTable tbody th.dt-body-center,table.dataTable tbody td.dt-body-center{text-align:center}table.dataTable tbody th.dt-body-right,table.dataTable tbody td.dt-body-right{text-align:right}table.dataTable tbody th.dt-body-justify,table.dataTable tbody td.dt-body-justify{text-align:justify}table.dataTable tbody th.dt-body-nowrap,table.dataTable tbody td.dt-body-nowrap{white-space:nowrap}table.dataTable,table.dataTable th,table.dataTable td{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.dataTables_wrapper{position:relative;clear:both;*zoom:1;zoom:1}.dataTables_wrapper .dataTables_length{float:left}.dataTables_wrapper .dataTables_filter{float:right;text-align:right}.dataTables_wrapper .dataTables_filter input{margin-left:0.5em}.dataTables_wrapper .dataTables_info{clear:both;float:left;padding-top:0.755em}.dataTables_wrapper .dataTables_paginate{float:right;text-align:right;padding-top:0.25em}.dataTables_wrapper .dataTables_paginate .paginate_button{box-sizing:border-box;display:inline-block;min-width:1.5em;padding:0.5em 1em;margin-left:2px;text-align:center;text-decoration:none !important;cursor:pointer;*cursor:hand;color:#333 !important;border:1px solid transparent}.dataTables_wrapper .dataTables_paginate .paginate_button.current,.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover{color:#333 !important;border:1px solid #cacaca;background-color:#fff;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #fff), color-stop(100%, #dcdcdc));background:-webkit-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-moz-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-ms-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:-o-linear-gradient(top, #fff 0%, #dcdcdc 100%);background:linear-gradient(to bottom, #fff 0%, #dcdcdc 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover,.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:active{cursor:default;color:#666 !important;border:1px solid transparent;background:transparent;box-shadow:none}.dataTables_wrapper .dataTables_paginate .paginate_button:hover{color:white !important;border:1px solid #111;background-color:#585858;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #585858), color-stop(100%, #111));background:-webkit-linear-gradient(top, #585858 0%, #111 100%);background:-moz-linear-gradient(top, #585858 0%, #111 100%);background:-ms-linear-gradient(top, #585858 0%, #111 100%);background:-o-linear-gradient(top, #585858 0%, #111 100%);background:linear-gradient(to bottom, #585858 0%, #111 100%)}.dataTables_wrapper .dataTables_paginate .paginate_button:active{outline:none;background-color:#2b2b2b;background:-webkit-gradient(linear, left top, left bottom, color-stop(0%, #2b2b2b), color-stop(100%, #0c0c0c));background:-webkit-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-moz-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-ms-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:-o-linear-gradient(top, #2b2b2b 0%, #0c0c0c 100%);background:linear-gradient(to bottom, #2b2b2b 0%, #0c0c0c 100%);box-shadow:inset 0 0 3px #111}.dataTables_wrapper .dataTables_processing{position:absolute;top:50%;left:50%;width:100%;height:40px;margin-left:-50%;margin-top:-25px;padding-top:20px;text-align:center;font-size:1.2em;background-color:white;background:-webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255,255,255,0)), color-stop(25%, rgba(255,255,255,0.9)), color-stop(75%, rgba(255,255,255,0.9)), color-stop(100%, rgba(255,255,255,0)));background:-webkit-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-moz-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:-o-linear-gradient(left, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%);background:linear-gradient(to right, rgba(255,255,255,0) 0%, rgba(255,255,255,0.9) 25%, rgba(255,255,255,0.9) 75%, rgba(255,255,255,0) 100%)}.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter,.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_processing,.dataTables_wrapper .dataTables_paginate{color:#333}.dataTables_wrapper .dataTables_scroll{clear:both}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody{*margin-top:-1px;-webkit-overflow-scrolling:touch}.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody th>div.dataTables_sizing,.dataTables_wrapper .dataTables_scroll div.dataTables_scrollBody td>div.dataTables_sizing{height:0;overflow:hidden;margin:0 !important;padding:0 !important}.dataTables_wrapper.no-footer .dataTables_scrollBody{border-bottom:1px solid #111}.dataTables_wrapper.no-footer div.dataTables_scrollHead table,.dataTables_wrapper.no-footer div.dataTables_scrollBody table{border-bottom:none}.dataTables_wrapper:after{visibility:hidden;display:block;content:"";clear:both;height:0}@media screen and (max-width: 767px){.dataTables_wrapper .dataTables_info,.dataTables_wrapper .dataTables_paginate{float:none;text-align:center}.dataTables_wrapper .dataTables_paginate{margin-top:0.5em}}@media screen and (max-width: 640px){.dataTables_wrapper .dataTables_length,.dataTables_wrapper .dataTables_filter{float:none;text-align:center}.dataTables_wrapper .dataTables_filter{margin-top:0.5em}}
assets/dependencies/datatables/css/jquery.dataTables_themeroller.css ADDED
@@ -0,0 +1,330 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ * Table styles
3
+ */
4
+ table.dataTable {
5
+ width: 100%;
6
+ margin: 0 auto;
7
+ clear: both;
8
+ border-collapse: separate;
9
+ border-spacing: 0;
10
+ /*
11
+ * Header and footer styles
12
+ */
13
+ /*
14
+ * Body styles
15
+ */
16
+ }
17
+ table.dataTable thead th,
18
+ table.dataTable thead td,
19
+ table.dataTable tfoot th,
20
+ table.dataTable tfoot td {
21
+ padding: 4px 10px;
22
+ }
23
+ table.dataTable thead th,
24
+ table.dataTable tfoot th {
25
+ font-weight: bold;
26
+ }
27
+ table.dataTable thead th:active,
28
+ table.dataTable thead td:active {
29
+ outline: none;
30
+ }
31
+ table.dataTable thead .sorting_asc,
32
+ table.dataTable thead .sorting_desc,
33
+ table.dataTable thead .sorting {
34
+ cursor: pointer;
35
+ *cursor: hand;
36
+ }
37
+ table.dataTable thead th div.DataTables_sort_wrapper {
38
+ position: relative;
39
+ padding-right: 10px;
40
+ }
41
+ table.dataTable thead th div.DataTables_sort_wrapper span {
42
+ position: absolute;
43
+ top: 50%;
44
+ margin-top: -8px;
45
+ right: -5px;
46
+ }
47
+ table.dataTable thead th.ui-state-default {
48
+ border-right-width: 0;
49
+ }
50
+ table.dataTable thead th.ui-state-default:last-child {
51
+ border-right-width: 1px;
52
+ }
53
+ table.dataTable tbody tr {
54
+ background-color: white;
55
+ }
56
+ table.dataTable tbody tr.selected {
57
+ background-color: #b0bed9;
58
+ }
59
+ table.dataTable tbody th,
60
+ table.dataTable tbody td {
61
+ padding: 8px 10px;
62
+ }
63
+ table.dataTable th.center,
64
+ table.dataTable td.center,
65
+ table.dataTable td.dataTables_empty {
66
+ text-align: center;
67
+ }
68
+ table.dataTable th.right,
69
+ table.dataTable td.right {
70
+ text-align: right;
71
+ }
72
+ table.dataTable.row-border tbody th, table.dataTable.row-border tbody td, table.dataTable.display tbody th, table.dataTable.display tbody td {
73
+ border-top: 1px solid #dddddd;
74
+ }
75
+ table.dataTable.row-border tbody tr:first-child th,
76
+ table.dataTable.row-border tbody tr:first-child td, table.dataTable.display tbody tr:first-child th,
77
+ table.dataTable.display tbody tr:first-child td {
78
+ border-top: none;
79
+ }
80
+ table.dataTable.cell-border tbody th, table.dataTable.cell-border tbody td {
81
+ border-top: 1px solid #dddddd;
82
+ border-right: 1px solid #dddddd;
83
+ }
84
+ table.dataTable.cell-border tbody tr th:first-child,
85
+ table.dataTable.cell-border tbody tr td:first-child {
86
+ border-left: 1px solid #dddddd;
87
+ }
88
+ table.dataTable.cell-border tbody tr:first-child th,
89
+ table.dataTable.cell-border tbody tr:first-child td {
90
+ border-top: none;
91
+ }
92
+ table.dataTable.stripe tbody tr.odd, table.dataTable.display tbody tr.odd {
93
+ background-color: #f9f9f9;
94
+ }
95
+ table.dataTable.stripe tbody tr.odd.selected, table.dataTable.display tbody tr.odd.selected {
96
+ background-color: #abb9d3;
97
+ }
98
+ table.dataTable.hover tbody tr:hover,
99
+ table.dataTable.hover tbody tr.odd:hover,
100
+ table.dataTable.hover tbody tr.even:hover, table.dataTable.display tbody tr:hover,
101
+ table.dataTable.display tbody tr.odd:hover,
102
+ table.dataTable.display tbody tr.even:hover {
103
+ background-color: whitesmoke;
104
+ }
105
+ table.dataTable.hover tbody tr:hover.selected,
106
+ table.dataTable.hover tbody tr.odd:hover.selected,
107
+ table.dataTable.hover tbody tr.even:hover.selected, table.dataTable.display tbody tr:hover.selected,
108
+ table.dataTable.display tbody tr.odd:hover.selected,
109
+ table.dataTable.display tbody tr.even:hover.selected {
110
+ background-color: #a9b7d1;
111
+ }
112
+ table.dataTable.order-column tbody tr > .sorting_1,
113
+ table.dataTable.order-column tbody tr > .sorting_2,
114
+ table.dataTable.order-column tbody tr > .sorting_3, table.dataTable.display tbody tr > .sorting_1,
115
+ table.dataTable.display tbody tr > .sorting_2,
116
+ table.dataTable.display tbody tr > .sorting_3 {
117
+ background-color: #f9f9f9;
118
+ }
119
+ table.dataTable.order-column tbody tr.selected > .sorting_1,
120
+ table.dataTable.order-column tbody tr.selected > .sorting_2,
121
+ table.dataTable.order-column tbody tr.selected > .sorting_3, table.dataTable.display tbody tr.selected > .sorting_1,
122
+ table.dataTable.display tbody tr.selected > .sorting_2,
123
+ table.dataTable.display tbody tr.selected > .sorting_3 {
124
+ background-color: #acbad4;
125
+ }
126
+ table.dataTable.display tbody tr.odd > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd > .sorting_1 {
127
+ background-color: #f1f1f1;
128
+ }
129
+ table.dataTable.display tbody tr.odd > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd > .sorting_2 {
130
+ background-color: #f3f3f3;
131
+ }
132
+ table.dataTable.display tbody tr.odd > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd > .sorting_3 {
133
+ background-color: whitesmoke;
134
+ }
135
+ table.dataTable.display tbody tr.odd.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_1 {
136
+ background-color: #a6b3cd;
137
+ }
138
+ table.dataTable.display tbody tr.odd.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_2 {
139
+ background-color: #a7b5ce;
140
+ }
141
+ table.dataTable.display tbody tr.odd.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.odd.selected > .sorting_3 {
142
+ background-color: #a9b6d0;
143
+ }
144
+ table.dataTable.display tbody tr.even > .sorting_1, table.dataTable.order-column.stripe tbody tr.even > .sorting_1 {
145
+ background-color: #f9f9f9;
146
+ }
147
+ table.dataTable.display tbody tr.even > .sorting_2, table.dataTable.order-column.stripe tbody tr.even > .sorting_2 {
148
+ background-color: #fbfbfb;
149
+ }
150
+ table.dataTable.display tbody tr.even > .sorting_3, table.dataTable.order-column.stripe tbody tr.even > .sorting_3 {
151
+ background-color: #fdfdfd;
152
+ }
153
+ table.dataTable.display tbody tr.even.selected > .sorting_1, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_1 {
154
+ background-color: #acbad4;
155
+ }
156
+ table.dataTable.display tbody tr.even.selected > .sorting_2, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_2 {
157
+ background-color: #adbbd6;
158
+ }
159
+ table.dataTable.display tbody tr.even.selected > .sorting_3, table.dataTable.order-column.stripe tbody tr.even.selected > .sorting_3 {
160
+ background-color: #afbdd8;
161
+ }
162
+ table.dataTable.display tbody tr:hover > .sorting_1,
163
+ table.dataTable.display tbody tr.odd:hover > .sorting_1,
164
+ table.dataTable.display tbody tr.even:hover > .sorting_1, table.dataTable.order-column.hover tbody tr:hover > .sorting_1,
165
+ table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_1,
166
+ table.dataTable.order-column.hover tbody tr.even:hover > .sorting_1 {
167
+ background-color: #eaeaea;
168
+ }
169
+ table.dataTable.display tbody tr:hover > .sorting_2,
170
+ table.dataTable.display tbody tr.odd:hover > .sorting_2,
171
+ table.dataTable.display tbody tr.even:hover > .sorting_2, table.dataTable.order-column.hover tbody tr:hover > .sorting_2,
172
+ table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_2,
173
+ table.dataTable.order-column.hover tbody tr.even:hover > .sorting_2 {
174
+ background-color: #ebebeb;
175
+ }
176
+ table.dataTable.display tbody tr:hover > .sorting_3,
177
+ table.dataTable.display tbody tr.odd:hover > .sorting_3,
178
+ table.dataTable.display tbody tr.even:hover > .sorting_3, table.dataTable.order-column.hover tbody tr:hover > .sorting_3,
179
+ table.dataTable.order-column.hover tbody tr.odd:hover > .sorting_3,
180
+ table.dataTable.order-column.hover tbody tr.even:hover > .sorting_3 {
181
+ background-color: #eeeeee;
182
+ }
183
+ table.dataTable.display tbody tr:hover.selected > .sorting_1,
184
+ table.dataTable.display tbody tr.odd:hover.selected > .sorting_1,
185
+ table.dataTable.display tbody tr.even:hover.selected > .sorting_1, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_1,
186
+ table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_1,
187
+ table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_1 {
188
+ background-color: #a1aec7;
189
+ }
190
+ table.dataTable.display tbody tr:hover.selected > .sorting_2,
191
+ table.dataTable.display tbody tr.odd:hover.selected > .sorting_2,
192
+ table.dataTable.display tbody tr.even:hover.selected > .sorting_2, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_2,
193
+ table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_2,
194
+ table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_2 {
195
+ background-color: #a2afc8;
196
+ }
197
+ table.dataTable.display tbody tr:hover.selected > .sorting_3,
198
+ table.dataTable.display tbody tr.odd:hover.selected > .sorting_3,
199
+ table.dataTable.display tbody tr.even:hover.selected > .sorting_3, table.dataTable.order-column.hover tbody tr:hover.selected > .sorting_3,
200
+ table.dataTable.order-column.hover tbody tr.odd:hover.selected > .sorting_3,
201
+ table.dataTable.order-column.hover tbody tr.even:hover.selected > .sorting_3 {
202
+ background-color: #a4b2cb;
203
+ }
204
+
205
+ table.dataTable,
206
+ table.dataTable th,
207
+ table.dataTable td {
208
+ -webkit-box-sizing: content-box;
209
+ -moz-box-sizing: content-box;
210
+ box-sizing: content-box;
211
+ }
212
+
213
+ /*
214
+ * Control feature layout
215
+ */
216
+ .dataTables_wrapper {
217
+ position: relative;
218
+ clear: both;
219
+ *zoom: 1;
220
+ zoom: 1;
221
+ }
222
+ .dataTables_wrapper .dataTables_length {
223
+ float: left;
224
+ }
225
+ .dataTables_wrapper .dataTables_filter {
226
+ float: right;
227
+ text-align: right;
228
+ }
229
+ .dataTables_wrapper .dataTables_filter input {
230
+ margin-left: 0.5em;
231
+ }
232
+ .dataTables_wrapper .dataTables_info {
233
+ clear: both;
234
+ float: left;
235
+ padding-top: 0.55em;
236
+ }
237
+ .dataTables_wrapper .dataTables_paginate {
238
+ float: right;
239
+ text-align: right;
240
+ }
241
+ .dataTables_wrapper .dataTables_paginate .fg-button {
242
+ box-sizing: border-box;
243
+ display: inline-block;
244
+ min-width: 1.5em;
245
+ padding: 0.5em;
246
+ margin-left: 2px;
247
+ text-align: center;
248
+ text-decoration: none !important;
249
+ cursor: pointer;
250
+ *cursor: hand;
251
+ color: #333333 !important;
252
+ border: 1px solid transparent;
253
+ }
254
+ .dataTables_wrapper .dataTables_paginate .fg-button:active {
255
+ outline: none;
256
+ }
257
+ .dataTables_wrapper .dataTables_paginate .fg-button:first-child {
258
+ border-top-left-radius: 3px;
259
+ border-bottom-left-radius: 3px;
260
+ }
261
+ .dataTables_wrapper .dataTables_paginate .fg-button:last-child {
262
+ border-top-right-radius: 3px;
263
+ border-bottom-right-radius: 3px;
264
+ }
265
+ .dataTables_wrapper .dataTables_processing {
266
+ position: absolute;
267
+ top: 50%;
268
+ left: 50%;
269
+ width: 100%;
270
+ height: 40px;
271
+ margin-left: -50%;
272
+ margin-top: -25px;
273
+ padding-top: 20px;
274
+ text-align: center;
275
+ font-size: 1.2em;
276
+ background-color: white;
277
+ background: -webkit-gradient(linear, left top, right top, color-stop(0%, rgba(255, 255, 255, 0)), color-stop(25%, rgba(255, 255, 255, 0.9)), color-stop(75%, rgba(255, 255, 255, 0.9)), color-stop(100%, rgba(255, 255, 255, 0)));
278
+ /* Chrome,Safari4+ */
279
+ background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
280
+ /* Chrome10+,Safari5.1+ */
281
+ background: -moz-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
282
+ /* FF3.6+ */
283
+ background: -ms-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
284
+ /* IE10+ */
285
+ background: -o-linear-gradient(left, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
286
+ /* Opera 11.10+ */
287
+ background: linear-gradient(to right, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0.9) 25%, rgba(255, 255, 255, 0.9) 75%, rgba(255, 255, 255, 0) 100%);
288
+ /* W3C */
289
+ }
290
+ .dataTables_wrapper .dataTables_length,
291
+ .dataTables_wrapper .dataTables_filter,
292
+ .dataTables_wrapper .dataTables_info,
293
+ .dataTables_wrapper .dataTables_processing,
294
+ .dataTables_wrapper .dataTables_paginate {
295
+ color: #333333;
296
+ }
297
+ .dataTables_wrapper .dataTables_scroll {
298
+ clear: both;
299
+ }
300
+ .dataTables_wrapper .dataTables_scrollBody {
301
+ *margin-top: -1px;
302
+ -webkit-overflow-scrolling: touch;
303
+ }
304
+ .dataTables_wrapper .ui-widget-header {
305
+ font-weight: normal;
306
+ }
307
+ .dataTables_wrapper .ui-toolbar {
308
+ padding: 8px;
309
+ }
310
+ .dataTables_wrapper:after {
311
+ visibility: hidden;
312
+ display: block;
313
+ content: "";
314
+ clear: both;
315
+ height: 0;
316
+ }
317
+
318
+ @media screen and (max-width: 767px) {
319
+ .dataTables_wrapper .dataTables_length,
320
+ .dataTables_wrapper .dataTables_filter,
321
+ .dataTables_wrapper .dataTables_info,
322
+ .dataTables_wrapper .dataTables_paginate {
323
+ float: none;
324
+ text-align: center;
325
+ }
326
+ .dataTables_wrapper .dataTables_filter,
327
+ .dataTables_wrapper .dataTables_paginate {
328
+ margin-top: 0.5em;
329
+ }
330
+ }
assets/dependencies/datatables/images/Sorting icons.psd ADDED
Binary file
assets/dependencies/datatables/images/back_disabled.png ADDED
Binary file
assets/dependencies/datatables/images/back_enabled.png ADDED
Binary file
assets/dependencies/datatables/images/back_enabled_hover.png ADDED
Binary file
assets/dependencies/datatables/images/favicon.ico ADDED
Binary file
assets/dependencies/datatables/images/forward_disabled.png ADDED
Binary file
assets/dependencies/datatables/images/forward_enabled.png ADDED
Binary file
assets/dependencies/datatables/images/forward_enabled_hover.png ADDED
Binary file
assets/dependencies/datatables/images/sort_asc.png ADDED
Binary file
assets/dependencies/datatables/images/sort_asc_disabled.png ADDED
Binary file
assets/dependencies/datatables/images/sort_both.png ADDED
Binary file
assets/dependencies/datatables/images/sort_desc.png ADDED
Binary file
assets/dependencies/datatables/images/sort_desc_disabled.png ADDED
Binary file
assets/dependencies/datatables/js/jquery.dataTables.js ADDED
@@ -0,0 +1,14840 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! DataTables 1.10.4
2
+ * ©2008-2014 SpryMedia Ltd - datatables.net/license
3
+ */
4
+
5
+ /**
6
+ * @summary DataTables
7
+ * @description Paginate, search and order HTML tables
8
+ * @version 1.10.4
9
+ * @file jquery.dataTables.js
10
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
11
+ * @contact www.sprymedia.co.uk/contact
12
+ * @copyright Copyright 2008-2014 SpryMedia Ltd.
13
+ *
14
+ * This source file is free software, available under the following license:
15
+ * MIT license - http://datatables.net/license
16
+ *
17
+ * This source file is distributed in the hope that it will be useful, but
18
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
20
+ *
21
+ * For details please refer to: http://www.datatables.net
22
+ */
23
+
24
+ /*jslint evil: true, undef: true, browser: true */
25
+ /*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnScrollingWidthAdjust,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnScrollBarWidth,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
26
+
27
+ (/** @lends <global> */function( window, document, undefined ) {
28
+
29
+ (function( factory ) {
30
+ "use strict";
31
+
32
+ if ( typeof define === 'function' && define.amd ) {
33
+ // Define as an AMD module if possible
34
+ define( 'datatables', ['jquery'], factory );
35
+ }
36
+ else if ( typeof exports === 'object' ) {
37
+ // Node/CommonJS
38
+ factory( require( 'jquery' ) );
39
+ }
40
+ else if ( jQuery && !jQuery.fn.dataTable ) {
41
+ // Define using browser globals otherwise
42
+ // Prevent multiple instantiations if the script is loaded twice
43
+ factory( jQuery );
44
+ }
45
+ }
46
+ (/** @lends <global> */function( $ ) {
47
+ "use strict";
48
+
49
+ /**
50
+ * DataTables is a plug-in for the jQuery Javascript library. It is a highly
51
+ * flexible tool, based upon the foundations of progressive enhancement,
52
+ * which will add advanced interaction controls to any HTML table. For a
53
+ * full list of features please refer to
54
+ * [DataTables.net](href="http://datatables.net).
55
+ *
56
+ * Note that the `DataTable` object is not a global variable but is aliased
57
+ * to `jQuery.fn.DataTable` and `jQuery.fn.dataTable` through which it may
58
+ * be accessed.
59
+ *
60
+ * @class
61
+ * @param {object} [init={}] Configuration object for DataTables. Options
62
+ * are defined by {@link DataTable.defaults}
63
+ * @requires jQuery 1.7+
64
+ *
65
+ * @example
66
+ * // Basic initialisation
67
+ * $(document).ready( function {
68
+ * $('#example').dataTable();
69
+ * } );
70
+ *
71
+ * @example
72
+ * // Initialisation with configuration options - in this case, disable
73
+ * // pagination and sorting.
74
+ * $(document).ready( function {
75
+ * $('#example').dataTable( {
76
+ * "paginate": false,
77
+ * "sort": false
78
+ * } );
79
+ * } );
80
+ */
81
+ var DataTable;
82
+
83
+
84
+ /*
85
+ * It is useful to have variables which are scoped locally so only the
86
+ * DataTables functions can access them and they don't leak into global space.
87
+ * At the same time these functions are often useful over multiple files in the
88
+ * core and API, so we list, or at least document, all variables which are used
89
+ * by DataTables as private variables here. This also ensures that there is no
90
+ * clashing of variable names and that they can easily referenced for reuse.
91
+ */
92
+
93
+
94
+ // Defined else where
95
+ // _selector_run
96
+ // _selector_opts
97
+ // _selector_first
98
+ // _selector_row_indexes
99
+
100
+ var _ext; // DataTable.ext
101
+ var _Api; // DataTable.Api
102
+ var _api_register; // DataTable.Api.register
103
+ var _api_registerPlural; // DataTable.Api.registerPlural
104
+
105
+ var _re_dic = {};
106
+ var _re_new_lines = /[\r\n]/g;
107
+ var _re_html = /<.*?>/g;
108
+ var _re_date_start = /^[\w\+\-]/;
109
+ var _re_date_end = /[\w\+\-]$/;
110
+
111
+ // Escape regular expression special characters
112
+ var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
113
+
114
+ // U+2009 is thin space and U+202F is narrow no-break space, both used in many
115
+ // standards as thousands separators
116
+ var _re_formatted_numeric = /[',$£€¥%\u2009\u202F]/g;
117
+
118
+
119
+ var _empty = function ( d ) {
120
+ return !d || d === true || d === '-' ? true : false;
121
+ };
122
+
123
+
124
+ var _intVal = function ( s ) {
125
+ var integer = parseInt( s, 10 );
126
+ return !isNaN(integer) && isFinite(s) ? integer : null;
127
+ };
128
+
129
+ // Convert from a formatted number with characters other than `.` as the
130
+ // decimal place, to a Javascript number
131
+ var _numToDecimal = function ( num, decimalPoint ) {
132
+ // Cache created regular expressions for speed as this function is called often
133
+ if ( ! _re_dic[ decimalPoint ] ) {
134
+ _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
135
+ }
136
+ return typeof num === 'string' && decimalPoint !== '.' ?
137
+ num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
138
+ num;
139
+ };
140
+
141
+
142
+ var _isNumber = function ( d, decimalPoint, formatted ) {
143
+ var strType = typeof d === 'string';
144
+
145
+ if ( decimalPoint && strType ) {
146
+ d = _numToDecimal( d, decimalPoint );
147
+ }
148
+
149
+ if ( formatted && strType ) {
150
+ d = d.replace( _re_formatted_numeric, '' );
151
+ }
152
+
153
+ return _empty( d ) || (!isNaN( parseFloat(d) ) && isFinite( d ));
154
+ };
155
+
156
+
157
+ // A string without HTML in it can be considered to be HTML still
158
+ var _isHtml = function ( d ) {
159
+ return _empty( d ) || typeof d === 'string';
160
+ };
161
+
162
+
163
+ var _htmlNumeric = function ( d, decimalPoint, formatted ) {
164
+ if ( _empty( d ) ) {
165
+ return true;
166
+ }
167
+
168
+ var html = _isHtml( d );
169
+ return ! html ?
170
+ null :
171
+ _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
172
+ true :
173
+ null;
174
+ };
175
+
176
+
177
+ var _pluck = function ( a, prop, prop2 ) {
178
+ var out = [];
179
+ var i=0, ien=a.length;
180
+
181
+ // Could have the test in the loop for slightly smaller code, but speed
182
+ // is essential here
183
+ if ( prop2 !== undefined ) {
184
+ for ( ; i<ien ; i++ ) {
185
+ if ( a[i] && a[i][ prop ] ) {
186
+ out.push( a[i][ prop ][ prop2 ] );
187
+ }
188
+ }
189
+ }
190
+ else {
191
+ for ( ; i<ien ; i++ ) {
192
+ if ( a[i] ) {
193
+ out.push( a[i][ prop ] );
194
+ }
195
+ }
196
+ }
197
+
198
+ return out;
199
+ };
200
+
201
+
202
+ // Basically the same as _pluck, but rather than looping over `a` we use `order`
203
+ // as the indexes to pick from `a`
204
+ var _pluck_order = function ( a, order, prop, prop2 )
205
+ {
206
+ var out = [];
207
+ var i=0, ien=order.length;
208
+
209
+ // Could have the test in the loop for slightly smaller code, but speed
210
+ // is essential here
211
+ if ( prop2 !== undefined ) {
212
+ for ( ; i<ien ; i++ ) {
213
+ if ( a[ order[i] ][ prop ] ) {
214
+ out.push( a[ order[i] ][ prop ][ prop2 ] );
215
+ }
216
+ }
217
+ }
218
+ else {
219
+ for ( ; i<ien ; i++ ) {
220
+ out.push( a[ order[i] ][ prop ] );
221
+ }
222
+ }
223
+
224
+ return out;
225
+ };
226
+
227
+
228
+ var _range = function ( len, start )
229
+ {
230
+ var out = [];
231
+ var end;
232
+
233
+ if ( start === undefined ) {
234
+ start = 0;
235
+ end = len;
236
+ }
237
+ else {
238
+ end = start;
239
+ start = len;
240
+ }
241
+
242
+ for ( var i=start ; i<end ; i++ ) {
243
+ out.push( i );
244
+ }
245
+
246
+ return out;
247
+ };
248
+
249
+
250
+ var _removeEmpty = function ( a )
251
+ {
252
+ var out = [];
253
+
254
+ for ( var i=0, ien=a.length ; i<ien ; i++ ) {
255
+ if ( a[i] ) { // careful - will remove all falsy values!
256
+ out.push( a[i] );
257
+ }
258
+ }
259
+
260
+ return out;
261
+ };
262
+
263
+
264
+ var _stripHtml = function ( d ) {
265
+ return d.replace( _re_html, '' );
266
+ };
267
+
268
+
269
+ /**
270
+ * Find the unique elements in a source array.
271
+ *
272
+ * @param {array} src Source array
273
+ * @return {array} Array of unique items
274
+ * @ignore
275
+ */
276
+ var _unique = function ( src )
277
+ {
278
+ // A faster unique method is to use object keys to identify used values,
279
+ // but this doesn't work with arrays or objects, which we must also
280
+ // consider. See jsperf.com/compare-array-unique-versions/4 for more
281
+ // information.
282
+ var
283
+ out = [],
284
+ val,
285
+ i, ien=src.length,
286
+ j, k=0;
287
+
288
+ again: for ( i=0 ; i<ien ; i++ ) {
289
+ val = src[i];
290
+
291
+ for ( j=0 ; j<k ; j++ ) {
292
+ if ( out[j] === val ) {
293
+ continue again;
294
+ }
295
+ }
296
+
297
+ out.push( val );
298
+ k++;
299
+ }
300
+
301
+ return out;
302
+ };
303
+
304
+
305
+
306
+ /**
307
+ * Create a mapping object that allows camel case parameters to be looked up
308
+ * for their Hungarian counterparts. The mapping is stored in a private
309
+ * parameter called `_hungarianMap` which can be accessed on the source object.
310
+ * @param {object} o
311
+ * @memberof DataTable#oApi
312
+ */
313
+ function _fnHungarianMap ( o )
314
+ {
315
+ var
316
+ hungarian = 'a aa ai ao as b fn i m o s ',
317
+ match,
318
+ newKey,
319
+ map = {};
320
+
321
+ $.each( o, function (key, val) {
322
+ match = key.match(/^([^A-Z]+?)([A-Z])/);
323
+
324
+ if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
325
+ {
326
+ newKey = key.replace( match[0], match[2].toLowerCase() );
327
+ map[ newKey ] = key;
328
+
329
+ if ( match[1] === 'o' )
330
+ {
331
+ _fnHungarianMap( o[key] );
332
+ }
333
+ }
334
+ } );
335
+
336
+ o._hungarianMap = map;
337
+ }
338
+
339
+
340
+ /**
341
+ * Convert from camel case parameters to Hungarian, based on a Hungarian map
342
+ * created by _fnHungarianMap.
343
+ * @param {object} src The model object which holds all parameters that can be
344
+ * mapped.
345
+ * @param {object} user The object to convert from camel case to Hungarian.
346
+ * @param {boolean} force When set to `true`, properties which already have a
347
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
348
+ * won't be.
349
+ * @memberof DataTable#oApi
350
+ */
351
+ function _fnCamelToHungarian ( src, user, force )
352
+ {
353
+ if ( ! src._hungarianMap ) {
354
+ _fnHungarianMap( src );
355
+ }
356
+
357
+ var hungarianKey;
358
+
359
+ $.each( user, function (key, val) {
360
+ hungarianKey = src._hungarianMap[ key ];
361
+
362
+ if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
363
+ {
364
+ // For objects, we need to buzz down into the object to copy parameters
365
+ if ( hungarianKey.charAt(0) === 'o' )
366
+ {
367
+ // Copy the camelCase options over to the hungarian
368
+ if ( ! user[ hungarianKey ] ) {
369
+ user[ hungarianKey ] = {};
370
+ }
371
+ $.extend( true, user[hungarianKey], user[key] );
372
+
373
+ _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
374
+ }
375
+ else {
376
+ user[hungarianKey] = user[ key ];
377
+ }
378
+ }
379
+ } );
380
+ }
381
+
382
+
383
+ /**
384
+ * Language compatibility - when certain options are given, and others aren't, we
385
+ * need to duplicate the values over, in order to provide backwards compatibility
386
+ * with older language files.
387
+ * @param {object} oSettings dataTables settings object
388
+ * @memberof DataTable#oApi
389
+ */
390
+ function _fnLanguageCompat( lang )
391
+ {
392
+ var defaults = DataTable.defaults.oLanguage;
393
+ var zeroRecords = lang.sZeroRecords;
394
+
395
+ /* Backwards compatibility - if there is no sEmptyTable given, then use the same as
396
+ * sZeroRecords - assuming that is given.
397
+ */
398
+ if ( ! lang.sEmptyTable && zeroRecords &&
399
+ defaults.sEmptyTable === "No data available in table" )
400
+ {
401
+ _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
402
+ }
403
+
404
+ /* Likewise with loading records */
405
+ if ( ! lang.sLoadingRecords && zeroRecords &&
406
+ defaults.sLoadingRecords === "Loading..." )
407
+ {
408
+ _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
409
+ }
410
+
411
+ // Old parameter name of the thousands separator mapped onto the new
412
+ if ( lang.sInfoThousands ) {
413
+ lang.sThousands = lang.sInfoThousands;
414
+ }
415
+
416
+ var decimal = lang.sDecimal;
417
+ if ( decimal ) {
418
+ _addNumericSort( decimal );
419
+ }
420
+ }
421
+
422
+
423
+ /**
424
+ * Map one parameter onto another
425
+ * @param {object} o Object to map
426
+ * @param {*} knew The new parameter name
427
+ * @param {*} old The old parameter name
428
+ */
429
+ var _fnCompatMap = function ( o, knew, old ) {
430
+ if ( o[ knew ] !== undefined ) {
431
+ o[ old ] = o[ knew ];
432
+ }
433
+ };
434
+
435
+
436
+ /**
437
+ * Provide backwards compatibility for the main DT options. Note that the new
438
+ * options are mapped onto the old parameters, so this is an external interface
439
+ * change only.
440
+ * @param {object} init Object to map
441
+ */
442
+ function _fnCompatOpts ( init )
443
+ {
444
+ _fnCompatMap( init, 'ordering', 'bSort' );
445
+ _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
446
+ _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
447
+ _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
448
+ _fnCompatMap( init, 'order', 'aaSorting' );
449
+ _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
450
+ _fnCompatMap( init, 'paging', 'bPaginate' );
451
+ _fnCompatMap( init, 'pagingType', 'sPaginationType' );
452
+ _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
453
+ _fnCompatMap( init, 'searching', 'bFilter' );
454
+
455
+ // Column search objects are in an array, so it needs to be converted
456
+ // element by element
457
+ var searchCols = init.aoSearchCols;
458
+
459
+ if ( searchCols ) {
460
+ for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
461
+ if ( searchCols[i] ) {
462
+ _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
463
+ }
464
+ }
465
+ }
466
+ }
467
+
468
+
469
+ /**
470
+ * Provide backwards compatibility for column options. Note that the new options
471
+ * are mapped onto the old parameters, so this is an external interface change
472
+ * only.
473
+ * @param {object} init Object to map
474
+ */
475
+ function _fnCompatCols ( init )
476
+ {
477
+ _fnCompatMap( init, 'orderable', 'bSortable' );
478
+ _fnCompatMap( init, 'orderData', 'aDataSort' );
479
+ _fnCompatMap( init, 'orderSequence', 'asSorting' );
480
+ _fnCompatMap( init, 'orderDataType', 'sortDataType' );
481
+ }
482
+
483
+
484
+ /**
485
+ * Browser feature detection for capabilities, quirks
486
+ * @param {object} settings dataTables settings object
487
+ * @memberof DataTable#oApi
488
+ */
489
+ function _fnBrowserDetect( settings )
490
+ {
491
+ var browser = settings.oBrowser;
492
+
493
+ // Scrolling feature / quirks detection
494
+ var n = $('<div/>')
495
+ .css( {
496
+ position: 'absolute',
497
+ top: 0,
498
+ left: 0,
499
+ height: 1,
500
+ width: 1,
501
+ overflow: 'hidden'
502
+ } )
503
+ .append(
504
+ $('<div/>')
505
+ .css( {
506
+ position: 'absolute',
507
+ top: 1,
508
+ left: 1,
509
+ width: 100,
510
+ overflow: 'scroll'
511
+ } )
512
+ .append(
513
+ $('<div class="test"/>')
514
+ .css( {
515
+ width: '100%',
516
+ height: 10
517
+ } )
518
+ )
519
+ )
520
+ .appendTo( 'body' );
521
+
522
+ var test = n.find('.test');
523
+
524
+ // IE6/7 will oversize a width 100% element inside a scrolling element, to
525
+ // include the width of the scrollbar, while other browsers ensure the inner
526
+ // element is contained without forcing scrolling
527
+ browser.bScrollOversize = test[0].offsetWidth === 100;
528
+
529
+ // In rtl text layout, some browsers (most, but not all) will place the
530
+ // scrollbar on the left, rather than the right.
531
+ browser.bScrollbarLeft = test.offset().left !== 1;
532
+
533
+ n.remove();
534
+ }
535
+
536
+
537
+ /**
538
+ * Array.prototype reduce[Right] method, used for browsers which don't support
539
+ * JS 1.6. Done this way to reduce code size, since we iterate either way
540
+ * @param {object} settings dataTables settings object
541
+ * @memberof DataTable#oApi
542
+ */
543
+ function _fnReduce ( that, fn, init, start, end, inc )
544
+ {
545
+ var
546
+ i = start,
547
+ value,
548
+ isSet = false;
549
+
550
+ if ( init !== undefined ) {
551
+ value = init;
552
+ isSet = true;
553
+ }
554
+
555
+ while ( i !== end ) {
556
+ if ( ! that.hasOwnProperty(i) ) {
557
+ continue;
558
+ }
559
+
560
+ value = isSet ?
561
+ fn( value, that[i], i, that ) :
562
+ that[i];
563
+
564
+ isSet = true;
565
+ i += inc;
566
+ }
567
+
568
+ return value;
569
+ }
570
+
571
+ /**
572
+ * Add a column to the list used for the table with default values
573
+ * @param {object} oSettings dataTables settings object
574
+ * @param {node} nTh The th element for this column
575
+ * @memberof DataTable#oApi
576
+ */
577
+ function _fnAddColumn( oSettings, nTh )
578
+ {
579
+ // Add column to aoColumns array
580
+ var oDefaults = DataTable.defaults.column;
581
+ var iCol = oSettings.aoColumns.length;
582
+ var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
583
+ "nTh": nTh ? nTh : document.createElement('th'),
584
+ "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
585
+ "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
586
+ "mData": oDefaults.mData ? oDefaults.mData : iCol,
587
+ idx: iCol
588
+ } );
589
+ oSettings.aoColumns.push( oCol );
590
+
591
+ // Add search object for column specific search. Note that the `searchCols[ iCol ]`
592
+ // passed into extend can be undefined. This allows the user to give a default
593
+ // with only some of the parameters defined, and also not give a default
594
+ var searchCols = oSettings.aoPreSearchCols;
595
+ searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
596
+
597
+ // Use the default column options function to initialise classes etc
598
+ _fnColumnOptions( oSettings, iCol, null );
599
+ }
600
+
601
+
602
+ /**
603
+ * Apply options for a column
604
+ * @param {object} oSettings dataTables settings object
605
+ * @param {int} iCol column index to consider
606
+ * @param {object} oOptions object with sType, bVisible and bSearchable etc
607
+ * @memberof DataTable#oApi
608
+ */
609
+ function _fnColumnOptions( oSettings, iCol, oOptions )
610
+ {
611
+ var oCol = oSettings.aoColumns[ iCol ];
612
+ var oClasses = oSettings.oClasses;
613
+ var th = $(oCol.nTh);
614
+
615
+ // Try to get width information from the DOM. We can't get it from CSS
616
+ // as we'd need to parse the CSS stylesheet. `width` option can override
617
+ if ( ! oCol.sWidthOrig ) {
618
+ // Width attribute
619
+ oCol.sWidthOrig = th.attr('width') || null;
620
+
621
+ // Style attribute
622
+ var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
623
+ if ( t ) {
624
+ oCol.sWidthOrig = t[1];
625
+ }
626
+ }
627
+
628
+ /* User specified column options */
629
+ if ( oOptions !== undefined && oOptions !== null )
630
+ {
631
+ // Backwards compatibility
632
+ _fnCompatCols( oOptions );
633
+
634
+ // Map camel case parameters to their Hungarian counterparts
635
+ _fnCamelToHungarian( DataTable.defaults.column, oOptions );
636
+
637
+ /* Backwards compatibility for mDataProp */
638
+ if ( oOptions.mDataProp !== undefined && !oOptions.mData )
639
+ {
640
+ oOptions.mData = oOptions.mDataProp;
641
+ }
642
+
643
+ if ( oOptions.sType )
644
+ {
645
+ oCol._sManualType = oOptions.sType;
646
+ }
647
+
648
+ // `class` is a reserved word in Javascript, so we need to provide
649
+ // the ability to use a valid name for the camel case input
650
+ if ( oOptions.className && ! oOptions.sClass )
651
+ {
652
+ oOptions.sClass = oOptions.className;
653
+ }
654
+
655
+ $.extend( oCol, oOptions );
656
+ _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
657
+
658
+ /* iDataSort to be applied (backwards compatibility), but aDataSort will take
659
+ * priority if defined
660
+ */
661
+ if ( typeof oOptions.iDataSort === 'number' )
662
+ {
663
+ oCol.aDataSort = [ oOptions.iDataSort ];
664
+ }
665
+ _fnMap( oCol, oOptions, "aDataSort" );
666
+ }
667
+
668
+ /* Cache the data get and set functions for speed */
669
+ var mDataSrc = oCol.mData;
670
+ var mData = _fnGetObjectDataFn( mDataSrc );
671
+ var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
672
+
673
+ var attrTest = function( src ) {
674
+ return typeof src === 'string' && src.indexOf('@') !== -1;
675
+ };
676
+ oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
677
+ attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
678
+ );
679
+
680
+ oCol.fnGetData = function (rowData, type, meta) {
681
+ var innerData = mData( rowData, type, undefined, meta );
682
+
683
+ return mRender && type ?
684
+ mRender( innerData, type, rowData, meta ) :
685
+ innerData;
686
+ };
687
+ oCol.fnSetData = function ( rowData, val, meta ) {
688
+ return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
689
+ };
690
+
691
+ // Indicate if DataTables should read DOM data as an object or array
692
+ // Used in _fnGetRowElements
693
+ if ( typeof mDataSrc !== 'number' ) {
694
+ oSettings._rowReadObject = true;
695
+ }
696
+
697
+ /* Feature sorting overrides column specific when off */
698
+ if ( !oSettings.oFeatures.bSort )
699
+ {
700
+ oCol.bSortable = false;
701
+ th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
702
+ }
703
+
704
+ /* Check that the class assignment is correct for sorting */
705
+ var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
706
+ var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
707
+ if ( !oCol.bSortable || (!bAsc && !bDesc) )
708
+ {
709
+ oCol.sSortingClass = oClasses.sSortableNone;
710
+ oCol.sSortingClassJUI = "";
711
+ }
712
+ else if ( bAsc && !bDesc )
713
+ {
714
+ oCol.sSortingClass = oClasses.sSortableAsc;
715
+ oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
716
+ }
717
+ else if ( !bAsc && bDesc )
718
+ {
719
+ oCol.sSortingClass = oClasses.sSortableDesc;
720
+ oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
721
+ }
722
+ else
723
+ {
724
+ oCol.sSortingClass = oClasses.sSortable;
725
+ oCol.sSortingClassJUI = oClasses.sSortJUI;
726
+ }
727
+ }
728
+
729
+
730
+ /**
731
+ * Adjust the table column widths for new data. Note: you would probably want to
732
+ * do a redraw after calling this function!
733
+ * @param {object} settings dataTables settings object
734
+ * @memberof DataTable#oApi
735
+ */
736
+ function _fnAdjustColumnSizing ( settings )
737
+ {
738
+ /* Not interested in doing column width calculation if auto-width is disabled */
739
+ if ( settings.oFeatures.bAutoWidth !== false )
740
+ {
741
+ var columns = settings.aoColumns;
742
+
743
+ _fnCalculateColumnWidths( settings );
744
+ for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
745
+ {
746
+ columns[i].nTh.style.width = columns[i].sWidth;
747
+ }
748
+ }
749
+
750
+ var scroll = settings.oScroll;
751
+ if ( scroll.sY !== '' || scroll.sX !== '')
752
+ {
753
+ _fnScrollDraw( settings );
754
+ }
755
+
756
+ _fnCallbackFire( settings, null, 'column-sizing', [settings] );
757
+ }
758
+
759
+
760
+ /**
761
+ * Covert the index of a visible column to the index in the data array (take account
762
+ * of hidden columns)
763
+ * @param {object} oSettings dataTables settings object
764
+ * @param {int} iMatch Visible column index to lookup
765
+ * @returns {int} i the data index
766
+ * @memberof DataTable#oApi
767
+ */
768
+ function _fnVisibleToColumnIndex( oSettings, iMatch )
769
+ {
770
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
771
+
772
+ return typeof aiVis[iMatch] === 'number' ?
773
+ aiVis[iMatch] :
774
+ null;
775
+ }
776
+
777
+
778
+ /**
779
+ * Covert the index of an index in the data array and convert it to the visible
780
+ * column index (take account of hidden columns)
781
+ * @param {int} iMatch Column index to lookup
782
+ * @param {object} oSettings dataTables settings object
783
+ * @returns {int} i the data index
784
+ * @memberof DataTable#oApi
785
+ */
786
+ function _fnColumnIndexToVisible( oSettings, iMatch )
787
+ {
788
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
789
+ var iPos = $.inArray( iMatch, aiVis );
790
+
791
+ return iPos !== -1 ? iPos : null;
792
+ }
793
+
794
+
795
+ /**
796
+ * Get the number of visible columns
797
+ * @param {object} oSettings dataTables settings object
798
+ * @returns {int} i the number of visible columns
799
+ * @memberof DataTable#oApi
800
+ */
801
+ function _fnVisbleColumns( oSettings )
802
+ {
803
+ return _fnGetColumns( oSettings, 'bVisible' ).length;
804
+ }
805
+
806
+
807
+ /**
808
+ * Get an array of column indexes that match a given property
809
+ * @param {object} oSettings dataTables settings object
810
+ * @param {string} sParam Parameter in aoColumns to look for - typically
811
+ * bVisible or bSearchable
812
+ * @returns {array} Array of indexes with matched properties
813
+ * @memberof DataTable#oApi
814
+ */
815
+ function _fnGetColumns( oSettings, sParam )
816
+ {
817
+ var a = [];
818
+
819
+ $.map( oSettings.aoColumns, function(val, i) {
820
+ if ( val[sParam] ) {
821
+ a.push( i );
822
+ }
823
+ } );
824
+
825
+ return a;
826
+ }
827
+
828
+
829
+ /**
830
+ * Calculate the 'type' of a column
831
+ * @param {object} settings dataTables settings object
832
+ * @memberof DataTable#oApi
833
+ */
834
+ function _fnColumnTypes ( settings )
835
+ {
836
+ var columns = settings.aoColumns;
837
+ var data = settings.aoData;
838
+ var types = DataTable.ext.type.detect;
839
+ var i, ien, j, jen, k, ken;
840
+ var col, cell, detectedType, cache;
841
+
842
+ // For each column, spin over the
843
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
844
+ col = columns[i];
845
+ cache = [];
846
+
847
+ if ( ! col.sType && col._sManualType ) {
848
+ col.sType = col._sManualType;
849
+ }
850
+ else if ( ! col.sType ) {
851
+ for ( j=0, jen=types.length ; j<jen ; j++ ) {
852
+ for ( k=0, ken=data.length ; k<ken ; k++ ) {
853
+ // Use a cache array so we only need to get the type data
854
+ // from the formatter once (when using multiple detectors)
855
+ if ( cache[k] === undefined ) {
856
+ cache[k] = _fnGetCellData( settings, k, i, 'type' );
857
+ }
858
+
859
+ detectedType = types[j]( cache[k], settings );
860
+
861
+ // If null, then this type can't apply to this column, so
862
+ // rather than testing all cells, break out. There is an
863
+ // exception for the last type which is `html`. We need to
864
+ // scan all rows since it is possible to mix string and HTML
865
+ // types
866
+ if ( ! detectedType && j !== types.length-1 ) {
867
+ break;
868
+ }
869
+
870
+ // Only a single match is needed for html type since it is
871
+ // bottom of the pile and very similar to string
872
+ if ( detectedType === 'html' ) {
873
+ break;
874
+ }
875
+ }
876
+
877
+ // Type is valid for all data points in the column - use this
878
+ // type
879
+ if ( detectedType ) {
880
+ col.sType = detectedType;
881
+ break;
882
+ }
883
+ }
884
+
885
+ // Fall back - if no type was detected, always use string
886
+ if ( ! col.sType ) {
887
+ col.sType = 'string';
888
+ }
889
+ }
890
+ }
891
+ }
892
+
893
+
894
+ /**
895
+ * Take the column definitions and static columns arrays and calculate how
896
+ * they relate to column indexes. The callback function will then apply the
897
+ * definition found for a column to a suitable configuration object.
898
+ * @param {object} oSettings dataTables settings object
899
+ * @param {array} aoColDefs The aoColumnDefs array that is to be applied
900
+ * @param {array} aoCols The aoColumns array that defines columns individually
901
+ * @param {function} fn Callback function - takes two parameters, the calculated
902
+ * column index and the definition for that column.
903
+ * @memberof DataTable#oApi
904
+ */
905
+ function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
906
+ {
907
+ var i, iLen, j, jLen, k, kLen, def;
908
+ var columns = oSettings.aoColumns;
909
+
910
+ // Column definitions with aTargets
911
+ if ( aoColDefs )
912
+ {
913
+ /* Loop over the definitions array - loop in reverse so first instance has priority */
914
+ for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
915
+ {
916
+ def = aoColDefs[i];
917
+
918
+ /* Each definition can target multiple columns, as it is an array */
919
+ var aTargets = def.targets !== undefined ?
920
+ def.targets :
921
+ def.aTargets;
922
+
923
+ if ( ! $.isArray( aTargets ) )
924
+ {
925
+ aTargets = [ aTargets ];
926
+ }
927
+
928
+ for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
929
+ {
930
+ if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
931
+ {
932
+ /* Add columns that we don't yet know about */
933
+ while( columns.length <= aTargets[j] )
934
+ {
935
+ _fnAddColumn( oSettings );
936
+ }
937
+
938
+ /* Integer, basic index */
939
+ fn( aTargets[j], def );
940
+ }
941
+ else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
942
+ {
943
+ /* Negative integer, right to left column counting */
944
+ fn( columns.length+aTargets[j], def );
945
+ }
946
+ else if ( typeof aTargets[j] === 'string' )
947
+ {
948
+ /* Class name matching on TH element */
949
+ for ( k=0, kLen=columns.length ; k<kLen ; k++ )
950
+ {
951
+ if ( aTargets[j] == "_all" ||
952
+ $(columns[k].nTh).hasClass( aTargets[j] ) )
953
+ {
954
+ fn( k, def );
955
+ }
956
+ }
957
+ }
958
+ }
959
+ }
960
+ }
961
+
962
+ // Statically defined columns array
963
+ if ( aoCols )
964
+ {
965
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
966
+ {
967
+ fn( i, aoCols[i] );
968
+ }
969
+ }
970
+ }
971
+
972
+ /**
973
+ * Add a data array to the table, creating DOM node etc. This is the parallel to
974
+ * _fnGatherData, but for adding rows from a Javascript source, rather than a
975
+ * DOM source.
976
+ * @param {object} oSettings dataTables settings object
977
+ * @param {array} aData data array to be added
978
+ * @param {node} [nTr] TR element to add to the table - optional. If not given,
979
+ * DataTables will create a row automatically
980
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
981
+ * if nTr is.
982
+ * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
983
+ * @memberof DataTable#oApi
984
+ */
985
+ function _fnAddData ( oSettings, aDataIn, nTr, anTds )
986
+ {
987
+ /* Create the object for storing information about this new row */
988
+ var iRow = oSettings.aoData.length;
989
+ var oData = $.extend( true, {}, DataTable.models.oRow, {
990
+ src: nTr ? 'dom' : 'data'
991
+ } );
992
+
993
+ oData._aData = aDataIn;
994
+ oSettings.aoData.push( oData );
995
+
996
+ /* Create the cells */
997
+ var nTd, sThisType;
998
+ var columns = oSettings.aoColumns;
999
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
1000
+ {
1001
+ // When working with a row, the data source object must be populated. In
1002
+ // all other cases, the data source object is already populated, so we
1003
+ // don't overwrite it, which might break bindings etc
1004
+ if ( nTr ) {
1005
+ _fnSetCellData( oSettings, iRow, i, _fnGetCellData( oSettings, iRow, i ) );
1006
+ }
1007
+ columns[i].sType = null;
1008
+ }
1009
+
1010
+ /* Add to the display array */
1011
+ oSettings.aiDisplayMaster.push( iRow );
1012
+
1013
+ /* Create the DOM information, or register it if already present */
1014
+ if ( nTr || ! oSettings.oFeatures.bDeferRender )
1015
+ {
1016
+ _fnCreateTr( oSettings, iRow, nTr, anTds );
1017
+ }
1018
+
1019
+ return iRow;
1020
+ }
1021
+
1022
+
1023
+ /**
1024
+ * Add one or more TR elements to the table. Generally we'd expect to
1025
+ * use this for reading data from a DOM sourced table, but it could be
1026
+ * used for an TR element. Note that if a TR is given, it is used (i.e.
1027
+ * it is not cloned).
1028
+ * @param {object} settings dataTables settings object
1029
+ * @param {array|node|jQuery} trs The TR element(s) to add to the table
1030
+ * @returns {array} Array of indexes for the added rows
1031
+ * @memberof DataTable#oApi
1032
+ */
1033
+ function _fnAddTr( settings, trs )
1034
+ {
1035
+ var row;
1036
+
1037
+ // Allow an individual node to be passed in
1038
+ if ( ! (trs instanceof $) ) {
1039
+ trs = $(trs);
1040
+ }
1041
+
1042
+ return trs.map( function (i, el) {
1043
+ row = _fnGetRowElements( settings, el );
1044
+ return _fnAddData( settings, row.data, el, row.cells );
1045
+ } );
1046
+ }
1047
+
1048
+
1049
+ /**
1050
+ * Take a TR element and convert it to an index in aoData
1051
+ * @param {object} oSettings dataTables settings object
1052
+ * @param {node} n the TR element to find
1053
+ * @returns {int} index if the node is found, null if not
1054
+ * @memberof DataTable#oApi
1055
+ */
1056
+ function _fnNodeToDataIndex( oSettings, n )
1057
+ {
1058
+ return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
1059
+ }
1060
+
1061
+
1062
+ /**
1063
+ * Take a TD element and convert it into a column data index (not the visible index)
1064
+ * @param {object} oSettings dataTables settings object
1065
+ * @param {int} iRow The row number the TD/TH can be found in
1066
+ * @param {node} n The TD/TH element to find
1067
+ * @returns {int} index if the node is found, -1 if not
1068
+ * @memberof DataTable#oApi
1069
+ */
1070
+ function _fnNodeToColumnIndex( oSettings, iRow, n )
1071
+ {
1072
+ return $.inArray( n, oSettings.aoData[ iRow ].anCells );
1073
+ }
1074
+
1075
+
1076
+ /**
1077
+ * Get the data for a given cell from the internal cache, taking into account data mapping
1078
+ * @param {object} settings dataTables settings object
1079
+ * @param {int} rowIdx aoData row id
1080
+ * @param {int} colIdx Column index
1081
+ * @param {string} type data get type ('display', 'type' 'filter' 'sort')
1082
+ * @returns {*} Cell data
1083
+ * @memberof DataTable#oApi
1084
+ */
1085
+ function _fnGetCellData( settings, rowIdx, colIdx, type )
1086
+ {
1087
+ var draw = settings.iDraw;
1088
+ var col = settings.aoColumns[colIdx];
1089
+ var rowData = settings.aoData[rowIdx]._aData;
1090
+ var defaultContent = col.sDefaultContent;
1091
+ var cellData = col.fnGetData( rowData, type, {
1092
+ settings: settings,
1093
+ row: rowIdx,
1094
+ col: colIdx
1095
+ } );
1096
+
1097
+ if ( cellData === undefined ) {
1098
+ if ( settings.iDrawError != draw && defaultContent === null ) {
1099
+ _fnLog( settings, 0, "Requested unknown parameter "+
1100
+ (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
1101
+ " for row "+rowIdx, 4 );
1102
+ settings.iDrawError = draw;
1103
+ }
1104
+ return defaultContent;
1105
+ }
1106
+
1107
+ /* When the data source is null, we can use default column data */
1108
+ if ( (cellData === rowData || cellData === null) && defaultContent !== null ) {
1109
+ cellData = defaultContent;
1110
+ }
1111
+ else if ( typeof cellData === 'function' ) {
1112
+ // If the data source is a function, then we run it and use the return,
1113
+ // executing in the scope of the data object (for instances)
1114
+ return cellData.call( rowData );
1115
+ }
1116
+
1117
+ if ( cellData === null && type == 'display' ) {
1118
+ return '';
1119
+ }
1120
+ return cellData;
1121
+ }
1122
+
1123
+
1124
+ /**
1125
+ * Set the value for a specific cell, into the internal data cache
1126
+ * @param {object} settings dataTables settings object
1127
+ * @param {int} rowIdx aoData row id
1128
+ * @param {int} colIdx Column index
1129
+ * @param {*} val Value to set
1130
+ * @memberof DataTable#oApi
1131
+ */
1132
+ function _fnSetCellData( settings, rowIdx, colIdx, val )
1133
+ {
1134
+ var col = settings.aoColumns[colIdx];
1135
+ var rowData = settings.aoData[rowIdx]._aData;
1136
+
1137
+ col.fnSetData( rowData, val, {
1138
+ settings: settings,
1139
+ row: rowIdx,
1140
+ col: colIdx
1141
+ } );
1142
+ }
1143
+
1144
+
1145
+ // Private variable that is used to match action syntax in the data property object
1146
+ var __reArray = /\[.*?\]$/;
1147
+ var __reFn = /\(\)$/;
1148
+
1149
+ /**
1150
+ * Split string on periods, taking into account escaped periods
1151
+ * @param {string} str String to split
1152
+ * @return {array} Split string
1153
+ */
1154
+ function _fnSplitObjNotation( str )
1155
+ {
1156
+ return $.map( str.match(/(\\.|[^\.])+/g), function ( s ) {
1157
+ return s.replace(/\\./g, '.');
1158
+ } );
1159
+ }
1160
+
1161
+
1162
+ /**
1163
+ * Return a function that can be used to get data from a source object, taking
1164
+ * into account the ability to use nested objects as a source
1165
+ * @param {string|int|function} mSource The data source for the object
1166
+ * @returns {function} Data get function
1167
+ * @memberof DataTable#oApi
1168
+ */
1169
+ function _fnGetObjectDataFn( mSource )
1170
+ {
1171
+ if ( $.isPlainObject( mSource ) )
1172
+ {
1173
+ /* Build an object of get functions, and wrap them in a single call */
1174
+ var o = {};
1175
+ $.each( mSource, function (key, val) {
1176
+ if ( val ) {
1177
+ o[key] = _fnGetObjectDataFn( val );
1178
+ }
1179
+ } );
1180
+
1181
+ return function (data, type, row, meta) {
1182
+ var t = o[type] || o._;
1183
+ return t !== undefined ?
1184
+ t(data, type, row, meta) :
1185
+ data;
1186
+ };
1187
+ }
1188
+ else if ( mSource === null )
1189
+ {
1190
+ /* Give an empty string for rendering / sorting etc */
1191
+ return function (data) { // type, row and meta also passed, but not used
1192
+ return data;
1193
+ };
1194
+ }
1195
+ else if ( typeof mSource === 'function' )
1196
+ {
1197
+ return function (data, type, row, meta) {
1198
+ return mSource( data, type, row, meta );
1199
+ };
1200
+ }
1201
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1202
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1203
+ {
1204
+ /* If there is a . in the source string then the data source is in a
1205
+ * nested object so we loop over the data for each level to get the next
1206
+ * level down. On each loop we test for undefined, and if found immediately
1207
+ * return. This allows entire objects to be missing and sDefaultContent to
1208
+ * be used if defined, rather than throwing an error
1209
+ */
1210
+ var fetchData = function (data, type, src) {
1211
+ var arrayNotation, funcNotation, out, innerSrc;
1212
+
1213
+ if ( src !== "" )
1214
+ {
1215
+ var a = _fnSplitObjNotation( src );
1216
+
1217
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1218
+ {
1219
+ // Check if we are dealing with special notation
1220
+ arrayNotation = a[i].match(__reArray);
1221
+ funcNotation = a[i].match(__reFn);
1222
+
1223
+ if ( arrayNotation )
1224
+ {
1225
+ // Array notation
1226
+ a[i] = a[i].replace(__reArray, '');
1227
+
1228
+ // Condition allows simply [] to be passed in
1229
+ if ( a[i] !== "" ) {
1230
+ data = data[ a[i] ];
1231
+ }
1232
+ out = [];
1233
+
1234
+ // Get the remainder of the nested object to get
1235
+ a.splice( 0, i+1 );
1236
+ innerSrc = a.join('.');
1237
+
1238
+ // Traverse each entry in the array getting the properties requested
1239
+ for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
1240
+ out.push( fetchData( data[j], type, innerSrc ) );
1241
+ }
1242
+
1243
+ // If a string is given in between the array notation indicators, that
1244
+ // is used to join the strings together, otherwise an array is returned
1245
+ var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
1246
+ data = (join==="") ? out : out.join(join);
1247
+
1248
+ // The inner call to fetchData has already traversed through the remainder
1249
+ // of the source requested, so we exit from the loop
1250
+ break;
1251
+ }
1252
+ else if ( funcNotation )
1253
+ {
1254
+ // Function call
1255
+ a[i] = a[i].replace(__reFn, '');
1256
+ data = data[ a[i] ]();
1257
+ continue;
1258
+ }
1259
+
1260
+ if ( data === null || data[ a[i] ] === undefined )
1261
+ {
1262
+ return undefined;
1263
+ }
1264
+ data = data[ a[i] ];
1265
+ }
1266
+ }
1267
+
1268
+ return data;
1269
+ };
1270
+
1271
+ return function (data, type) { // row and meta also passed, but not used
1272
+ return fetchData( data, type, mSource );
1273
+ };
1274
+ }
1275
+ else
1276
+ {
1277
+ /* Array or flat object mapping */
1278
+ return function (data, type) { // row and meta also passed, but not used
1279
+ return data[mSource];
1280
+ };
1281
+ }
1282
+ }
1283
+
1284
+
1285
+ /**
1286
+ * Return a function that can be used to set data from a source object, taking
1287
+ * into account the ability to use nested objects as a source
1288
+ * @param {string|int|function} mSource The data source for the object
1289
+ * @returns {function} Data set function
1290
+ * @memberof DataTable#oApi
1291
+ */
1292
+ function _fnSetObjectDataFn( mSource )
1293
+ {
1294
+ if ( $.isPlainObject( mSource ) )
1295
+ {
1296
+ /* Unlike get, only the underscore (global) option is used for for
1297
+ * setting data since we don't know the type here. This is why an object
1298
+ * option is not documented for `mData` (which is read/write), but it is
1299
+ * for `mRender` which is read only.
1300
+ */
1301
+ return _fnSetObjectDataFn( mSource._ );
1302
+ }
1303
+ else if ( mSource === null )
1304
+ {
1305
+ /* Nothing to do when the data source is null */
1306
+ return function () {};
1307
+ }
1308
+ else if ( typeof mSource === 'function' )
1309
+ {
1310
+ return function (data, val, meta) {
1311
+ mSource( data, 'set', val, meta );
1312
+ };
1313
+ }
1314
+ else if ( typeof mSource === 'string' && (mSource.indexOf('.') !== -1 ||
1315
+ mSource.indexOf('[') !== -1 || mSource.indexOf('(') !== -1) )
1316
+ {
1317
+ /* Like the get, we need to get data from a nested object */
1318
+ var setData = function (data, val, src) {
1319
+ var a = _fnSplitObjNotation( src ), b;
1320
+ var aLast = a[a.length-1];
1321
+ var arrayNotation, funcNotation, o, innerSrc;
1322
+
1323
+ for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ )
1324
+ {
1325
+ // Check if we are dealing with an array notation request
1326
+ arrayNotation = a[i].match(__reArray);
1327
+ funcNotation = a[i].match(__reFn);
1328
+
1329
+ if ( arrayNotation )
1330
+ {
1331
+ a[i] = a[i].replace(__reArray, '');
1332
+ data[ a[i] ] = [];
1333
+
1334
+ // Get the remainder of the nested object to set so we can recurse
1335
+ b = a.slice();
1336
+ b.splice( 0, i+1 );
1337
+ innerSrc = b.join('.');
1338
+
1339
+ // Traverse each entry in the array setting the properties requested
1340
+ for ( var j=0, jLen=val.length ; j<jLen ; j++ )
1341
+ {
1342
+ o = {};
1343
+ setData( o, val[j], innerSrc );
1344
+ data[ a[i] ].push( o );
1345
+ }
1346
+
1347
+ // The inner call to setData has already traversed through the remainder
1348
+ // of the source and has set the data, thus we can exit here
1349
+ return;
1350
+ }
1351
+ else if ( funcNotation )
1352
+ {
1353
+ // Function call
1354
+ a[i] = a[i].replace(__reFn, '');
1355
+ data = data[ a[i] ]( val );
1356
+ }
1357
+
1358
+ // If the nested object doesn't currently exist - since we are
1359
+ // trying to set the value - create it
1360
+ if ( data[ a[i] ] === null || data[ a[i] ] === undefined )
1361
+ {
1362
+ data[ a[i] ] = {};
1363
+ }
1364
+ data = data[ a[i] ];
1365
+ }
1366
+
1367
+ // Last item in the input - i.e, the actual set
1368
+ if ( aLast.match(__reFn ) )
1369
+ {
1370
+ // Function call
1371
+ data = data[ aLast.replace(__reFn, '') ]( val );
1372
+ }
1373
+ else
1374
+ {
1375
+ // If array notation is used, we just want to strip it and use the property name
1376
+ // and assign the value. If it isn't used, then we get the result we want anyway
1377
+ data[ aLast.replace(__reArray, '') ] = val;
1378
+ }
1379
+ };
1380
+
1381
+ return function (data, val) { // meta is also passed in, but not used
1382
+ return setData( data, val, mSource );
1383
+ };
1384
+ }
1385
+ else
1386
+ {
1387
+ /* Array or flat object mapping */
1388
+ return function (data, val) { // meta is also passed in, but not used
1389
+ data[mSource] = val;
1390
+ };
1391
+ }
1392
+ }
1393
+
1394
+
1395
+ /**
1396
+ * Return an array with the full table data
1397
+ * @param {object} oSettings dataTables settings object
1398
+ * @returns array {array} aData Master data array
1399
+ * @memberof DataTable#oApi
1400
+ */
1401
+ function _fnGetDataMaster ( settings )
1402
+ {
1403
+ return _pluck( settings.aoData, '_aData' );
1404
+ }
1405
+
1406
+
1407
+ /**
1408
+ * Nuke the table
1409
+ * @param {object} oSettings dataTables settings object
1410
+ * @memberof DataTable#oApi
1411
+ */
1412
+ function _fnClearTable( settings )
1413
+ {
1414
+ settings.aoData.length = 0;
1415
+ settings.aiDisplayMaster.length = 0;
1416
+ settings.aiDisplay.length = 0;
1417
+ }
1418
+
1419
+
1420
+ /**
1421
+ * Take an array of integers (index array) and remove a target integer (value - not
1422
+ * the key!)
1423
+ * @param {array} a Index array to target
1424
+ * @param {int} iTarget value to find
1425
+ * @memberof DataTable#oApi
1426
+ */
1427
+ function _fnDeleteIndex( a, iTarget, splice )
1428
+ {
1429
+ var iTargetIndex = -1;
1430
+
1431
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
1432
+ {
1433
+ if ( a[i] == iTarget )
1434
+ {
1435
+ iTargetIndex = i;
1436
+ }
1437
+ else if ( a[i] > iTarget )
1438
+ {
1439
+ a[i]--;
1440
+ }
1441
+ }
1442
+
1443
+ if ( iTargetIndex != -1 && splice === undefined )
1444
+ {
1445
+ a.splice( iTargetIndex, 1 );
1446
+ }
1447
+ }
1448
+
1449
+
1450
+ /**
1451
+ * Mark cached data as invalid such that a re-read of the data will occur when
1452
+ * the cached data is next requested. Also update from the data source object.
1453
+ *
1454
+ * @param {object} settings DataTables settings object
1455
+ * @param {int} rowIdx Row index to invalidate
1456
+ * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
1457
+ * or 'data'
1458
+ * @param {int} [colIdx] Column index to invalidate. If undefined the whole
1459
+ * row will be invalidated
1460
+ * @memberof DataTable#oApi
1461
+ *
1462
+ * @todo For the modularisation of v1.11 this will need to become a callback, so
1463
+ * the sort and filter methods can subscribe to it. That will required
1464
+ * initialisation options for sorting, which is why it is not already baked in
1465
+ */
1466
+ function _fnInvalidate( settings, rowIdx, src, colIdx )
1467
+ {
1468
+ var row = settings.aoData[ rowIdx ];
1469
+ var i, ien;
1470
+ var cellWrite = function ( cell, col ) {
1471
+ // This is very frustrating, but in IE if you just write directly
1472
+ // to innerHTML, and elements that are overwritten are GC'ed,
1473
+ // even if there is a reference to them elsewhere
1474
+ while ( cell.childNodes.length ) {
1475
+ cell.removeChild( cell.firstChild );
1476
+ }
1477
+
1478
+ cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
1479
+ };
1480
+
1481
+ // Are we reading last data from DOM or the data object?
1482
+ if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
1483
+ // Read the data from the DOM
1484
+ row._aData = _fnGetRowElements(
1485
+ settings, row, colIdx, colIdx === undefined ? undefined : row._aData
1486
+ )
1487
+ .data;
1488
+ }
1489
+ else {
1490
+ // Reading from data object, update the DOM
1491
+ var cells = row.anCells;
1492
+
1493
+ if ( cells ) {
1494
+ if ( colIdx !== undefined ) {
1495
+ cellWrite( cells[colIdx], colIdx );
1496
+ }
1497
+ else {
1498
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1499
+ cellWrite( cells[i], i );
1500
+ }
1501
+ }
1502
+ }
1503
+ }
1504
+
1505
+ // For both row and cell invalidation, the cached data for sorting and
1506
+ // filtering is nulled out
1507
+ row._aSortData = null;
1508
+ row._aFilterData = null;
1509
+
1510
+ // Invalidate the type for a specific column (if given) or all columns since
1511
+ // the data might have changed
1512
+ var cols = settings.aoColumns;
1513
+ if ( colIdx !== undefined ) {
1514
+ cols[ colIdx ].sType = null;
1515
+ }
1516
+ else {
1517
+ for ( i=0, ien=cols.length ; i<ien ; i++ ) {
1518
+ cols[i].sType = null;
1519
+ }
1520
+
1521
+ // Update DataTables special `DT_*` attributes for the row
1522
+ _fnRowAttributes( row );
1523
+ }
1524
+ }
1525
+
1526
+
1527
+ /**
1528
+ * Build a data source object from an HTML row, reading the contents of the
1529
+ * cells that are in the row.
1530
+ *
1531
+ * @param {object} settings DataTables settings object
1532
+ * @param {node|object} TR element from which to read data or existing row
1533
+ * object from which to re-read the data from the cells
1534
+ * @param {int} [colIdx] Optional column index
1535
+ * @param {array|object} [d] Data source object. If `colIdx` is given then this
1536
+ * parameter should also be given and will be used to write the data into.
1537
+ * Only the column in question will be written
1538
+ * @returns {object} Object with two parameters: `data` the data read, in
1539
+ * document order, and `cells` and array of nodes (they can be useful to the
1540
+ * caller, so rather than needing a second traversal to get them, just return
1541
+ * them from here).
1542
+ * @memberof DataTable#oApi
1543
+ */
1544
+ function _fnGetRowElements( settings, row, colIdx, d )
1545
+ {
1546
+ var
1547
+ tds = [],
1548
+ td = row.firstChild,
1549
+ name, col, o, i=0, contents,
1550
+ columns = settings.aoColumns,
1551
+ objectRead = settings._rowReadObject;
1552
+
1553
+ // Allow the data object to be passed in, or construct
1554
+ d = d || objectRead ? {} : [];
1555
+
1556
+ var attr = function ( str, td ) {
1557
+ if ( typeof str === 'string' ) {
1558
+ var idx = str.indexOf('@');
1559
+
1560
+ if ( idx !== -1 ) {
1561
+ var attr = str.substring( idx+1 );
1562
+ var setter = _fnSetObjectDataFn( str );
1563
+ setter( d, td.getAttribute( attr ) );
1564
+ }
1565
+ }
1566
+ };
1567
+
1568
+ // Read data from a cell and store into the data object
1569
+ var cellProcess = function ( cell ) {
1570
+ if ( colIdx === undefined || colIdx === i ) {
1571
+ col = columns[i];
1572
+ contents = $.trim(cell.innerHTML);
1573
+
1574
+ if ( col && col._bAttrSrc ) {
1575
+ var setter = _fnSetObjectDataFn( col.mData._ );
1576
+ setter( d, contents );
1577
+
1578
+ attr( col.mData.sort, cell );
1579
+ attr( col.mData.type, cell );
1580
+ attr( col.mData.filter, cell );
1581
+ }
1582
+ else {
1583
+ // Depending on the `data` option for the columns the data can
1584
+ // be read to either an object or an array.
1585
+ if ( objectRead ) {
1586
+ if ( ! col._setter ) {
1587
+ // Cache the setter function
1588
+ col._setter = _fnSetObjectDataFn( col.mData );
1589
+ }
1590
+ col._setter( d, contents );
1591
+ }
1592
+ else {
1593
+ d[i] = contents;
1594
+ }
1595
+ }
1596
+ }
1597
+
1598
+ i++;
1599
+ };
1600
+
1601
+ if ( td ) {
1602
+ // `tr` element was passed in
1603
+ while ( td ) {
1604
+ name = td.nodeName.toUpperCase();
1605
+
1606
+ if ( name == "TD" || name == "TH" ) {
1607
+ cellProcess( td );
1608
+ tds.push( td );
1609
+ }
1610
+
1611
+ td = td.nextSibling;
1612
+ }
1613
+ }
1614
+ else {
1615
+ // Existing row object passed in
1616
+ tds = row.anCells;
1617
+
1618
+ for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
1619
+ cellProcess( tds[j] );
1620
+ }
1621
+ }
1622
+
1623
+ return {
1624
+ data: d,
1625
+ cells: tds
1626
+ };
1627
+ }
1628
+ /**
1629
+ * Create a new TR element (and it's TD children) for a row
1630
+ * @param {object} oSettings dataTables settings object
1631
+ * @param {int} iRow Row to consider
1632
+ * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
1633
+ * DataTables will create a row automatically
1634
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
1635
+ * if nTr is.
1636
+ * @memberof DataTable#oApi
1637
+ */
1638
+ function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
1639
+ {
1640
+ var
1641
+ row = oSettings.aoData[iRow],
1642
+ rowData = row._aData,
1643
+ cells = [],
1644
+ nTr, nTd, oCol,
1645
+ i, iLen;
1646
+
1647
+ if ( row.nTr === null )
1648
+ {
1649
+ nTr = nTrIn || document.createElement('tr');
1650
+
1651
+ row.nTr = nTr;
1652
+ row.anCells = cells;
1653
+
1654
+ /* Use a private property on the node to allow reserve mapping from the node
1655
+ * to the aoData array for fast look up
1656
+ */
1657
+ nTr._DT_RowIndex = iRow;
1658
+
1659
+ /* Special parameters can be given by the data source to be used on the row */
1660
+ _fnRowAttributes( row );
1661
+
1662
+ /* Process each column */
1663
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
1664
+ {
1665
+ oCol = oSettings.aoColumns[i];
1666
+
1667
+ nTd = nTrIn ? anTds[i] : document.createElement( oCol.sCellType );
1668
+ cells.push( nTd );
1669
+
1670
+ // Need to create the HTML if new, or if a rendering function is defined
1671
+ if ( !nTrIn || oCol.mRender || oCol.mData !== i )
1672
+ {
1673
+ nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
1674
+ }
1675
+
1676
+ /* Add user defined class */
1677
+ if ( oCol.sClass )
1678
+ {
1679
+ nTd.className += ' '+oCol.sClass;
1680
+ }
1681
+
1682
+ // Visibility - add or remove as required
1683
+ if ( oCol.bVisible && ! nTrIn )
1684
+ {
1685
+ nTr.appendChild( nTd );
1686
+ }
1687
+ else if ( ! oCol.bVisible && nTrIn )
1688
+ {
1689
+ nTd.parentNode.removeChild( nTd );
1690
+ }
1691
+
1692
+ if ( oCol.fnCreatedCell )
1693
+ {
1694
+ oCol.fnCreatedCell.call( oSettings.oInstance,
1695
+ nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
1696
+ );
1697
+ }
1698
+ }
1699
+
1700
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow] );
1701
+ }
1702
+
1703
+ // Remove once webkit bug 131819 and Chromium bug 365619 have been resolved
1704
+ // and deployed
1705
+ row.nTr.setAttribute( 'role', 'row' );
1706
+ }
1707
+
1708
+
1709
+ /**
1710
+ * Add attributes to a row based on the special `DT_*` parameters in a data
1711
+ * source object.
1712
+ * @param {object} DataTables row object for the row to be modified
1713
+ * @memberof DataTable#oApi
1714
+ */
1715
+ function _fnRowAttributes( row )
1716
+ {
1717
+ var tr = row.nTr;
1718
+ var data = row._aData;
1719
+
1720
+ if ( tr ) {
1721
+ if ( data.DT_RowId ) {
1722
+ tr.id = data.DT_RowId;
1723
+ }
1724
+
1725
+ if ( data.DT_RowClass ) {
1726
+ // Remove any classes added by DT_RowClass before
1727
+ var a = data.DT_RowClass.split(' ');
1728
+ row.__rowc = row.__rowc ?
1729
+ _unique( row.__rowc.concat( a ) ) :
1730
+ a;
1731
+
1732
+ $(tr)
1733
+ .removeClass( row.__rowc.join(' ') )
1734
+ .addClass( data.DT_RowClass );
1735
+ }
1736
+
1737
+ if ( data.DT_RowData ) {
1738
+ $(tr).data( data.DT_RowData );
1739
+ }
1740
+ }
1741
+ }
1742
+
1743
+
1744
+ /**
1745
+ * Create the HTML header for the table
1746
+ * @param {object} oSettings dataTables settings object
1747
+ * @memberof DataTable#oApi
1748
+ */
1749
+ function _fnBuildHead( oSettings )
1750
+ {
1751
+ var i, ien, cell, row, column;
1752
+ var thead = oSettings.nTHead;
1753
+ var tfoot = oSettings.nTFoot;
1754
+ var createHeader = $('th, td', thead).length === 0;
1755
+ var classes = oSettings.oClasses;
1756
+ var columns = oSettings.aoColumns;
1757
+
1758
+ if ( createHeader ) {
1759
+ row = $('<tr/>').appendTo( thead );
1760
+ }
1761
+
1762
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
1763
+ column = columns[i];
1764
+ cell = $( column.nTh ).addClass( column.sClass );
1765
+
1766
+ if ( createHeader ) {
1767
+ cell.appendTo( row );
1768
+ }
1769
+
1770
+ // 1.11 move into sorting
1771
+ if ( oSettings.oFeatures.bSort ) {
1772
+ cell.addClass( column.sSortingClass );
1773
+
1774
+ if ( column.bSortable !== false ) {
1775
+ cell
1776
+ .attr( 'tabindex', oSettings.iTabIndex )
1777
+ .attr( 'aria-controls', oSettings.sTableId );
1778
+
1779
+ _fnSortAttachListener( oSettings, column.nTh, i );
1780
+ }
1781
+ }
1782
+
1783
+ if ( column.sTitle != cell.html() ) {
1784
+ cell.html( column.sTitle );
1785
+ }
1786
+
1787
+ _fnRenderer( oSettings, 'header' )(
1788
+ oSettings, cell, column, classes
1789
+ );
1790
+ }
1791
+
1792
+ if ( createHeader ) {
1793
+ _fnDetectHeader( oSettings.aoHeader, thead );
1794
+ }
1795
+
1796
+ /* ARIA role for the rows */
1797
+ $(thead).find('>tr').attr('role', 'row');
1798
+
1799
+ /* Deal with the footer - add classes if required */
1800
+ $(thead).find('>tr>th, >tr>td').addClass( classes.sHeaderTH );
1801
+ $(tfoot).find('>tr>th, >tr>td').addClass( classes.sFooterTH );
1802
+
1803
+ // Cache the footer cells. Note that we only take the cells from the first
1804
+ // row in the footer. If there is more than one row the user wants to
1805
+ // interact with, they need to use the table().foot() method. Note also this
1806
+ // allows cells to be used for multiple columns using colspan
1807
+ if ( tfoot !== null ) {
1808
+ var cells = oSettings.aoFooter[0];
1809
+
1810
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
1811
+ column = columns[i];
1812
+ column.nTf = cells[i].cell;
1813
+
1814
+ if ( column.sClass ) {
1815
+ $(column.nTf).addClass( column.sClass );
1816
+ }
1817
+ }
1818
+ }
1819
+ }
1820
+
1821
+
1822
+ /**
1823
+ * Draw the header (or footer) element based on the column visibility states. The
1824
+ * methodology here is to use the layout array from _fnDetectHeader, modified for
1825
+ * the instantaneous column visibility, to construct the new layout. The grid is
1826
+ * traversed over cell at a time in a rows x columns grid fashion, although each
1827
+ * cell insert can cover multiple elements in the grid - which is tracks using the
1828
+ * aApplied array. Cell inserts in the grid will only occur where there isn't
1829
+ * already a cell in that position.
1830
+ * @param {object} oSettings dataTables settings object
1831
+ * @param array {objects} aoSource Layout array from _fnDetectHeader
1832
+ * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
1833
+ * @memberof DataTable#oApi
1834
+ */
1835
+ function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
1836
+ {
1837
+ var i, iLen, j, jLen, k, kLen, n, nLocalTr;
1838
+ var aoLocal = [];
1839
+ var aApplied = [];
1840
+ var iColumns = oSettings.aoColumns.length;
1841
+ var iRowspan, iColspan;
1842
+
1843
+ if ( ! aoSource )
1844
+ {
1845
+ return;
1846
+ }
1847
+
1848
+ if ( bIncludeHidden === undefined )
1849
+ {
1850
+ bIncludeHidden = false;
1851
+ }
1852
+
1853
+ /* Make a copy of the master layout array, but without the visible columns in it */
1854
+ for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
1855
+ {
1856
+ aoLocal[i] = aoSource[i].slice();
1857
+ aoLocal[i].nTr = aoSource[i].nTr;
1858
+
1859
+ /* Remove any columns which are currently hidden */
1860
+ for ( j=iColumns-1 ; j>=0 ; j-- )
1861
+ {
1862
+ if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
1863
+ {
1864
+ aoLocal[i].splice( j, 1 );
1865
+ }
1866
+ }
1867
+
1868
+ /* Prep the applied array - it needs an element for each row */
1869
+ aApplied.push( [] );
1870
+ }
1871
+
1872
+ for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
1873
+ {
1874
+ nLocalTr = aoLocal[i].nTr;
1875
+
1876
+ /* All cells are going to be replaced, so empty out the row */
1877
+ if ( nLocalTr )
1878
+ {
1879
+ while( (n = nLocalTr.firstChild) )
1880
+ {
1881
+ nLocalTr.removeChild( n );
1882
+ }
1883
+ }
1884
+
1885
+ for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
1886
+ {
1887
+ iRowspan = 1;
1888
+ iColspan = 1;
1889
+
1890
+ /* Check to see if there is already a cell (row/colspan) covering our target
1891
+ * insert point. If there is, then there is nothing to do.
1892
+ */
1893
+ if ( aApplied[i][j] === undefined )
1894
+ {
1895
+ nLocalTr.appendChild( aoLocal[i][j].cell );
1896
+ aApplied[i][j] = 1;
1897
+
1898
+ /* Expand the cell to cover as many rows as needed */
1899
+ while ( aoLocal[i+iRowspan] !== undefined &&
1900
+ aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
1901
+ {
1902
+ aApplied[i+iRowspan][j] = 1;
1903
+ iRowspan++;
1904
+ }
1905
+
1906
+ /* Expand the cell to cover as many columns as needed */
1907
+ while ( aoLocal[i][j+iColspan] !== undefined &&
1908
+ aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
1909
+ {
1910
+ /* Must update the applied array over the rows for the columns */
1911
+ for ( k=0 ; k<iRowspan ; k++ )
1912
+ {
1913
+ aApplied[i+k][j+iColspan] = 1;
1914
+ }
1915
+ iColspan++;
1916
+ }
1917
+
1918
+ /* Do the actual expansion in the DOM */
1919
+ $(aoLocal[i][j].cell)
1920
+ .attr('rowspan', iRowspan)
1921
+ .attr('colspan', iColspan);
1922
+ }
1923
+ }
1924
+ }
1925
+ }
1926
+
1927
+
1928
+ /**
1929
+ * Insert the required TR nodes into the table for display
1930
+ * @param {object} oSettings dataTables settings object
1931
+ * @memberof DataTable#oApi
1932
+ */
1933
+ function _fnDraw( oSettings )
1934
+ {
1935
+ /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
1936
+ var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
1937
+ if ( $.inArray( false, aPreDraw ) !== -1 )
1938
+ {
1939
+ _fnProcessingDisplay( oSettings, false );
1940
+ return;
1941
+ }
1942
+
1943
+ var i, iLen, n;
1944
+ var anRows = [];
1945
+ var iRowCount = 0;
1946
+ var asStripeClasses = oSettings.asStripeClasses;
1947
+ var iStripes = asStripeClasses.length;
1948
+ var iOpenRows = oSettings.aoOpenRows.length;
1949
+ var oLang = oSettings.oLanguage;
1950
+ var iInitDisplayStart = oSettings.iInitDisplayStart;
1951
+ var bServerSide = _fnDataSource( oSettings ) == 'ssp';
1952
+ var aiDisplay = oSettings.aiDisplay;
1953
+
1954
+ oSettings.bDrawing = true;
1955
+
1956
+ /* Check and see if we have an initial draw position from state saving */
1957
+ if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
1958
+ {
1959
+ oSettings._iDisplayStart = bServerSide ?
1960
+ iInitDisplayStart :
1961
+ iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
1962
+ 0 :
1963
+ iInitDisplayStart;
1964
+
1965
+ oSettings.iInitDisplayStart = -1;
1966
+ }
1967
+
1968
+ var iDisplayStart = oSettings._iDisplayStart;
1969
+ var iDisplayEnd = oSettings.fnDisplayEnd();
1970
+
1971
+ /* Server-side processing draw intercept */
1972
+ if ( oSettings.bDeferLoading )
1973
+ {
1974
+ oSettings.bDeferLoading = false;
1975
+ oSettings.iDraw++;
1976
+ _fnProcessingDisplay( oSettings, false );
1977
+ }
1978
+ else if ( !bServerSide )
1979
+ {
1980
+ oSettings.iDraw++;
1981
+ }
1982
+ else if ( !oSettings.bDestroying && !_fnAjaxUpdate( oSettings ) )
1983
+ {
1984
+ return;
1985
+ }
1986
+
1987
+ if ( aiDisplay.length !== 0 )
1988
+ {
1989
+ var iStart = bServerSide ? 0 : iDisplayStart;
1990
+ var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
1991
+
1992
+ for ( var j=iStart ; j<iEnd ; j++ )
1993
+ {
1994
+ var iDataIndex = aiDisplay[j];
1995
+ var aoData = oSettings.aoData[ iDataIndex ];
1996
+ if ( aoData.nTr === null )
1997
+ {
1998
+ _fnCreateTr( oSettings, iDataIndex );
1999
+ }
2000
+
2001
+ var nRow = aoData.nTr;
2002
+
2003
+ /* Remove the old striping classes and then add the new one */
2004
+ if ( iStripes !== 0 )
2005
+ {
2006
+ var sStripe = asStripeClasses[ iRowCount % iStripes ];
2007
+ if ( aoData._sRowStripe != sStripe )
2008
+ {
2009
+ $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
2010
+ aoData._sRowStripe = sStripe;
2011
+ }
2012
+ }
2013
+
2014
+ // Row callback functions - might want to manipulate the row
2015
+ // iRowCount and j are not currently documented. Are they at all
2016
+ // useful?
2017
+ _fnCallbackFire( oSettings, 'aoRowCallback', null,
2018
+ [nRow, aoData._aData, iRowCount, j] );
2019
+
2020
+ anRows.push( nRow );
2021
+ iRowCount++;
2022
+ }
2023
+ }
2024
+ else
2025
+ {
2026
+ /* Table is empty - create a row with an empty message in it */
2027
+ var sZero = oLang.sZeroRecords;
2028
+ if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
2029
+ {
2030
+ sZero = oLang.sLoadingRecords;
2031
+ }
2032
+ else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
2033
+ {
2034
+ sZero = oLang.sEmptyTable;
2035
+ }
2036
+
2037
+ anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
2038
+ .append( $('<td />', {
2039
+ 'valign': 'top',
2040
+ 'colSpan': _fnVisbleColumns( oSettings ),
2041
+ 'class': oSettings.oClasses.sRowEmpty
2042
+ } ).html( sZero ) )[0];
2043
+ }
2044
+
2045
+ /* Header and footer callbacks */
2046
+ _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
2047
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2048
+
2049
+ _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
2050
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
2051
+
2052
+ var body = $(oSettings.nTBody);
2053
+
2054
+ body.children().detach();
2055
+ body.append( $(anRows) );
2056
+
2057
+ /* Call all required callback functions for the end of a draw */
2058
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
2059
+
2060
+ /* Draw is complete, sorting and filtering must be as well */
2061
+ oSettings.bSorted = false;
2062
+ oSettings.bFiltered = false;
2063
+ oSettings.bDrawing = false;
2064
+ }
2065
+
2066
+
2067
+ /**
2068
+ * Redraw the table - taking account of the various features which are enabled
2069
+ * @param {object} oSettings dataTables settings object
2070
+ * @param {boolean} [holdPosition] Keep the current paging position. By default
2071
+ * the paging is reset to the first page
2072
+ * @memberof DataTable#oApi
2073
+ */
2074
+ function _fnReDraw( settings, holdPosition )
2075
+ {
2076
+ var
2077
+ features = settings.oFeatures,
2078
+ sort = features.bSort,
2079
+ filter = features.bFilter;
2080
+
2081
+ if ( sort ) {
2082
+ _fnSort( settings );
2083
+ }
2084
+
2085
+ if ( filter ) {
2086
+ _fnFilterComplete( settings, settings.oPreviousSearch );
2087
+ }
2088
+ else {
2089
+ // No filtering, so we want to just use the display master
2090
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
2091
+ }
2092
+
2093
+ if ( holdPosition !== true ) {
2094
+ settings._iDisplayStart = 0;
2095
+ }
2096
+
2097
+ // Let any modules know about the draw hold position state (used by
2098
+ // scrolling internally)
2099
+ settings._drawHold = holdPosition;
2100
+
2101
+ _fnDraw( settings );
2102
+
2103
+ settings._drawHold = false;
2104
+ }
2105
+
2106
+
2107
+ /**
2108
+ * Add the options to the page HTML for the table
2109
+ * @param {object} oSettings dataTables settings object
2110
+ * @memberof DataTable#oApi
2111
+ */
2112
+ function _fnAddOptionsHtml ( oSettings )
2113
+ {
2114
+ var classes = oSettings.oClasses;
2115
+ var table = $(oSettings.nTable);
2116
+ var holding = $('<div/>').insertBefore( table ); // Holding element for speed
2117
+ var features = oSettings.oFeatures;
2118
+
2119
+ // All DataTables are wrapped in a div
2120
+ var insert = $('<div/>', {
2121
+ id: oSettings.sTableId+'_wrapper',
2122
+ 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
2123
+ } );
2124
+
2125
+ oSettings.nHolding = holding[0];
2126
+ oSettings.nTableWrapper = insert[0];
2127
+ oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
2128
+
2129
+ /* Loop over the user set positioning and place the elements as needed */
2130
+ var aDom = oSettings.sDom.split('');
2131
+ var featureNode, cOption, nNewNode, cNext, sAttr, j;
2132
+ for ( var i=0 ; i<aDom.length ; i++ )
2133
+ {
2134
+ featureNode = null;
2135
+ cOption = aDom[i];
2136
+
2137
+ if ( cOption == '<' )
2138
+ {
2139
+ /* New container div */
2140
+ nNewNode = $('<div/>')[0];
2141
+
2142
+ /* Check to see if we should append an id and/or a class name to the container */
2143
+ cNext = aDom[i+1];
2144
+ if ( cNext == "'" || cNext == '"' )
2145
+ {
2146
+ sAttr = "";
2147
+ j = 2;
2148
+ while ( aDom[i+j] != cNext )
2149
+ {
2150
+ sAttr += aDom[i+j];
2151
+ j++;
2152
+ }
2153
+
2154
+ /* Replace jQuery UI constants @todo depreciated */
2155
+ if ( sAttr == "H" )
2156
+ {
2157
+ sAttr = classes.sJUIHeader;
2158
+ }
2159
+ else if ( sAttr == "F" )
2160
+ {
2161
+ sAttr = classes.sJUIFooter;
2162
+ }
2163
+
2164
+ /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
2165
+ * breaks the string into parts and applies them as needed
2166
+ */
2167
+ if ( sAttr.indexOf('.') != -1 )
2168
+ {
2169
+ var aSplit = sAttr.split('.');
2170
+ nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
2171
+ nNewNode.className = aSplit[1];
2172
+ }
2173
+ else if ( sAttr.charAt(0) == "#" )
2174
+ {
2175
+ nNewNode.id = sAttr.substr(1, sAttr.length-1);
2176
+ }
2177
+ else
2178
+ {
2179
+ nNewNode.className = sAttr;
2180
+ }
2181
+
2182
+ i += j; /* Move along the position array */
2183
+ }
2184
+
2185
+ insert.append( nNewNode );
2186
+ insert = $(nNewNode);
2187
+ }
2188
+ else if ( cOption == '>' )
2189
+ {
2190
+ /* End container div */
2191
+ insert = insert.parent();
2192
+ }
2193
+ // @todo Move options into their own plugins?
2194
+ else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
2195
+ {
2196
+ /* Length */
2197
+ featureNode = _fnFeatureHtmlLength( oSettings );
2198
+ }
2199
+ else if ( cOption == 'f' && features.bFilter )
2200
+ {
2201
+ /* Filter */
2202
+ featureNode = _fnFeatureHtmlFilter( oSettings );
2203
+ }
2204
+ else if ( cOption == 'r' && features.bProcessing )
2205
+ {
2206
+ /* pRocessing */
2207
+ featureNode = _fnFeatureHtmlProcessing( oSettings );
2208
+ }
2209
+ else if ( cOption == 't' )
2210
+ {
2211
+ /* Table */
2212
+ featureNode = _fnFeatureHtmlTable( oSettings );
2213
+ }
2214
+ else if ( cOption == 'i' && features.bInfo )
2215
+ {
2216
+ /* Info */
2217
+ featureNode = _fnFeatureHtmlInfo( oSettings );
2218
+ }
2219
+ else if ( cOption == 'p' && features.bPaginate )
2220
+ {
2221
+ /* Pagination */
2222
+ featureNode = _fnFeatureHtmlPaginate( oSettings );
2223
+ }
2224
+ else if ( DataTable.ext.feature.length !== 0 )
2225
+ {
2226
+ /* Plug-in features */
2227
+ var aoFeatures = DataTable.ext.feature;
2228
+ for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
2229
+ {
2230
+ if ( cOption == aoFeatures[k].cFeature )
2231
+ {
2232
+ featureNode = aoFeatures[k].fnInit( oSettings );
2233
+ break;
2234
+ }
2235
+ }
2236
+ }
2237
+
2238
+ /* Add to the 2D features array */
2239
+ if ( featureNode )
2240
+ {
2241
+ var aanFeatures = oSettings.aanFeatures;
2242
+
2243
+ if ( ! aanFeatures[cOption] )
2244
+ {
2245
+ aanFeatures[cOption] = [];
2246
+ }
2247
+
2248
+ aanFeatures[cOption].push( featureNode );
2249
+ insert.append( featureNode );
2250
+ }
2251
+ }
2252
+
2253
+ /* Built our DOM structure - replace the holding div with what we want */
2254
+ holding.replaceWith( insert );
2255
+ }
2256
+
2257
+
2258
+ /**
2259
+ * Use the DOM source to create up an array of header cells. The idea here is to
2260
+ * create a layout grid (array) of rows x columns, which contains a reference
2261
+ * to the cell that that point in the grid (regardless of col/rowspan), such that
2262
+ * any column / row could be removed and the new grid constructed
2263
+ * @param array {object} aLayout Array to store the calculated layout in
2264
+ * @param {node} nThead The header/footer element for the table
2265
+ * @memberof DataTable#oApi
2266
+ */
2267
+ function _fnDetectHeader ( aLayout, nThead )
2268
+ {
2269
+ var nTrs = $(nThead).children('tr');
2270
+ var nTr, nCell;
2271
+ var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
2272
+ var bUnique;
2273
+ var fnShiftCol = function ( a, i, j ) {
2274
+ var k = a[i];
2275
+ while ( k[j] ) {
2276
+ j++;
2277
+ }
2278
+ return j;
2279
+ };
2280
+
2281
+ aLayout.splice( 0, aLayout.length );
2282
+
2283
+ /* We know how many rows there are in the layout - so prep it */
2284
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2285
+ {
2286
+ aLayout.push( [] );
2287
+ }
2288
+
2289
+ /* Calculate a layout array */
2290
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
2291
+ {
2292
+ nTr = nTrs[i];
2293
+ iColumn = 0;
2294
+
2295
+ /* For every cell in the row... */
2296
+ nCell = nTr.firstChild;
2297
+ while ( nCell ) {
2298
+ if ( nCell.nodeName.toUpperCase() == "TD" ||
2299
+ nCell.nodeName.toUpperCase() == "TH" )
2300
+ {
2301
+ /* Get the col and rowspan attributes from the DOM and sanitise them */
2302
+ iColspan = nCell.getAttribute('colspan') * 1;
2303
+ iRowspan = nCell.getAttribute('rowspan') * 1;
2304
+ iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
2305
+ iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
2306
+
2307
+ /* There might be colspan cells already in this row, so shift our target
2308
+ * accordingly
2309
+ */
2310
+ iColShifted = fnShiftCol( aLayout, i, iColumn );
2311
+
2312
+ /* Cache calculation for unique columns */
2313
+ bUnique = iColspan === 1 ? true : false;
2314
+
2315
+ /* If there is col / rowspan, copy the information into the layout grid */
2316
+ for ( l=0 ; l<iColspan ; l++ )
2317
+ {
2318
+ for ( k=0 ; k<iRowspan ; k++ )
2319
+ {
2320
+ aLayout[i+k][iColShifted+l] = {
2321
+ "cell": nCell,
2322
+ "unique": bUnique
2323
+ };
2324
+ aLayout[i+k].nTr = nTr;
2325
+ }
2326
+ }
2327
+ }
2328
+ nCell = nCell.nextSibling;
2329
+ }
2330
+ }
2331
+ }
2332
+
2333
+
2334
+ /**
2335
+ * Get an array of unique th elements, one for each column
2336
+ * @param {object} oSettings dataTables settings object
2337
+ * @param {node} nHeader automatically detect the layout from this node - optional
2338
+ * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
2339
+ * @returns array {node} aReturn list of unique th's
2340
+ * @memberof DataTable#oApi
2341
+ */
2342
+ function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
2343
+ {
2344
+ var aReturn = [];
2345
+ if ( !aLayout )
2346
+ {
2347
+ aLayout = oSettings.aoHeader;
2348
+ if ( nHeader )
2349
+ {
2350
+ aLayout = [];
2351
+ _fnDetectHeader( aLayout, nHeader );
2352
+ }
2353
+ }
2354
+
2355
+ for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
2356
+ {
2357
+ for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
2358
+ {
2359
+ if ( aLayout[i][j].unique &&
2360
+ (!aReturn[j] || !oSettings.bSortCellsTop) )
2361
+ {
2362
+ aReturn[j] = aLayout[i][j].cell;
2363
+ }
2364
+ }
2365
+ }
2366
+
2367
+ return aReturn;
2368
+ }
2369
+
2370
+
2371
+
2372
+ /**
2373
+ * Create an Ajax call based on the table's settings, taking into account that
2374
+ * parameters can have multiple forms, and backwards compatibility.
2375
+ *
2376
+ * @param {object} oSettings dataTables settings object
2377
+ * @param {array} data Data to send to the server, required by
2378
+ * DataTables - may be augmented by developer callbacks
2379
+ * @param {function} fn Callback function to run when data is obtained
2380
+ */
2381
+ function _fnBuildAjax( oSettings, data, fn )
2382
+ {
2383
+ // Compatibility with 1.9-, allow fnServerData and event to manipulate
2384
+ _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
2385
+
2386
+ // Convert to object based for 1.10+ if using the old array scheme which can
2387
+ // come from server-side processing or serverParams
2388
+ if ( data && $.isArray(data) ) {
2389
+ var tmp = {};
2390
+ var rbracket = /(.*?)\[\]$/;
2391
+
2392
+ $.each( data, function (key, val) {
2393
+ var match = val.name.match(rbracket);
2394
+
2395
+ if ( match ) {
2396
+ // Support for arrays
2397
+ var name = match[0];
2398
+
2399
+ if ( ! tmp[ name ] ) {
2400
+ tmp[ name ] = [];
2401
+ }
2402
+ tmp[ name ].push( val.value );
2403
+ }
2404
+ else {
2405
+ tmp[val.name] = val.value;
2406
+ }
2407
+ } );
2408
+ data = tmp;
2409
+ }
2410
+
2411
+ var ajaxData;
2412
+ var ajax = oSettings.ajax;
2413
+ var instance = oSettings.oInstance;
2414
+
2415
+ if ( $.isPlainObject( ajax ) && ajax.data )
2416
+ {
2417
+ ajaxData = ajax.data;
2418
+
2419
+ var newData = $.isFunction( ajaxData ) ?
2420
+ ajaxData( data ) : // fn can manipulate data or return an object
2421
+ ajaxData; // object or array to merge
2422
+
2423
+ // If the function returned an object, use that alone
2424
+ data = $.isFunction( ajaxData ) && newData ?
2425
+ newData :
2426
+ $.extend( true, data, newData );
2427
+
2428
+ // Remove the data property as we've resolved it already and don't want
2429
+ // jQuery to do it again (it is restored at the end of the function)
2430
+ delete ajax.data;
2431
+ }
2432
+
2433
+ var baseAjax = {
2434
+ "data": data,
2435
+ "success": function (json) {
2436
+ var error = json.error || json.sError;
2437
+ if ( error ) {
2438
+ oSettings.oApi._fnLog( oSettings, 0, error );
2439
+ }
2440
+
2441
+ oSettings.json = json;
2442
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json] );
2443
+ fn( json );
2444
+ },
2445
+ "dataType": "json",
2446
+ "cache": false,
2447
+ "type": oSettings.sServerMethod,
2448
+ "error": function (xhr, error, thrown) {
2449
+ var log = oSettings.oApi._fnLog;
2450
+
2451
+ if ( error == "parsererror" ) {
2452
+ log( oSettings, 0, 'Invalid JSON response', 1 );
2453
+ }
2454
+ else if ( xhr.readyState === 4 ) {
2455
+ log( oSettings, 0, 'Ajax error', 7 );
2456
+ }
2457
+
2458
+ _fnProcessingDisplay( oSettings, false );
2459
+ }
2460
+ };
2461
+
2462
+ // Store the data submitted for the API
2463
+ oSettings.oAjaxData = data;
2464
+
2465
+ // Allow plug-ins and external processes to modify the data
2466
+ _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
2467
+
2468
+ if ( oSettings.fnServerData )
2469
+ {
2470
+ // DataTables 1.9- compatibility
2471
+ oSettings.fnServerData.call( instance,
2472
+ oSettings.sAjaxSource,
2473
+ $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
2474
+ return { name: key, value: val };
2475
+ } ),
2476
+ fn,
2477
+ oSettings
2478
+ );
2479
+ }
2480
+ else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
2481
+ {
2482
+ // DataTables 1.9- compatibility
2483
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
2484
+ url: ajax || oSettings.sAjaxSource
2485
+ } ) );
2486
+ }
2487
+ else if ( $.isFunction( ajax ) )
2488
+ {
2489
+ // Is a function - let the caller define what needs to be done
2490
+ oSettings.jqXHR = ajax.call( instance, data, fn, oSettings );
2491
+ }
2492
+ else
2493
+ {
2494
+ // Object to extend the base settings
2495
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
2496
+
2497
+ // Restore for next time around
2498
+ ajax.data = ajaxData;
2499
+ }
2500
+ }
2501
+
2502
+
2503
+ /**
2504
+ * Update the table using an Ajax call
2505
+ * @param {object} settings dataTables settings object
2506
+ * @returns {boolean} Block the table drawing or not
2507
+ * @memberof DataTable#oApi
2508
+ */
2509
+ function _fnAjaxUpdate( settings )
2510
+ {
2511
+ if ( settings.bAjaxDataGet ) {
2512
+ settings.iDraw++;
2513
+ _fnProcessingDisplay( settings, true );
2514
+
2515
+ _fnBuildAjax(
2516
+ settings,
2517
+ _fnAjaxParameters( settings ),
2518
+ function(json) {
2519
+ _fnAjaxUpdateDraw( settings, json );
2520
+ }
2521
+ );
2522
+
2523
+ return false;
2524
+ }
2525
+ return true;
2526
+ }
2527
+
2528
+
2529
+ /**
2530
+ * Build up the parameters in an object needed for a server-side processing
2531
+ * request. Note that this is basically done twice, is different ways - a modern
2532
+ * method which is used by default in DataTables 1.10 which uses objects and
2533
+ * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
2534
+ * the sAjaxSource option is used in the initialisation, or the legacyAjax
2535
+ * option is set.
2536
+ * @param {object} oSettings dataTables settings object
2537
+ * @returns {bool} block the table drawing or not
2538
+ * @memberof DataTable#oApi
2539
+ */
2540
+ function _fnAjaxParameters( settings )
2541
+ {
2542
+ var
2543
+ columns = settings.aoColumns,
2544
+ columnCount = columns.length,
2545
+ features = settings.oFeatures,
2546
+ preSearch = settings.oPreviousSearch,
2547
+ preColSearch = settings.aoPreSearchCols,
2548
+ i, data = [], dataProp, column, columnSearch,
2549
+ sort = _fnSortFlatten( settings ),
2550
+ displayStart = settings._iDisplayStart,
2551
+ displayLength = features.bPaginate !== false ?
2552
+ settings._iDisplayLength :
2553
+ -1;
2554
+
2555
+ var param = function ( name, value ) {
2556
+ data.push( { 'name': name, 'value': value } );
2557
+ };
2558
+
2559
+ // DataTables 1.9- compatible method
2560
+ param( 'sEcho', settings.iDraw );
2561
+ param( 'iColumns', columnCount );
2562
+ param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
2563
+ param( 'iDisplayStart', displayStart );
2564
+ param( 'iDisplayLength', displayLength );
2565
+
2566
+ // DataTables 1.10+ method
2567
+ var d = {
2568
+ draw: settings.iDraw,
2569
+ columns: [],
2570
+ order: [],
2571
+ start: displayStart,
2572
+ length: displayLength,
2573
+ search: {
2574
+ value: preSearch.sSearch,
2575
+ regex: preSearch.bRegex
2576
+ }
2577
+ };
2578
+
2579
+ for ( i=0 ; i<columnCount ; i++ ) {
2580
+ column = columns[i];
2581
+ columnSearch = preColSearch[i];
2582
+ dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
2583
+
2584
+ d.columns.push( {
2585
+ data: dataProp,
2586
+ name: column.sName,
2587
+ searchable: column.bSearchable,
2588
+ orderable: column.bSortable,
2589
+ search: {
2590
+ value: columnSearch.sSearch,
2591
+ regex: columnSearch.bRegex
2592
+ }
2593
+ } );
2594
+
2595
+ param( "mDataProp_"+i, dataProp );
2596
+
2597
+ if ( features.bFilter ) {
2598
+ param( 'sSearch_'+i, columnSearch.sSearch );
2599
+ param( 'bRegex_'+i, columnSearch.bRegex );
2600
+ param( 'bSearchable_'+i, column.bSearchable );
2601
+ }
2602
+
2603
+ if ( features.bSort ) {
2604
+ param( 'bSortable_'+i, column.bSortable );
2605
+ }
2606
+ }
2607
+
2608
+ if ( features.bFilter ) {
2609
+ param( 'sSearch', preSearch.sSearch );
2610
+ param( 'bRegex', preSearch.bRegex );
2611
+ }
2612
+
2613
+ if ( features.bSort ) {
2614
+ $.each( sort, function ( i, val ) {
2615
+ d.order.push( { column: val.col, dir: val.dir } );
2616
+
2617
+ param( 'iSortCol_'+i, val.col );
2618
+ param( 'sSortDir_'+i, val.dir );
2619
+ } );
2620
+
2621
+ param( 'iSortingCols', sort.length );
2622
+ }
2623
+
2624
+ // If the legacy.ajax parameter is null, then we automatically decide which
2625
+ // form to use, based on sAjaxSource
2626
+ var legacy = DataTable.ext.legacy.ajax;
2627
+ if ( legacy === null ) {
2628
+ return settings.sAjaxSource ? data : d;
2629
+ }
2630
+
2631
+ // Otherwise, if legacy has been specified then we use that to decide on the
2632
+ // form
2633
+ return legacy ? data : d;
2634
+ }
2635
+
2636
+
2637
+ /**
2638
+ * Data the data from the server (nuking the old) and redraw the table
2639
+ * @param {object} oSettings dataTables settings object
2640
+ * @param {object} json json data return from the server.
2641
+ * @param {string} json.sEcho Tracking flag for DataTables to match requests
2642
+ * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
2643
+ * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
2644
+ * @param {array} json.aaData The data to display on this page
2645
+ * @param {string} [json.sColumns] Column ordering (sName, comma separated)
2646
+ * @memberof DataTable#oApi
2647
+ */
2648
+ function _fnAjaxUpdateDraw ( settings, json )
2649
+ {
2650
+ // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
2651
+ // Support both
2652
+ var compat = function ( old, modern ) {
2653
+ return json[old] !== undefined ? json[old] : json[modern];
2654
+ };
2655
+
2656
+ var draw = compat( 'sEcho', 'draw' );
2657
+ var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
2658
+ var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
2659
+
2660
+ if ( draw ) {
2661
+ // Protect against out of sequence returns
2662
+ if ( draw*1 < settings.iDraw ) {
2663
+ return;
2664
+ }
2665
+ settings.iDraw = draw * 1;
2666
+ }
2667
+
2668
+ _fnClearTable( settings );
2669
+ settings._iRecordsTotal = parseInt(recordsTotal, 10);
2670
+ settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
2671
+
2672
+ var data = _fnAjaxDataSrc( settings, json );
2673
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
2674
+ _fnAddData( settings, data[i] );
2675
+ }
2676
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
2677
+
2678
+ settings.bAjaxDataGet = false;
2679
+ _fnDraw( settings );
2680
+
2681
+ if ( ! settings._bInitComplete ) {
2682
+ _fnInitComplete( settings, json );
2683
+ }
2684
+
2685
+ settings.bAjaxDataGet = true;
2686
+ _fnProcessingDisplay( settings, false );
2687
+ }
2688
+
2689
+
2690
+ /**
2691
+ * Get the data from the JSON data source to use for drawing a table. Using
2692
+ * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
2693
+ * source object, or from a processing function.
2694
+ * @param {object} oSettings dataTables settings object
2695
+ * @param {object} json Data source object / array from the server
2696
+ * @return {array} Array of data to use
2697
+ */
2698
+ function _fnAjaxDataSrc ( oSettings, json )
2699
+ {
2700
+ var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
2701
+ oSettings.ajax.dataSrc :
2702
+ oSettings.sAjaxDataProp; // Compatibility with 1.9-.
2703
+
2704
+ // Compatibility with 1.9-. In order to read from aaData, check if the
2705
+ // default has been changed, if not, check for aaData
2706
+ if ( dataSrc === 'data' ) {
2707
+ return json.aaData || json[dataSrc];
2708
+ }
2709
+
2710
+ return dataSrc !== "" ?
2711
+ _fnGetObjectDataFn( dataSrc )( json ) :
2712
+ json;
2713
+ }
2714
+
2715
+
2716
+ /**
2717
+ * Generate the node required for filtering text
2718
+ * @returns {node} Filter control element
2719
+ * @param {object} oSettings dataTables settings object
2720
+ * @memberof DataTable#oApi
2721
+ */
2722
+ function _fnFeatureHtmlFilter ( settings )
2723
+ {
2724
+ var classes = settings.oClasses;
2725
+ var tableId = settings.sTableId;
2726
+ var language = settings.oLanguage;
2727
+ var previousSearch = settings.oPreviousSearch;
2728
+ var features = settings.aanFeatures;
2729
+ var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
2730
+
2731
+ var str = language.sSearch;
2732
+ str = str.match(/_INPUT_/) ?
2733
+ str.replace('_INPUT_', input) :
2734
+ str+input;
2735
+
2736
+ var filter = $('<div/>', {
2737
+ 'id': ! features.f ? tableId+'_filter' : null,
2738
+ 'class': classes.sFilter
2739
+ } )
2740
+ .append( $('<label/>' ).append( str ) );
2741
+
2742
+ var searchFn = function() {
2743
+ /* Update all other filter input elements for the new display */
2744
+ var n = features.f;
2745
+ var val = !this.value ? "" : this.value; // mental IE8 fix :-(
2746
+
2747
+ /* Now do the filter */
2748
+ if ( val != previousSearch.sSearch ) {
2749
+ _fnFilterComplete( settings, {
2750
+ "sSearch": val,
2751
+ "bRegex": previousSearch.bRegex,
2752
+ "bSmart": previousSearch.bSmart ,
2753
+ "bCaseInsensitive": previousSearch.bCaseInsensitive
2754
+ } );
2755
+
2756
+ // Need to redraw, without resorting
2757
+ settings._iDisplayStart = 0;
2758
+ _fnDraw( settings );
2759
+ }
2760
+ };
2761
+
2762
+ var searchDelay = settings.searchDelay !== null ?
2763
+ settings.searchDelay :
2764
+ _fnDataSource( settings ) === 'ssp' ?
2765
+ 400 :
2766
+ 0;
2767
+
2768
+ var jqFilter = $('input', filter)
2769
+ .val( previousSearch.sSearch )
2770
+ .attr( 'placeholder', language.sSearchPlaceholder )
2771
+ .bind(
2772
+ 'keyup.DT search.DT input.DT paste.DT cut.DT',
2773
+ searchDelay ?
2774
+ _fnThrottle( searchFn, searchDelay ) :
2775
+ searchFn
2776
+ )
2777
+ .bind( 'keypress.DT', function(e) {
2778
+ /* Prevent form submission */
2779
+ if ( e.keyCode == 13 ) {
2780
+ return false;
2781
+ }
2782
+ } )
2783
+ .attr('aria-controls', tableId);
2784
+
2785
+ // Update the input elements whenever the table is filtered
2786
+ $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
2787
+ if ( settings === s ) {
2788
+ // IE9 throws an 'unknown error' if document.activeElement is used
2789
+ // inside an iframe or frame...
2790
+ try {
2791
+ if ( jqFilter[0] !== document.activeElement ) {
2792
+ jqFilter.val( previousSearch.sSearch );
2793
+ }
2794
+ }
2795
+ catch ( e ) {}
2796
+ }
2797
+ } );
2798
+
2799
+ return filter[0];
2800
+ }
2801
+
2802
+
2803
+ /**
2804
+ * Filter the table using both the global filter and column based filtering
2805
+ * @param {object} oSettings dataTables settings object
2806
+ * @param {object} oSearch search information
2807
+ * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
2808
+ * @memberof DataTable#oApi
2809
+ */
2810
+ function _fnFilterComplete ( oSettings, oInput, iForce )
2811
+ {
2812
+ var oPrevSearch = oSettings.oPreviousSearch;
2813
+ var aoPrevSearch = oSettings.aoPreSearchCols;
2814
+ var fnSaveFilter = function ( oFilter ) {
2815
+ /* Save the filtering values */
2816
+ oPrevSearch.sSearch = oFilter.sSearch;
2817
+ oPrevSearch.bRegex = oFilter.bRegex;
2818
+ oPrevSearch.bSmart = oFilter.bSmart;
2819
+ oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
2820
+ };
2821
+ var fnRegex = function ( o ) {
2822
+ // Backwards compatibility with the bEscapeRegex option
2823
+ return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
2824
+ };
2825
+
2826
+ // Resolve any column types that are unknown due to addition or invalidation
2827
+ // @todo As per sort - can this be moved into an event handler?
2828
+ _fnColumnTypes( oSettings );
2829
+
2830
+ /* In server-side processing all filtering is done by the server, so no point hanging around here */
2831
+ if ( _fnDataSource( oSettings ) != 'ssp' )
2832
+ {
2833
+ /* Global filter */
2834
+ _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive );
2835
+ fnSaveFilter( oInput );
2836
+
2837
+ /* Now do the individual column filter */
2838
+ for ( var i=0 ; i<aoPrevSearch.length ; i++ )
2839
+ {
2840
+ _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
2841
+ aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
2842
+ }
2843
+
2844
+ /* Custom filtering */
2845
+ _fnFilterCustom( oSettings );
2846
+ }
2847
+ else
2848
+ {
2849
+ fnSaveFilter( oInput );
2850
+ }
2851
+
2852
+ /* Tell the draw function we have been filtering */
2853
+ oSettings.bFiltered = true;
2854
+ _fnCallbackFire( oSettings, null, 'search', [oSettings] );
2855
+ }
2856
+
2857
+
2858
+ /**
2859
+ * Apply custom filtering functions
2860
+ * @param {object} oSettings dataTables settings object
2861
+ * @memberof DataTable#oApi
2862
+ */
2863
+ function _fnFilterCustom( settings )
2864
+ {
2865
+ var filters = DataTable.ext.search;
2866
+ var displayRows = settings.aiDisplay;
2867
+ var row, rowIdx;
2868
+
2869
+ for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
2870
+ var rows = [];
2871
+
2872
+ // Loop over each row and see if it should be included
2873
+ for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
2874
+ rowIdx = displayRows[ j ];
2875
+ row = settings.aoData[ rowIdx ];
2876
+
2877
+ if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
2878
+ rows.push( rowIdx );
2879
+ }
2880
+ }
2881
+
2882
+ // So the array reference doesn't break set the results into the
2883
+ // existing array
2884
+ displayRows.length = 0;
2885
+ displayRows.push.apply( displayRows, rows );
2886
+ }
2887
+ }
2888
+
2889
+
2890
+ /**
2891
+ * Filter the table on a per-column basis
2892
+ * @param {object} oSettings dataTables settings object
2893
+ * @param {string} sInput string to filter on
2894
+ * @param {int} iColumn column to filter
2895
+ * @param {bool} bRegex treat search string as a regular expression or not
2896
+ * @param {bool} bSmart use smart filtering or not
2897
+ * @param {bool} bCaseInsensitive Do case insenstive matching or not
2898
+ * @memberof DataTable#oApi
2899
+ */
2900
+ function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
2901
+ {
2902
+ if ( searchStr === '' ) {
2903
+ return;
2904
+ }
2905
+
2906
+ var data;
2907
+ var display = settings.aiDisplay;
2908
+ var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
2909
+
2910
+ for ( var i=display.length-1 ; i>=0 ; i-- ) {
2911
+ data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
2912
+
2913
+ if ( ! rpSearch.test( data ) ) {
2914
+ display.splice( i, 1 );
2915
+ }
2916
+ }
2917
+ }
2918
+
2919
+
2920
+ /**
2921
+ * Filter the data table based on user input and draw the table
2922
+ * @param {object} settings dataTables settings object
2923
+ * @param {string} input string to filter on
2924
+ * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
2925
+ * @param {bool} regex treat as a regular expression or not
2926
+ * @param {bool} smart perform smart filtering or not
2927
+ * @param {bool} caseInsensitive Do case insenstive matching or not
2928
+ * @memberof DataTable#oApi
2929
+ */
2930
+ function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
2931
+ {
2932
+ var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
2933
+ var prevSearch = settings.oPreviousSearch.sSearch;
2934
+ var displayMaster = settings.aiDisplayMaster;
2935
+ var display, invalidated, i;
2936
+
2937
+ // Need to take account of custom filtering functions - always filter
2938
+ if ( DataTable.ext.search.length !== 0 ) {
2939
+ force = true;
2940
+ }
2941
+
2942
+ // Check if any of the rows were invalidated
2943
+ invalidated = _fnFilterData( settings );
2944
+
2945
+ // If the input is blank - we just want the full data set
2946
+ if ( input.length <= 0 ) {
2947
+ settings.aiDisplay = displayMaster.slice();
2948
+ }
2949
+ else {
2950
+ // New search - start from the master array
2951
+ if ( invalidated ||
2952
+ force ||
2953
+ prevSearch.length > input.length ||
2954
+ input.indexOf(prevSearch) !== 0 ||
2955
+ settings.bSorted // On resort, the display master needs to be
2956
+ // re-filtered since indexes will have changed
2957
+ ) {
2958
+ settings.aiDisplay = displayMaster.slice();
2959
+ }
2960
+
2961
+ // Search the display array
2962
+ display = settings.aiDisplay;
2963
+
2964
+ for ( i=display.length-1 ; i>=0 ; i-- ) {
2965
+ if ( ! rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
2966
+ display.splice( i, 1 );
2967
+ }
2968
+ }
2969
+ }
2970
+ }
2971
+
2972
+
2973
+ /**
2974
+ * Build a regular expression object suitable for searching a table
2975
+ * @param {string} sSearch string to search for
2976
+ * @param {bool} bRegex treat as a regular expression or not
2977
+ * @param {bool} bSmart perform smart filtering or not
2978
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
2979
+ * @returns {RegExp} constructed object
2980
+ * @memberof DataTable#oApi
2981
+ */
2982
+ function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
2983
+ {
2984
+ search = regex ?
2985
+ search :
2986
+ _fnEscapeRegex( search );
2987
+
2988
+ if ( smart ) {
2989
+ /* For smart filtering we want to allow the search to work regardless of
2990
+ * word order. We also want double quoted text to be preserved, so word
2991
+ * order is important - a la google. So this is what we want to
2992
+ * generate:
2993
+ *
2994
+ * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
2995
+ */
2996
+ var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || '', function ( word ) {
2997
+ if ( word.charAt(0) === '"' ) {
2998
+ var m = word.match( /^"(.*)"$/ );
2999
+ word = m ? m[1] : word;
3000
+ }
3001
+
3002
+ return word.replace('"', '');
3003
+ } );
3004
+
3005
+ search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
3006
+ }
3007
+
3008
+ return new RegExp( search, caseInsensitive ? 'i' : '' );
3009
+ }
3010
+
3011
+
3012
+ /**
3013
+ * Escape a string such that it can be used in a regular expression
3014
+ * @param {string} sVal string to escape
3015
+ * @returns {string} escaped string
3016
+ * @memberof DataTable#oApi
3017
+ */
3018
+ function _fnEscapeRegex ( sVal )
3019
+ {
3020
+ return sVal.replace( _re_escape_regex, '\\$1' );
3021
+ }
3022
+
3023
+
3024
+
3025
+ var __filter_div = $('<div>')[0];
3026
+ var __filter_div_textContent = __filter_div.textContent !== undefined;
3027
+
3028
+ // Update the filtering data for each row if needed (by invalidation or first run)
3029
+ function _fnFilterData ( settings )
3030
+ {
3031
+ var columns = settings.aoColumns;
3032
+ var column;
3033
+ var i, j, ien, jen, filterData, cellData, row;
3034
+ var fomatters = DataTable.ext.type.search;
3035
+ var wasInvalidated = false;
3036
+
3037
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
3038
+ row = settings.aoData[i];
3039
+
3040
+ if ( ! row._aFilterData ) {
3041
+ filterData = [];
3042
+
3043
+ for ( j=0, jen=columns.length ; j<jen ; j++ ) {
3044
+ column = columns[j];
3045
+
3046
+ if ( column.bSearchable ) {
3047
+ cellData = _fnGetCellData( settings, i, j, 'filter' );
3048
+
3049
+ if ( fomatters[ column.sType ] ) {
3050
+ cellData = fomatters[ column.sType ]( cellData );
3051
+ }
3052
+
3053
+ // Search in DataTables 1.10 is string based. In 1.11 this
3054
+ // should be altered to also allow strict type checking.
3055
+ if ( cellData === null ) {
3056
+ cellData = '';
3057
+ }
3058
+
3059
+ if ( typeof cellData !== 'string' && cellData.toString ) {
3060
+ cellData = cellData.toString();
3061
+ }
3062
+ }
3063
+ else {
3064
+ cellData = '';
3065
+ }
3066
+
3067
+ // If it looks like there is an HTML entity in the string,
3068
+ // attempt to decode it so sorting works as expected. Note that
3069
+ // we could use a single line of jQuery to do this, but the DOM
3070
+ // method used here is much faster http://jsperf.com/html-decode
3071
+ if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
3072
+ __filter_div.innerHTML = cellData;
3073
+ cellData = __filter_div_textContent ?
3074
+ __filter_div.textContent :
3075
+ __filter_div.innerText;
3076
+ }
3077
+
3078
+ if ( cellData.replace ) {
3079
+ cellData = cellData.replace(/[\r\n]/g, '');
3080
+ }
3081
+
3082
+ filterData.push( cellData );
3083
+ }
3084
+
3085
+ row._aFilterData = filterData;
3086
+ row._sFilterRow = filterData.join(' ');
3087
+ wasInvalidated = true;
3088
+ }
3089
+ }
3090
+
3091
+ return wasInvalidated;
3092
+ }
3093
+
3094
+
3095
+ /**
3096
+ * Convert from the internal Hungarian notation to camelCase for external
3097
+ * interaction
3098
+ * @param {object} obj Object to convert
3099
+ * @returns {object} Inverted object
3100
+ * @memberof DataTable#oApi
3101
+ */
3102
+ function _fnSearchToCamel ( obj )
3103
+ {
3104
+ return {
3105
+ search: obj.sSearch,
3106
+ smart: obj.bSmart,
3107
+ regex: obj.bRegex,
3108
+ caseInsensitive: obj.bCaseInsensitive
3109
+ };
3110
+ }
3111
+
3112
+
3113
+
3114
+ /**
3115
+ * Convert from camelCase notation to the internal Hungarian. We could use the
3116
+ * Hungarian convert function here, but this is cleaner
3117
+ * @param {object} obj Object to convert
3118
+ * @returns {object} Inverted object
3119
+ * @memberof DataTable#oApi
3120
+ */
3121
+ function _fnSearchToHung ( obj )
3122
+ {
3123
+ return {
3124
+ sSearch: obj.search,
3125
+ bSmart: obj.smart,
3126
+ bRegex: obj.regex,
3127
+ bCaseInsensitive: obj.caseInsensitive
3128
+ };
3129
+ }
3130
+
3131
+ /**
3132
+ * Generate the node required for the info display
3133
+ * @param {object} oSettings dataTables settings object
3134
+ * @returns {node} Information element
3135
+ * @memberof DataTable#oApi
3136
+ */
3137
+ function _fnFeatureHtmlInfo ( settings )
3138
+ {
3139
+ var
3140
+ tid = settings.sTableId,
3141
+ nodes = settings.aanFeatures.i,
3142
+ n = $('<div/>', {
3143
+ 'class': settings.oClasses.sInfo,
3144
+ 'id': ! nodes ? tid+'_info' : null
3145
+ } );
3146
+
3147
+ if ( ! nodes ) {
3148
+ // Update display on each draw
3149
+ settings.aoDrawCallback.push( {
3150
+ "fn": _fnUpdateInfo,
3151
+ "sName": "information"
3152
+ } );
3153
+
3154
+ n
3155
+ .attr( 'role', 'status' )
3156
+ .attr( 'aria-live', 'polite' );
3157
+
3158
+ // Table is described by our info div
3159
+ $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
3160
+ }
3161
+
3162
+ return n[0];
3163
+ }
3164
+
3165
+
3166
+ /**
3167
+ * Update the information elements in the display
3168
+ * @param {object} settings dataTables settings object
3169
+ * @memberof DataTable#oApi
3170
+ */
3171
+ function _fnUpdateInfo ( settings )
3172
+ {
3173
+ /* Show information about the table */
3174
+ var nodes = settings.aanFeatures.i;
3175
+ if ( nodes.length === 0 ) {
3176
+ return;
3177
+ }
3178
+
3179
+ var
3180
+ lang = settings.oLanguage,
3181
+ start = settings._iDisplayStart+1,
3182
+ end = settings.fnDisplayEnd(),
3183
+ max = settings.fnRecordsTotal(),
3184
+ total = settings.fnRecordsDisplay(),
3185
+ out = total ?
3186
+ lang.sInfo :
3187
+ lang.sInfoEmpty;
3188
+
3189
+ if ( total !== max ) {
3190
+ /* Record set after filtering */
3191
+ out += ' ' + lang.sInfoFiltered;
3192
+ }
3193
+
3194
+ // Convert the macros
3195
+ out += lang.sInfoPostFix;
3196
+ out = _fnInfoMacros( settings, out );
3197
+
3198
+ var callback = lang.fnInfoCallback;
3199
+ if ( callback !== null ) {
3200
+ out = callback.call( settings.oInstance,
3201
+ settings, start, end, max, total, out
3202
+ );
3203
+ }
3204
+
3205
+ $(nodes).html( out );
3206
+ }
3207
+
3208
+
3209
+ function _fnInfoMacros ( settings, str )
3210
+ {
3211
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
3212
+ // internally
3213
+ var
3214
+ formatter = settings.fnFormatNumber,
3215
+ start = settings._iDisplayStart+1,
3216
+ len = settings._iDisplayLength,
3217
+ vis = settings.fnRecordsDisplay(),
3218
+ all = len === -1;
3219
+
3220
+ return str.
3221
+ replace(/_START_/g, formatter.call( settings, start ) ).
3222
+ replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
3223
+ replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
3224
+ replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
3225
+ replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
3226
+ replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
3227
+ }
3228
+
3229
+
3230
+
3231
+ /**
3232
+ * Draw the table for the first time, adding all required features
3233
+ * @param {object} settings dataTables settings object
3234
+ * @memberof DataTable#oApi
3235
+ */
3236
+ function _fnInitialise ( settings )
3237
+ {
3238
+ var i, iLen, iAjaxStart=settings.iInitDisplayStart;
3239
+ var columns = settings.aoColumns, column;
3240
+ var features = settings.oFeatures;
3241
+
3242
+ /* Ensure that the table data is fully initialised */
3243
+ if ( ! settings.bInitialised ) {
3244
+ setTimeout( function(){ _fnInitialise( settings ); }, 200 );
3245
+ return;
3246
+ }
3247
+
3248
+ /* Show the display HTML options */
3249
+ _fnAddOptionsHtml( settings );
3250
+
3251
+ /* Build and draw the header / footer for the table */
3252
+ _fnBuildHead( settings );
3253
+ _fnDrawHead( settings, settings.aoHeader );
3254
+ _fnDrawHead( settings, settings.aoFooter );
3255
+
3256
+ /* Okay to show that something is going on now */
3257
+ _fnProcessingDisplay( settings, true );
3258
+
3259
+ /* Calculate sizes for columns */
3260
+ if ( features.bAutoWidth ) {
3261
+ _fnCalculateColumnWidths( settings );
3262
+ }
3263
+
3264
+ for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
3265
+ column = columns[i];
3266
+
3267
+ if ( column.sWidth ) {
3268
+ column.nTh.style.width = _fnStringToCss( column.sWidth );
3269
+ }
3270
+ }
3271
+
3272
+ // If there is default sorting required - let's do it. The sort function
3273
+ // will do the drawing for us. Otherwise we draw the table regardless of the
3274
+ // Ajax source - this allows the table to look initialised for Ajax sourcing
3275
+ // data (show 'loading' message possibly)
3276
+ _fnReDraw( settings );
3277
+
3278
+ // Server-side processing init complete is done by _fnAjaxUpdateDraw
3279
+ var dataSrc = _fnDataSource( settings );
3280
+ if ( dataSrc != 'ssp' ) {
3281
+ // if there is an ajax source load the data
3282
+ if ( dataSrc == 'ajax' ) {
3283
+ _fnBuildAjax( settings, [], function(json) {
3284
+ var aData = _fnAjaxDataSrc( settings, json );
3285
+
3286
+ // Got the data - add it to the table
3287
+ for ( i=0 ; i<aData.length ; i++ ) {
3288
+ _fnAddData( settings, aData[i] );
3289
+ }
3290
+
3291
+ // Reset the init display for cookie saving. We've already done
3292
+ // a filter, and therefore cleared it before. So we need to make
3293
+ // it appear 'fresh'
3294
+ settings.iInitDisplayStart = iAjaxStart;
3295
+
3296
+ _fnReDraw( settings );
3297
+
3298
+ _fnProcessingDisplay( settings, false );
3299
+ _fnInitComplete( settings, json );
3300
+ }, settings );
3301
+ }
3302
+ else {
3303
+ _fnProcessingDisplay( settings, false );
3304
+ _fnInitComplete( settings );
3305
+ }
3306
+ }
3307
+ }
3308
+
3309
+
3310
+ /**
3311
+ * Draw the table for the first time, adding all required features
3312
+ * @param {object} oSettings dataTables settings object
3313
+ * @param {object} [json] JSON from the server that completed the table, if using Ajax source
3314
+ * with client-side processing (optional)
3315
+ * @memberof DataTable#oApi
3316
+ */
3317
+ function _fnInitComplete ( settings, json )
3318
+ {
3319
+ settings._bInitComplete = true;
3320
+
3321
+ // On an Ajax load we now have data and therefore want to apply the column
3322
+ // sizing
3323
+ if ( json ) {
3324
+ _fnAdjustColumnSizing( settings );
3325
+ }
3326
+
3327
+ _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
3328
+ }
3329
+
3330
+
3331
+ function _fnLengthChange ( settings, val )
3332
+ {
3333
+ var len = parseInt( val, 10 );
3334
+ settings._iDisplayLength = len;
3335
+
3336
+ _fnLengthOverflow( settings );
3337
+
3338
+ // Fire length change event
3339
+ _fnCallbackFire( settings, null, 'length', [settings, len] );
3340
+ }
3341
+
3342
+
3343
+ /**
3344
+ * Generate the node required for user display length changing
3345
+ * @param {object} settings dataTables settings object
3346
+ * @returns {node} Display length feature node
3347
+ * @memberof DataTable#oApi
3348
+ */
3349
+ function _fnFeatureHtmlLength ( settings )
3350
+ {
3351
+ var
3352
+ classes = settings.oClasses,
3353
+ tableId = settings.sTableId,
3354
+ menu = settings.aLengthMenu,
3355
+ d2 = $.isArray( menu[0] ),
3356
+ lengths = d2 ? menu[0] : menu,
3357
+ language = d2 ? menu[1] : menu;
3358
+
3359
+ var select = $('<select/>', {
3360
+ 'name': tableId+'_length',
3361
+ 'aria-controls': tableId,
3362
+ 'class': classes.sLengthSelect
3363
+ } );
3364
+
3365
+ for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
3366
+ select[0][ i ] = new Option( language[i], lengths[i] );
3367
+ }
3368
+
3369
+ var div = $('<div><label/></div>').addClass( classes.sLength );
3370
+ if ( ! settings.aanFeatures.l ) {
3371
+ div[0].id = tableId+'_length';
3372
+ }
3373
+
3374
+ div.children().append(
3375
+ settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
3376
+ );
3377
+
3378
+ // Can't use `select` variable as user might provide their own and the
3379
+ // reference is broken by the use of outerHTML
3380
+ $('select', div)
3381
+ .val( settings._iDisplayLength )
3382
+ .bind( 'change.DT', function(e) {
3383
+ _fnLengthChange( settings, $(this).val() );
3384
+ _fnDraw( settings );
3385
+ } );
3386
+
3387
+ // Update node value whenever anything changes the table's length
3388
+ $(settings.nTable).bind( 'length.dt.DT', function (e, s, len) {
3389
+ if ( settings === s ) {
3390
+ $('select', div).val( len );
3391
+ }
3392
+ } );
3393
+
3394
+ return div[0];
3395
+ }
3396
+
3397
+
3398
+
3399
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3400
+ * Note that most of the paging logic is done in
3401
+ * DataTable.ext.pager
3402
+ */
3403
+
3404
+ /**
3405
+ * Generate the node required for default pagination
3406
+ * @param {object} oSettings dataTables settings object
3407
+ * @returns {node} Pagination feature node
3408
+ * @memberof DataTable#oApi
3409
+ */
3410
+ function _fnFeatureHtmlPaginate ( settings )
3411
+ {
3412
+ var
3413
+ type = settings.sPaginationType,
3414
+ plugin = DataTable.ext.pager[ type ],
3415
+ modern = typeof plugin === 'function',
3416
+ redraw = function( settings ) {
3417
+ _fnDraw( settings );
3418
+ },
3419
+ node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
3420
+ features = settings.aanFeatures;
3421
+
3422
+ if ( ! modern ) {
3423
+ plugin.fnInit( settings, node, redraw );
3424
+ }
3425
+
3426
+ /* Add a draw callback for the pagination on first instance, to update the paging display */
3427
+ if ( ! features.p )
3428
+ {
3429
+ node.id = settings.sTableId+'_paginate';
3430
+
3431
+ settings.aoDrawCallback.push( {
3432
+ "fn": function( settings ) {
3433
+ if ( modern ) {
3434
+ var
3435
+ start = settings._iDisplayStart,
3436
+ len = settings._iDisplayLength,
3437
+ visRecords = settings.fnRecordsDisplay(),
3438
+ all = len === -1,
3439
+ page = all ? 0 : Math.ceil( start / len ),
3440
+ pages = all ? 1 : Math.ceil( visRecords / len ),
3441
+ buttons = plugin(page, pages),
3442
+ i, ien;
3443
+
3444
+ for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
3445
+ _fnRenderer( settings, 'pageButton' )(
3446
+ settings, features.p[i], i, buttons, page, pages
3447
+ );
3448
+ }
3449
+ }
3450
+ else {
3451
+ plugin.fnUpdate( settings, redraw );
3452
+ }
3453
+ },
3454
+ "sName": "pagination"
3455
+ } );
3456
+ }
3457
+
3458
+ return node;
3459
+ }
3460
+
3461
+
3462
+ /**
3463
+ * Alter the display settings to change the page
3464
+ * @param {object} settings DataTables settings object
3465
+ * @param {string|int} action Paging action to take: "first", "previous",
3466
+ * "next" or "last" or page number to jump to (integer)
3467
+ * @param [bool] redraw Automatically draw the update or not
3468
+ * @returns {bool} true page has changed, false - no change
3469
+ * @memberof DataTable#oApi
3470
+ */
3471
+ function _fnPageChange ( settings, action, redraw )
3472
+ {
3473
+ var
3474
+ start = settings._iDisplayStart,
3475
+ len = settings._iDisplayLength,
3476
+ records = settings.fnRecordsDisplay();
3477
+
3478
+ if ( records === 0 || len === -1 )
3479
+ {
3480
+ start = 0;
3481
+ }
3482
+ else if ( typeof action === "number" )
3483
+ {
3484
+ start = action * len;
3485
+
3486
+ if ( start > records )
3487
+ {
3488
+ start = 0;
3489
+ }
3490
+ }
3491
+ else if ( action == "first" )
3492
+ {
3493
+ start = 0;
3494
+ }
3495
+ else if ( action == "previous" )
3496
+ {
3497
+ start = len >= 0 ?
3498
+ start - len :
3499
+ 0;
3500
+
3501
+ if ( start < 0 )
3502
+ {
3503
+ start = 0;
3504
+ }
3505
+ }
3506
+ else if ( action == "next" )
3507
+ {
3508
+ if ( start + len < records )
3509
+ {
3510
+ start += len;
3511
+ }
3512
+ }
3513
+ else if ( action == "last" )
3514
+ {
3515
+ start = Math.floor( (records-1) / len) * len;
3516
+ }
3517
+ else
3518
+ {
3519
+ _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
3520
+ }
3521
+
3522
+ var changed = settings._iDisplayStart !== start;
3523
+ settings._iDisplayStart = start;
3524
+
3525
+ if ( changed ) {
3526
+ _fnCallbackFire( settings, null, 'page', [settings] );
3527
+
3528
+ if ( redraw ) {
3529
+ _fnDraw( settings );
3530
+ }
3531
+ }
3532
+
3533
+ return changed;
3534
+ }
3535
+
3536
+
3537
+
3538
+ /**
3539
+ * Generate the node required for the processing node
3540
+ * @param {object} settings dataTables settings object
3541
+ * @returns {node} Processing element
3542
+ * @memberof DataTable#oApi
3543
+ */
3544
+ function _fnFeatureHtmlProcessing ( settings )
3545
+ {
3546
+ return $('<div/>', {
3547
+ 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
3548
+ 'class': settings.oClasses.sProcessing
3549
+ } )
3550
+ .html( settings.oLanguage.sProcessing )
3551
+ .insertBefore( settings.nTable )[0];
3552
+ }
3553
+
3554
+
3555
+ /**
3556
+ * Display or hide the processing indicator
3557
+ * @param {object} settings dataTables settings object
3558
+ * @param {bool} show Show the processing indicator (true) or not (false)
3559
+ * @memberof DataTable#oApi
3560
+ */
3561
+ function _fnProcessingDisplay ( settings, show )
3562
+ {
3563
+ if ( settings.oFeatures.bProcessing ) {
3564
+ $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
3565
+ }
3566
+
3567
+ _fnCallbackFire( settings, null, 'processing', [settings, show] );
3568
+ }
3569
+
3570
+ /**
3571
+ * Add any control elements for the table - specifically scrolling
3572
+ * @param {object} settings dataTables settings object
3573
+ * @returns {node} Node to add to the DOM
3574
+ * @memberof DataTable#oApi
3575
+ */
3576
+ function _fnFeatureHtmlTable ( settings )
3577
+ {
3578
+ var table = $(settings.nTable);
3579
+
3580
+ // Add the ARIA grid role to the table
3581
+ table.attr( 'role', 'grid' );
3582
+
3583
+ // Scrolling from here on in
3584
+ var scroll = settings.oScroll;
3585
+
3586
+ if ( scroll.sX === '' && scroll.sY === '' ) {
3587
+ return settings.nTable;
3588
+ }
3589
+
3590
+ var scrollX = scroll.sX;
3591
+ var scrollY = scroll.sY;
3592
+ var classes = settings.oClasses;
3593
+ var caption = table.children('caption');
3594
+ var captionSide = caption.length ? caption[0]._captionSide : null;
3595
+ var headerClone = $( table[0].cloneNode(false) );
3596
+ var footerClone = $( table[0].cloneNode(false) );
3597
+ var footer = table.children('tfoot');
3598
+ var _div = '<div/>';
3599
+ var size = function ( s ) {
3600
+ return !s ? null : _fnStringToCss( s );
3601
+ };
3602
+
3603
+ // This is fairly messy, but with x scrolling enabled, if the table has a
3604
+ // width attribute, regardless of any width applied using the column width
3605
+ // options, the browser will shrink or grow the table as needed to fit into
3606
+ // that 100%. That would make the width options useless. So we remove it.
3607
+ // This is okay, under the assumption that width:100% is applied to the
3608
+ // table in CSS (it is in the default stylesheet) which will set the table
3609
+ // width as appropriate (the attribute and css behave differently...)
3610
+ if ( scroll.sX && table.attr('width') === '100%' ) {
3611
+ table.removeAttr('width');
3612
+ }
3613
+
3614
+ if ( ! footer.length ) {
3615
+ footer = null;
3616
+ }
3617
+
3618
+ /*
3619
+ * The HTML structure that we want to generate in this function is:
3620
+ * div - scroller
3621
+ * div - scroll head
3622
+ * div - scroll head inner
3623
+ * table - scroll head table
3624
+ * thead - thead
3625
+ * div - scroll body
3626
+ * table - table (master table)
3627
+ * thead - thead clone for sizing
3628
+ * tbody - tbody
3629
+ * div - scroll foot
3630
+ * div - scroll foot inner
3631
+ * table - scroll foot table
3632
+ * tfoot - tfoot
3633
+ */
3634
+ var scroller = $( _div, { 'class': classes.sScrollWrapper } )
3635
+ .append(
3636
+ $(_div, { 'class': classes.sScrollHead } )
3637
+ .css( {
3638
+ overflow: 'hidden',
3639
+ position: 'relative',
3640
+ border: 0,
3641
+ width: scrollX ? size(scrollX) : '100%'
3642
+ } )
3643
+ .append(
3644
+ $(_div, { 'class': classes.sScrollHeadInner } )
3645
+ .css( {
3646
+ 'box-sizing': 'content-box',
3647
+ width: scroll.sXInner || '100%'
3648
+ } )
3649
+ .append(
3650
+ headerClone
3651
+ .removeAttr('id')
3652
+ .css( 'margin-left', 0 )
3653
+ .append( captionSide === 'top' ? caption : null )
3654
+ .append(
3655
+ table.children('thead')
3656
+ )
3657
+ )
3658
+ )
3659
+ )
3660
+ .append(
3661
+ $(_div, { 'class': classes.sScrollBody } )
3662
+ .css( {
3663
+ overflow: 'auto',
3664
+ height: size( scrollY ),
3665
+ width: size( scrollX )
3666
+ } )
3667
+ .append( table )
3668
+ );
3669
+
3670
+ if ( footer ) {
3671
+ scroller.append(
3672
+ $(_div, { 'class': classes.sScrollFoot } )
3673
+ .css( {
3674
+ overflow: 'hidden',
3675
+ border: 0,
3676
+ width: scrollX ? size(scrollX) : '100%'
3677
+ } )
3678
+ .append(
3679
+ $(_div, { 'class': classes.sScrollFootInner } )
3680
+ .append(
3681
+ footerClone
3682
+ .removeAttr('id')
3683
+ .css( 'margin-left', 0 )
3684
+ .append( captionSide === 'bottom' ? caption : null )
3685
+ .append(
3686
+ table.children('tfoot')
3687
+ )
3688
+ )
3689
+ )
3690
+ );
3691
+ }
3692
+
3693
+ var children = scroller.children();
3694
+ var scrollHead = children[0];
3695
+ var scrollBody = children[1];
3696
+ var scrollFoot = footer ? children[2] : null;
3697
+
3698
+ // When the body is scrolled, then we also want to scroll the headers
3699
+ if ( scrollX ) {
3700
+ $(scrollBody).scroll( function (e) {
3701
+ var scrollLeft = this.scrollLeft;
3702
+
3703
+ scrollHead.scrollLeft = scrollLeft;
3704
+
3705
+ if ( footer ) {
3706
+ scrollFoot.scrollLeft = scrollLeft;
3707
+ }
3708
+ } );
3709
+ }
3710
+
3711
+ settings.nScrollHead = scrollHead;
3712
+ settings.nScrollBody = scrollBody;
3713
+ settings.nScrollFoot = scrollFoot;
3714
+
3715
+ // On redraw - align columns
3716
+ settings.aoDrawCallback.push( {
3717
+ "fn": _fnScrollDraw,
3718
+ "sName": "scrolling"
3719
+ } );
3720
+
3721
+ return scroller[0];
3722
+ }
3723
+
3724
+
3725
+
3726
+ /**
3727
+ * Update the header, footer and body tables for resizing - i.e. column
3728
+ * alignment.
3729
+ *
3730
+ * Welcome to the most horrible function DataTables. The process that this
3731
+ * function follows is basically:
3732
+ * 1. Re-create the table inside the scrolling div
3733
+ * 2. Take live measurements from the DOM
3734
+ * 3. Apply the measurements to align the columns
3735
+ * 4. Clean up
3736
+ *
3737
+ * @param {object} settings dataTables settings object
3738
+ * @memberof DataTable#oApi
3739
+ */
3740
+ function _fnScrollDraw ( settings )
3741
+ {
3742
+ // Given that this is such a monster function, a lot of variables are use
3743
+ // to try and keep the minimised size as small as possible
3744
+ var
3745
+ scroll = settings.oScroll,
3746
+ scrollX = scroll.sX,
3747
+ scrollXInner = scroll.sXInner,
3748
+ scrollY = scroll.sY,
3749
+ barWidth = scroll.iBarWidth,
3750
+ divHeader = $(settings.nScrollHead),
3751
+ divHeaderStyle = divHeader[0].style,
3752
+ divHeaderInner = divHeader.children('div'),
3753
+ divHeaderInnerStyle = divHeaderInner[0].style,
3754
+ divHeaderTable = divHeaderInner.children('table'),
3755
+ divBodyEl = settings.nScrollBody,
3756
+ divBody = $(divBodyEl),
3757
+ divBodyStyle = divBodyEl.style,
3758
+ divFooter = $(settings.nScrollFoot),
3759
+ divFooterInner = divFooter.children('div'),
3760
+ divFooterTable = divFooterInner.children('table'),
3761
+ header = $(settings.nTHead),
3762
+ table = $(settings.nTable),
3763
+ tableEl = table[0],
3764
+ tableStyle = tableEl.style,
3765
+ footer = settings.nTFoot ? $(settings.nTFoot) : null,
3766
+ browser = settings.oBrowser,
3767
+ ie67 = browser.bScrollOversize,
3768
+ headerTrgEls, footerTrgEls,
3769
+ headerSrcEls, footerSrcEls,
3770
+ headerCopy, footerCopy,
3771
+ headerWidths=[], footerWidths=[],
3772
+ headerContent=[],
3773
+ idx, correction, sanityWidth,
3774
+ zeroOut = function(nSizer) {
3775
+ var style = nSizer.style;
3776
+ style.paddingTop = "0";
3777
+ style.paddingBottom = "0";
3778
+ style.borderTopWidth = "0";
3779
+ style.borderBottomWidth = "0";
3780
+ style.height = 0;
3781
+ };
3782
+
3783
+ /*
3784
+ * 1. Re-create the table inside the scrolling div
3785
+ */
3786
+
3787
+ // Remove the old minimised thead and tfoot elements in the inner table
3788
+ table.children('thead, tfoot').remove();
3789
+
3790
+ // Clone the current header and footer elements and then place it into the inner table
3791
+ headerCopy = header.clone().prependTo( table );
3792
+ headerTrgEls = header.find('tr'); // original header is in its own table
3793
+ headerSrcEls = headerCopy.find('tr');
3794
+ headerCopy.find('th, td').removeAttr('tabindex');
3795
+
3796
+ if ( footer ) {
3797
+ footerCopy = footer.clone().prependTo( table );
3798
+ footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
3799
+ footerSrcEls = footerCopy.find('tr');
3800
+ }
3801
+
3802
+
3803
+ /*
3804
+ * 2. Take live measurements from the DOM - do not alter the DOM itself!
3805
+ */
3806
+
3807
+ // Remove old sizing and apply the calculated column widths
3808
+ // Get the unique column headers in the newly created (cloned) header. We want to apply the
3809
+ // calculated sizes to this header
3810
+ if ( ! scrollX )
3811
+ {
3812
+ divBodyStyle.width = '100%';
3813
+ divHeader[0].style.width = '100%';
3814
+ }
3815
+
3816
+ $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
3817
+ idx = _fnVisibleToColumnIndex( settings, i );
3818
+ el.style.width = settings.aoColumns[idx].sWidth;
3819
+ } );
3820
+
3821
+ if ( footer ) {
3822
+ _fnApplyToChildren( function(n) {
3823
+ n.style.width = "";
3824
+ }, footerSrcEls );
3825
+ }
3826
+
3827
+ // If scroll collapse is enabled, when we put the headers back into the body for sizing, we
3828
+ // will end up forcing the scrollbar to appear, making our measurements wrong for when we
3829
+ // then hide it (end of this function), so add the header height to the body scroller.
3830
+ if ( scroll.bCollapse && scrollY !== "" ) {
3831
+ divBodyStyle.height = (divBody[0].offsetHeight + header[0].offsetHeight)+"px";
3832
+ }
3833
+
3834
+ // Size the table as a whole
3835
+ sanityWidth = table.outerWidth();
3836
+ if ( scrollX === "" ) {
3837
+ // No x scrolling
3838
+ tableStyle.width = "100%";
3839
+
3840
+ // IE7 will make the width of the table when 100% include the scrollbar
3841
+ // - which is shouldn't. When there is a scrollbar we need to take this
3842
+ // into account.
3843
+ if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
3844
+ divBody.css('overflow-y') == "scroll")
3845
+ ) {
3846
+ tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
3847
+ }
3848
+ }
3849
+ else
3850
+ {
3851
+ // x scrolling
3852
+ if ( scrollXInner !== "" ) {
3853
+ // x scroll inner has been given - use it
3854
+ tableStyle.width = _fnStringToCss(scrollXInner);
3855
+ }
3856
+ else if ( sanityWidth == divBody.width() && divBody.height() < table.height() ) {
3857
+ // There is y-scrolling - try to take account of the y scroll bar
3858
+ tableStyle.width = _fnStringToCss( sanityWidth-barWidth );
3859
+ if ( table.outerWidth() > sanityWidth-barWidth ) {
3860
+ // Not possible to take account of it
3861
+ tableStyle.width = _fnStringToCss( sanityWidth );
3862
+ }
3863
+ }
3864
+ else {
3865
+ // When all else fails
3866
+ tableStyle.width = _fnStringToCss( sanityWidth );
3867
+ }
3868
+ }
3869
+
3870
+ // Recalculate the sanity width - now that we've applied the required width,
3871
+ // before it was a temporary variable. This is required because the column
3872
+ // width calculation is done before this table DOM is created.
3873
+ sanityWidth = table.outerWidth();
3874
+
3875
+ // Hidden header should have zero height, so remove padding and borders. Then
3876
+ // set the width based on the real headers
3877
+
3878
+ // Apply all styles in one pass
3879
+ _fnApplyToChildren( zeroOut, headerSrcEls );
3880
+
3881
+ // Read all widths in next pass
3882
+ _fnApplyToChildren( function(nSizer) {
3883
+ headerContent.push( nSizer.innerHTML );
3884
+ headerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3885
+ }, headerSrcEls );
3886
+
3887
+ // Apply all widths in final pass
3888
+ _fnApplyToChildren( function(nToSize, i) {
3889
+ nToSize.style.width = headerWidths[i];
3890
+ }, headerTrgEls );
3891
+
3892
+ $(headerSrcEls).height(0);
3893
+
3894
+ /* Same again with the footer if we have one */
3895
+ if ( footer )
3896
+ {
3897
+ _fnApplyToChildren( zeroOut, footerSrcEls );
3898
+
3899
+ _fnApplyToChildren( function(nSizer) {
3900
+ footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
3901
+ }, footerSrcEls );
3902
+
3903
+ _fnApplyToChildren( function(nToSize, i) {
3904
+ nToSize.style.width = footerWidths[i];
3905
+ }, footerTrgEls );
3906
+
3907
+ $(footerSrcEls).height(0);
3908
+ }
3909
+
3910
+
3911
+ /*
3912
+ * 3. Apply the measurements
3913
+ */
3914
+
3915
+ // "Hide" the header and footer that we used for the sizing. We need to keep
3916
+ // the content of the cell so that the width applied to the header and body
3917
+ // both match, but we want to hide it completely. We want to also fix their
3918
+ // width to what they currently are
3919
+ _fnApplyToChildren( function(nSizer, i) {
3920
+ nSizer.innerHTML = '<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+headerContent[i]+'</div>';
3921
+ nSizer.style.width = headerWidths[i];
3922
+ }, headerSrcEls );
3923
+
3924
+ if ( footer )
3925
+ {
3926
+ _fnApplyToChildren( function(nSizer, i) {
3927
+ nSizer.innerHTML = "";
3928
+ nSizer.style.width = footerWidths[i];
3929
+ }, footerSrcEls );
3930
+ }
3931
+
3932
+ // Sanity check that the table is of a sensible width. If not then we are going to get
3933
+ // misalignment - try to prevent this by not allowing the table to shrink below its min width
3934
+ if ( table.outerWidth() < sanityWidth )
3935
+ {
3936
+ // The min width depends upon if we have a vertical scrollbar visible or not */
3937
+ correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
3938
+ divBody.css('overflow-y') == "scroll")) ?
3939
+ sanityWidth+barWidth :
3940
+ sanityWidth;
3941
+
3942
+ // IE6/7 are a law unto themselves...
3943
+ if ( ie67 && (divBodyEl.scrollHeight >
3944
+ divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
3945
+ ) {
3946
+ tableStyle.width = _fnStringToCss( correction-barWidth );
3947
+ }
3948
+
3949
+ // And give the user a warning that we've stopped the table getting too small
3950
+ if ( scrollX === "" || scrollXInner !== "" ) {
3951
+ _fnLog( settings, 1, 'Possible column misalignment', 6 );
3952
+ }
3953
+ }
3954
+ else
3955
+ {
3956
+ correction = '100%';
3957
+ }
3958
+
3959
+ // Apply to the container elements
3960
+ divBodyStyle.width = _fnStringToCss( correction );
3961
+ divHeaderStyle.width = _fnStringToCss( correction );
3962
+
3963
+ if ( footer ) {
3964
+ settings.nScrollFoot.style.width = _fnStringToCss( correction );
3965
+ }
3966
+
3967
+
3968
+ /*
3969
+ * 4. Clean up
3970
+ */
3971
+ if ( ! scrollY ) {
3972
+ /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
3973
+ * the scrollbar height from the visible display, rather than adding it on. We need to
3974
+ * set the height in order to sort this. Don't want to do it in any other browsers.
3975
+ */
3976
+ if ( ie67 ) {
3977
+ divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
3978
+ }
3979
+ }
3980
+
3981
+ if ( scrollY && scroll.bCollapse ) {
3982
+ divBodyStyle.height = _fnStringToCss( scrollY );
3983
+
3984
+ var iExtra = (scrollX && tableEl.offsetWidth > divBodyEl.offsetWidth) ?
3985
+ barWidth :
3986
+ 0;
3987
+
3988
+ if ( tableEl.offsetHeight < divBodyEl.offsetHeight ) {
3989
+ divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+iExtra );
3990
+ }
3991
+ }
3992
+
3993
+ /* Finally set the width's of the header and footer tables */
3994
+ var iOuterWidth = table.outerWidth();
3995
+ divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
3996
+ divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
3997
+
3998
+ // Figure out if there are scrollbar present - if so then we need a the header and footer to
3999
+ // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
4000
+ var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
4001
+ var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
4002
+ divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
4003
+
4004
+ if ( footer ) {
4005
+ divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
4006
+ divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
4007
+ divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
4008
+ }
4009
+
4010
+ /* Adjust the position of the header in case we loose the y-scrollbar */
4011
+ divBody.scroll();
4012
+
4013
+ // If sorting or filtering has occurred, jump the scrolling back to the top
4014
+ // only if we aren't holding the position
4015
+ if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
4016
+ divBodyEl.scrollTop = 0;
4017
+ }
4018
+ }
4019
+
4020
+
4021
+
4022
+ /**
4023
+ * Apply a given function to the display child nodes of an element array (typically
4024
+ * TD children of TR rows
4025
+ * @param {function} fn Method to apply to the objects
4026
+ * @param array {nodes} an1 List of elements to look through for display children
4027
+ * @param array {nodes} an2 Another list (identical structure to the first) - optional
4028
+ * @memberof DataTable#oApi
4029
+ */
4030
+ function _fnApplyToChildren( fn, an1, an2 )
4031
+ {
4032
+ var index=0, i=0, iLen=an1.length;
4033
+ var nNode1, nNode2;
4034
+
4035
+ while ( i < iLen ) {
4036
+ nNode1 = an1[i].firstChild;
4037
+ nNode2 = an2 ? an2[i].firstChild : null;
4038
+
4039
+ while ( nNode1 ) {
4040
+ if ( nNode1.nodeType === 1 ) {
4041
+ if ( an2 ) {
4042
+ fn( nNode1, nNode2, index );
4043
+ }
4044
+ else {
4045
+ fn( nNode1, index );
4046
+ }
4047
+
4048
+ index++;
4049
+ }
4050
+
4051
+ nNode1 = nNode1.nextSibling;
4052
+ nNode2 = an2 ? nNode2.nextSibling : null;
4053
+ }
4054
+
4055
+ i++;
4056
+ }
4057
+ }
4058
+
4059
+
4060
+
4061
+ var __re_html_remove = /<.*?>/g;
4062
+
4063
+
4064
+ /**
4065
+ * Calculate the width of columns for the table
4066
+ * @param {object} oSettings dataTables settings object
4067
+ * @memberof DataTable#oApi
4068
+ */
4069
+ function _fnCalculateColumnWidths ( oSettings )
4070
+ {
4071
+ var
4072
+ table = oSettings.nTable,
4073
+ columns = oSettings.aoColumns,
4074
+ scroll = oSettings.oScroll,
4075
+ scrollY = scroll.sY,
4076
+ scrollX = scroll.sX,
4077
+ scrollXInner = scroll.sXInner,
4078
+ columnCount = columns.length,
4079
+ visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
4080
+ headerCells = $('th', oSettings.nTHead),
4081
+ tableWidthAttr = table.getAttribute('width'),
4082
+ tableContainer = table.parentNode,
4083
+ userInputs = false,
4084
+ i, column, columnIdx, width, outerWidth;
4085
+
4086
+ /* Convert any user input sizes into pixel sizes */
4087
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4088
+ column = columns[ visibleColumns[i] ];
4089
+
4090
+ if ( column.sWidth !== null ) {
4091
+ column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
4092
+
4093
+ userInputs = true;
4094
+ }
4095
+ }
4096
+
4097
+ /* If the number of columns in the DOM equals the number that we have to
4098
+ * process in DataTables, then we can use the offsets that are created by
4099
+ * the web- browser. No custom sizes can be set in order for this to happen,
4100
+ * nor scrolling used
4101
+ */
4102
+ if ( ! userInputs && ! scrollX && ! scrollY &&
4103
+ columnCount == _fnVisbleColumns( oSettings ) &&
4104
+ columnCount == headerCells.length
4105
+ ) {
4106
+ for ( i=0 ; i<columnCount ; i++ ) {
4107
+ columns[i].sWidth = _fnStringToCss( headerCells.eq(i).width() );
4108
+ }
4109
+ }
4110
+ else
4111
+ {
4112
+ // Otherwise construct a single row table with the widest node in the
4113
+ // data, assign any user defined widths, then insert it into the DOM and
4114
+ // allow the browser to do all the hard work of calculating table widths
4115
+ var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
4116
+ .empty()
4117
+ .css( 'visibility', 'hidden' )
4118
+ .removeAttr( 'id' )
4119
+ .append( $(oSettings.nTHead).clone( false ) )
4120
+ .append( $(oSettings.nTFoot).clone( false ) )
4121
+ .append( $('<tbody><tr/></tbody>') );
4122
+
4123
+ // Remove any assigned widths from the footer (from scrolling)
4124
+ tmpTable.find('tfoot th, tfoot td').css('width', '');
4125
+
4126
+ var tr = tmpTable.find( 'tbody tr' );
4127
+
4128
+ // Apply custom sizing to the cloned header
4129
+ headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
4130
+
4131
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4132
+ column = columns[ visibleColumns[i] ];
4133
+
4134
+ headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
4135
+ _fnStringToCss( column.sWidthOrig ) :
4136
+ '';
4137
+ }
4138
+
4139
+ // Find the widest cell for each column and put it into the table
4140
+ if ( oSettings.aoData.length ) {
4141
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4142
+ columnIdx = visibleColumns[i];
4143
+ column = columns[ columnIdx ];
4144
+
4145
+ $( _fnGetWidestNode( oSettings, columnIdx ) )
4146
+ .clone( false )
4147
+ .append( column.sContentPadding )
4148
+ .appendTo( tr );
4149
+ }
4150
+ }
4151
+
4152
+ // Table has been built, attach to the document so we can work with it
4153
+ tmpTable.appendTo( tableContainer );
4154
+
4155
+ // When scrolling (X or Y) we want to set the width of the table as
4156
+ // appropriate. However, when not scrolling leave the table width as it
4157
+ // is. This results in slightly different, but I think correct behaviour
4158
+ if ( scrollX && scrollXInner ) {
4159
+ tmpTable.width( scrollXInner );
4160
+ }
4161
+ else if ( scrollX ) {
4162
+ tmpTable.css( 'width', 'auto' );
4163
+
4164
+ if ( tmpTable.width() < tableContainer.offsetWidth ) {
4165
+ tmpTable.width( tableContainer.offsetWidth );
4166
+ }
4167
+ }
4168
+ else if ( scrollY ) {
4169
+ tmpTable.width( tableContainer.offsetWidth );
4170
+ }
4171
+ else if ( tableWidthAttr ) {
4172
+ tmpTable.width( tableWidthAttr );
4173
+ }
4174
+
4175
+ // Take into account the y scrollbar
4176
+ _fnScrollingWidthAdjust( oSettings, tmpTable[0] );
4177
+
4178
+ // Browsers need a bit of a hand when a width is assigned to any columns
4179
+ // when x-scrolling as they tend to collapse the table to the min-width,
4180
+ // even if we sent the column widths. So we need to keep track of what
4181
+ // the table width should be by summing the user given values, and the
4182
+ // automatic values
4183
+ if ( scrollX )
4184
+ {
4185
+ var total = 0;
4186
+
4187
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4188
+ column = columns[ visibleColumns[i] ];
4189
+ outerWidth = $(headerCells[i]).outerWidth();
4190
+
4191
+ total += column.sWidthOrig === null ?
4192
+ outerWidth :
4193
+ parseInt( column.sWidth, 10 ) + outerWidth - $(headerCells[i]).width();
4194
+ }
4195
+
4196
+ tmpTable.width( _fnStringToCss( total ) );
4197
+ table.style.width = _fnStringToCss( total );
4198
+ }
4199
+
4200
+ // Get the width of each column in the constructed table
4201
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
4202
+ column = columns[ visibleColumns[i] ];
4203
+ width = $(headerCells[i]).width();
4204
+
4205
+ if ( width ) {
4206
+ column.sWidth = _fnStringToCss( width );
4207
+ }
4208
+ }
4209
+
4210
+ table.style.width = _fnStringToCss( tmpTable.css('width') );
4211
+
4212
+ // Finished with the table - ditch it
4213
+ tmpTable.remove();
4214
+ }
4215
+
4216
+ // If there is a width attr, we want to attach an event listener which
4217
+ // allows the table sizing to automatically adjust when the window is
4218
+ // resized. Use the width attr rather than CSS, since we can't know if the
4219
+ // CSS is a relative value or absolute - DOM read is always px.
4220
+ if ( tableWidthAttr ) {
4221
+ table.style.width = _fnStringToCss( tableWidthAttr );
4222
+ }
4223
+
4224
+ if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
4225
+ $(window).bind('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
4226
+ _fnAdjustColumnSizing( oSettings );
4227
+ } ) );
4228
+
4229
+ oSettings._reszEvt = true;
4230
+ }
4231
+ }
4232
+
4233
+
4234
+ /**
4235
+ * Throttle the calls to a function. Arguments and context are maintained for
4236
+ * the throttled function
4237
+ * @param {function} fn Function to be called
4238
+ * @param {int} [freq=200] call frequency in mS
4239
+ * @returns {function} wrapped function
4240
+ * @memberof DataTable#oApi
4241
+ */
4242
+ function _fnThrottle( fn, freq ) {
4243
+ var
4244
+ frequency = freq !== undefined ? freq : 200,
4245
+ last,
4246
+ timer;
4247
+
4248
+ return function () {
4249
+ var
4250
+ that = this,
4251
+ now = +new Date(),
4252
+ args = arguments;
4253
+
4254
+ if ( last && now < last + frequency ) {
4255
+ clearTimeout( timer );
4256
+
4257
+ timer = setTimeout( function () {
4258
+ last = undefined;
4259
+ fn.apply( that, args );
4260
+ }, frequency );
4261
+ }
4262
+ else if ( last ) {
4263
+ last = now;
4264
+ fn.apply( that, args );
4265
+ }
4266
+ else {
4267
+ last = now;
4268
+ }
4269
+ };
4270
+ }
4271
+
4272
+
4273
+ /**
4274
+ * Convert a CSS unit width to pixels (e.g. 2em)
4275
+ * @param {string} width width to be converted
4276
+ * @param {node} parent parent to get the with for (required for relative widths) - optional
4277
+ * @returns {int} width in pixels
4278
+ * @memberof DataTable#oApi
4279
+ */
4280
+ function _fnConvertToWidth ( width, parent )
4281
+ {
4282
+ if ( ! width ) {
4283
+ return 0;
4284
+ }
4285
+
4286
+ var n = $('<div/>')
4287
+ .css( 'width', _fnStringToCss( width ) )
4288
+ .appendTo( parent || document.body );
4289
+
4290
+ var val = n[0].offsetWidth;
4291
+ n.remove();
4292
+
4293
+ return val;
4294
+ }
4295
+
4296
+
4297
+ /**
4298
+ * Adjust a table's width to take account of vertical scroll bar
4299
+ * @param {object} oSettings dataTables settings object
4300
+ * @param {node} n table node
4301
+ * @memberof DataTable#oApi
4302
+ */
4303
+
4304
+ function _fnScrollingWidthAdjust ( settings, n )
4305
+ {
4306
+ var scroll = settings.oScroll;
4307
+
4308
+ if ( scroll.sX || scroll.sY ) {
4309
+ // When y-scrolling only, we want to remove the width of the scroll bar
4310
+ // so the table + scroll bar will fit into the area available, otherwise
4311
+ // we fix the table at its current size with no adjustment
4312
+ var correction = ! scroll.sX ? scroll.iBarWidth : 0;
4313
+ n.style.width = _fnStringToCss( $(n).outerWidth() - correction );
4314
+ }
4315
+ }
4316
+
4317
+
4318
+ /**
4319
+ * Get the widest node
4320
+ * @param {object} settings dataTables settings object
4321
+ * @param {int} colIdx column of interest
4322
+ * @returns {node} widest table node
4323
+ * @memberof DataTable#oApi
4324
+ */
4325
+ function _fnGetWidestNode( settings, colIdx )
4326
+ {
4327
+ var idx = _fnGetMaxLenString( settings, colIdx );
4328
+ if ( idx < 0 ) {
4329
+ return null;
4330
+ }
4331
+
4332
+ var data = settings.aoData[ idx ];
4333
+ return ! data.nTr ? // Might not have been created when deferred rendering
4334
+ $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
4335
+ data.anCells[ colIdx ];
4336
+ }
4337
+
4338
+
4339
+ /**
4340
+ * Get the maximum strlen for each data column
4341
+ * @param {object} settings dataTables settings object
4342
+ * @param {int} colIdx column of interest
4343
+ * @returns {string} max string length for each column
4344
+ * @memberof DataTable#oApi
4345
+ */
4346
+ function _fnGetMaxLenString( settings, colIdx )
4347
+ {
4348
+ var s, max=-1, maxIdx = -1;
4349
+
4350
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4351
+ s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
4352
+ s = s.replace( __re_html_remove, '' );
4353
+
4354
+ if ( s.length > max ) {
4355
+ max = s.length;
4356
+ maxIdx = i;
4357
+ }
4358
+ }
4359
+
4360
+ return maxIdx;
4361
+ }
4362
+
4363
+
4364
+ /**
4365
+ * Append a CSS unit (only if required) to a string
4366
+ * @param {string} value to css-ify
4367
+ * @returns {string} value with css unit
4368
+ * @memberof DataTable#oApi
4369
+ */
4370
+ function _fnStringToCss( s )
4371
+ {
4372
+ if ( s === null ) {
4373
+ return '0px';
4374
+ }
4375
+
4376
+ if ( typeof s == 'number' ) {
4377
+ return s < 0 ?
4378
+ '0px' :
4379
+ s+'px';
4380
+ }
4381
+
4382
+ // Check it has a unit character already
4383
+ return s.match(/\d$/) ?
4384
+ s+'px' :
4385
+ s;
4386
+ }
4387
+
4388
+
4389
+ /**
4390
+ * Get the width of a scroll bar in this browser being used
4391
+ * @returns {int} width in pixels
4392
+ * @memberof DataTable#oApi
4393
+ */
4394
+ function _fnScrollBarWidth ()
4395
+ {
4396
+ // On first run a static variable is set, since this is only needed once.
4397
+ // Subsequent runs will just use the previously calculated value
4398
+ if ( ! DataTable.__scrollbarWidth ) {
4399
+ var inner = $('<p/>').css( {
4400
+ width: '100%',
4401
+ height: 200,
4402
+ padding: 0
4403
+ } )[0];
4404
+
4405
+ var outer = $('<div/>')
4406
+ .css( {
4407
+ position: 'absolute',
4408
+ top: 0,
4409
+ left: 0,
4410
+ width: 200,
4411
+ height: 150,
4412
+ padding: 0,
4413
+ overflow: 'hidden',
4414
+ visibility: 'hidden'
4415
+ } )
4416
+ .append( inner )
4417
+ .appendTo( 'body' );
4418
+
4419
+ var w1 = inner.offsetWidth;
4420
+ outer.css( 'overflow', 'scroll' );
4421
+ var w2 = inner.offsetWidth;
4422
+
4423
+ if ( w1 === w2 ) {
4424
+ w2 = outer[0].clientWidth;
4425
+ }
4426
+
4427
+ outer.remove();
4428
+
4429
+ DataTable.__scrollbarWidth = w1 - w2;
4430
+ }
4431
+
4432
+ return DataTable.__scrollbarWidth;
4433
+ }
4434
+
4435
+
4436
+
4437
+ function _fnSortFlatten ( settings )
4438
+ {
4439
+ var
4440
+ i, iLen, k, kLen,
4441
+ aSort = [],
4442
+ aiOrig = [],
4443
+ aoColumns = settings.aoColumns,
4444
+ aDataSort, iCol, sType, srcCol,
4445
+ fixed = settings.aaSortingFixed,
4446
+ fixedObj = $.isPlainObject( fixed ),
4447
+ nestedSort = [],
4448
+ add = function ( a ) {
4449
+ if ( a.length && ! $.isArray( a[0] ) ) {
4450
+ // 1D array
4451
+ nestedSort.push( a );
4452
+ }
4453
+ else {
4454
+ // 2D array
4455
+ nestedSort.push.apply( nestedSort, a );
4456
+ }
4457
+ };
4458
+
4459
+ // Build the sort array, with pre-fix and post-fix options if they have been
4460
+ // specified
4461
+ if ( $.isArray( fixed ) ) {
4462
+ add( fixed );
4463
+ }
4464
+
4465
+ if ( fixedObj && fixed.pre ) {
4466
+ add( fixed.pre );
4467
+ }
4468
+
4469
+ add( settings.aaSorting );
4470
+
4471
+ if (fixedObj && fixed.post ) {
4472
+ add( fixed.post );
4473
+ }
4474
+
4475
+ for ( i=0 ; i<nestedSort.length ; i++ )
4476
+ {
4477
+ srcCol = nestedSort[i][0];
4478
+ aDataSort = aoColumns[ srcCol ].aDataSort;
4479
+
4480
+ for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
4481
+ {
4482
+ iCol = aDataSort[k];
4483
+ sType = aoColumns[ iCol ].sType || 'string';
4484
+
4485
+ if ( nestedSort[i]._idx === undefined ) {
4486
+ nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
4487
+ }
4488
+
4489
+ aSort.push( {
4490
+ src: srcCol,
4491
+ col: iCol,
4492
+ dir: nestedSort[i][1],
4493
+ index: nestedSort[i]._idx,
4494
+ type: sType,
4495
+ formatter: DataTable.ext.type.order[ sType+"-pre" ]
4496
+ } );
4497
+ }
4498
+ }
4499
+
4500
+ return aSort;
4501
+ }
4502
+
4503
+ /**
4504
+ * Change the order of the table
4505
+ * @param {object} oSettings dataTables settings object
4506
+ * @memberof DataTable#oApi
4507
+ * @todo This really needs split up!
4508
+ */
4509
+ function _fnSort ( oSettings )
4510
+ {
4511
+ var
4512
+ i, ien, iLen, j, jLen, k, kLen,
4513
+ sDataType, nTh,
4514
+ aiOrig = [],
4515
+ oExtSort = DataTable.ext.type.order,
4516
+ aoData = oSettings.aoData,
4517
+ aoColumns = oSettings.aoColumns,
4518
+ aDataSort, data, iCol, sType, oSort,
4519
+ formatters = 0,
4520
+ sortCol,
4521
+ displayMaster = oSettings.aiDisplayMaster,
4522
+ aSort;
4523
+
4524
+ // Resolve any column types that are unknown due to addition or invalidation
4525
+ // @todo Can this be moved into a 'data-ready' handler which is called when
4526
+ // data is going to be used in the table?
4527
+ _fnColumnTypes( oSettings );
4528
+
4529
+ aSort = _fnSortFlatten( oSettings );
4530
+
4531
+ for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
4532
+ sortCol = aSort[i];
4533
+
4534
+ // Track if we can use the fast sort algorithm
4535
+ if ( sortCol.formatter ) {
4536
+ formatters++;
4537
+ }
4538
+
4539
+ // Load the data needed for the sort, for each cell
4540
+ _fnSortData( oSettings, sortCol.col );
4541
+ }
4542
+
4543
+ /* No sorting required if server-side or no sorting array */
4544
+ if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
4545
+ {
4546
+ // Create a value - key array of the current row positions such that we can use their
4547
+ // current position during the sort, if values match, in order to perform stable sorting
4548
+ for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
4549
+ aiOrig[ displayMaster[i] ] = i;
4550
+ }
4551
+
4552
+ /* Do the sort - here we want multi-column sorting based on a given data source (column)
4553
+ * and sorting function (from oSort) in a certain direction. It's reasonably complex to
4554
+ * follow on it's own, but this is what we want (example two column sorting):
4555
+ * fnLocalSorting = function(a,b){
4556
+ * var iTest;
4557
+ * iTest = oSort['string-asc']('data11', 'data12');
4558
+ * if (iTest !== 0)
4559
+ * return iTest;
4560
+ * iTest = oSort['numeric-desc']('data21', 'data22');
4561
+ * if (iTest !== 0)
4562
+ * return iTest;
4563
+ * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
4564
+ * }
4565
+ * Basically we have a test for each sorting column, if the data in that column is equal,
4566
+ * test the next column. If all columns match, then we use a numeric sort on the row
4567
+ * positions in the original data array to provide a stable sort.
4568
+ *
4569
+ * Note - I know it seems excessive to have two sorting methods, but the first is around
4570
+ * 15% faster, so the second is only maintained for backwards compatibility with sorting
4571
+ * methods which do not have a pre-sort formatting function.
4572
+ */
4573
+ if ( formatters === aSort.length ) {
4574
+ // All sort types have formatting functions
4575
+ displayMaster.sort( function ( a, b ) {
4576
+ var
4577
+ x, y, k, test, sort,
4578
+ len=aSort.length,
4579
+ dataA = aoData[a]._aSortData,
4580
+ dataB = aoData[b]._aSortData;
4581
+
4582
+ for ( k=0 ; k<len ; k++ ) {
4583
+ sort = aSort[k];
4584
+
4585
+ x = dataA[ sort.col ];
4586
+ y = dataB[ sort.col ];
4587
+
4588
+ test = x<y ? -1 : x>y ? 1 : 0;
4589
+ if ( test !== 0 ) {
4590
+ return sort.dir === 'asc' ? test : -test;
4591
+ }
4592
+ }
4593
+
4594
+ x = aiOrig[a];
4595
+ y = aiOrig[b];
4596
+ return x<y ? -1 : x>y ? 1 : 0;
4597
+ } );
4598
+ }
4599
+ else {
4600
+ // Depreciated - remove in 1.11 (providing a plug-in option)
4601
+ // Not all sort types have formatting methods, so we have to call their sorting
4602
+ // methods.
4603
+ displayMaster.sort( function ( a, b ) {
4604
+ var
4605
+ x, y, k, l, test, sort, fn,
4606
+ len=aSort.length,
4607
+ dataA = aoData[a]._aSortData,
4608
+ dataB = aoData[b]._aSortData;
4609
+
4610
+ for ( k=0 ; k<len ; k++ ) {
4611
+ sort = aSort[k];
4612
+
4613
+ x = dataA[ sort.col ];
4614
+ y = dataB[ sort.col ];
4615
+
4616
+ fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
4617
+ test = fn( x, y );
4618
+ if ( test !== 0 ) {
4619
+ return test;
4620
+ }
4621
+ }
4622
+
4623
+ x = aiOrig[a];
4624
+ y = aiOrig[b];
4625
+ return x<y ? -1 : x>y ? 1 : 0;
4626
+ } );
4627
+ }
4628
+ }
4629
+
4630
+ /* Tell the draw function that we have sorted the data */
4631
+ oSettings.bSorted = true;
4632
+ }
4633
+
4634
+
4635
+ function _fnSortAria ( settings )
4636
+ {
4637
+ var label;
4638
+ var nextSort;
4639
+ var columns = settings.aoColumns;
4640
+ var aSort = _fnSortFlatten( settings );
4641
+ var oAria = settings.oLanguage.oAria;
4642
+
4643
+ // ARIA attributes - need to loop all columns, to update all (removing old
4644
+ // attributes as needed)
4645
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
4646
+ {
4647
+ var col = columns[i];
4648
+ var asSorting = col.asSorting;
4649
+ var sTitle = col.sTitle.replace( /<.*?>/g, "" );
4650
+ var th = col.nTh;
4651
+
4652
+ // IE7 is throwing an error when setting these properties with jQuery's
4653
+ // attr() and removeAttr() methods...
4654
+ th.removeAttribute('aria-sort');
4655
+
4656
+ /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
4657
+ if ( col.bSortable ) {
4658
+ if ( aSort.length > 0 && aSort[0].col == i ) {
4659
+ th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
4660
+ nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
4661
+ }
4662
+ else {
4663
+ nextSort = asSorting[0];
4664
+ }
4665
+
4666
+ label = sTitle + ( nextSort === "asc" ?
4667
+ oAria.sSortAscending :
4668
+ oAria.sSortDescending
4669
+ );
4670
+ }
4671
+ else {
4672
+ label = sTitle;
4673
+ }
4674
+
4675
+ th.setAttribute('aria-label', label);
4676
+ }
4677
+ }
4678
+
4679
+
4680
+ /**
4681
+ * Function to run on user sort request
4682
+ * @param {object} settings dataTables settings object
4683
+ * @param {node} attachTo node to attach the handler to
4684
+ * @param {int} colIdx column sorting index
4685
+ * @param {boolean} [append=false] Append the requested sort to the existing
4686
+ * sort if true (i.e. multi-column sort)
4687
+ * @param {function} [callback] callback function
4688
+ * @memberof DataTable#oApi
4689
+ */
4690
+ function _fnSortListener ( settings, colIdx, append, callback )
4691
+ {
4692
+ var col = settings.aoColumns[ colIdx ];
4693
+ var sorting = settings.aaSorting;
4694
+ var asSorting = col.asSorting;
4695
+ var nextSortIdx;
4696
+ var next = function ( a, overflow ) {
4697
+ var idx = a._idx;
4698
+ if ( idx === undefined ) {
4699
+ idx = $.inArray( a[1], asSorting );
4700
+ }
4701
+
4702
+ return idx+1 < asSorting.length ?
4703
+ idx+1 :
4704
+ overflow ?
4705
+ null :
4706
+ 0;
4707
+ };
4708
+
4709
+ // Convert to 2D array if needed
4710
+ if ( typeof sorting[0] === 'number' ) {
4711
+ sorting = settings.aaSorting = [ sorting ];
4712
+ }
4713
+
4714
+ // If appending the sort then we are multi-column sorting
4715
+ if ( append && settings.oFeatures.bSortMulti ) {
4716
+ // Are we already doing some kind of sort on this column?
4717
+ var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
4718
+
4719
+ if ( sortIdx !== -1 ) {
4720
+ // Yes, modify the sort
4721
+ nextSortIdx = next( sorting[sortIdx], true );
4722
+
4723
+ if ( nextSortIdx === null ) {
4724
+ sorting.splice( sortIdx, 1 );
4725
+ }
4726
+ else {
4727
+ sorting[sortIdx][1] = asSorting[ nextSortIdx ];
4728
+ sorting[sortIdx]._idx = nextSortIdx;
4729
+ }
4730
+ }
4731
+ else {
4732
+ // No sort on this column yet
4733
+ sorting.push( [ colIdx, asSorting[0], 0 ] );
4734
+ sorting[sorting.length-1]._idx = 0;
4735
+ }
4736
+ }
4737
+ else if ( sorting.length && sorting[0][0] == colIdx ) {
4738
+ // Single column - already sorting on this column, modify the sort
4739
+ nextSortIdx = next( sorting[0] );
4740
+
4741
+ sorting.length = 1;
4742
+ sorting[0][1] = asSorting[ nextSortIdx ];
4743
+ sorting[0]._idx = nextSortIdx;
4744
+ }
4745
+ else {
4746
+ // Single column - sort only on this column
4747
+ sorting.length = 0;
4748
+ sorting.push( [ colIdx, asSorting[0] ] );
4749
+ sorting[0]._idx = 0;
4750
+ }
4751
+
4752
+ // Run the sort by calling a full redraw
4753
+ _fnReDraw( settings );
4754
+
4755
+ // callback used for async user interaction
4756
+ if ( typeof callback == 'function' ) {
4757
+ callback( settings );
4758
+ }
4759
+ }
4760
+
4761
+
4762
+ /**
4763
+ * Attach a sort handler (click) to a node
4764
+ * @param {object} settings dataTables settings object
4765
+ * @param {node} attachTo node to attach the handler to
4766
+ * @param {int} colIdx column sorting index
4767
+ * @param {function} [callback] callback function
4768
+ * @memberof DataTable#oApi
4769
+ */
4770
+ function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
4771
+ {
4772
+ var col = settings.aoColumns[ colIdx ];
4773
+
4774
+ _fnBindAction( attachTo, {}, function (e) {
4775
+ /* If the column is not sortable - don't to anything */
4776
+ if ( col.bSortable === false ) {
4777
+ return;
4778
+ }
4779
+
4780
+ // If processing is enabled use a timeout to allow the processing
4781
+ // display to be shown - otherwise to it synchronously
4782
+ if ( settings.oFeatures.bProcessing ) {
4783
+ _fnProcessingDisplay( settings, true );
4784
+
4785
+ setTimeout( function() {
4786
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
4787
+
4788
+ // In server-side processing, the draw callback will remove the
4789
+ // processing display
4790
+ if ( _fnDataSource( settings ) !== 'ssp' ) {
4791
+ _fnProcessingDisplay( settings, false );
4792
+ }
4793
+ }, 0 );
4794
+ }
4795
+ else {
4796
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
4797
+ }
4798
+ } );
4799
+ }
4800
+
4801
+
4802
+ /**
4803
+ * Set the sorting classes on table's body, Note: it is safe to call this function
4804
+ * when bSort and bSortClasses are false
4805
+ * @param {object} oSettings dataTables settings object
4806
+ * @memberof DataTable#oApi
4807
+ */
4808
+ function _fnSortingClasses( settings )
4809
+ {
4810
+ var oldSort = settings.aLastSort;
4811
+ var sortClass = settings.oClasses.sSortColumn;
4812
+ var sort = _fnSortFlatten( settings );
4813
+ var features = settings.oFeatures;
4814
+ var i, ien, colIdx;
4815
+
4816
+ if ( features.bSort && features.bSortClasses ) {
4817
+ // Remove old sorting classes
4818
+ for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
4819
+ colIdx = oldSort[i].src;
4820
+
4821
+ // Remove column sorting
4822
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
4823
+ .removeClass( sortClass + (i<2 ? i+1 : 3) );
4824
+ }
4825
+
4826
+ // Add new column sorting
4827
+ for ( i=0, ien=sort.length ; i<ien ; i++ ) {
4828
+ colIdx = sort[i].src;
4829
+
4830
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
4831
+ .addClass( sortClass + (i<2 ? i+1 : 3) );
4832
+ }
4833
+ }
4834
+
4835
+ settings.aLastSort = sort;
4836
+ }
4837
+
4838
+
4839
+ // Get the data to sort a column, be it from cache, fresh (populating the
4840
+ // cache), or from a sort formatter
4841
+ function _fnSortData( settings, idx )
4842
+ {
4843
+ // Custom sorting function - provided by the sort data type
4844
+ var column = settings.aoColumns[ idx ];
4845
+ var customSort = DataTable.ext.order[ column.sSortDataType ];
4846
+ var customData;
4847
+
4848
+ if ( customSort ) {
4849
+ customData = customSort.call( settings.oInstance, settings, idx,
4850
+ _fnColumnIndexToVisible( settings, idx )
4851
+ );
4852
+ }
4853
+
4854
+ // Use / populate cache
4855
+ var row, cellData;
4856
+ var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
4857
+
4858
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
4859
+ row = settings.aoData[i];
4860
+
4861
+ if ( ! row._aSortData ) {
4862
+ row._aSortData = [];
4863
+ }
4864
+
4865
+ if ( ! row._aSortData[idx] || customSort ) {
4866
+ cellData = customSort ?
4867
+ customData[i] : // If there was a custom sort function, use data from there
4868
+ _fnGetCellData( settings, i, idx, 'sort' );
4869
+
4870
+ row._aSortData[ idx ] = formatter ?
4871
+ formatter( cellData ) :
4872
+ cellData;
4873
+ }
4874
+ }
4875
+ }
4876
+
4877
+
4878
+
4879
+ /**
4880
+ * Save the state of a table
4881
+ * @param {object} oSettings dataTables settings object
4882
+ * @memberof DataTable#oApi
4883
+ */
4884
+ function _fnSaveState ( settings )
4885
+ {
4886
+ if ( !settings.oFeatures.bStateSave || settings.bDestroying )
4887
+ {
4888
+ return;
4889
+ }
4890
+
4891
+ /* Store the interesting variables */
4892
+ var state = {
4893
+ time: +new Date(),
4894
+ start: settings._iDisplayStart,
4895
+ length: settings._iDisplayLength,
4896
+ order: $.extend( true, [], settings.aaSorting ),
4897
+ search: _fnSearchToCamel( settings.oPreviousSearch ),
4898
+ columns: $.map( settings.aoColumns, function ( col, i ) {
4899
+ return {
4900
+ visible: col.bVisible,
4901
+ search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
4902
+ };
4903
+ } )
4904
+ };
4905
+
4906
+ _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
4907
+
4908
+ settings.oSavedState = state;
4909
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
4910
+ }
4911
+
4912
+
4913
+ /**
4914
+ * Attempt to load a saved table state
4915
+ * @param {object} oSettings dataTables settings object
4916
+ * @param {object} oInit DataTables init object so we can override settings
4917
+ * @memberof DataTable#oApi
4918
+ */
4919
+ function _fnLoadState ( settings, oInit )
4920
+ {
4921
+ var i, ien;
4922
+ var columns = settings.aoColumns;
4923
+
4924
+ if ( ! settings.oFeatures.bStateSave ) {
4925
+ return;
4926
+ }
4927
+
4928
+ var state = settings.fnStateLoadCallback.call( settings.oInstance, settings );
4929
+ if ( ! state || ! state.time ) {
4930
+ return;
4931
+ }
4932
+
4933
+ /* Allow custom and plug-in manipulation functions to alter the saved data set and
4934
+ * cancelling of loading by returning false
4935
+ */
4936
+ var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, state] );
4937
+ if ( $.inArray( false, abStateLoad ) !== -1 ) {
4938
+ return;
4939
+ }
4940
+
4941
+ /* Reject old data */
4942
+ var duration = settings.iStateDuration;
4943
+ if ( duration > 0 && state.time < +new Date() - (duration*1000) ) {
4944
+ return;
4945
+ }
4946
+
4947
+ // Number of columns have changed - all bets are off, no restore of settings
4948
+ if ( columns.length !== state.columns.length ) {
4949
+ return;
4950
+ }
4951
+
4952
+ // Store the saved state so it might be accessed at any time
4953
+ settings.oLoadedState = $.extend( true, {}, state );
4954
+
4955
+ // Restore key features - todo - for 1.11 this needs to be done by
4956
+ // subscribed events
4957
+ settings._iDisplayStart = state.start;
4958
+ settings.iInitDisplayStart = state.start;
4959
+ settings._iDisplayLength = state.length;
4960
+ settings.aaSorting = [];
4961
+
4962
+ // Order
4963
+ $.each( state.order, function ( i, col ) {
4964
+ settings.aaSorting.push( col[0] >= columns.length ?
4965
+ [ 0, col[1] ] :
4966
+ col
4967
+ );
4968
+ } );
4969
+
4970
+ // Search
4971
+ $.extend( settings.oPreviousSearch, _fnSearchToHung( state.search ) );
4972
+
4973
+ // Columns
4974
+ for ( i=0, ien=state.columns.length ; i<ien ; i++ ) {
4975
+ var col = state.columns[i];
4976
+
4977
+ // Visibility
4978
+ columns[i].bVisible = col.visible;
4979
+
4980
+ // Search
4981
+ $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
4982
+ }
4983
+
4984
+ _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, state] );
4985
+ }
4986
+
4987
+
4988
+ /**
4989
+ * Return the settings object for a particular table
4990
+ * @param {node} table table we are using as a dataTable
4991
+ * @returns {object} Settings object - or null if not found
4992
+ * @memberof DataTable#oApi
4993
+ */
4994
+ function _fnSettingsFromNode ( table )
4995
+ {
4996
+ var settings = DataTable.settings;
4997
+ var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
4998
+
4999
+ return idx !== -1 ?
5000
+ settings[ idx ] :
5001
+ null;
5002
+ }
5003
+
5004
+
5005
+ /**
5006
+ * Log an error message
5007
+ * @param {object} settings dataTables settings object
5008
+ * @param {int} level log error messages, or display them to the user
5009
+ * @param {string} msg error message
5010
+ * @param {int} tn Technical note id to get more information about the error.
5011
+ * @memberof DataTable#oApi
5012
+ */
5013
+ function _fnLog( settings, level, msg, tn )
5014
+ {
5015
+ msg = 'DataTables warning: '+
5016
+ (settings!==null ? 'table id='+settings.sTableId+' - ' : '')+msg;
5017
+
5018
+ if ( tn ) {
5019
+ msg += '. For more information about this error, please see '+
5020
+ 'http://datatables.net/tn/'+tn;
5021
+ }
5022
+
5023
+ if ( ! level ) {
5024
+ // Backwards compatibility pre 1.10
5025
+ var ext = DataTable.ext;
5026
+ var type = ext.sErrMode || ext.errMode;
5027
+
5028
+ if ( type == 'alert' ) {
5029
+ alert( msg );
5030
+ }
5031
+ else {
5032
+ throw new Error(msg);
5033
+ }
5034
+ }
5035
+ else if ( window.console && console.log ) {
5036
+ console.log( msg );
5037
+ }
5038
+ }
5039
+
5040
+
5041
+ /**
5042
+ * See if a property is defined on one object, if so assign it to the other object
5043
+ * @param {object} ret target object
5044
+ * @param {object} src source object
5045
+ * @param {string} name property
5046
+ * @param {string} [mappedName] name to map too - optional, name used if not given
5047
+ * @memberof DataTable#oApi
5048
+ */
5049
+ function _fnMap( ret, src, name, mappedName )
5050
+ {
5051
+ if ( $.isArray( name ) ) {
5052
+ $.each( name, function (i, val) {
5053
+ if ( $.isArray( val ) ) {
5054
+ _fnMap( ret, src, val[0], val[1] );
5055
+ }
5056
+ else {
5057
+ _fnMap( ret, src, val );
5058
+ }
5059
+ } );
5060
+
5061
+ return;
5062
+ }
5063
+
5064
+ if ( mappedName === undefined ) {
5065
+ mappedName = name;
5066
+ }
5067
+
5068
+ if ( src[name] !== undefined ) {
5069
+ ret[mappedName] = src[name];
5070
+ }
5071
+ }
5072
+
5073
+
5074
+ /**
5075
+ * Extend objects - very similar to jQuery.extend, but deep copy objects, and
5076
+ * shallow copy arrays. The reason we need to do this, is that we don't want to
5077
+ * deep copy array init values (such as aaSorting) since the dev wouldn't be
5078
+ * able to override them, but we do want to deep copy arrays.
5079
+ * @param {object} out Object to extend
5080
+ * @param {object} extender Object from which the properties will be applied to
5081
+ * out
5082
+ * @param {boolean} breakRefs If true, then arrays will be sliced to take an
5083
+ * independent copy with the exception of the `data` or `aaData` parameters
5084
+ * if they are present. This is so you can pass in a collection to
5085
+ * DataTables and have that used as your data source without breaking the
5086
+ * references
5087
+ * @returns {object} out Reference, just for convenience - out === the return.
5088
+ * @memberof DataTable#oApi
5089
+ * @todo This doesn't take account of arrays inside the deep copied objects.
5090
+ */
5091
+ function _fnExtend( out, extender, breakRefs )
5092
+ {
5093
+ var val;
5094
+
5095
+ for ( var prop in extender ) {
5096
+ if ( extender.hasOwnProperty(prop) ) {
5097
+ val = extender[prop];
5098
+
5099
+ if ( $.isPlainObject( val ) ) {
5100
+ if ( ! $.isPlainObject( out[prop] ) ) {
5101
+ out[prop] = {};
5102
+ }
5103
+ $.extend( true, out[prop], val );
5104
+ }
5105
+ else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && $.isArray(val) ) {
5106
+ out[prop] = val.slice();
5107
+ }
5108
+ else {
5109
+ out[prop] = val;
5110
+ }
5111
+ }
5112
+ }
5113
+
5114
+ return out;
5115
+ }
5116
+
5117
+
5118
+ /**
5119
+ * Bind an event handers to allow a click or return key to activate the callback.
5120
+ * This is good for accessibility since a return on the keyboard will have the
5121
+ * same effect as a click, if the element has focus.
5122
+ * @param {element} n Element to bind the action to
5123
+ * @param {object} oData Data object to pass to the triggered function
5124
+ * @param {function} fn Callback function for when the event is triggered
5125
+ * @memberof DataTable#oApi
5126
+ */
5127
+ function _fnBindAction( n, oData, fn )
5128
+ {
5129
+ $(n)
5130
+ .bind( 'click.DT', oData, function (e) {
5131
+ n.blur(); // Remove focus outline for mouse users
5132
+ fn(e);
5133
+ } )
5134
+ .bind( 'keypress.DT', oData, function (e){
5135
+ if ( e.which === 13 ) {
5136
+ e.preventDefault();
5137
+ fn(e);
5138
+ }
5139
+ } )
5140
+ .bind( 'selectstart.DT', function () {
5141
+ /* Take the brutal approach to cancelling text selection */
5142
+ return false;
5143
+ } );
5144
+ }
5145
+
5146
+
5147
+ /**
5148
+ * Register a callback function. Easily allows a callback function to be added to
5149
+ * an array store of callback functions that can then all be called together.
5150
+ * @param {object} oSettings dataTables settings object
5151
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
5152
+ * @param {function} fn Function to be called back
5153
+ * @param {string} sName Identifying name for the callback (i.e. a label)
5154
+ * @memberof DataTable#oApi
5155
+ */
5156
+ function _fnCallbackReg( oSettings, sStore, fn, sName )
5157
+ {
5158
+ if ( fn )
5159
+ {
5160
+ oSettings[sStore].push( {
5161
+ "fn": fn,
5162
+ "sName": sName
5163
+ } );
5164
+ }
5165
+ }
5166
+
5167
+
5168
+ /**
5169
+ * Fire callback functions and trigger events. Note that the loop over the
5170
+ * callback array store is done backwards! Further note that you do not want to
5171
+ * fire off triggers in time sensitive applications (for example cell creation)
5172
+ * as its slow.
5173
+ * @param {object} settings dataTables settings object
5174
+ * @param {string} callbackArr Name of the array storage for the callbacks in
5175
+ * oSettings
5176
+ * @param {string} event Name of the jQuery custom event to trigger. If null no
5177
+ * trigger is fired
5178
+ * @param {array} args Array of arguments to pass to the callback function /
5179
+ * trigger
5180
+ * @memberof DataTable#oApi
5181
+ */
5182
+ function _fnCallbackFire( settings, callbackArr, e, args )
5183
+ {
5184
+ var ret = [];
5185
+
5186
+ if ( callbackArr ) {
5187
+ ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
5188
+ return val.fn.apply( settings.oInstance, args );
5189
+ } );
5190
+ }
5191
+
5192
+ if ( e !== null ) {
5193
+ $(settings.nTable).trigger( e+'.dt', args );
5194
+ }
5195
+
5196
+ return ret;
5197
+ }
5198
+
5199
+
5200
+ function _fnLengthOverflow ( settings )
5201
+ {
5202
+ var
5203
+ start = settings._iDisplayStart,
5204
+ end = settings.fnDisplayEnd(),
5205
+ len = settings._iDisplayLength;
5206
+
5207
+ /* If we have space to show extra rows (backing up from the end point - then do so */
5208
+ if ( start >= end )
5209
+ {
5210
+ start = end - len;
5211
+ }
5212
+
5213
+ // Keep the start record on the current page
5214
+ start -= (start % len);
5215
+
5216
+ if ( len === -1 || start < 0 )
5217
+ {
5218
+ start = 0;
5219
+ }
5220
+
5221
+ settings._iDisplayStart = start;
5222
+ }
5223
+
5224
+
5225
+ function _fnRenderer( settings, type )
5226
+ {
5227
+ var renderer = settings.renderer;
5228
+ var host = DataTable.ext.renderer[type];
5229
+
5230
+ if ( $.isPlainObject( renderer ) && renderer[type] ) {
5231
+ // Specific renderer for this type. If available use it, otherwise use
5232
+ // the default.
5233
+ return host[renderer[type]] || host._;
5234
+ }
5235
+ else if ( typeof renderer === 'string' ) {
5236
+ // Common renderer - if there is one available for this type use it,
5237
+ // otherwise use the default
5238
+ return host[renderer] || host._;
5239
+ }
5240
+
5241
+ // Use the default
5242
+ return host._;
5243
+ }
5244
+
5245
+
5246
+ /**
5247
+ * Detect the data source being used for the table. Used to simplify the code
5248
+ * a little (ajax) and to make it compress a little smaller.
5249
+ *
5250
+ * @param {object} settings dataTables settings object
5251
+ * @returns {string} Data source
5252
+ * @memberof DataTable#oApi
5253
+ */
5254
+ function _fnDataSource ( settings )
5255
+ {
5256
+ if ( settings.oFeatures.bServerSide ) {
5257
+ return 'ssp';
5258
+ }
5259
+ else if ( settings.ajax || settings.sAjaxSource ) {
5260
+ return 'ajax';
5261
+ }
5262
+ return 'dom';
5263
+ }
5264
+
5265
+
5266
+ DataTable = function( options )
5267
+ {
5268
+ /**
5269
+ * Perform a jQuery selector action on the table's TR elements (from the tbody) and
5270
+ * return the resulting jQuery object.
5271
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5272
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5273
+ * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
5274
+ * criterion ("applied") or all TR elements (i.e. no filter).
5275
+ * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
5276
+ * Can be either 'current', whereby the current sorting of the table is used, or
5277
+ * 'original' whereby the original order the data was read into the table is used.
5278
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5279
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5280
+ * 'current' and filter is 'applied', regardless of what they might be given as.
5281
+ * @returns {object} jQuery object, filtered by the given selector.
5282
+ * @dtopt API
5283
+ * @deprecated Since v1.10
5284
+ *
5285
+ * @example
5286
+ * $(document).ready(function() {
5287
+ * var oTable = $('#example').dataTable();
5288
+ *
5289
+ * // Highlight every second row
5290
+ * oTable.$('tr:odd').css('backgroundColor', 'blue');
5291
+ * } );
5292
+ *
5293
+ * @example
5294
+ * $(document).ready(function() {
5295
+ * var oTable = $('#example').dataTable();
5296
+ *
5297
+ * // Filter to rows with 'Webkit' in them, add a background colour and then
5298
+ * // remove the filter, thus highlighting the 'Webkit' rows only.
5299
+ * oTable.fnFilter('Webkit');
5300
+ * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
5301
+ * oTable.fnFilter('');
5302
+ * } );
5303
+ */
5304
+ this.$ = function ( sSelector, oOpts )
5305
+ {
5306
+ return this.api(true).$( sSelector, oOpts );
5307
+ };
5308
+
5309
+
5310
+ /**
5311
+ * Almost identical to $ in operation, but in this case returns the data for the matched
5312
+ * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
5313
+ * rather than any descendants, so the data can be obtained for the row/cell. If matching
5314
+ * rows are found, the data returned is the original data array/object that was used to
5315
+ * create the row (or a generated array if from a DOM source).
5316
+ *
5317
+ * This method is often useful in-combination with $ where both functions are given the
5318
+ * same parameters and the array indexes will match identically.
5319
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
5320
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
5321
+ * @param {string} [oOpts.filter=none] Select elements that meet the current filter
5322
+ * criterion ("applied") or all elements (i.e. no filter).
5323
+ * @param {string} [oOpts.order=current] Order of the data in the processed array.
5324
+ * Can be either 'current', whereby the current sorting of the table is used, or
5325
+ * 'original' whereby the original order the data was read into the table is used.
5326
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
5327
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
5328
+ * 'current' and filter is 'applied', regardless of what they might be given as.
5329
+ * @returns {array} Data for the matched elements. If any elements, as a result of the
5330
+ * selector, were not TR, TD or TH elements in the DataTable, they will have a null
5331
+ * entry in the array.
5332
+ * @dtopt API
5333
+ * @deprecated Since v1.10
5334
+ *
5335
+ * @example
5336
+ * $(document).ready(function() {
5337
+ * var oTable = $('#example').dataTable();
5338
+ *
5339
+ * // Get the data from the first row in the table
5340
+ * var data = oTable._('tr:first');
5341
+ *
5342
+ * // Do something useful with the data
5343
+ * alert( "First cell is: "+data[0] );
5344
+ * } );
5345
+ *
5346
+ * @example
5347
+ * $(document).ready(function() {
5348
+ * var oTable = $('#example').dataTable();
5349
+ *
5350
+ * // Filter to 'Webkit' and get all data for
5351
+ * oTable.fnFilter('Webkit');
5352
+ * var data = oTable._('tr', {"search": "applied"});
5353
+ *
5354
+ * // Do something with the data
5355
+ * alert( data.length+" rows matched the search" );
5356
+ * } );
5357
+ */
5358
+ this._ = function ( sSelector, oOpts )
5359
+ {
5360
+ return this.api(true).rows( sSelector, oOpts ).data();
5361
+ };
5362
+
5363
+
5364
+ /**
5365
+ * Create a DataTables Api instance, with the currently selected tables for
5366
+ * the Api's context.
5367
+ * @param {boolean} [traditional=false] Set the API instance's context to be
5368
+ * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
5369
+ * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
5370
+ * or if all tables captured in the jQuery object should be used.
5371
+ * @return {DataTables.Api}
5372
+ */
5373
+ this.api = function ( traditional )
5374
+ {
5375
+ return traditional ?
5376
+ new _Api(
5377
+ _fnSettingsFromNode( this[ _ext.iApiIndex ] )
5378
+ ) :
5379
+ new _Api( this );
5380
+ };
5381
+
5382
+
5383
+ /**
5384
+ * Add a single new row or multiple rows of data to the table. Please note
5385
+ * that this is suitable for client-side processing only - if you are using
5386
+ * server-side processing (i.e. "bServerSide": true), then to add data, you
5387
+ * must add it to the data source, i.e. the server-side, through an Ajax call.
5388
+ * @param {array|object} data The data to be added to the table. This can be:
5389
+ * <ul>
5390
+ * <li>1D array of data - add a single row with the data provided</li>
5391
+ * <li>2D array of arrays - add multiple rows in a single call</li>
5392
+ * <li>object - data object when using <i>mData</i></li>
5393
+ * <li>array of objects - multiple data objects when using <i>mData</i></li>
5394
+ * </ul>
5395
+ * @param {bool} [redraw=true] redraw the table or not
5396
+ * @returns {array} An array of integers, representing the list of indexes in
5397
+ * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
5398
+ * the table.
5399
+ * @dtopt API
5400
+ * @deprecated Since v1.10
5401
+ *
5402
+ * @example
5403
+ * // Global var for counter
5404
+ * var giCount = 2;
5405
+ *
5406
+ * $(document).ready(function() {
5407
+ * $('#example').dataTable();
5408
+ * } );
5409
+ *
5410
+ * function fnClickAddRow() {
5411
+ * $('#example').dataTable().fnAddData( [
5412
+ * giCount+".1",
5413
+ * giCount+".2",
5414
+ * giCount+".3",
5415
+ * giCount+".4" ]
5416
+ * );
5417
+ *
5418
+ * giCount++;
5419
+ * }
5420
+ */
5421
+ this.fnAddData = function( data, redraw )
5422
+ {
5423
+ var api = this.api( true );
5424
+
5425
+ /* Check if we want to add multiple rows or not */
5426
+ var rows = $.isArray(data) && ( $.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
5427
+ api.rows.add( data ) :
5428
+ api.row.add( data );
5429
+
5430
+ if ( redraw === undefined || redraw ) {
5431
+ api.draw();
5432
+ }
5433
+
5434
+ return rows.flatten().toArray();
5435
+ };
5436
+
5437
+
5438
+ /**
5439
+ * This function will make DataTables recalculate the column sizes, based on the data
5440
+ * contained in the table and the sizes applied to the columns (in the DOM, CSS or
5441
+ * through the sWidth parameter). This can be useful when the width of the table's
5442
+ * parent element changes (for example a window resize).
5443
+ * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
5444
+ * @dtopt API
5445
+ * @deprecated Since v1.10
5446
+ *
5447
+ * @example
5448
+ * $(document).ready(function() {
5449
+ * var oTable = $('#example').dataTable( {
5450
+ * "sScrollY": "200px",
5451
+ * "bPaginate": false
5452
+ * } );
5453
+ *
5454
+ * $(window).bind('resize', function () {
5455
+ * oTable.fnAdjustColumnSizing();
5456
+ * } );
5457
+ * } );
5458
+ */
5459
+ this.fnAdjustColumnSizing = function ( bRedraw )
5460
+ {
5461
+ var api = this.api( true ).columns.adjust();
5462
+ var settings = api.settings()[0];
5463
+ var scroll = settings.oScroll;
5464
+
5465
+ if ( bRedraw === undefined || bRedraw ) {
5466
+ api.draw( false );
5467
+ }
5468
+ else if ( scroll.sX !== "" || scroll.sY !== "" ) {
5469
+ /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
5470
+ _fnScrollDraw( settings );
5471
+ }
5472
+ };
5473
+
5474
+
5475
+ /**
5476
+ * Quickly and simply clear a table
5477
+ * @param {bool} [bRedraw=true] redraw the table or not
5478
+ * @dtopt API
5479
+ * @deprecated Since v1.10
5480
+ *
5481
+ * @example
5482
+ * $(document).ready(function() {
5483
+ * var oTable = $('#example').dataTable();
5484
+ *
5485
+ * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
5486
+ * oTable.fnClearTable();
5487
+ * } );
5488
+ */
5489
+ this.fnClearTable = function( bRedraw )
5490
+ {
5491
+ var api = this.api( true ).clear();
5492
+
5493
+ if ( bRedraw === undefined || bRedraw ) {
5494
+ api.draw();
5495
+ }
5496
+ };
5497
+
5498
+
5499
+ /**
5500
+ * The exact opposite of 'opening' a row, this function will close any rows which
5501
+ * are currently 'open'.
5502
+ * @param {node} nTr the table row to 'close'
5503
+ * @returns {int} 0 on success, or 1 if failed (can't find the row)
5504
+ * @dtopt API
5505
+ * @deprecated Since v1.10
5506
+ *
5507
+ * @example
5508
+ * $(document).ready(function() {
5509
+ * var oTable;
5510
+ *
5511
+ * // 'open' an information row when a row is clicked on
5512
+ * $('#example tbody tr').click( function () {
5513
+ * if ( oTable.fnIsOpen(this) ) {
5514
+ * oTable.fnClose( this );
5515
+ * } else {
5516
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5517
+ * }
5518
+ * } );
5519
+ *
5520
+ * oTable = $('#example').dataTable();
5521
+ * } );
5522
+ */
5523
+ this.fnClose = function( nTr )
5524
+ {
5525
+ this.api( true ).row( nTr ).child.hide();
5526
+ };
5527
+
5528
+
5529
+ /**
5530
+ * Remove a row for the table
5531
+ * @param {mixed} target The index of the row from aoData to be deleted, or
5532
+ * the TR element you want to delete
5533
+ * @param {function|null} [callBack] Callback function
5534
+ * @param {bool} [redraw=true] Redraw the table or not
5535
+ * @returns {array} The row that was deleted
5536
+ * @dtopt API
5537
+ * @deprecated Since v1.10
5538
+ *
5539
+ * @example
5540
+ * $(document).ready(function() {
5541
+ * var oTable = $('#example').dataTable();
5542
+ *
5543
+ * // Immediately remove the first row
5544
+ * oTable.fnDeleteRow( 0 );
5545
+ * } );
5546
+ */
5547
+ this.fnDeleteRow = function( target, callback, redraw )
5548
+ {
5549
+ var api = this.api( true );
5550
+ var rows = api.rows( target );
5551
+ var settings = rows.settings()[0];
5552
+ var data = settings.aoData[ rows[0][0] ];
5553
+
5554
+ rows.remove();
5555
+
5556
+ if ( callback ) {
5557
+ callback.call( this, settings, data );
5558
+ }
5559
+
5560
+ if ( redraw === undefined || redraw ) {
5561
+ api.draw();
5562
+ }
5563
+
5564
+ return data;
5565
+ };
5566
+
5567
+
5568
+ /**
5569
+ * Restore the table to it's original state in the DOM by removing all of DataTables
5570
+ * enhancements, alterations to the DOM structure of the table and event listeners.
5571
+ * @param {boolean} [remove=false] Completely remove the table from the DOM
5572
+ * @dtopt API
5573
+ * @deprecated Since v1.10
5574
+ *
5575
+ * @example
5576
+ * $(document).ready(function() {
5577
+ * // This example is fairly pointless in reality, but shows how fnDestroy can be used
5578
+ * var oTable = $('#example').dataTable();
5579
+ * oTable.fnDestroy();
5580
+ * } );
5581
+ */
5582
+ this.fnDestroy = function ( remove )
5583
+ {
5584
+ this.api( true ).destroy( remove );
5585
+ };
5586
+
5587
+
5588
+ /**
5589
+ * Redraw the table
5590
+ * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
5591
+ * @dtopt API
5592
+ * @deprecated Since v1.10
5593
+ *
5594
+ * @example
5595
+ * $(document).ready(function() {
5596
+ * var oTable = $('#example').dataTable();
5597
+ *
5598
+ * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
5599
+ * oTable.fnDraw();
5600
+ * } );
5601
+ */
5602
+ this.fnDraw = function( complete )
5603
+ {
5604
+ // Note that this isn't an exact match to the old call to _fnDraw - it takes
5605
+ // into account the new data, but can old position.
5606
+ this.api( true ).draw( ! complete );
5607
+ };
5608
+
5609
+
5610
+ /**
5611
+ * Filter the input based on data
5612
+ * @param {string} sInput String to filter the table on
5613
+ * @param {int|null} [iColumn] Column to limit filtering to
5614
+ * @param {bool} [bRegex=false] Treat as regular expression or not
5615
+ * @param {bool} [bSmart=true] Perform smart filtering or not
5616
+ * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
5617
+ * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
5618
+ * @dtopt API
5619
+ * @deprecated Since v1.10
5620
+ *
5621
+ * @example
5622
+ * $(document).ready(function() {
5623
+ * var oTable = $('#example').dataTable();
5624
+ *
5625
+ * // Sometime later - filter...
5626
+ * oTable.fnFilter( 'test string' );
5627
+ * } );
5628
+ */
5629
+ this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
5630
+ {
5631
+ var api = this.api( true );
5632
+
5633
+ if ( iColumn === null || iColumn === undefined ) {
5634
+ api.search( sInput, bRegex, bSmart, bCaseInsensitive );
5635
+ }
5636
+ else {
5637
+ api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
5638
+ }
5639
+
5640
+ api.draw();
5641
+ };
5642
+
5643
+
5644
+ /**
5645
+ * Get the data for the whole table, an individual row or an individual cell based on the
5646
+ * provided parameters.
5647
+ * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
5648
+ * a TR node then the data source for the whole row will be returned. If given as a
5649
+ * TD/TH cell node then iCol will be automatically calculated and the data for the
5650
+ * cell returned. If given as an integer, then this is treated as the aoData internal
5651
+ * data index for the row (see fnGetPosition) and the data for that row used.
5652
+ * @param {int} [col] Optional column index that you want the data of.
5653
+ * @returns {array|object|string} If mRow is undefined, then the data for all rows is
5654
+ * returned. If mRow is defined, just data for that row, and is iCol is
5655
+ * defined, only data for the designated cell is returned.
5656
+ * @dtopt API
5657
+ * @deprecated Since v1.10
5658
+ *
5659
+ * @example
5660
+ * // Row data
5661
+ * $(document).ready(function() {
5662
+ * oTable = $('#example').dataTable();
5663
+ *
5664
+ * oTable.$('tr').click( function () {
5665
+ * var data = oTable.fnGetData( this );
5666
+ * // ... do something with the array / object of data for the row
5667
+ * } );
5668
+ * } );
5669
+ *
5670
+ * @example
5671
+ * // Individual cell data
5672
+ * $(document).ready(function() {
5673
+ * oTable = $('#example').dataTable();
5674
+ *
5675
+ * oTable.$('td').click( function () {
5676
+ * var sData = oTable.fnGetData( this );
5677
+ * alert( 'The cell clicked on had the value of '+sData );
5678
+ * } );
5679
+ * } );
5680
+ */
5681
+ this.fnGetData = function( src, col )
5682
+ {
5683
+ var api = this.api( true );
5684
+
5685
+ if ( src !== undefined ) {
5686
+ var type = src.nodeName ? src.nodeName.toLowerCase() : '';
5687
+
5688
+ return col !== undefined || type == 'td' || type == 'th' ?
5689
+ api.cell( src, col ).data() :
5690
+ api.row( src ).data() || null;
5691
+ }
5692
+
5693
+ return api.data().toArray();
5694
+ };
5695
+
5696
+
5697
+ /**
5698
+ * Get an array of the TR nodes that are used in the table's body. Note that you will
5699
+ * typically want to use the '$' API method in preference to this as it is more
5700
+ * flexible.
5701
+ * @param {int} [iRow] Optional row index for the TR element you want
5702
+ * @returns {array|node} If iRow is undefined, returns an array of all TR elements
5703
+ * in the table's body, or iRow is defined, just the TR element requested.
5704
+ * @dtopt API
5705
+ * @deprecated Since v1.10
5706
+ *
5707
+ * @example
5708
+ * $(document).ready(function() {
5709
+ * var oTable = $('#example').dataTable();
5710
+ *
5711
+ * // Get the nodes from the table
5712
+ * var nNodes = oTable.fnGetNodes( );
5713
+ * } );
5714
+ */
5715
+ this.fnGetNodes = function( iRow )
5716
+ {
5717
+ var api = this.api( true );
5718
+
5719
+ return iRow !== undefined ?
5720
+ api.row( iRow ).node() :
5721
+ api.rows().nodes().flatten().toArray();
5722
+ };
5723
+
5724
+
5725
+ /**
5726
+ * Get the array indexes of a particular cell from it's DOM element
5727
+ * and column index including hidden columns
5728
+ * @param {node} node this can either be a TR, TD or TH in the table's body
5729
+ * @returns {int} If nNode is given as a TR, then a single index is returned, or
5730
+ * if given as a cell, an array of [row index, column index (visible),
5731
+ * column index (all)] is given.
5732
+ * @dtopt API
5733
+ * @deprecated Since v1.10
5734
+ *
5735
+ * @example
5736
+ * $(document).ready(function() {
5737
+ * $('#example tbody td').click( function () {
5738
+ * // Get the position of the current data from the node
5739
+ * var aPos = oTable.fnGetPosition( this );
5740
+ *
5741
+ * // Get the data array for this row
5742
+ * var aData = oTable.fnGetData( aPos[0] );
5743
+ *
5744
+ * // Update the data array and return the value
5745
+ * aData[ aPos[1] ] = 'clicked';
5746
+ * this.innerHTML = 'clicked';
5747
+ * } );
5748
+ *
5749
+ * // Init DataTables
5750
+ * oTable = $('#example').dataTable();
5751
+ * } );
5752
+ */
5753
+ this.fnGetPosition = function( node )
5754
+ {
5755
+ var api = this.api( true );
5756
+ var nodeName = node.nodeName.toUpperCase();
5757
+
5758
+ if ( nodeName == 'TR' ) {
5759
+ return api.row( node ).index();
5760
+ }
5761
+ else if ( nodeName == 'TD' || nodeName == 'TH' ) {
5762
+ var cell = api.cell( node ).index();
5763
+
5764
+ return [
5765
+ cell.row,
5766
+ cell.columnVisible,
5767
+ cell.column
5768
+ ];
5769
+ }
5770
+ return null;
5771
+ };
5772
+
5773
+
5774
+ /**
5775
+ * Check to see if a row is 'open' or not.
5776
+ * @param {node} nTr the table row to check
5777
+ * @returns {boolean} true if the row is currently open, false otherwise
5778
+ * @dtopt API
5779
+ * @deprecated Since v1.10
5780
+ *
5781
+ * @example
5782
+ * $(document).ready(function() {
5783
+ * var oTable;
5784
+ *
5785
+ * // 'open' an information row when a row is clicked on
5786
+ * $('#example tbody tr').click( function () {
5787
+ * if ( oTable.fnIsOpen(this) ) {
5788
+ * oTable.fnClose( this );
5789
+ * } else {
5790
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5791
+ * }
5792
+ * } );
5793
+ *
5794
+ * oTable = $('#example').dataTable();
5795
+ * } );
5796
+ */
5797
+ this.fnIsOpen = function( nTr )
5798
+ {
5799
+ return this.api( true ).row( nTr ).child.isShown();
5800
+ };
5801
+
5802
+
5803
+ /**
5804
+ * This function will place a new row directly after a row which is currently
5805
+ * on display on the page, with the HTML contents that is passed into the
5806
+ * function. This can be used, for example, to ask for confirmation that a
5807
+ * particular record should be deleted.
5808
+ * @param {node} nTr The table row to 'open'
5809
+ * @param {string|node|jQuery} mHtml The HTML to put into the row
5810
+ * @param {string} sClass Class to give the new TD cell
5811
+ * @returns {node} The row opened. Note that if the table row passed in as the
5812
+ * first parameter, is not found in the table, this method will silently
5813
+ * return.
5814
+ * @dtopt API
5815
+ * @deprecated Since v1.10
5816
+ *
5817
+ * @example
5818
+ * $(document).ready(function() {
5819
+ * var oTable;
5820
+ *
5821
+ * // 'open' an information row when a row is clicked on
5822
+ * $('#example tbody tr').click( function () {
5823
+ * if ( oTable.fnIsOpen(this) ) {
5824
+ * oTable.fnClose( this );
5825
+ * } else {
5826
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
5827
+ * }
5828
+ * } );
5829
+ *
5830
+ * oTable = $('#example').dataTable();
5831
+ * } );
5832
+ */
5833
+ this.fnOpen = function( nTr, mHtml, sClass )
5834
+ {
5835
+ return this.api( true )
5836
+ .row( nTr )
5837
+ .child( mHtml, sClass )
5838
+ .show()
5839
+ .child()[0];
5840
+ };
5841
+
5842
+
5843
+ /**
5844
+ * Change the pagination - provides the internal logic for pagination in a simple API
5845
+ * function. With this function you can have a DataTables table go to the next,
5846
+ * previous, first or last pages.
5847
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
5848
+ * or page number to jump to (integer), note that page 0 is the first page.
5849
+ * @param {bool} [bRedraw=true] Redraw the table or not
5850
+ * @dtopt API
5851
+ * @deprecated Since v1.10
5852
+ *
5853
+ * @example
5854
+ * $(document).ready(function() {
5855
+ * var oTable = $('#example').dataTable();
5856
+ * oTable.fnPageChange( 'next' );
5857
+ * } );
5858
+ */
5859
+ this.fnPageChange = function ( mAction, bRedraw )
5860
+ {
5861
+ var api = this.api( true ).page( mAction );
5862
+
5863
+ if ( bRedraw === undefined || bRedraw ) {
5864
+ api.draw(false);
5865
+ }
5866
+ };
5867
+
5868
+
5869
+ /**
5870
+ * Show a particular column
5871
+ * @param {int} iCol The column whose display should be changed
5872
+ * @param {bool} bShow Show (true) or hide (false) the column
5873
+ * @param {bool} [bRedraw=true] Redraw the table or not
5874
+ * @dtopt API
5875
+ * @deprecated Since v1.10
5876
+ *
5877
+ * @example
5878
+ * $(document).ready(function() {
5879
+ * var oTable = $('#example').dataTable();
5880
+ *
5881
+ * // Hide the second column after initialisation
5882
+ * oTable.fnSetColumnVis( 1, false );
5883
+ * } );
5884
+ */
5885
+ this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
5886
+ {
5887
+ var api = this.api( true ).column( iCol ).visible( bShow );
5888
+
5889
+ if ( bRedraw === undefined || bRedraw ) {
5890
+ api.columns.adjust().draw();
5891
+ }
5892
+ };
5893
+
5894
+
5895
+ /**
5896
+ * Get the settings for a particular table for external manipulation
5897
+ * @returns {object} DataTables settings object. See
5898
+ * {@link DataTable.models.oSettings}
5899
+ * @dtopt API
5900
+ * @deprecated Since v1.10
5901
+ *
5902
+ * @example
5903
+ * $(document).ready(function() {
5904
+ * var oTable = $('#example').dataTable();
5905
+ * var oSettings = oTable.fnSettings();
5906
+ *
5907
+ * // Show an example parameter from the settings
5908
+ * alert( oSettings._iDisplayStart );
5909
+ * } );
5910
+ */
5911
+ this.fnSettings = function()
5912
+ {
5913
+ return _fnSettingsFromNode( this[_ext.iApiIndex] );
5914
+ };
5915
+
5916
+
5917
+ /**
5918
+ * Sort the table by a particular column
5919
+ * @param {int} iCol the data index to sort on. Note that this will not match the
5920
+ * 'display index' if you have hidden data entries
5921
+ * @dtopt API
5922
+ * @deprecated Since v1.10
5923
+ *
5924
+ * @example
5925
+ * $(document).ready(function() {
5926
+ * var oTable = $('#example').dataTable();
5927
+ *
5928
+ * // Sort immediately with columns 0 and 1
5929
+ * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
5930
+ * } );
5931
+ */
5932
+ this.fnSort = function( aaSort )
5933
+ {
5934
+ this.api( true ).order( aaSort ).draw();
5935
+ };
5936
+
5937
+
5938
+ /**
5939
+ * Attach a sort listener to an element for a given column
5940
+ * @param {node} nNode the element to attach the sort listener to
5941
+ * @param {int} iColumn the column that a click on this node will sort on
5942
+ * @param {function} [fnCallback] callback function when sort is run
5943
+ * @dtopt API
5944
+ * @deprecated Since v1.10
5945
+ *
5946
+ * @example
5947
+ * $(document).ready(function() {
5948
+ * var oTable = $('#example').dataTable();
5949
+ *
5950
+ * // Sort on column 1, when 'sorter' is clicked on
5951
+ * oTable.fnSortListener( document.getElementById('sorter'), 1 );
5952
+ * } );
5953
+ */
5954
+ this.fnSortListener = function( nNode, iColumn, fnCallback )
5955
+ {
5956
+ this.api( true ).order.listener( nNode, iColumn, fnCallback );
5957
+ };
5958
+
5959
+
5960
+ /**
5961
+ * Update a table cell or row - this method will accept either a single value to
5962
+ * update the cell with, an array of values with one element for each column or
5963
+ * an object in the same format as the original data source. The function is
5964
+ * self-referencing in order to make the multi column updates easier.
5965
+ * @param {object|array|string} mData Data to update the cell/row with
5966
+ * @param {node|int} mRow TR element you want to update or the aoData index
5967
+ * @param {int} [iColumn] The column to update, give as null or undefined to
5968
+ * update a whole row.
5969
+ * @param {bool} [bRedraw=true] Redraw the table or not
5970
+ * @param {bool} [bAction=true] Perform pre-draw actions or not
5971
+ * @returns {int} 0 on success, 1 on error
5972
+ * @dtopt API
5973
+ * @deprecated Since v1.10
5974
+ *
5975
+ * @example
5976
+ * $(document).ready(function() {
5977
+ * var oTable = $('#example').dataTable();
5978
+ * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
5979
+ * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
5980
+ * } );
5981
+ */
5982
+ this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
5983
+ {
5984
+ var api = this.api( true );
5985
+
5986
+ if ( iColumn === undefined || iColumn === null ) {
5987
+ api.row( mRow ).data( mData );
5988
+ }
5989
+ else {
5990
+ api.cell( mRow, iColumn ).data( mData );
5991
+ }
5992
+
5993
+ if ( bAction === undefined || bAction ) {
5994
+ api.columns.adjust();
5995
+ }
5996
+
5997
+ if ( bRedraw === undefined || bRedraw ) {
5998
+ api.draw();
5999
+ }
6000
+ return 0;
6001
+ };
6002
+
6003
+
6004
+ /**
6005
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
6006
+ * to ensure compatibility.
6007
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
6008
+ * formats "X" and "X.Y" are also acceptable.
6009
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
6010
+ * version, or false if this version of DataTales is not suitable
6011
+ * @method
6012
+ * @dtopt API
6013
+ * @deprecated Since v1.10
6014
+ *
6015
+ * @example
6016
+ * $(document).ready(function() {
6017
+ * var oTable = $('#example').dataTable();
6018
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
6019
+ * } );
6020
+ */
6021
+ this.fnVersionCheck = _ext.fnVersionCheck;
6022
+
6023
+
6024
+ var _that = this;
6025
+ var emptyInit = options === undefined;
6026
+ var len = this.length;
6027
+
6028
+ if ( emptyInit ) {
6029
+ options = {};
6030
+ }
6031
+
6032
+ this.oApi = this.internal = _ext.internal;
6033
+
6034
+ // Extend with old style plug-in API methods
6035
+ for ( var fn in DataTable.ext.internal ) {
6036
+ if ( fn ) {
6037
+ this[fn] = _fnExternApiFunc(fn);
6038
+ }
6039
+ }
6040
+
6041
+ this.each(function() {
6042
+ // For each initialisation we want to give it a clean initialisation
6043
+ // object that can be bashed around
6044
+ var o = {};
6045
+ var oInit = len > 1 ? // optimisation for single table case
6046
+ _fnExtend( o, options, true ) :
6047
+ options;
6048
+
6049
+ /*global oInit,_that,emptyInit*/
6050
+ var i=0, iLen, j, jLen, k, kLen;
6051
+ var sId = this.getAttribute( 'id' );
6052
+ var bInitHandedOff = false;
6053
+ var defaults = DataTable.defaults;
6054
+
6055
+
6056
+ /* Sanity check */
6057
+ if ( this.nodeName.toLowerCase() != 'table' )
6058
+ {
6059
+ _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
6060
+ return;
6061
+ }
6062
+
6063
+ /* Backwards compatibility for the defaults */
6064
+ _fnCompatOpts( defaults );
6065
+ _fnCompatCols( defaults.column );
6066
+
6067
+ /* Convert the camel-case defaults to Hungarian */
6068
+ _fnCamelToHungarian( defaults, defaults, true );
6069
+ _fnCamelToHungarian( defaults.column, defaults.column, true );
6070
+
6071
+ /* Setting up the initialisation object */
6072
+ _fnCamelToHungarian( defaults, oInit );
6073
+
6074
+ /* Check to see if we are re-initialising a table */
6075
+ var allSettings = DataTable.settings;
6076
+ for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
6077
+ {
6078
+ /* Base check on table node */
6079
+ if ( allSettings[i].nTable == this )
6080
+ {
6081
+ var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
6082
+ var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
6083
+
6084
+ if ( emptyInit || bRetrieve )
6085
+ {
6086
+ return allSettings[i].oInstance;
6087
+ }
6088
+ else if ( bDestroy )
6089
+ {
6090
+ allSettings[i].oInstance.fnDestroy();
6091
+ break;
6092
+ }
6093
+ else
6094
+ {
6095
+ _fnLog( allSettings[i], 0, 'Cannot reinitialise DataTable', 3 );
6096
+ return;
6097
+ }
6098
+ }
6099
+
6100
+ /* If the element we are initialising has the same ID as a table which was previously
6101
+ * initialised, but the table nodes don't match (from before) then we destroy the old
6102
+ * instance by simply deleting it. This is under the assumption that the table has been
6103
+ * destroyed by other methods. Anyone using non-id selectors will need to do this manually
6104
+ */
6105
+ if ( allSettings[i].sTableId == this.id )
6106
+ {
6107
+ allSettings.splice( i, 1 );
6108
+ break;
6109
+ }
6110
+ }
6111
+
6112
+ /* Ensure the table has an ID - required for accessibility */
6113
+ if ( sId === null || sId === "" )
6114
+ {
6115
+ sId = "DataTables_Table_"+(DataTable.ext._unique++);
6116
+ this.id = sId;
6117
+ }
6118
+
6119
+ /* Create the settings object for this table and set some of the default parameters */
6120
+ var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
6121
+ "nTable": this,
6122
+ "oApi": _that.internal,
6123
+ "oInit": oInit,
6124
+ "sDestroyWidth": $(this)[0].style.width,
6125
+ "sInstance": sId,
6126
+ "sTableId": sId
6127
+ } );
6128
+ allSettings.push( oSettings );
6129
+
6130
+ // Need to add the instance after the instance after the settings object has been added
6131
+ // to the settings array, so we can self reference the table instance if more than one
6132
+ oSettings.oInstance = (_that.length===1) ? _that : $(this).dataTable();
6133
+
6134
+ // Backwards compatibility, before we apply all the defaults
6135
+ _fnCompatOpts( oInit );
6136
+
6137
+ if ( oInit.oLanguage )
6138
+ {
6139
+ _fnLanguageCompat( oInit.oLanguage );
6140
+ }
6141
+
6142
+ // If the length menu is given, but the init display length is not, use the length menu
6143
+ if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
6144
+ {
6145
+ oInit.iDisplayLength = $.isArray( oInit.aLengthMenu[0] ) ?
6146
+ oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
6147
+ }
6148
+
6149
+ // Apply the defaults and init options to make a single init object will all
6150
+ // options defined from defaults and instance options.
6151
+ oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
6152
+
6153
+
6154
+ // Map the initialisation options onto the settings object
6155
+ _fnMap( oSettings.oFeatures, oInit, [
6156
+ "bPaginate",
6157
+ "bLengthChange",
6158
+ "bFilter",
6159
+ "bSort",
6160
+ "bSortMulti",
6161
+ "bInfo",
6162
+ "bProcessing",
6163
+ "bAutoWidth",
6164
+ "bSortClasses",
6165
+ "bServerSide",
6166
+ "bDeferRender"
6167
+ ] );
6168
+ _fnMap( oSettings, oInit, [
6169
+ "asStripeClasses",
6170
+ "ajax",
6171
+ "fnServerData",
6172
+ "fnFormatNumber",
6173
+ "sServerMethod",
6174
+ "aaSorting",
6175
+ "aaSortingFixed",
6176
+ "aLengthMenu",
6177
+ "sPaginationType",
6178
+ "sAjaxSource",
6179
+ "sAjaxDataProp",
6180
+ "iStateDuration",
6181
+ "sDom",
6182
+ "bSortCellsTop",
6183
+ "iTabIndex",
6184
+ "fnStateLoadCallback",
6185
+ "fnStateSaveCallback",
6186
+ "renderer",
6187
+ "searchDelay",
6188
+ [ "iCookieDuration", "iStateDuration" ], // backwards compat
6189
+ [ "oSearch", "oPreviousSearch" ],
6190
+ [ "aoSearchCols", "aoPreSearchCols" ],
6191
+ [ "iDisplayLength", "_iDisplayLength" ],
6192
+ [ "bJQueryUI", "bJUI" ]
6193
+ ] );
6194
+ _fnMap( oSettings.oScroll, oInit, [
6195
+ [ "sScrollX", "sX" ],
6196
+ [ "sScrollXInner", "sXInner" ],
6197
+ [ "sScrollY", "sY" ],
6198
+ [ "bScrollCollapse", "bCollapse" ]
6199
+ ] );
6200
+ _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
6201
+
6202
+ /* Callback functions which are array driven */
6203
+ _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
6204
+ _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
6205
+ _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
6206
+ _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
6207
+ _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
6208
+ _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
6209
+ _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
6210
+ _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
6211
+ _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
6212
+ _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
6213
+ _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
6214
+
6215
+ var oClasses = oSettings.oClasses;
6216
+
6217
+ // @todo Remove in 1.11
6218
+ if ( oInit.bJQueryUI )
6219
+ {
6220
+ /* Use the JUI classes object for display. You could clone the oStdClasses object if
6221
+ * you want to have multiple tables with multiple independent classes
6222
+ */
6223
+ $.extend( oClasses, DataTable.ext.oJUIClasses, oInit.oClasses );
6224
+
6225
+ if ( oInit.sDom === defaults.sDom && defaults.sDom === "lfrtip" )
6226
+ {
6227
+ /* Set the DOM to use a layout suitable for jQuery UI's theming */
6228
+ oSettings.sDom = '<"H"lfr>t<"F"ip>';
6229
+ }
6230
+
6231
+ if ( ! oSettings.renderer ) {
6232
+ oSettings.renderer = 'jqueryui';
6233
+ }
6234
+ else if ( $.isPlainObject( oSettings.renderer ) && ! oSettings.renderer.header ) {
6235
+ oSettings.renderer.header = 'jqueryui';
6236
+ }
6237
+ }
6238
+ else
6239
+ {
6240
+ $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
6241
+ }
6242
+ $(this).addClass( oClasses.sTable );
6243
+
6244
+ /* Calculate the scroll bar width and cache it for use later on */
6245
+ if ( oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "" )
6246
+ {
6247
+ oSettings.oScroll.iBarWidth = _fnScrollBarWidth();
6248
+ }
6249
+ if ( oSettings.oScroll.sX === true ) { // Easy initialisation of x-scrolling
6250
+ oSettings.oScroll.sX = '100%';
6251
+ }
6252
+
6253
+ if ( oSettings.iInitDisplayStart === undefined )
6254
+ {
6255
+ /* Display start point, taking into account the save saving */
6256
+ oSettings.iInitDisplayStart = oInit.iDisplayStart;
6257
+ oSettings._iDisplayStart = oInit.iDisplayStart;
6258
+ }
6259
+
6260
+ if ( oInit.iDeferLoading !== null )
6261
+ {
6262
+ oSettings.bDeferLoading = true;
6263
+ var tmp = $.isArray( oInit.iDeferLoading );
6264
+ oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
6265
+ oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
6266
+ }
6267
+
6268
+ /* Language definitions */
6269
+ var oLanguage = oSettings.oLanguage;
6270
+ $.extend( true, oLanguage, oInit.oLanguage );
6271
+
6272
+ if ( oLanguage.sUrl !== "" )
6273
+ {
6274
+ /* Get the language definitions from a file - because this Ajax call makes the language
6275
+ * get async to the remainder of this function we use bInitHandedOff to indicate that
6276
+ * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
6277
+ */
6278
+ $.ajax( {
6279
+ dataType: 'json',
6280
+ url: oLanguage.sUrl,
6281
+ success: function ( json ) {
6282
+ _fnLanguageCompat( json );
6283
+ _fnCamelToHungarian( defaults.oLanguage, json );
6284
+ $.extend( true, oLanguage, json );
6285
+ _fnInitialise( oSettings );
6286
+ },
6287
+ error: function () {
6288
+ // Error occurred loading language file, continue on as best we can
6289
+ _fnInitialise( oSettings );
6290
+ }
6291
+ } );
6292
+ bInitHandedOff = true;
6293
+ }
6294
+
6295
+ /*
6296
+ * Stripes
6297
+ */
6298
+ if ( oInit.asStripeClasses === null )
6299
+ {
6300
+ oSettings.asStripeClasses =[
6301
+ oClasses.sStripeOdd,
6302
+ oClasses.sStripeEven
6303
+ ];
6304
+ }
6305
+
6306
+ /* Remove row stripe classes if they are already on the table row */
6307
+ var stripeClasses = oSettings.asStripeClasses;
6308
+ var rowOne = $('tbody tr:eq(0)', this);
6309
+ if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
6310
+ return rowOne.hasClass(el);
6311
+ } ) ) !== -1 ) {
6312
+ $('tbody tr', this).removeClass( stripeClasses.join(' ') );
6313
+ oSettings.asDestroyStripes = stripeClasses.slice();
6314
+ }
6315
+
6316
+ /*
6317
+ * Columns
6318
+ * See if we should load columns automatically or use defined ones
6319
+ */
6320
+ var anThs = [];
6321
+ var aoColumnsInit;
6322
+ var nThead = this.getElementsByTagName('thead');
6323
+ if ( nThead.length !== 0 )
6324
+ {
6325
+ _fnDetectHeader( oSettings.aoHeader, nThead[0] );
6326
+ anThs = _fnGetUniqueThs( oSettings );
6327
+ }
6328
+
6329
+ /* If not given a column array, generate one with nulls */
6330
+ if ( oInit.aoColumns === null )
6331
+ {
6332
+ aoColumnsInit = [];
6333
+ for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
6334
+ {
6335
+ aoColumnsInit.push( null );
6336
+ }
6337
+ }
6338
+ else
6339
+ {
6340
+ aoColumnsInit = oInit.aoColumns;
6341
+ }
6342
+
6343
+ /* Add the columns */
6344
+ for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
6345
+ {
6346
+ _fnAddColumn( oSettings, anThs ? anThs[i] : null );
6347
+ }
6348
+
6349
+ /* Apply the column definitions */
6350
+ _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
6351
+ _fnColumnOptions( oSettings, iCol, oDef );
6352
+ } );
6353
+
6354
+ /* HTML5 attribute detection - build an mData object automatically if the
6355
+ * attributes are found
6356
+ */
6357
+ if ( rowOne.length ) {
6358
+ var a = function ( cell, name ) {
6359
+ return cell.getAttribute( 'data-'+name ) ? name : null;
6360
+ };
6361
+
6362
+ $.each( _fnGetRowElements( oSettings, rowOne[0] ).cells, function (i, cell) {
6363
+ var col = oSettings.aoColumns[i];
6364
+
6365
+ if ( col.mData === i ) {
6366
+ var sort = a( cell, 'sort' ) || a( cell, 'order' );
6367
+ var filter = a( cell, 'filter' ) || a( cell, 'search' );
6368
+
6369
+ if ( sort !== null || filter !== null ) {
6370
+ col.mData = {
6371
+ _: i+'.display',
6372
+ sort: sort !== null ? i+'.@data-'+sort : undefined,
6373
+ type: sort !== null ? i+'.@data-'+sort : undefined,
6374
+ filter: filter !== null ? i+'.@data-'+filter : undefined
6375
+ };
6376
+
6377
+ _fnColumnOptions( oSettings, i );
6378
+ }
6379
+ }
6380
+ } );
6381
+ }
6382
+
6383
+ var features = oSettings.oFeatures;
6384
+
6385
+ /* Must be done after everything which can be overridden by the state saving! */
6386
+ if ( oInit.bStateSave )
6387
+ {
6388
+ features.bStateSave = true;
6389
+ _fnLoadState( oSettings, oInit );
6390
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
6391
+ }
6392
+
6393
+
6394
+ /*
6395
+ * Sorting
6396
+ * @todo For modularisation (1.11) this needs to do into a sort start up handler
6397
+ */
6398
+
6399
+ // If aaSorting is not defined, then we use the first indicator in asSorting
6400
+ // in case that has been altered, so the default sort reflects that option
6401
+ if ( oInit.aaSorting === undefined )
6402
+ {
6403
+ var sorting = oSettings.aaSorting;
6404
+ for ( i=0, iLen=sorting.length ; i<iLen ; i++ )
6405
+ {
6406
+ sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
6407
+ }
6408
+ }
6409
+
6410
+ /* Do a first pass on the sorting classes (allows any size changes to be taken into
6411
+ * account, and also will apply sorting disabled classes if disabled
6412
+ */
6413
+ _fnSortingClasses( oSettings );
6414
+
6415
+ if ( features.bSort )
6416
+ {
6417
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6418
+ if ( oSettings.bSorted ) {
6419
+ var aSort = _fnSortFlatten( oSettings );
6420
+ var sortedColumns = {};
6421
+
6422
+ $.each( aSort, function (i, val) {
6423
+ sortedColumns[ val.src ] = val.dir;
6424
+ } );
6425
+
6426
+ _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
6427
+ _fnSortAria( oSettings );
6428
+ }
6429
+ } );
6430
+ }
6431
+
6432
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
6433
+ if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
6434
+ _fnSortingClasses( oSettings );
6435
+ }
6436
+ }, 'sc' );
6437
+
6438
+
6439
+ /*
6440
+ * Final init
6441
+ * Cache the header, body and footer as required, creating them if needed
6442
+ */
6443
+
6444
+ /* Browser support detection */
6445
+ _fnBrowserDetect( oSettings );
6446
+
6447
+ // Work around for Webkit bug 83867 - store the caption-side before removing from doc
6448
+ var captions = $(this).children('caption').each( function () {
6449
+ this._captionSide = $(this).css('caption-side');
6450
+ } );
6451
+
6452
+ var thead = $(this).children('thead');
6453
+ if ( thead.length === 0 )
6454
+ {
6455
+ thead = $('<thead/>').appendTo(this);
6456
+ }
6457
+ oSettings.nTHead = thead[0];
6458
+
6459
+ var tbody = $(this).children('tbody');
6460
+ if ( tbody.length === 0 )
6461
+ {
6462
+ tbody = $('<tbody/>').appendTo(this);
6463
+ }
6464
+ oSettings.nTBody = tbody[0];
6465
+
6466
+ var tfoot = $(this).children('tfoot');
6467
+ if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") )
6468
+ {
6469
+ // If we are a scrolling table, and no footer has been given, then we need to create
6470
+ // a tfoot element for the caption element to be appended to
6471
+ tfoot = $('<tfoot/>').appendTo(this);
6472
+ }
6473
+
6474
+ if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
6475
+ $(this).addClass( oClasses.sNoFooter );
6476
+ }
6477
+ else if ( tfoot.length > 0 ) {
6478
+ oSettings.nTFoot = tfoot[0];
6479
+ _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
6480
+ }
6481
+
6482
+ /* Check if there is data passing into the constructor */
6483
+ if ( oInit.aaData )
6484
+ {
6485
+ for ( i=0 ; i<oInit.aaData.length ; i++ )
6486
+ {
6487
+ _fnAddData( oSettings, oInit.aaData[ i ] );
6488
+ }
6489
+ }
6490
+ else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' )
6491
+ {
6492
+ /* Grab the data from the page - only do this when deferred loading or no Ajax
6493
+ * source since there is no point in reading the DOM data if we are then going
6494
+ * to replace it with Ajax data
6495
+ */
6496
+ _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
6497
+ }
6498
+
6499
+ /* Copy the data index array */
6500
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
6501
+
6502
+ /* Initialisation complete - table can be drawn */
6503
+ oSettings.bInitialised = true;
6504
+
6505
+ /* Check if we need to initialise the table (it might not have been handed off to the
6506
+ * language processor)
6507
+ */
6508
+ if ( bInitHandedOff === false )
6509
+ {
6510
+ _fnInitialise( oSettings );
6511
+ }
6512
+ } );
6513
+ _that = null;
6514
+ return this;
6515
+ };
6516
+
6517
+
6518
+
6519
+ /**
6520
+ * Computed structure of the DataTables API, defined by the options passed to
6521
+ * `DataTable.Api.register()` when building the API.
6522
+ *
6523
+ * The structure is built in order to speed creation and extension of the Api
6524
+ * objects since the extensions are effectively pre-parsed.
6525
+ *
6526
+ * The array is an array of objects with the following structure, where this
6527
+ * base array represents the Api prototype base:
6528
+ *
6529
+ * [
6530
+ * {
6531
+ * name: 'data' -- string - Property name
6532
+ * val: function () {}, -- function - Api method (or undefined if just an object
6533
+ * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
6534
+ * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
6535
+ * },
6536
+ * {
6537
+ * name: 'row'
6538
+ * val: {},
6539
+ * methodExt: [ ... ],
6540
+ * propExt: [
6541
+ * {
6542
+ * name: 'data'
6543
+ * val: function () {},
6544
+ * methodExt: [ ... ],
6545
+ * propExt: [ ... ]
6546
+ * },
6547
+ * ...
6548
+ * ]
6549
+ * }
6550
+ * ]
6551
+ *
6552
+ * @type {Array}
6553
+ * @ignore
6554
+ */
6555
+ var __apiStruct = [];
6556
+
6557
+
6558
+ /**
6559
+ * `Array.prototype` reference.
6560
+ *
6561
+ * @type object
6562
+ * @ignore
6563
+ */
6564
+ var __arrayProto = Array.prototype;
6565
+
6566
+
6567
+ /**
6568
+ * Abstraction for `context` parameter of the `Api` constructor to allow it to
6569
+ * take several different forms for ease of use.
6570
+ *
6571
+ * Each of the input parameter types will be converted to a DataTables settings
6572
+ * object where possible.
6573
+ *
6574
+ * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
6575
+ * of:
6576
+ *
6577
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
6578
+ * with be found and used.
6579
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
6580
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
6581
+ * * `object` - DataTables settings object
6582
+ * * `DataTables.Api` - API instance
6583
+ * @return {array|null} Matching DataTables settings objects. `null` or
6584
+ * `undefined` is returned if no matching DataTable is found.
6585
+ * @ignore
6586
+ */
6587
+ var _toSettings = function ( mixed )
6588
+ {
6589
+ var idx, jq;
6590
+ var settings = DataTable.settings;
6591
+ var tables = $.map( settings, function (el, i) {
6592
+ return el.nTable;
6593
+ } );
6594
+
6595
+ if ( ! mixed ) {
6596
+ return [];
6597
+ }
6598
+ else if ( mixed.nTable && mixed.oApi ) {
6599
+ // DataTables settings object
6600
+ return [ mixed ];
6601
+ }
6602
+ else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
6603
+ // Table node
6604
+ idx = $.inArray( mixed, tables );
6605
+ return idx !== -1 ? [ settings[idx] ] : null;
6606
+ }
6607
+ else if ( mixed && typeof mixed.settings === 'function' ) {
6608
+ return mixed.settings().toArray();
6609
+ }
6610
+ else if ( typeof mixed === 'string' ) {
6611
+ // jQuery selector
6612
+ jq = $(mixed);
6613
+ }
6614
+ else if ( mixed instanceof $ ) {
6615
+ // jQuery object (also DataTables instance)
6616
+ jq = mixed;
6617
+ }
6618
+
6619
+ if ( jq ) {
6620
+ return jq.map( function(i) {
6621
+ idx = $.inArray( this, tables );
6622
+ return idx !== -1 ? settings[idx] : null;
6623
+ } ).toArray();
6624
+ }
6625
+ };
6626
+
6627
+
6628
+ /**
6629
+ * DataTables API class - used to control and interface with one or more
6630
+ * DataTables enhanced tables.
6631
+ *
6632
+ * The API class is heavily based on jQuery, presenting a chainable interface
6633
+ * that you can use to interact with tables. Each instance of the API class has
6634
+ * a "context" - i.e. the tables that it will operate on. This could be a single
6635
+ * table, all tables on a page or a sub-set thereof.
6636
+ *
6637
+ * Additionally the API is designed to allow you to easily work with the data in
6638
+ * the tables, retrieving and manipulating it as required. This is done by
6639
+ * presenting the API class as an array like interface. The contents of the
6640
+ * array depend upon the actions requested by each method (for example
6641
+ * `rows().nodes()` will return an array of nodes, while `rows().data()` will
6642
+ * return an array of objects or arrays depending upon your table's
6643
+ * configuration). The API object has a number of array like methods (`push`,
6644
+ * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
6645
+ * `unique` etc) to assist your working with the data held in a table.
6646
+ *
6647
+ * Most methods (those which return an Api instance) are chainable, which means
6648
+ * the return from a method call also has all of the methods available that the
6649
+ * top level object had. For example, these two calls are equivalent:
6650
+ *
6651
+ * // Not chained
6652
+ * api.row.add( {...} );
6653
+ * api.draw();
6654
+ *
6655
+ * // Chained
6656
+ * api.row.add( {...} ).draw();
6657
+ *
6658
+ * @class DataTable.Api
6659
+ * @param {array|object|string|jQuery} context DataTable identifier. This is
6660
+ * used to define which DataTables enhanced tables this API will operate on.
6661
+ * Can be one of:
6662
+ *
6663
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
6664
+ * with be found and used.
6665
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
6666
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
6667
+ * * `object` - DataTables settings object
6668
+ * @param {array} [data] Data to initialise the Api instance with.
6669
+ *
6670
+ * @example
6671
+ * // Direct initialisation during DataTables construction
6672
+ * var api = $('#example').DataTable();
6673
+ *
6674
+ * @example
6675
+ * // Initialisation using a DataTables jQuery object
6676
+ * var api = $('#example').dataTable().api();
6677
+ *
6678
+ * @example
6679
+ * // Initialisation as a constructor
6680
+ * var api = new $.fn.DataTable.Api( 'table.dataTable' );
6681
+ */
6682
+ _Api = function ( context, data )
6683
+ {
6684
+ if ( ! this instanceof _Api ) {
6685
+ throw 'DT API must be constructed as a new object';
6686
+ // or should it do the 'new' for the caller?
6687
+ // return new _Api.apply( this, arguments );
6688
+ }
6689
+
6690
+ var settings = [];
6691
+ var ctxSettings = function ( o ) {
6692
+ var a = _toSettings( o );
6693
+ if ( a ) {
6694
+ settings.push.apply( settings, a );
6695
+ }
6696
+ };
6697
+
6698
+ if ( $.isArray( context ) ) {
6699
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
6700
+ ctxSettings( context[i] );
6701
+ }
6702
+ }
6703
+ else {
6704
+ ctxSettings( context );
6705
+ }
6706
+
6707
+ // Remove duplicates
6708
+ this.context = _unique( settings );
6709
+
6710
+ // Initial data
6711
+ if ( data ) {
6712
+ this.push.apply( this, data.toArray ? data.toArray() : data );
6713
+ }
6714
+
6715
+ // selector
6716
+ this.selector = {
6717
+ rows: null,
6718
+ cols: null,
6719
+ opts: null
6720
+ };
6721
+
6722
+ _Api.extend( this, this, __apiStruct );
6723
+ };
6724
+
6725
+ DataTable.Api = _Api;
6726
+
6727
+ _Api.prototype = /** @lends DataTables.Api */{
6728
+ /**
6729
+ * Return a new Api instance, comprised of the data held in the current
6730
+ * instance, join with the other array(s) and/or value(s).
6731
+ *
6732
+ * An alias for `Array.prototype.concat`.
6733
+ *
6734
+ * @type method
6735
+ * @param {*} value1 Arrays and/or values to concatenate.
6736
+ * @param {*} [...] Additional arrays and/or values to concatenate.
6737
+ * @returns {DataTables.Api} New API instance, comprising of the combined
6738
+ * array.
6739
+ */
6740
+ concat: __arrayProto.concat,
6741
+
6742
+
6743
+ context: [], // array of table settings objects
6744
+
6745
+
6746
+ each: function ( fn )
6747
+ {
6748
+ for ( var i=0, ien=this.length ; i<ien; i++ ) {
6749
+ fn.call( this, this[i], i, this );
6750
+ }
6751
+
6752
+ return this;
6753
+ },
6754
+
6755
+
6756
+ eq: function ( idx )
6757
+ {
6758
+ var ctx = this.context;
6759
+
6760
+ return ctx.length > idx ?
6761
+ new _Api( ctx[idx], this[idx] ) :
6762
+ null;
6763
+ },
6764
+
6765
+
6766
+ filter: function ( fn )
6767
+ {
6768
+ var a = [];
6769
+
6770
+ if ( __arrayProto.filter ) {
6771
+ a = __arrayProto.filter.call( this, fn, this );
6772
+ }
6773
+ else {
6774
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6775
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6776
+ if ( fn.call( this, this[i], i, this ) ) {
6777
+ a.push( this[i] );
6778
+ }
6779
+ }
6780
+ }
6781
+
6782
+ return new _Api( this.context, a );
6783
+ },
6784
+
6785
+
6786
+ flatten: function ()
6787
+ {
6788
+ var a = [];
6789
+ return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
6790
+ },
6791
+
6792
+
6793
+ join: __arrayProto.join,
6794
+
6795
+
6796
+ indexOf: __arrayProto.indexOf || function (obj, start)
6797
+ {
6798
+ for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
6799
+ if ( this[i] === obj ) {
6800
+ return i;
6801
+ }
6802
+ }
6803
+ return -1;
6804
+ },
6805
+
6806
+ // Note that `alwaysNew` is internal - use iteratorNew externally
6807
+ iterator: function ( flatten, type, fn, alwaysNew ) {
6808
+ var
6809
+ a = [], ret,
6810
+ i, ien, j, jen,
6811
+ context = this.context,
6812
+ rows, items, item,
6813
+ selector = this.selector;
6814
+
6815
+ // Argument shifting
6816
+ if ( typeof flatten === 'string' ) {
6817
+ alwaysNew = fn;
6818
+ fn = type;
6819
+ type = flatten;
6820
+ flatten = false;
6821
+ }
6822
+
6823
+ for ( i=0, ien=context.length ; i<ien ; i++ ) {
6824
+ var apiInst = new _Api( context[i] );
6825
+
6826
+ if ( type === 'table' ) {
6827
+ ret = fn.call( apiInst, context[i], i );
6828
+
6829
+ if ( ret !== undefined ) {
6830
+ a.push( ret );
6831
+ }
6832
+ }
6833
+ else if ( type === 'columns' || type === 'rows' ) {
6834
+ // this has same length as context - one entry for each table
6835
+ ret = fn.call( apiInst, context[i], this[i], i );
6836
+
6837
+ if ( ret !== undefined ) {
6838
+ a.push( ret );
6839
+ }
6840
+ }
6841
+ else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
6842
+ // columns and rows share the same structure.
6843
+ // 'this' is an array of column indexes for each context
6844
+ items = this[i];
6845
+
6846
+ if ( type === 'column-rows' ) {
6847
+ rows = _selector_row_indexes( context[i], selector.opts );
6848
+ }
6849
+
6850
+ for ( j=0, jen=items.length ; j<jen ; j++ ) {
6851
+ item = items[j];
6852
+
6853
+ if ( type === 'cell' ) {
6854
+ ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
6855
+ }
6856
+ else {
6857
+ ret = fn.call( apiInst, context[i], item, i, j, rows );
6858
+ }
6859
+
6860
+ if ( ret !== undefined ) {
6861
+ a.push( ret );
6862
+ }
6863
+ }
6864
+ }
6865
+ }
6866
+
6867
+ if ( a.length || alwaysNew ) {
6868
+ var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
6869
+ var apiSelector = api.selector;
6870
+ apiSelector.rows = selector.rows;
6871
+ apiSelector.cols = selector.cols;
6872
+ apiSelector.opts = selector.opts;
6873
+ return api;
6874
+ }
6875
+ return this;
6876
+ },
6877
+
6878
+
6879
+ lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
6880
+ {
6881
+ // Bit cheeky...
6882
+ return this.indexOf.apply( this.toArray.reverse(), arguments );
6883
+ },
6884
+
6885
+
6886
+ length: 0,
6887
+
6888
+
6889
+ map: function ( fn )
6890
+ {
6891
+ var a = [];
6892
+
6893
+ if ( __arrayProto.map ) {
6894
+ a = __arrayProto.map.call( this, fn, this );
6895
+ }
6896
+ else {
6897
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
6898
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
6899
+ a.push( fn.call( this, this[i], i ) );
6900
+ }
6901
+ }
6902
+
6903
+ return new _Api( this.context, a );
6904
+ },
6905
+
6906
+
6907
+ pluck: function ( prop )
6908
+ {
6909
+ return this.map( function ( el ) {
6910
+ return el[ prop ];
6911
+ } );
6912
+ },
6913
+
6914
+ pop: __arrayProto.pop,
6915
+
6916
+
6917
+ push: __arrayProto.push,
6918
+
6919
+
6920
+ // Does not return an API instance
6921
+ reduce: __arrayProto.reduce || function ( fn, init )
6922
+ {
6923
+ return _fnReduce( this, fn, init, 0, this.length, 1 );
6924
+ },
6925
+
6926
+
6927
+ reduceRight: __arrayProto.reduceRight || function ( fn, init )
6928
+ {
6929
+ return _fnReduce( this, fn, init, this.length-1, -1, -1 );
6930
+ },
6931
+
6932
+
6933
+ reverse: __arrayProto.reverse,
6934
+
6935
+
6936
+ // Object with rows, columns and opts
6937
+ selector: null,
6938
+
6939
+
6940
+ shift: __arrayProto.shift,
6941
+
6942
+
6943
+ sort: __arrayProto.sort, // ? name - order?
6944
+
6945
+
6946
+ splice: __arrayProto.splice,
6947
+
6948
+
6949
+ toArray: function ()
6950
+ {
6951
+ return __arrayProto.slice.call( this );
6952
+ },
6953
+
6954
+
6955
+ to$: function ()
6956
+ {
6957
+ return $( this );
6958
+ },
6959
+
6960
+
6961
+ toJQuery: function ()
6962
+ {
6963
+ return $( this );
6964
+ },
6965
+
6966
+
6967
+ unique: function ()
6968
+ {
6969
+ return new _Api( this.context, _unique(this) );
6970
+ },
6971
+
6972
+
6973
+ unshift: __arrayProto.unshift
6974
+ };
6975
+
6976
+
6977
+ _Api.extend = function ( scope, obj, ext )
6978
+ {
6979
+ // Only extend API instances and static properties of the API
6980
+ if ( ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
6981
+ return;
6982
+ }
6983
+
6984
+ var
6985
+ i, ien,
6986
+ j, jen,
6987
+ struct, inner,
6988
+ methodScoping = function ( scope, fn, struc ) {
6989
+ return function () {
6990
+ var ret = fn.apply( scope, arguments );
6991
+
6992
+ // Method extension
6993
+ _Api.extend( ret, ret, struc.methodExt );
6994
+ return ret;
6995
+ };
6996
+ };
6997
+
6998
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
6999
+ struct = ext[i];
7000
+
7001
+ // Value
7002
+ obj[ struct.name ] = typeof struct.val === 'function' ?
7003
+ methodScoping( scope, struct.val, struct ) :
7004
+ $.isPlainObject( struct.val ) ?
7005
+ {} :
7006
+ struct.val;
7007
+
7008
+ obj[ struct.name ].__dt_wrapper = true;
7009
+
7010
+ // Property extension
7011
+ _Api.extend( scope, obj[ struct.name ], struct.propExt );
7012
+ }
7013
+ };
7014
+
7015
+
7016
+ // @todo - Is there need for an augment function?
7017
+ // _Api.augment = function ( inst, name )
7018
+ // {
7019
+ // // Find src object in the structure from the name
7020
+ // var parts = name.split('.');
7021
+
7022
+ // _Api.extend( inst, obj );
7023
+ // };
7024
+
7025
+
7026
+ // [
7027
+ // {
7028
+ // name: 'data' -- string - Property name
7029
+ // val: function () {}, -- function - Api method (or undefined if just an object
7030
+ // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
7031
+ // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
7032
+ // },
7033
+ // {
7034
+ // name: 'row'
7035
+ // val: {},
7036
+ // methodExt: [ ... ],
7037
+ // propExt: [
7038
+ // {
7039
+ // name: 'data'
7040
+ // val: function () {},
7041
+ // methodExt: [ ... ],
7042
+ // propExt: [ ... ]
7043
+ // },
7044
+ // ...
7045
+ // ]
7046
+ // }
7047
+ // ]
7048
+
7049
+ _Api.register = _api_register = function ( name, val )
7050
+ {
7051
+ if ( $.isArray( name ) ) {
7052
+ for ( var j=0, jen=name.length ; j<jen ; j++ ) {
7053
+ _Api.register( name[j], val );
7054
+ }
7055
+ return;
7056
+ }
7057
+
7058
+ var
7059
+ i, ien,
7060
+ heir = name.split('.'),
7061
+ struct = __apiStruct,
7062
+ key, method;
7063
+
7064
+ var find = function ( src, name ) {
7065
+ for ( var i=0, ien=src.length ; i<ien ; i++ ) {
7066
+ if ( src[i].name === name ) {
7067
+ return src[i];
7068
+ }
7069
+ }
7070
+ return null;
7071
+ };
7072
+
7073
+ for ( i=0, ien=heir.length ; i<ien ; i++ ) {
7074
+ method = heir[i].indexOf('()') !== -1;
7075
+ key = method ?
7076
+ heir[i].replace('()', '') :
7077
+ heir[i];
7078
+
7079
+ var src = find( struct, key );
7080
+ if ( ! src ) {
7081
+ src = {
7082
+ name: key,
7083
+ val: {},
7084
+ methodExt: [],
7085
+ propExt: []
7086
+ };
7087
+ struct.push( src );
7088
+ }
7089
+
7090
+ if ( i === ien-1 ) {
7091
+ src.val = val;
7092
+ }
7093
+ else {
7094
+ struct = method ?
7095
+ src.methodExt :
7096
+ src.propExt;
7097
+ }
7098
+ }
7099
+ };
7100
+
7101
+
7102
+ _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
7103
+ _Api.register( pluralName, val );
7104
+
7105
+ _Api.register( singularName, function () {
7106
+ var ret = val.apply( this, arguments );
7107
+
7108
+ if ( ret === this ) {
7109
+ // Returned item is the API instance that was passed in, return it
7110
+ return this;
7111
+ }
7112
+ else if ( ret instanceof _Api ) {
7113
+ // New API instance returned, want the value from the first item
7114
+ // in the returned array for the singular result.
7115
+ return ret.length ?
7116
+ $.isArray( ret[0] ) ?
7117
+ new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
7118
+ ret[0] :
7119
+ undefined;
7120
+ }
7121
+
7122
+ // Non-API return - just fire it back
7123
+ return ret;
7124
+ } );
7125
+ };
7126
+
7127
+
7128
+ /**
7129
+ * Selector for HTML tables. Apply the given selector to the give array of
7130
+ * DataTables settings objects.
7131
+ *
7132
+ * @param {string|integer} [selector] jQuery selector string or integer
7133
+ * @param {array} Array of DataTables settings objects to be filtered
7134
+ * @return {array}
7135
+ * @ignore
7136
+ */
7137
+ var __table_selector = function ( selector, a )
7138
+ {
7139
+ // Integer is used to pick out a table by index
7140
+ if ( typeof selector === 'number' ) {
7141
+ return [ a[ selector ] ];
7142
+ }
7143
+
7144
+ // Perform a jQuery selector on the table nodes
7145
+ var nodes = $.map( a, function (el, i) {
7146
+ return el.nTable;
7147
+ } );
7148
+
7149
+ return $(nodes)
7150
+ .filter( selector )
7151
+ .map( function (i) {
7152
+ // Need to translate back from the table node to the settings
7153
+ var idx = $.inArray( this, nodes );
7154
+ return a[ idx ];
7155
+ } )
7156
+ .toArray();
7157
+ };
7158
+
7159
+
7160
+
7161
+ /**
7162
+ * Context selector for the API's context (i.e. the tables the API instance
7163
+ * refers to.
7164
+ *
7165
+ * @name DataTable.Api#tables
7166
+ * @param {string|integer} [selector] Selector to pick which tables the iterator
7167
+ * should operate on. If not given, all tables in the current context are
7168
+ * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
7169
+ * select multiple tables or as an integer to select a single table.
7170
+ * @returns {DataTable.Api} Returns a new API instance if a selector is given.
7171
+ */
7172
+ _api_register( 'tables()', function ( selector ) {
7173
+ // A new instance is created if there was a selector specified
7174
+ return selector ?
7175
+ new _Api( __table_selector( selector, this.context ) ) :
7176
+ this;
7177
+ } );
7178
+
7179
+
7180
+ _api_register( 'table()', function ( selector ) {
7181
+ var tables = this.tables( selector );
7182
+ var ctx = tables.context;
7183
+
7184
+ // Truncate to the first matched table
7185
+ return ctx.length ?
7186
+ new _Api( ctx[0] ) :
7187
+ tables;
7188
+ } );
7189
+
7190
+
7191
+ _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
7192
+ return this.iterator( 'table', function ( ctx ) {
7193
+ return ctx.nTable;
7194
+ }, 1 );
7195
+ } );
7196
+
7197
+
7198
+ _api_registerPlural( 'tables().body()', 'table().body()' , function () {
7199
+ return this.iterator( 'table', function ( ctx ) {
7200
+ return ctx.nTBody;
7201
+ }, 1 );
7202
+ } );
7203
+
7204
+
7205
+ _api_registerPlural( 'tables().header()', 'table().header()' , function () {
7206
+ return this.iterator( 'table', function ( ctx ) {
7207
+ return ctx.nTHead;
7208
+ }, 1 );
7209
+ } );
7210
+
7211
+
7212
+ _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
7213
+ return this.iterator( 'table', function ( ctx ) {
7214
+ return ctx.nTFoot;
7215
+ }, 1 );
7216
+ } );
7217
+
7218
+
7219
+ _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
7220
+ return this.iterator( 'table', function ( ctx ) {
7221
+ return ctx.nTableWrapper;
7222
+ }, 1 );
7223
+ } );
7224
+
7225
+
7226
+
7227
+ /**
7228
+ * Redraw the tables in the current context.
7229
+ *
7230
+ * @param {boolean} [reset=true] Reset (default) or hold the current paging
7231
+ * position. A full re-sort and re-filter is performed when this method is
7232
+ * called, which is why the pagination reset is the default action.
7233
+ * @returns {DataTables.Api} this
7234
+ */
7235
+ _api_register( 'draw()', function ( resetPaging ) {
7236
+ return this.iterator( 'table', function ( settings ) {
7237
+ _fnReDraw( settings, resetPaging===false );
7238
+ } );
7239
+ } );
7240
+
7241
+
7242
+
7243
+ /**
7244
+ * Get the current page index.
7245
+ *
7246
+ * @return {integer} Current page index (zero based)
7247
+ *//**
7248
+ * Set the current page.
7249
+ *
7250
+ * Note that if you attempt to show a page which does not exist, DataTables will
7251
+ * not throw an error, but rather reset the paging.
7252
+ *
7253
+ * @param {integer|string} action The paging action to take. This can be one of:
7254
+ * * `integer` - The page index to jump to
7255
+ * * `string` - An action to take:
7256
+ * * `first` - Jump to first page.
7257
+ * * `next` - Jump to the next page
7258
+ * * `previous` - Jump to previous page
7259
+ * * `last` - Jump to the last page.
7260
+ * @returns {DataTables.Api} this
7261
+ */
7262
+ _api_register( 'page()', function ( action ) {
7263
+ if ( action === undefined ) {
7264
+ return this.page.info().page; // not an expensive call
7265
+ }
7266
+
7267
+ // else, have an action to take on all tables
7268
+ return this.iterator( 'table', function ( settings ) {
7269
+ _fnPageChange( settings, action );
7270
+ } );
7271
+ } );
7272
+
7273
+
7274
+ /**
7275
+ * Paging information for the first table in the current context.
7276
+ *
7277
+ * If you require paging information for another table, use the `table()` method
7278
+ * with a suitable selector.
7279
+ *
7280
+ * @return {object} Object with the following properties set:
7281
+ * * `page` - Current page index (zero based - i.e. the first page is `0`)
7282
+ * * `pages` - Total number of pages
7283
+ * * `start` - Display index for the first record shown on the current page
7284
+ * * `end` - Display index for the last record shown on the current page
7285
+ * * `length` - Display length (number of records). Note that generally `start
7286
+ * + length = end`, but this is not always true, for example if there are
7287
+ * only 2 records to show on the final page, with a length of 10.
7288
+ * * `recordsTotal` - Full data set length
7289
+ * * `recordsDisplay` - Data set length once the current filtering criterion
7290
+ * are applied.
7291
+ */
7292
+ _api_register( 'page.info()', function ( action ) {
7293
+ if ( this.context.length === 0 ) {
7294
+ return undefined;
7295
+ }
7296
+
7297
+ var
7298
+ settings = this.context[0],
7299
+ start = settings._iDisplayStart,
7300
+ len = settings._iDisplayLength,
7301
+ visRecords = settings.fnRecordsDisplay(),
7302
+ all = len === -1;
7303
+
7304
+ return {
7305
+ "page": all ? 0 : Math.floor( start / len ),
7306
+ "pages": all ? 1 : Math.ceil( visRecords / len ),
7307
+ "start": start,
7308
+ "end": settings.fnDisplayEnd(),
7309
+ "length": len,
7310
+ "recordsTotal": settings.fnRecordsTotal(),
7311
+ "recordsDisplay": visRecords
7312
+ };
7313
+ } );
7314
+
7315
+
7316
+ /**
7317
+ * Get the current page length.
7318
+ *
7319
+ * @return {integer} Current page length. Note `-1` indicates that all records
7320
+ * are to be shown.
7321
+ *//**
7322
+ * Set the current page length.
7323
+ *
7324
+ * @param {integer} Page length to set. Use `-1` to show all records.
7325
+ * @returns {DataTables.Api} this
7326
+ */
7327
+ _api_register( 'page.len()', function ( len ) {
7328
+ // Note that we can't call this function 'length()' because `length`
7329
+ // is a Javascript property of functions which defines how many arguments
7330
+ // the function expects.
7331
+ if ( len === undefined ) {
7332
+ return this.context.length !== 0 ?
7333
+ this.context[0]._iDisplayLength :
7334
+ undefined;
7335
+ }
7336
+
7337
+ // else, set the page length
7338
+ return this.iterator( 'table', function ( settings ) {
7339
+ _fnLengthChange( settings, len );
7340
+ } );
7341
+ } );
7342
+
7343
+
7344
+
7345
+ var __reload = function ( settings, holdPosition, callback ) {
7346
+ if ( _fnDataSource( settings ) == 'ssp' ) {
7347
+ _fnReDraw( settings, holdPosition );
7348
+ }
7349
+ else {
7350
+ // Trigger xhr
7351
+ _fnProcessingDisplay( settings, true );
7352
+
7353
+ _fnBuildAjax( settings, [], function( json ) {
7354
+ _fnClearTable( settings );
7355
+
7356
+ var data = _fnAjaxDataSrc( settings, json );
7357
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7358
+ _fnAddData( settings, data[i] );
7359
+ }
7360
+
7361
+ _fnReDraw( settings, holdPosition );
7362
+ _fnProcessingDisplay( settings, false );
7363
+ } );
7364
+ }
7365
+
7366
+ // Use the draw event to trigger a callback, regardless of if it is an async
7367
+ // or sync draw
7368
+ if ( callback ) {
7369
+ var api = new _Api( settings );
7370
+
7371
+ api.one( 'draw', function () {
7372
+ callback( api.ajax.json() );
7373
+ } );
7374
+ }
7375
+ };
7376
+
7377
+
7378
+ /**
7379
+ * Get the JSON response from the last Ajax request that DataTables made to the
7380
+ * server. Note that this returns the JSON from the first table in the current
7381
+ * context.
7382
+ *
7383
+ * @return {object} JSON received from the server.
7384
+ */
7385
+ _api_register( 'ajax.json()', function () {
7386
+ var ctx = this.context;
7387
+
7388
+ if ( ctx.length > 0 ) {
7389
+ return ctx[0].json;
7390
+ }
7391
+
7392
+ // else return undefined;
7393
+ } );
7394
+
7395
+
7396
+ /**
7397
+ * Get the data submitted in the last Ajax request
7398
+ */
7399
+ _api_register( 'ajax.params()', function () {
7400
+ var ctx = this.context;
7401
+
7402
+ if ( ctx.length > 0 ) {
7403
+ return ctx[0].oAjaxData;
7404
+ }
7405
+
7406
+ // else return undefined;
7407
+ } );
7408
+
7409
+
7410
+ /**
7411
+ * Reload tables from the Ajax data source. Note that this function will
7412
+ * automatically re-draw the table when the remote data has been loaded.
7413
+ *
7414
+ * @param {boolean} [reset=true] Reset (default) or hold the current paging
7415
+ * position. A full re-sort and re-filter is performed when this method is
7416
+ * called, which is why the pagination reset is the default action.
7417
+ * @returns {DataTables.Api} this
7418
+ */
7419
+ _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
7420
+ return this.iterator( 'table', function (settings) {
7421
+ __reload( settings, resetPaging===false, callback );
7422
+ } );
7423
+ } );
7424
+
7425
+
7426
+ /**
7427
+ * Get the current Ajax URL. Note that this returns the URL from the first
7428
+ * table in the current context.
7429
+ *
7430
+ * @return {string} Current Ajax source URL
7431
+ *//**
7432
+ * Set the Ajax URL. Note that this will set the URL for all tables in the
7433
+ * current context.
7434
+ *
7435
+ * @param {string} url URL to set.
7436
+ * @returns {DataTables.Api} this
7437
+ */
7438
+ _api_register( 'ajax.url()', function ( url ) {
7439
+ var ctx = this.context;
7440
+
7441
+ if ( url === undefined ) {
7442
+ // get
7443
+ if ( ctx.length === 0 ) {
7444
+ return undefined;
7445
+ }
7446
+ ctx = ctx[0];
7447
+
7448
+ return ctx.ajax ?
7449
+ $.isPlainObject( ctx.ajax ) ?
7450
+ ctx.ajax.url :
7451
+ ctx.ajax :
7452
+ ctx.sAjaxSource;
7453
+ }
7454
+
7455
+ // set
7456
+ return this.iterator( 'table', function ( settings ) {
7457
+ if ( $.isPlainObject( settings.ajax ) ) {
7458
+ settings.ajax.url = url;
7459
+ }
7460
+ else {
7461
+ settings.ajax = url;
7462
+ }
7463
+ // No need to consider sAjaxSource here since DataTables gives priority
7464
+ // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
7465
+ // value of `sAjaxSource` redundant.
7466
+ } );
7467
+ } );
7468
+
7469
+
7470
+ /**
7471
+ * Load data from the newly set Ajax URL. Note that this method is only
7472
+ * available when `ajax.url()` is used to set a URL. Additionally, this method
7473
+ * has the same effect as calling `ajax.reload()` but is provided for
7474
+ * convenience when setting a new URL. Like `ajax.reload()` it will
7475
+ * automatically redraw the table once the remote data has been loaded.
7476
+ *
7477
+ * @returns {DataTables.Api} this
7478
+ */
7479
+ _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
7480
+ // Same as a reload, but makes sense to present it for easy access after a
7481
+ // url change
7482
+ return this.iterator( 'table', function ( ctx ) {
7483
+ __reload( ctx, resetPaging===false, callback );
7484
+ } );
7485
+ } );
7486
+
7487
+
7488
+
7489
+
7490
+ var _selector_run = function ( selector, select )
7491
+ {
7492
+ var
7493
+ out = [], res,
7494
+ a, i, ien, j, jen,
7495
+ selectorType = typeof selector;
7496
+
7497
+ // Can't just check for isArray here, as an API or jQuery instance might be
7498
+ // given with their array like look
7499
+ if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
7500
+ selector = [ selector ];
7501
+ }
7502
+
7503
+ for ( i=0, ien=selector.length ; i<ien ; i++ ) {
7504
+ a = selector[i] && selector[i].split ?
7505
+ selector[i].split(',') :
7506
+ [ selector[i] ];
7507
+
7508
+ for ( j=0, jen=a.length ; j<jen ; j++ ) {
7509
+ res = select( typeof a[j] === 'string' ? $.trim(a[j]) : a[j] );
7510
+
7511
+ if ( res && res.length ) {
7512
+ out.push.apply( out, res );
7513
+ }
7514
+ }
7515
+ }
7516
+
7517
+ return out;
7518
+ };
7519
+
7520
+
7521
+ var _selector_opts = function ( opts )
7522
+ {
7523
+ if ( ! opts ) {
7524
+ opts = {};
7525
+ }
7526
+
7527
+ // Backwards compatibility for 1.9- which used the terminology filter rather
7528
+ // than search
7529
+ if ( opts.filter && ! opts.search ) {
7530
+ opts.search = opts.filter;
7531
+ }
7532
+
7533
+ return {
7534
+ search: opts.search || 'none',
7535
+ order: opts.order || 'current',
7536
+ page: opts.page || 'all'
7537
+ };
7538
+ };
7539
+
7540
+
7541
+ var _selector_first = function ( inst )
7542
+ {
7543
+ // Reduce the API instance to the first item found
7544
+ for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
7545
+ if ( inst[i].length > 0 ) {
7546
+ // Assign the first element to the first item in the instance
7547
+ // and truncate the instance and context
7548
+ inst[0] = inst[i];
7549
+ inst.length = 1;
7550
+ inst.context = [ inst.context[i] ];
7551
+
7552
+ return inst;
7553
+ }
7554
+ }
7555
+
7556
+ // Not found - return an empty instance
7557
+ inst.length = 0;
7558
+ return inst;
7559
+ };
7560
+
7561
+
7562
+ var _selector_row_indexes = function ( settings, opts )
7563
+ {
7564
+ var
7565
+ i, ien, tmp, a=[],
7566
+ displayFiltered = settings.aiDisplay,
7567
+ displayMaster = settings.aiDisplayMaster;
7568
+
7569
+ var
7570
+ search = opts.search, // none, applied, removed
7571
+ order = opts.order, // applied, current, index (original - compatibility with 1.9)
7572
+ page = opts.page; // all, current
7573
+
7574
+ if ( _fnDataSource( settings ) == 'ssp' ) {
7575
+ // In server-side processing mode, most options are irrelevant since
7576
+ // rows not shown don't exist and the index order is the applied order
7577
+ // Removed is a special case - for consistency just return an empty
7578
+ // array
7579
+ return search === 'removed' ?
7580
+ [] :
7581
+ _range( 0, displayMaster.length );
7582
+ }
7583
+ else if ( page == 'current' ) {
7584
+ // Current page implies that order=current and fitler=applied, since it is
7585
+ // fairly senseless otherwise, regardless of what order and search actually
7586
+ // are
7587
+ for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
7588
+ a.push( displayFiltered[i] );
7589
+ }
7590
+ }
7591
+ else if ( order == 'current' || order == 'applied' ) {
7592
+ a = search == 'none' ?
7593
+ displayMaster.slice() : // no search
7594
+ search == 'applied' ?
7595
+ displayFiltered.slice() : // applied search
7596
+ $.map( displayMaster, function (el, i) { // removed search
7597
+ return $.inArray( el, displayFiltered ) === -1 ? el : null;
7598
+ } );
7599
+ }
7600
+ else if ( order == 'index' || order == 'original' ) {
7601
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
7602
+ if ( search == 'none' ) {
7603
+ a.push( i );
7604
+ }
7605
+ else { // applied | removed
7606
+ tmp = $.inArray( i, displayFiltered );
7607
+
7608
+ if ((tmp === -1 && search == 'removed') ||
7609
+ (tmp >= 0 && search == 'applied') )
7610
+ {
7611
+ a.push( i );
7612
+ }
7613
+ }
7614
+ }
7615
+ }
7616
+
7617
+ return a;
7618
+ };
7619
+
7620
+
7621
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
7622
+ * Rows
7623
+ *
7624
+ * {} - no selector - use all available rows
7625
+ * {integer} - row aoData index
7626
+ * {node} - TR node
7627
+ * {string} - jQuery selector to apply to the TR elements
7628
+ * {array} - jQuery array of nodes, or simply an array of TR nodes
7629
+ *
7630
+ */
7631
+
7632
+
7633
+ var __row_selector = function ( settings, selector, opts )
7634
+ {
7635
+ return _selector_run( selector, function ( sel ) {
7636
+ var selInt = _intVal( sel );
7637
+ var i, ien;
7638
+
7639
+ // Short cut - selector is a number and no options provided (default is
7640
+ // all records, so no need to check if the index is in there, since it
7641
+ // must be - dev error if the index doesn't exist).
7642
+ if ( selInt !== null && ! opts ) {
7643
+ return [ selInt ];
7644
+ }
7645
+
7646
+ var rows = _selector_row_indexes( settings, opts );
7647
+
7648
+ if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
7649
+ // Selector - integer
7650
+ return [ selInt ];
7651
+ }
7652
+ else if ( ! sel ) {
7653
+ // Selector - none
7654
+ return rows;
7655
+ }
7656
+
7657
+ // Selector - function
7658
+ if ( typeof sel === 'function' ) {
7659
+ return $.map( rows, function (idx) {
7660
+ var row = settings.aoData[ idx ];
7661
+ return sel( idx, row._aData, row.nTr ) ? idx : null;
7662
+ } );
7663
+ }
7664
+
7665
+ // Get nodes in the order from the `rows` array with null values removed
7666
+ var nodes = _removeEmpty(
7667
+ _pluck_order( settings.aoData, rows, 'nTr' )
7668
+ );
7669
+
7670
+ // Selector - node
7671
+ if ( sel.nodeName ) {
7672
+ if ( $.inArray( sel, nodes ) !== -1 ) {
7673
+ return [ sel._DT_RowIndex ]; // sel is a TR node that is in the table
7674
+ // and DataTables adds a prop for fast lookup
7675
+ }
7676
+ }
7677
+
7678
+ // Selector - jQuery selector string, array of nodes or jQuery object/
7679
+ // As jQuery's .filter() allows jQuery objects to be passed in filter,
7680
+ // it also allows arrays, so this will cope with all three options
7681
+ return $(nodes)
7682
+ .filter( sel )
7683
+ .map( function () {
7684
+ return this._DT_RowIndex;
7685
+ } )
7686
+ .toArray();
7687
+ } );
7688
+ };
7689
+
7690
+
7691
+ /**
7692
+ *
7693
+ */
7694
+ _api_register( 'rows()', function ( selector, opts ) {
7695
+ // argument shifting
7696
+ if ( selector === undefined ) {
7697
+ selector = '';
7698
+ }
7699
+ else if ( $.isPlainObject( selector ) ) {
7700
+ opts = selector;
7701
+ selector = '';
7702
+ }
7703
+
7704
+ opts = _selector_opts( opts );
7705
+
7706
+ var inst = this.iterator( 'table', function ( settings ) {
7707
+ return __row_selector( settings, selector, opts );
7708
+ }, 1 );
7709
+
7710
+ // Want argument shifting here and in __row_selector?
7711
+ inst.selector.rows = selector;
7712
+ inst.selector.opts = opts;
7713
+
7714
+ return inst;
7715
+ } );
7716
+
7717
+
7718
+ _api_register( 'rows().nodes()', function () {
7719
+ return this.iterator( 'row', function ( settings, row ) {
7720
+ return settings.aoData[ row ].nTr || undefined;
7721
+ }, 1 );
7722
+ } );
7723
+
7724
+ _api_register( 'rows().data()', function () {
7725
+ return this.iterator( true, 'rows', function ( settings, rows ) {
7726
+ return _pluck_order( settings.aoData, rows, '_aData' );
7727
+ }, 1 );
7728
+ } );
7729
+
7730
+ _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
7731
+ return this.iterator( 'row', function ( settings, row ) {
7732
+ var r = settings.aoData[ row ];
7733
+ return type === 'search' ? r._aFilterData : r._aSortData;
7734
+ }, 1 );
7735
+ } );
7736
+
7737
+ _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
7738
+ return this.iterator( 'row', function ( settings, row ) {
7739
+ _fnInvalidate( settings, row, src );
7740
+ } );
7741
+ } );
7742
+
7743
+ _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
7744
+ return this.iterator( 'row', function ( settings, row ) {
7745
+ return row;
7746
+ }, 1 );
7747
+ } );
7748
+
7749
+ _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
7750
+ var that = this;
7751
+
7752
+ return this.iterator( 'row', function ( settings, row, thatIdx ) {
7753
+ var data = settings.aoData;
7754
+
7755
+ data.splice( row, 1 );
7756
+
7757
+ // Update the _DT_RowIndex parameter on all rows in the table
7758
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7759
+ if ( data[i].nTr !== null ) {
7760
+ data[i].nTr._DT_RowIndex = i;
7761
+ }
7762
+ }
7763
+
7764
+ // Remove the target row from the search array
7765
+ var displayIndex = $.inArray( row, settings.aiDisplay );
7766
+
7767
+ // Delete from the display arrays
7768
+ _fnDeleteIndex( settings.aiDisplayMaster, row );
7769
+ _fnDeleteIndex( settings.aiDisplay, row );
7770
+ _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
7771
+
7772
+ // Check for an 'overflow' they case for displaying the table
7773
+ _fnLengthOverflow( settings );
7774
+ } );
7775
+ } );
7776
+
7777
+
7778
+ _api_register( 'rows.add()', function ( rows ) {
7779
+ var newRows = this.iterator( 'table', function ( settings ) {
7780
+ var row, i, ien;
7781
+ var out = [];
7782
+
7783
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
7784
+ row = rows[i];
7785
+
7786
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7787
+ out.push( _fnAddTr( settings, row )[0] );
7788
+ }
7789
+ else {
7790
+ out.push( _fnAddData( settings, row ) );
7791
+ }
7792
+ }
7793
+
7794
+ return out;
7795
+ }, 1 );
7796
+
7797
+ // Return an Api.rows() extended instance, so rows().nodes() etc can be used
7798
+ var modRows = this.rows( -1 );
7799
+ modRows.pop();
7800
+ modRows.push.apply( modRows, newRows.toArray() );
7801
+
7802
+ return modRows;
7803
+ } );
7804
+
7805
+
7806
+
7807
+
7808
+
7809
+ /**
7810
+ *
7811
+ */
7812
+ _api_register( 'row()', function ( selector, opts ) {
7813
+ return _selector_first( this.rows( selector, opts ) );
7814
+ } );
7815
+
7816
+
7817
+ _api_register( 'row().data()', function ( data ) {
7818
+ var ctx = this.context;
7819
+
7820
+ if ( data === undefined ) {
7821
+ // Get
7822
+ return ctx.length && this.length ?
7823
+ ctx[0].aoData[ this[0] ]._aData :
7824
+ undefined;
7825
+ }
7826
+
7827
+ // Set
7828
+ ctx[0].aoData[ this[0] ]._aData = data;
7829
+
7830
+ // Automatically invalidate
7831
+ _fnInvalidate( ctx[0], this[0], 'data' );
7832
+
7833
+ return this;
7834
+ } );
7835
+
7836
+
7837
+ _api_register( 'row().node()', function () {
7838
+ var ctx = this.context;
7839
+
7840
+ return ctx.length && this.length ?
7841
+ ctx[0].aoData[ this[0] ].nTr || null :
7842
+ null;
7843
+ } );
7844
+
7845
+
7846
+ _api_register( 'row.add()', function ( row ) {
7847
+ // Allow a jQuery object to be passed in - only a single row is added from
7848
+ // it though - the first element in the set
7849
+ if ( row instanceof $ && row.length ) {
7850
+ row = row[0];
7851
+ }
7852
+
7853
+ var rows = this.iterator( 'table', function ( settings ) {
7854
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
7855
+ return _fnAddTr( settings, row )[0];
7856
+ }
7857
+ return _fnAddData( settings, row );
7858
+ } );
7859
+
7860
+ // Return an Api.rows() extended instance, with the newly added row selected
7861
+ return this.row( rows[0] );
7862
+ } );
7863
+
7864
+
7865
+
7866
+ var __details_add = function ( ctx, row, data, klass )
7867
+ {
7868
+ // Convert to array of TR elements
7869
+ var rows = [];
7870
+ var addRow = function ( r, k ) {
7871
+ // If we get a TR element, then just add it directly - up to the dev
7872
+ // to add the correct number of columns etc
7873
+ if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
7874
+ rows.push( r );
7875
+ }
7876
+ else {
7877
+ // Otherwise create a row with a wrapper
7878
+ var created = $('<tr><td/></tr>').addClass( k );
7879
+ $('td', created)
7880
+ .addClass( k )
7881
+ .html( r )
7882
+ [0].colSpan = _fnVisbleColumns( ctx );
7883
+
7884
+ rows.push( created[0] );
7885
+ }
7886
+ };
7887
+
7888
+ if ( $.isArray( data ) || data instanceof $ ) {
7889
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7890
+ addRow( data[i], klass );
7891
+ }
7892
+ }
7893
+ else {
7894
+ addRow( data, klass );
7895
+ }
7896
+
7897
+ if ( row._details ) {
7898
+ row._details.remove();
7899
+ }
7900
+
7901
+ row._details = $(rows);
7902
+
7903
+ // If the children were already shown, that state should be retained
7904
+ if ( row._detailsShow ) {
7905
+ row._details.insertAfter( row.nTr );
7906
+ }
7907
+ };
7908
+
7909
+
7910
+ var __details_remove = function ( api, idx )
7911
+ {
7912
+ var ctx = api.context;
7913
+
7914
+ if ( ctx.length ) {
7915
+ var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
7916
+
7917
+ if ( row._details ) {
7918
+ row._details.remove();
7919
+
7920
+ row._detailsShow = undefined;
7921
+ row._details = undefined;
7922
+ }
7923
+ }
7924
+ };
7925
+
7926
+
7927
+ var __details_display = function ( api, show ) {
7928
+ var ctx = api.context;
7929
+
7930
+ if ( ctx.length && api.length ) {
7931
+ var row = ctx[0].aoData[ api[0] ];
7932
+
7933
+ if ( row._details ) {
7934
+ row._detailsShow = show;
7935
+
7936
+ if ( show ) {
7937
+ row._details.insertAfter( row.nTr );
7938
+ }
7939
+ else {
7940
+ row._details.detach();
7941
+ }
7942
+
7943
+ __details_events( ctx[0] );
7944
+ }
7945
+ }
7946
+ };
7947
+
7948
+
7949
+ var __details_events = function ( settings )
7950
+ {
7951
+ var api = new _Api( settings );
7952
+ var namespace = '.dt.DT_details';
7953
+ var drawEvent = 'draw'+namespace;
7954
+ var colvisEvent = 'column-visibility'+namespace;
7955
+ var destroyEvent = 'destroy'+namespace;
7956
+ var data = settings.aoData;
7957
+
7958
+ api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
7959
+
7960
+ if ( _pluck( data, '_details' ).length > 0 ) {
7961
+ // On each draw, insert the required elements into the document
7962
+ api.on( drawEvent, function ( e, ctx ) {
7963
+ if ( settings !== ctx ) {
7964
+ return;
7965
+ }
7966
+
7967
+ api.rows( {page:'current'} ).eq(0).each( function (idx) {
7968
+ // Internal data grab
7969
+ var row = data[ idx ];
7970
+
7971
+ if ( row._detailsShow ) {
7972
+ row._details.insertAfter( row.nTr );
7973
+ }
7974
+ } );
7975
+ } );
7976
+
7977
+ // Column visibility change - update the colspan
7978
+ api.on( colvisEvent, function ( e, ctx, idx, vis ) {
7979
+ if ( settings !== ctx ) {
7980
+ return;
7981
+ }
7982
+
7983
+ // Update the colspan for the details rows (note, only if it already has
7984
+ // a colspan)
7985
+ var row, visible = _fnVisbleColumns( ctx );
7986
+
7987
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
7988
+ row = data[i];
7989
+
7990
+ if ( row._details ) {
7991
+ row._details.children('td[colspan]').attr('colspan', visible );
7992
+ }
7993
+ }
7994
+ } );
7995
+
7996
+ // Table destroyed - nuke any child rows
7997
+ api.on( destroyEvent, function ( e, ctx ) {
7998
+ if ( settings !== ctx ) {
7999
+ return;
8000
+ }
8001
+
8002
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
8003
+ if ( data[i]._details ) {
8004
+ __details_remove( api, i );
8005
+ }
8006
+ }
8007
+ } );
8008
+ }
8009
+ };
8010
+
8011
+ // Strings for the method names to help minification
8012
+ var _emp = '';
8013
+ var _child_obj = _emp+'row().child';
8014
+ var _child_mth = _child_obj+'()';
8015
+
8016
+ // data can be:
8017
+ // tr
8018
+ // string
8019
+ // jQuery or array of any of the above
8020
+ _api_register( _child_mth, function ( data, klass ) {
8021
+ var ctx = this.context;
8022
+
8023
+ if ( data === undefined ) {
8024
+ // get
8025
+ return ctx.length && this.length ?
8026
+ ctx[0].aoData[ this[0] ]._details :
8027
+ undefined;
8028
+ }
8029
+ else if ( data === true ) {
8030
+ // show
8031
+ this.child.show();
8032
+ }
8033
+ else if ( data === false ) {
8034
+ // remove
8035
+ __details_remove( this );
8036
+ }
8037
+ else if ( ctx.length && this.length ) {
8038
+ // set
8039
+ __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
8040
+ }
8041
+
8042
+ return this;
8043
+ } );
8044
+
8045
+
8046
+ _api_register( [
8047
+ _child_obj+'.show()',
8048
+ _child_mth+'.show()' // only when `child()` was called with parameters (without
8049
+ ], function ( show ) { // it returns an object and this method is not executed)
8050
+ __details_display( this, true );
8051
+ return this;
8052
+ } );
8053
+
8054
+
8055
+ _api_register( [
8056
+ _child_obj+'.hide()',
8057
+ _child_mth+'.hide()' // only when `child()` was called with parameters (without
8058
+ ], function () { // it returns an object and this method is not executed)
8059
+ __details_display( this, false );
8060
+ return this;
8061
+ } );
8062
+
8063
+
8064
+ _api_register( [
8065
+ _child_obj+'.remove()',
8066
+ _child_mth+'.remove()' // only when `child()` was called with parameters (without
8067
+ ], function () { // it returns an object and this method is not executed)
8068
+ __details_remove( this );
8069
+ return this;
8070
+ } );
8071
+
8072
+
8073
+ _api_register( _child_obj+'.isShown()', function () {
8074
+ var ctx = this.context;
8075
+
8076
+ if ( ctx.length && this.length ) {
8077
+ // _detailsShown as false or undefined will fall through to return false
8078
+ return ctx[0].aoData[ this[0] ]._detailsShow || false;
8079
+ }
8080
+ return false;
8081
+ } );
8082
+
8083
+
8084
+
8085
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
8086
+ * Columns
8087
+ *
8088
+ * {integer} - column index (>=0 count from left, <0 count from right)
8089
+ * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
8090
+ * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
8091
+ * "{string}:name" - column name
8092
+ * "{string}" - jQuery selector on column header nodes
8093
+ *
8094
+ */
8095
+
8096
+ // can be an array of these items, comma separated list, or an array of comma
8097
+ // separated lists
8098
+
8099
+ var __re_column_selector = /^(.+):(name|visIdx|visible)$/;
8100
+
8101
+
8102
+ // r1 and r2 are redundant - but it means that the parameters match for the
8103
+ // iterator callback in columns().data()
8104
+ var __columnData = function ( settings, column, r1, r2, rows ) {
8105
+ var a = [];
8106
+ for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
8107
+ a.push( _fnGetCellData( settings, rows[row], column ) );
8108
+ }
8109
+ return a;
8110
+ };
8111
+
8112
+
8113
+ var __column_selector = function ( settings, selector, opts )
8114
+ {
8115
+ var
8116
+ columns = settings.aoColumns,
8117
+ names = _pluck( columns, 'sName' ),
8118
+ nodes = _pluck( columns, 'nTh' );
8119
+
8120
+ return _selector_run( selector, function ( s ) {
8121
+ var selInt = _intVal( s );
8122
+
8123
+ // Selector - all
8124
+ if ( s === '' ) {
8125
+ return _range( columns.length );
8126
+ }
8127
+
8128
+ // Selector - index
8129
+ if ( selInt !== null ) {
8130
+ return [ selInt >= 0 ?
8131
+ selInt : // Count from left
8132
+ columns.length + selInt // Count from right (+ because its a negative value)
8133
+ ];
8134
+ }
8135
+
8136
+ // Selector = function
8137
+ if ( typeof s === 'function' ) {
8138
+ var rows = _selector_row_indexes( settings, opts );
8139
+
8140
+ return $.map( columns, function (col, idx) {
8141
+ return s(
8142
+ idx,
8143
+ __columnData( settings, idx, 0, 0, rows ),
8144
+ nodes[ idx ]
8145
+ ) ? idx : null;
8146
+ } );
8147
+ }
8148
+
8149
+ // jQuery or string selector
8150
+ var match = typeof s === 'string' ?
8151
+ s.match( __re_column_selector ) :
8152
+ '';
8153
+
8154
+ if ( match ) {
8155
+ switch( match[2] ) {
8156
+ case 'visIdx':
8157
+ case 'visible':
8158
+ var idx = parseInt( match[1], 10 );
8159
+ // Visible index given, convert to column index
8160
+ if ( idx < 0 ) {
8161
+ // Counting from the right
8162
+ var visColumns = $.map( columns, function (col,i) {
8163
+ return col.bVisible ? i : null;
8164
+ } );
8165
+ return [ visColumns[ visColumns.length + idx ] ];
8166
+ }
8167
+ // Counting from the left
8168
+ return [ _fnVisibleToColumnIndex( settings, idx ) ];
8169
+
8170
+ case 'name':
8171
+ // match by name. `names` is column index complete and in order
8172
+ return $.map( names, function (name, i) {
8173
+ return name === match[1] ? i : null;
8174
+ } );
8175
+ }
8176
+ }
8177
+ else {
8178
+ // jQuery selector on the TH elements for the columns
8179
+ return $( nodes )
8180
+ .filter( s )
8181
+ .map( function () {
8182
+ return $.inArray( this, nodes ); // `nodes` is column index complete and in order
8183
+ } )
8184
+ .toArray();
8185
+ }
8186
+ } );
8187
+ };
8188
+
8189
+
8190
+ var __setColumnVis = function ( settings, column, vis, recalc ) {
8191
+ var
8192
+ cols = settings.aoColumns,
8193
+ col = cols[ column ],
8194
+ data = settings.aoData,
8195
+ row, cells, i, ien, tr;
8196
+
8197
+ // Get
8198
+ if ( vis === undefined ) {
8199
+ return col.bVisible;
8200
+ }
8201
+
8202
+ // Set
8203
+ // No change
8204
+ if ( col.bVisible === vis ) {
8205
+ return;
8206
+ }
8207
+
8208
+ if ( vis ) {
8209
+ // Insert column
8210
+ // Need to decide if we should use appendChild or insertBefore
8211
+ var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
8212
+
8213
+ for ( i=0, ien=data.length ; i<ien ; i++ ) {
8214
+ tr = data[i].nTr;
8215
+ cells = data[i].anCells;
8216
+
8217
+ if ( tr ) {
8218
+ // insertBefore can act like appendChild if 2nd arg is null
8219
+ tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
8220
+ }
8221
+ }
8222
+ }
8223
+ else {
8224
+ // Remove column
8225
+ $( _pluck( settings.aoData, 'anCells', column ) ).detach();
8226
+ }
8227
+
8228
+ // Common actions
8229
+ col.bVisible = vis;
8230
+ _fnDrawHead( settings, settings.aoHeader );
8231
+ _fnDrawHead( settings, settings.aoFooter );
8232
+
8233
+ if ( recalc === undefined || recalc ) {
8234
+ // Automatically adjust column sizing
8235
+ _fnAdjustColumnSizing( settings );
8236
+
8237
+ // Realign columns for scrolling
8238
+ if ( settings.oScroll.sX || settings.oScroll.sY ) {
8239
+ _fnScrollDraw( settings );
8240
+ }
8241
+ }
8242
+
8243
+ _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis] );
8244
+
8245
+ _fnSaveState( settings );
8246
+ };
8247
+
8248
+
8249
+ /**
8250
+ *
8251
+ */
8252
+ _api_register( 'columns()', function ( selector, opts ) {
8253
+ // argument shifting
8254
+ if ( selector === undefined ) {
8255
+ selector = '';
8256
+ }
8257
+ else if ( $.isPlainObject( selector ) ) {
8258
+ opts = selector;
8259
+ selector = '';
8260
+ }
8261
+
8262
+ opts = _selector_opts( opts );
8263
+
8264
+ var inst = this.iterator( 'table', function ( settings ) {
8265
+ return __column_selector( settings, selector, opts );
8266
+ }, 1 );
8267
+
8268
+ // Want argument shifting here and in _row_selector?
8269
+ inst.selector.cols = selector;
8270
+ inst.selector.opts = opts;
8271
+
8272
+ return inst;
8273
+ } );
8274
+
8275
+
8276
+ /**
8277
+ *
8278
+ */
8279
+ _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
8280
+ return this.iterator( 'column', function ( settings, column ) {
8281
+ return settings.aoColumns[column].nTh;
8282
+ }, 1 );
8283
+ } );
8284
+
8285
+
8286
+ /**
8287
+ *
8288
+ */
8289
+ _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
8290
+ return this.iterator( 'column', function ( settings, column ) {
8291
+ return settings.aoColumns[column].nTf;
8292
+ }, 1 );
8293
+ } );
8294
+
8295
+
8296
+ /**
8297
+ *
8298
+ */
8299
+ _api_registerPlural( 'columns().data()', 'column().data()', function () {
8300
+ return this.iterator( 'column-rows', __columnData, 1 );
8301
+ } );
8302
+
8303
+
8304
+ _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
8305
+ return this.iterator( 'column', function ( settings, column ) {
8306
+ return settings.aoColumns[column].mData;
8307
+ }, 1 );
8308
+ } );
8309
+
8310
+
8311
+ _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
8312
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8313
+ return _pluck_order( settings.aoData, rows,
8314
+ type === 'search' ? '_aFilterData' : '_aSortData', column
8315
+ );
8316
+ }, 1 );
8317
+ } );
8318
+
8319
+
8320
+ _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
8321
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
8322
+ return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
8323
+ }, 1 );
8324
+ } );
8325
+
8326
+
8327
+
8328
+ _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
8329
+ return this.iterator( 'column', function ( settings, column ) {
8330
+ if ( vis === undefined ) {
8331
+ return settings.aoColumns[ column ].bVisible;
8332
+ } // else
8333
+ __setColumnVis( settings, column, vis, calc );
8334
+ } );
8335
+ } );
8336
+
8337
+
8338
+
8339
+ _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
8340
+ return this.iterator( 'column', function ( settings, column ) {
8341
+ return type === 'visible' ?
8342
+ _fnColumnIndexToVisible( settings, column ) :
8343
+ column;
8344
+ }, 1 );
8345
+ } );
8346
+
8347
+
8348
+ // _api_register( 'columns().show()', function () {
8349
+ // var selector = this.selector;
8350
+ // return this.columns( selector.cols, selector.opts ).visible( true );
8351
+ // } );
8352
+
8353
+
8354
+ // _api_register( 'columns().hide()', function () {
8355
+ // var selector = this.selector;
8356
+ // return this.columns( selector.cols, selector.opts ).visible( false );
8357
+ // } );
8358
+
8359
+
8360
+
8361
+ _api_register( 'columns.adjust()', function () {
8362
+ return this.iterator( 'table', function ( settings ) {
8363
+ _fnAdjustColumnSizing( settings );
8364
+ }, 1 );
8365
+ } );
8366
+
8367
+
8368
+ // Convert from one column index type, to another type
8369
+ _api_register( 'column.index()', function ( type, idx ) {
8370
+ if ( this.context.length !== 0 ) {
8371
+ var ctx = this.context[0];
8372
+
8373
+ if ( type === 'fromVisible' || type === 'toData' ) {
8374
+ return _fnVisibleToColumnIndex( ctx, idx );
8375
+ }
8376
+ else if ( type === 'fromData' || type === 'toVisible' ) {
8377
+ return _fnColumnIndexToVisible( ctx, idx );
8378
+ }
8379
+ }
8380
+ } );
8381
+
8382
+
8383
+ _api_register( 'column()', function ( selector, opts ) {
8384
+ return _selector_first( this.columns( selector, opts ) );
8385
+ } );
8386
+
8387
+
8388
+
8389
+
8390
+ var __cell_selector = function ( settings, selector, opts )
8391
+ {
8392
+ var data = settings.aoData;
8393
+ var rows = _selector_row_indexes( settings, opts );
8394
+ var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
8395
+ var allCells = $( [].concat.apply([], cells) );
8396
+ var row;
8397
+ var columns = settings.aoColumns.length;
8398
+ var a, i, ien, j, o, host;
8399
+
8400
+ return _selector_run( selector, function ( s ) {
8401
+ var fnSelector = typeof s === 'function';
8402
+
8403
+ if ( s === null || s === undefined || fnSelector ) {
8404
+ // All cells and function selectors
8405
+ a = [];
8406
+
8407
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
8408
+ row = rows[i];
8409
+
8410
+ for ( j=0 ; j<columns ; j++ ) {
8411
+ o = {
8412
+ row: row,
8413
+ column: j
8414
+ };
8415
+
8416
+ if ( fnSelector ) {
8417
+ // Selector - function
8418
+ host = settings.aoData[ row ];
8419
+
8420
+ if ( s( o, _fnGetCellData(settings, row, j), host.anCells[j] ) ) {
8421
+ a.push( o );
8422
+ }
8423
+ }
8424
+ else {
8425
+ // Selector - all
8426
+ a.push( o );
8427
+ }
8428
+ }
8429
+ }
8430
+
8431
+ return a;
8432
+ }
8433
+
8434
+ // Selector - index
8435
+ if ( $.isPlainObject( s ) ) {
8436
+ return [s];
8437
+ }
8438
+
8439
+ // Selector - jQuery filtered cells
8440
+ return allCells
8441
+ .filter( s )
8442
+ .map( function (i, el) {
8443
+ row = el.parentNode._DT_RowIndex;
8444
+
8445
+ return {
8446
+ row: row,
8447
+ column: $.inArray( el, data[ row ].anCells )
8448
+ };
8449
+ } )
8450
+ .toArray();
8451
+ } );
8452
+ };
8453
+
8454
+
8455
+
8456
+
8457
+ _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
8458
+ // Argument shifting
8459
+ if ( $.isPlainObject( rowSelector ) ) {
8460
+ // Indexes
8461
+ if ( typeof rowSelector.row !== undefined ) {
8462
+ opts = columnSelector;
8463
+ columnSelector = null;
8464
+ }
8465
+ else {
8466
+ opts = rowSelector;
8467
+ rowSelector = null;
8468
+ }
8469
+ }
8470
+ if ( $.isPlainObject( columnSelector ) ) {
8471
+ opts = columnSelector;
8472
+ columnSelector = null;
8473
+ }
8474
+
8475
+ // Cell selector
8476
+ if ( columnSelector === null || columnSelector === undefined ) {
8477
+ return this.iterator( 'table', function ( settings ) {
8478
+ return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
8479
+ } );
8480
+ }
8481
+
8482
+ // Row + column selector
8483
+ var columns = this.columns( columnSelector, opts );
8484
+ var rows = this.rows( rowSelector, opts );
8485
+ var a, i, ien, j, jen;
8486
+
8487
+ var cells = this.iterator( 'table', function ( settings, idx ) {
8488
+ a = [];
8489
+
8490
+ for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
8491
+ for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
8492
+ a.push( {
8493
+ row: rows[idx][i],
8494
+ column: columns[idx][j]
8495
+ } );
8496
+ }
8497
+ }
8498
+
8499
+ return a;
8500
+ }, 1 );
8501
+
8502
+ $.extend( cells.selector, {
8503
+ cols: columnSelector,
8504
+ rows: rowSelector,
8505
+ opts: opts
8506
+ } );
8507
+
8508
+ return cells;
8509
+ } );
8510
+
8511
+
8512
+ _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
8513
+ return this.iterator( 'cell', function ( settings, row, column ) {
8514
+ var cells = settings.aoData[ row ].anCells;
8515
+ return cells ?
8516
+ cells[ column ] :
8517
+ undefined;
8518
+ }, 1 );
8519
+ } );
8520
+
8521
+
8522
+ _api_register( 'cells().data()', function () {
8523
+ return this.iterator( 'cell', function ( settings, row, column ) {
8524
+ return _fnGetCellData( settings, row, column );
8525
+ }, 1 );
8526
+ } );
8527
+
8528
+
8529
+ _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
8530
+ type = type === 'search' ? '_aFilterData' : '_aSortData';
8531
+
8532
+ return this.iterator( 'cell', function ( settings, row, column ) {
8533
+ return settings.aoData[ row ][ type ][ column ];
8534
+ }, 1 );
8535
+ } );
8536
+
8537
+
8538
+ _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
8539
+ return this.iterator( 'cell', function ( settings, row, column ) {
8540
+ return _fnGetCellData( settings, row, column, type );
8541
+ }, 1 );
8542
+ } );
8543
+
8544
+
8545
+ _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
8546
+ return this.iterator( 'cell', function ( settings, row, column ) {
8547
+ return {
8548
+ row: row,
8549
+ column: column,
8550
+ columnVisible: _fnColumnIndexToVisible( settings, column )
8551
+ };
8552
+ }, 1 );
8553
+ } );
8554
+
8555
+
8556
+ _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
8557
+ return this.iterator( 'cell', function ( settings, row, column ) {
8558
+ _fnInvalidate( settings, row, src, column );
8559
+ } );
8560
+ } );
8561
+
8562
+
8563
+
8564
+ _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
8565
+ return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
8566
+ } );
8567
+
8568
+
8569
+ _api_register( 'cell().data()', function ( data ) {
8570
+ var ctx = this.context;
8571
+ var cell = this[0];
8572
+
8573
+ if ( data === undefined ) {
8574
+ // Get
8575
+ return ctx.length && cell.length ?
8576
+ _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
8577
+ undefined;
8578
+ }
8579
+
8580
+ // Set
8581
+ _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
8582
+ _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
8583
+
8584
+ return this;
8585
+ } );
8586
+
8587
+
8588
+
8589
+ /**
8590
+ * Get current ordering (sorting) that has been applied to the table.
8591
+ *
8592
+ * @returns {array} 2D array containing the sorting information for the first
8593
+ * table in the current context. Each element in the parent array represents
8594
+ * a column being sorted upon (i.e. multi-sorting with two columns would have
8595
+ * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
8596
+ * the column index that the sorting condition applies to, the second is the
8597
+ * direction of the sort (`desc` or `asc`) and, optionally, the third is the
8598
+ * index of the sorting order from the `column.sorting` initialisation array.
8599
+ *//**
8600
+ * Set the ordering for the table.
8601
+ *
8602
+ * @param {integer} order Column index to sort upon.
8603
+ * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
8604
+ * @returns {DataTables.Api} this
8605
+ *//**
8606
+ * Set the ordering for the table.
8607
+ *
8608
+ * @param {array} order 1D array of sorting information to be applied.
8609
+ * @param {array} [...] Optional additional sorting conditions
8610
+ * @returns {DataTables.Api} this
8611
+ *//**
8612
+ * Set the ordering for the table.
8613
+ *
8614
+ * @param {array} order 2D array of sorting information to be applied.
8615
+ * @returns {DataTables.Api} this
8616
+ */
8617
+ _api_register( 'order()', function ( order, dir ) {
8618
+ var ctx = this.context;
8619
+
8620
+ if ( order === undefined ) {
8621
+ // get
8622
+ return ctx.length !== 0 ?
8623
+ ctx[0].aaSorting :
8624
+ undefined;
8625
+ }
8626
+
8627
+ // set
8628
+ if ( typeof order === 'number' ) {
8629
+ // Simple column / direction passed in
8630
+ order = [ [ order, dir ] ];
8631
+ }
8632
+ else if ( ! $.isArray( order[0] ) ) {
8633
+ // Arguments passed in (list of 1D arrays)
8634
+ order = Array.prototype.slice.call( arguments );
8635
+ }
8636
+ // otherwise a 2D array was passed in
8637
+
8638
+ return this.iterator( 'table', function ( settings ) {
8639
+ settings.aaSorting = order.slice();
8640
+ } );
8641
+ } );
8642
+
8643
+
8644
+ /**
8645
+ * Attach a sort listener to an element for a given column
8646
+ *
8647
+ * @param {node|jQuery|string} node Identifier for the element(s) to attach the
8648
+ * listener to. This can take the form of a single DOM node, a jQuery
8649
+ * collection of nodes or a jQuery selector which will identify the node(s).
8650
+ * @param {integer} column the column that a click on this node will sort on
8651
+ * @param {function} [callback] callback function when sort is run
8652
+ * @returns {DataTables.Api} this
8653
+ */
8654
+ _api_register( 'order.listener()', function ( node, column, callback ) {
8655
+ return this.iterator( 'table', function ( settings ) {
8656
+ _fnSortAttachListener( settings, node, column, callback );
8657
+ } );
8658
+ } );
8659
+
8660
+
8661
+ // Order by the selected column(s)
8662
+ _api_register( [
8663
+ 'columns().order()',
8664
+ 'column().order()'
8665
+ ], function ( dir ) {
8666
+ var that = this;
8667
+
8668
+ return this.iterator( 'table', function ( settings, i ) {
8669
+ var sort = [];
8670
+
8671
+ $.each( that[i], function (j, col) {
8672
+ sort.push( [ col, dir ] );
8673
+ } );
8674
+
8675
+ settings.aaSorting = sort;
8676
+ } );
8677
+ } );
8678
+
8679
+
8680
+
8681
+ _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
8682
+ var ctx = this.context;
8683
+
8684
+ if ( input === undefined ) {
8685
+ // get
8686
+ return ctx.length !== 0 ?
8687
+ ctx[0].oPreviousSearch.sSearch :
8688
+ undefined;
8689
+ }
8690
+
8691
+ // set
8692
+ return this.iterator( 'table', function ( settings ) {
8693
+ if ( ! settings.oFeatures.bFilter ) {
8694
+ return;
8695
+ }
8696
+
8697
+ _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
8698
+ "sSearch": input+"",
8699
+ "bRegex": regex === null ? false : regex,
8700
+ "bSmart": smart === null ? true : smart,
8701
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
8702
+ } ), 1 );
8703
+ } );
8704
+ } );
8705
+
8706
+
8707
+ _api_registerPlural(
8708
+ 'columns().search()',
8709
+ 'column().search()',
8710
+ function ( input, regex, smart, caseInsen ) {
8711
+ return this.iterator( 'column', function ( settings, column ) {
8712
+ var preSearch = settings.aoPreSearchCols;
8713
+
8714
+ if ( input === undefined ) {
8715
+ // get
8716
+ return preSearch[ column ].sSearch;
8717
+ }
8718
+
8719
+ // set
8720
+ if ( ! settings.oFeatures.bFilter ) {
8721
+ return;
8722
+ }
8723
+
8724
+ $.extend( preSearch[ column ], {
8725
+ "sSearch": input+"",
8726
+ "bRegex": regex === null ? false : regex,
8727
+ "bSmart": smart === null ? true : smart,
8728
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
8729
+ } );
8730
+
8731
+ _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
8732
+ } );
8733
+ }
8734
+ );
8735
+
8736
+ /*
8737
+ * State API methods
8738
+ */
8739
+
8740
+ _api_register( 'state()', function () {
8741
+ return this.context.length ?
8742
+ this.context[0].oSavedState :
8743
+ null;
8744
+ } );
8745
+
8746
+
8747
+ _api_register( 'state.clear()', function () {
8748
+ return this.iterator( 'table', function ( settings ) {
8749
+ // Save an empty object
8750
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
8751
+ } );
8752
+ } );
8753
+
8754
+
8755
+ _api_register( 'state.loaded()', function () {
8756
+ return this.context.length ?
8757
+ this.context[0].oLoadedState :
8758
+ null;
8759
+ } );
8760
+
8761
+
8762
+ _api_register( 'state.save()', function () {
8763
+ return this.iterator( 'table', function ( settings ) {
8764
+ _fnSaveState( settings );
8765
+ } );
8766
+ } );
8767
+
8768
+
8769
+
8770
+ /**
8771
+ * Provide a common method for plug-ins to check the version of DataTables being
8772
+ * used, in order to ensure compatibility.
8773
+ *
8774
+ * @param {string} version Version string to check for, in the format "X.Y.Z".
8775
+ * Note that the formats "X" and "X.Y" are also acceptable.
8776
+ * @returns {boolean} true if this version of DataTables is greater or equal to
8777
+ * the required version, or false if this version of DataTales is not
8778
+ * suitable
8779
+ * @static
8780
+ * @dtopt API-Static
8781
+ *
8782
+ * @example
8783
+ * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
8784
+ */
8785
+ DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
8786
+ {
8787
+ var aThis = DataTable.version.split('.');
8788
+ var aThat = version.split('.');
8789
+ var iThis, iThat;
8790
+
8791
+ for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
8792
+ iThis = parseInt( aThis[i], 10 ) || 0;
8793
+ iThat = parseInt( aThat[i], 10 ) || 0;
8794
+
8795
+ // Parts are the same, keep comparing
8796
+ if (iThis === iThat) {
8797
+ continue;
8798
+ }
8799
+
8800
+ // Parts are different, return immediately
8801
+ return iThis > iThat;
8802
+ }
8803
+
8804
+ return true;
8805
+ };
8806
+
8807
+
8808
+ /**
8809
+ * Check if a `<table>` node is a DataTable table already or not.
8810
+ *
8811
+ * @param {node|jquery|string} table Table node, jQuery object or jQuery
8812
+ * selector for the table to test. Note that if more than more than one
8813
+ * table is passed on, only the first will be checked
8814
+ * @returns {boolean} true the table given is a DataTable, or false otherwise
8815
+ * @static
8816
+ * @dtopt API-Static
8817
+ *
8818
+ * @example
8819
+ * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
8820
+ * $('#example').dataTable();
8821
+ * }
8822
+ */
8823
+ DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
8824
+ {
8825
+ var t = $(table).get(0);
8826
+ var is = false;
8827
+
8828
+ $.each( DataTable.settings, function (i, o) {
8829
+ if ( o.nTable === t || o.nScrollHead === t || o.nScrollFoot === t ) {
8830
+ is = true;
8831
+ }
8832
+ } );
8833
+
8834
+ return is;
8835
+ };
8836
+
8837
+
8838
+ /**
8839
+ * Get all DataTable tables that have been initialised - optionally you can
8840
+ * select to get only currently visible tables.
8841
+ *
8842
+ * @param {boolean} [visible=false] Flag to indicate if you want all (default)
8843
+ * or visible tables only.
8844
+ * @returns {array} Array of `table` nodes (not DataTable instances) which are
8845
+ * DataTables
8846
+ * @static
8847
+ * @dtopt API-Static
8848
+ *
8849
+ * @example
8850
+ * $.each( $.fn.dataTable.tables(true), function () {
8851
+ * $(table).DataTable().columns.adjust();
8852
+ * } );
8853
+ */
8854
+ DataTable.tables = DataTable.fnTables = function ( visible )
8855
+ {
8856
+ return $.map( DataTable.settings, function (o) {
8857
+ if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
8858
+ return o.nTable;
8859
+ }
8860
+ } );
8861
+ };
8862
+
8863
+
8864
+ /**
8865
+ * DataTables utility methods
8866
+ *
8867
+ * This namespace provides helper methods that DataTables uses internally to
8868
+ * create a DataTable, but which are not exclusively used only for DataTables.
8869
+ * These methods can be used by extension authors to save the duplication of
8870
+ * code.
8871
+ *
8872
+ * @namespace
8873
+ */
8874
+ DataTable.util = {
8875
+ /**
8876
+ * Throttle the calls to a function. Arguments and context are maintained
8877
+ * for the throttled function.
8878
+ *
8879
+ * @param {function} fn Function to be called
8880
+ * @param {integer} freq Call frequency in mS
8881
+ * @return {function} Wrapped function
8882
+ */
8883
+ throttle: _fnThrottle,
8884
+
8885
+
8886
+ /**
8887
+ * Escape a string such that it can be used in a regular expression
8888
+ *
8889
+ * @param {string} sVal string to escape
8890
+ * @returns {string} escaped string
8891
+ */
8892
+ escapeRegex: _fnEscapeRegex
8893
+ };
8894
+
8895
+
8896
+ /**
8897
+ * Convert from camel case parameters to Hungarian notation. This is made public
8898
+ * for the extensions to provide the same ability as DataTables core to accept
8899
+ * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
8900
+ * parameters.
8901
+ *
8902
+ * @param {object} src The model object which holds all parameters that can be
8903
+ * mapped.
8904
+ * @param {object} user The object to convert from camel case to Hungarian.
8905
+ * @param {boolean} force When set to `true`, properties which already have a
8906
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
8907
+ * won't be.
8908
+ */
8909
+ DataTable.camelToHungarian = _fnCamelToHungarian;
8910
+
8911
+
8912
+
8913
+ /**
8914
+ *
8915
+ */
8916
+ _api_register( '$()', function ( selector, opts ) {
8917
+ var
8918
+ rows = this.rows( opts ).nodes(), // Get all rows
8919
+ jqRows = $(rows);
8920
+
8921
+ return $( [].concat(
8922
+ jqRows.filter( selector ).toArray(),
8923
+ jqRows.find( selector ).toArray()
8924
+ ) );
8925
+ } );
8926
+
8927
+
8928
+ // jQuery functions to operate on the tables
8929
+ $.each( [ 'on', 'one', 'off' ], function (i, key) {
8930
+ _api_register( key+'()', function ( /* event, handler */ ) {
8931
+ var args = Array.prototype.slice.call(arguments);
8932
+
8933
+ // Add the `dt` namespace automatically if it isn't already present
8934
+ if ( ! args[0].match(/\.dt\b/) ) {
8935
+ args[0] += '.dt';
8936
+ }
8937
+
8938
+ var inst = $( this.tables().nodes() );
8939
+ inst[key].apply( inst, args );
8940
+ return this;
8941
+ } );
8942
+ } );
8943
+
8944
+
8945
+ _api_register( 'clear()', function () {
8946
+ return this.iterator( 'table', function ( settings ) {
8947
+ _fnClearTable( settings );
8948
+ } );
8949
+ } );
8950
+
8951
+
8952
+ _api_register( 'settings()', function () {
8953
+ return new _Api( this.context, this.context );
8954
+ } );
8955
+
8956
+
8957
+ _api_register( 'data()', function () {
8958
+ return this.iterator( 'table', function ( settings ) {
8959
+ return _pluck( settings.aoData, '_aData' );
8960
+ } ).flatten();
8961
+ } );
8962
+
8963
+
8964
+ _api_register( 'destroy()', function ( remove ) {
8965
+ remove = remove || false;
8966
+
8967
+ return this.iterator( 'table', function ( settings ) {
8968
+ var orig = settings.nTableWrapper.parentNode;
8969
+ var classes = settings.oClasses;
8970
+ var table = settings.nTable;
8971
+ var tbody = settings.nTBody;
8972
+ var thead = settings.nTHead;
8973
+ var tfoot = settings.nTFoot;
8974
+ var jqTable = $(table);
8975
+ var jqTbody = $(tbody);
8976
+ var jqWrapper = $(settings.nTableWrapper);
8977
+ var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
8978
+ var i, ien;
8979
+
8980
+ // Flag to note that the table is currently being destroyed - no action
8981
+ // should be taken
8982
+ settings.bDestroying = true;
8983
+
8984
+ // Fire off the destroy callbacks for plug-ins etc
8985
+ _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
8986
+
8987
+ // If not being removed from the document, make all columns visible
8988
+ if ( ! remove ) {
8989
+ new _Api( settings ).columns().visible( true );
8990
+ }
8991
+
8992
+ // Blitz all `DT` namespaced events (these are internal events, the
8993
+ // lowercase, `dt` events are user subscribed and they are responsible
8994
+ // for removing them
8995
+ jqWrapper.unbind('.DT').find(':not(tbody *)').unbind('.DT');
8996
+ $(window).unbind('.DT-'+settings.sInstance);
8997
+
8998
+ // When scrolling we had to break the table up - restore it
8999
+ if ( table != thead.parentNode ) {
9000
+ jqTable.children('thead').detach();
9001
+ jqTable.append( thead );
9002
+ }
9003
+
9004
+ if ( tfoot && table != tfoot.parentNode ) {
9005
+ jqTable.children('tfoot').detach();
9006
+ jqTable.append( tfoot );
9007
+ }
9008
+
9009
+ // Remove the DataTables generated nodes, events and classes
9010
+ jqTable.detach();
9011
+ jqWrapper.detach();
9012
+
9013
+ settings.aaSorting = [];
9014
+ settings.aaSortingFixed = [];
9015
+ _fnSortingClasses( settings );
9016
+
9017
+ $( rows ).removeClass( settings.asStripeClasses.join(' ') );
9018
+
9019
+ $('th, td', thead).removeClass( classes.sSortable+' '+
9020
+ classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
9021
+ );
9022
+
9023
+ if ( settings.bJUI ) {
9024
+ $('th span.'+classes.sSortIcon+ ', td span.'+classes.sSortIcon, thead).detach();
9025
+ $('th, td', thead).each( function () {
9026
+ var wrapper = $('div.'+classes.sSortJUIWrapper, this);
9027
+ $(this).append( wrapper.contents() );
9028
+ wrapper.detach();
9029
+ } );
9030
+ }
9031
+
9032
+ if ( ! remove && orig ) {
9033
+ // insertBefore acts like appendChild if !arg[1]
9034
+ orig.insertBefore( table, settings.nTableReinsertBefore );
9035
+ }
9036
+
9037
+ // Add the TR elements back into the table in their original order
9038
+ jqTbody.children().detach();
9039
+ jqTbody.append( rows );
9040
+
9041
+ // Restore the width of the original table - was read from the style property,
9042
+ // so we can restore directly to that
9043
+ jqTable
9044
+ .css( 'width', settings.sDestroyWidth )
9045
+ .removeClass( classes.sTable );
9046
+
9047
+ // If the were originally stripe classes - then we add them back here.
9048
+ // Note this is not fool proof (for example if not all rows had stripe
9049
+ // classes - but it's a good effort without getting carried away
9050
+ ien = settings.asDestroyStripes.length;
9051
+
9052
+ if ( ien ) {
9053
+ jqTbody.children().each( function (i) {
9054
+ $(this).addClass( settings.asDestroyStripes[i % ien] );
9055
+ } );
9056
+ }
9057
+
9058
+ /* Remove the settings object from the settings array */
9059
+ var idx = $.inArray( settings, DataTable.settings );
9060
+ if ( idx !== -1 ) {
9061
+ DataTable.settings.splice( idx, 1 );
9062
+ }
9063
+ } );
9064
+ } );
9065
+
9066
+
9067
+ /**
9068
+ * Version string for plug-ins to check compatibility. Allowed format is
9069
+ * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
9070
+ * only for non-release builds. See http://semver.org/ for more information.
9071
+ * @member
9072
+ * @type string
9073
+ * @default Version number
9074
+ */
9075
+ DataTable.version = "1.10.4";
9076
+
9077
+ /**
9078
+ * Private data store, containing all of the settings objects that are
9079
+ * created for the tables on a given page.
9080
+ *
9081
+ * Note that the `DataTable.settings` object is aliased to
9082
+ * `jQuery.fn.dataTableExt` through which it may be accessed and
9083
+ * manipulated, or `jQuery.fn.dataTable.settings`.
9084
+ * @member
9085
+ * @type array
9086
+ * @default []
9087
+ * @private
9088
+ */
9089
+ DataTable.settings = [];
9090
+
9091
+ /**
9092
+ * Object models container, for the various models that DataTables has
9093
+ * available to it. These models define the objects that are used to hold
9094
+ * the active state and configuration of the table.
9095
+ * @namespace
9096
+ */
9097
+ DataTable.models = {};
9098
+
9099
+
9100
+
9101
+ /**
9102
+ * Template object for the way in which DataTables holds information about
9103
+ * search information for the global filter and individual column filters.
9104
+ * @namespace
9105
+ */
9106
+ DataTable.models.oSearch = {
9107
+ /**
9108
+ * Flag to indicate if the filtering should be case insensitive or not
9109
+ * @type boolean
9110
+ * @default true
9111
+ */
9112
+ "bCaseInsensitive": true,
9113
+
9114
+ /**
9115
+ * Applied search term
9116
+ * @type string
9117
+ * @default <i>Empty string</i>
9118
+ */
9119
+ "sSearch": "",
9120
+
9121
+ /**
9122
+ * Flag to indicate if the search term should be interpreted as a
9123
+ * regular expression (true) or not (false) and therefore and special
9124
+ * regex characters escaped.
9125
+ * @type boolean
9126
+ * @default false
9127
+ */
9128
+ "bRegex": false,
9129
+
9130
+ /**
9131
+ * Flag to indicate if DataTables is to use its smart filtering or not.
9132
+ * @type boolean
9133
+ * @default true
9134
+ */
9135
+ "bSmart": true
9136
+ };
9137
+
9138
+
9139
+
9140
+
9141
+ /**
9142
+ * Template object for the way in which DataTables holds information about
9143
+ * each individual row. This is the object format used for the settings
9144
+ * aoData array.
9145
+ * @namespace
9146
+ */
9147
+ DataTable.models.oRow = {
9148
+ /**
9149
+ * TR element for the row
9150
+ * @type node
9151
+ * @default null
9152
+ */
9153
+ "nTr": null,
9154
+
9155
+ /**
9156
+ * Array of TD elements for each row. This is null until the row has been
9157
+ * created.
9158
+ * @type array nodes
9159
+ * @default []
9160
+ */
9161
+ "anCells": null,
9162
+
9163
+ /**
9164
+ * Data object from the original data source for the row. This is either
9165
+ * an array if using the traditional form of DataTables, or an object if
9166
+ * using mData options. The exact type will depend on the passed in
9167
+ * data from the data source, or will be an array if using DOM a data
9168
+ * source.
9169
+ * @type array|object
9170
+ * @default []
9171
+ */
9172
+ "_aData": [],
9173
+
9174
+ /**
9175
+ * Sorting data cache - this array is ostensibly the same length as the
9176
+ * number of columns (although each index is generated only as it is
9177
+ * needed), and holds the data that is used for sorting each column in the
9178
+ * row. We do this cache generation at the start of the sort in order that
9179
+ * the formatting of the sort data need be done only once for each cell
9180
+ * per sort. This array should not be read from or written to by anything
9181
+ * other than the master sorting methods.
9182
+ * @type array
9183
+ * @default null
9184
+ * @private
9185
+ */
9186
+ "_aSortData": null,
9187
+
9188
+ /**
9189
+ * Per cell filtering data cache. As per the sort data cache, used to
9190
+ * increase the performance of the filtering in DataTables
9191
+ * @type array
9192
+ * @default null
9193
+ * @private
9194
+ */
9195
+ "_aFilterData": null,
9196
+
9197
+ /**
9198
+ * Filtering data cache. This is the same as the cell filtering cache, but
9199
+ * in this case a string rather than an array. This is easily computed with
9200
+ * a join on `_aFilterData`, but is provided as a cache so the join isn't
9201
+ * needed on every search (memory traded for performance)
9202
+ * @type array
9203
+ * @default null
9204
+ * @private
9205
+ */
9206
+ "_sFilterRow": null,
9207
+
9208
+ /**
9209
+ * Cache of the class name that DataTables has applied to the row, so we
9210
+ * can quickly look at this variable rather than needing to do a DOM check
9211
+ * on className for the nTr property.
9212
+ * @type string
9213
+ * @default <i>Empty string</i>
9214
+ * @private
9215
+ */
9216
+ "_sRowStripe": "",
9217
+
9218
+ /**
9219
+ * Denote if the original data source was from the DOM, or the data source
9220
+ * object. This is used for invalidating data, so DataTables can
9221
+ * automatically read data from the original source, unless uninstructed
9222
+ * otherwise.
9223
+ * @type string
9224
+ * @default null
9225
+ * @private
9226
+ */
9227
+ "src": null
9228
+ };
9229
+
9230
+
9231
+ /**
9232
+ * Template object for the column information object in DataTables. This object
9233
+ * is held in the settings aoColumns array and contains all the information that
9234
+ * DataTables needs about each individual column.
9235
+ *
9236
+ * Note that this object is related to {@link DataTable.defaults.column}
9237
+ * but this one is the internal data store for DataTables's cache of columns.
9238
+ * It should NOT be manipulated outside of DataTables. Any configuration should
9239
+ * be done through the initialisation options.
9240
+ * @namespace
9241
+ */
9242
+ DataTable.models.oColumn = {
9243
+ /**
9244
+ * Column index. This could be worked out on-the-fly with $.inArray, but it
9245
+ * is faster to just hold it as a variable
9246
+ * @type integer
9247
+ * @default null
9248
+ */
9249
+ "idx": null,
9250
+
9251
+ /**
9252
+ * A list of the columns that sorting should occur on when this column
9253
+ * is sorted. That this property is an array allows multi-column sorting
9254
+ * to be defined for a column (for example first name / last name columns
9255
+ * would benefit from this). The values are integers pointing to the
9256
+ * columns to be sorted on (typically it will be a single integer pointing
9257
+ * at itself, but that doesn't need to be the case).
9258
+ * @type array
9259
+ */
9260
+ "aDataSort": null,
9261
+
9262
+ /**
9263
+ * Define the sorting directions that are applied to the column, in sequence
9264
+ * as the column is repeatedly sorted upon - i.e. the first value is used
9265
+ * as the sorting direction when the column if first sorted (clicked on).
9266
+ * Sort it again (click again) and it will move on to the next index.
9267
+ * Repeat until loop.
9268
+ * @type array
9269
+ */
9270
+ "asSorting": null,
9271
+
9272
+ /**
9273
+ * Flag to indicate if the column is searchable, and thus should be included
9274
+ * in the filtering or not.
9275
+ * @type boolean
9276
+ */
9277
+ "bSearchable": null,
9278
+
9279
+ /**
9280
+ * Flag to indicate if the column is sortable or not.
9281
+ * @type boolean
9282
+ */
9283
+ "bSortable": null,
9284
+
9285
+ /**
9286
+ * Flag to indicate if the column is currently visible in the table or not
9287
+ * @type boolean
9288
+ */
9289
+ "bVisible": null,
9290
+
9291
+ /**
9292
+ * Store for manual type assignment using the `column.type` option. This
9293
+ * is held in store so we can manipulate the column's `sType` property.
9294
+ * @type string
9295
+ * @default null
9296
+ * @private
9297
+ */
9298
+ "_sManualType": null,
9299
+
9300
+ /**
9301
+ * Flag to indicate if HTML5 data attributes should be used as the data
9302
+ * source for filtering or sorting. True is either are.
9303
+ * @type boolean
9304
+ * @default false
9305
+ * @private
9306
+ */
9307
+ "_bAttrSrc": false,
9308
+
9309
+ /**
9310
+ * Developer definable function that is called whenever a cell is created (Ajax source,
9311
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
9312
+ * allowing you to modify the DOM element (add background colour for example) when the
9313
+ * element is available.
9314
+ * @type function
9315
+ * @param {element} nTd The TD node that has been created
9316
+ * @param {*} sData The Data for the cell
9317
+ * @param {array|object} oData The data for the whole row
9318
+ * @param {int} iRow The row index for the aoData data store
9319
+ * @default null
9320
+ */
9321
+ "fnCreatedCell": null,
9322
+
9323
+ /**
9324
+ * Function to get data from a cell in a column. You should <b>never</b>
9325
+ * access data directly through _aData internally in DataTables - always use
9326
+ * the method attached to this property. It allows mData to function as
9327
+ * required. This function is automatically assigned by the column
9328
+ * initialisation method
9329
+ * @type function
9330
+ * @param {array|object} oData The data array/object for the array
9331
+ * (i.e. aoData[]._aData)
9332
+ * @param {string} sSpecific The specific data type you want to get -
9333
+ * 'display', 'type' 'filter' 'sort'
9334
+ * @returns {*} The data for the cell from the given row's data
9335
+ * @default null
9336
+ */
9337
+ "fnGetData": null,
9338
+
9339
+ /**
9340
+ * Function to set data for a cell in the column. You should <b>never</b>
9341
+ * set the data directly to _aData internally in DataTables - always use
9342
+ * this method. It allows mData to function as required. This function
9343
+ * is automatically assigned by the column initialisation method
9344
+ * @type function
9345
+ * @param {array|object} oData The data array/object for the array
9346
+ * (i.e. aoData[]._aData)
9347
+ * @param {*} sValue Value to set
9348
+ * @default null
9349
+ */
9350
+ "fnSetData": null,
9351
+
9352
+ /**
9353
+ * Property to read the value for the cells in the column from the data
9354
+ * source array / object. If null, then the default content is used, if a
9355
+ * function is given then the return from the function is used.
9356
+ * @type function|int|string|null
9357
+ * @default null
9358
+ */
9359
+ "mData": null,
9360
+
9361
+ /**
9362
+ * Partner property to mData which is used (only when defined) to get
9363
+ * the data - i.e. it is basically the same as mData, but without the
9364
+ * 'set' option, and also the data fed to it is the result from mData.
9365
+ * This is the rendering method to match the data method of mData.
9366
+ * @type function|int|string|null
9367
+ * @default null
9368
+ */
9369
+ "mRender": null,
9370
+
9371
+ /**
9372
+ * Unique header TH/TD element for this column - this is what the sorting
9373
+ * listener is attached to (if sorting is enabled.)
9374
+ * @type node
9375
+ * @default null
9376
+ */
9377
+ "nTh": null,
9378
+
9379
+ /**
9380
+ * Unique footer TH/TD element for this column (if there is one). Not used
9381
+ * in DataTables as such, but can be used for plug-ins to reference the
9382
+ * footer for each column.
9383
+ * @type node
9384
+ * @default null
9385
+ */
9386
+ "nTf": null,
9387
+
9388
+ /**
9389
+ * The class to apply to all TD elements in the table's TBODY for the column
9390
+ * @type string
9391
+ * @default null
9392
+ */
9393
+ "sClass": null,
9394
+
9395
+ /**
9396
+ * When DataTables calculates the column widths to assign to each column,
9397
+ * it finds the longest string in each column and then constructs a
9398
+ * temporary table and reads the widths from that. The problem with this
9399
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
9400
+ * string - thus the calculation can go wrong (doing it properly and putting
9401
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
9402
+ * a "work around" we provide this option. It will append its value to the
9403
+ * text that is found to be the longest string for the column - i.e. padding.
9404
+ * @type string
9405
+ */
9406
+ "sContentPadding": null,
9407
+
9408
+ /**
9409
+ * Allows a default value to be given for a column's data, and will be used
9410
+ * whenever a null data source is encountered (this can be because mData
9411
+ * is set to null, or because the data source itself is null).
9412
+ * @type string
9413
+ * @default null
9414
+ */
9415
+ "sDefaultContent": null,
9416
+
9417
+ /**
9418
+ * Name for the column, allowing reference to the column by name as well as
9419
+ * by index (needs a lookup to work by name).
9420
+ * @type string
9421
+ */
9422
+ "sName": null,
9423
+
9424
+ /**
9425
+ * Custom sorting data type - defines which of the available plug-ins in
9426
+ * afnSortData the custom sorting will use - if any is defined.
9427
+ * @type string
9428
+ * @default std
9429
+ */
9430
+ "sSortDataType": 'std',
9431
+
9432
+ /**
9433
+ * Class to be applied to the header element when sorting on this column
9434
+ * @type string
9435
+ * @default null
9436
+ */
9437
+ "sSortingClass": null,
9438
+
9439
+ /**
9440
+ * Class to be applied to the header element when sorting on this column -
9441
+ * when jQuery UI theming is used.
9442
+ * @type string
9443
+ * @default null
9444
+ */
9445
+ "sSortingClassJUI": null,
9446
+
9447
+ /**
9448
+ * Title of the column - what is seen in the TH element (nTh).
9449
+ * @type string
9450
+ */
9451
+ "sTitle": null,
9452
+
9453
+ /**
9454
+ * Column sorting and filtering type
9455
+ * @type string
9456
+ * @default null
9457
+ */
9458
+ "sType": null,
9459
+
9460
+ /**
9461
+ * Width of the column
9462
+ * @type string
9463
+ * @default null
9464
+ */
9465
+ "sWidth": null,
9466
+
9467
+ /**
9468
+ * Width of the column when it was first "encountered"
9469
+ * @type string
9470
+ * @default null
9471
+ */
9472
+ "sWidthOrig": null
9473
+ };
9474
+
9475
+
9476
+ /*
9477
+ * Developer note: The properties of the object below are given in Hungarian
9478
+ * notation, that was used as the interface for DataTables prior to v1.10, however
9479
+ * from v1.10 onwards the primary interface is camel case. In order to avoid
9480
+ * breaking backwards compatibility utterly with this change, the Hungarian
9481
+ * version is still, internally the primary interface, but is is not documented
9482
+ * - hence the @name tags in each doc comment. This allows a Javascript function
9483
+ * to create a map from Hungarian notation to camel case (going the other direction
9484
+ * would require each property to be listed, which would at around 3K to the size
9485
+ * of DataTables, while this method is about a 0.5K hit.
9486
+ *
9487
+ * Ultimately this does pave the way for Hungarian notation to be dropped
9488
+ * completely, but that is a massive amount of work and will break current
9489
+ * installs (therefore is on-hold until v2).
9490
+ */
9491
+
9492
+ /**
9493
+ * Initialisation options that can be given to DataTables at initialisation
9494
+ * time.
9495
+ * @namespace
9496
+ */
9497
+ DataTable.defaults = {
9498
+ /**
9499
+ * An array of data to use for the table, passed in at initialisation which
9500
+ * will be used in preference to any data which is already in the DOM. This is
9501
+ * particularly useful for constructing tables purely in Javascript, for
9502
+ * example with a custom Ajax call.
9503
+ * @type array
9504
+ * @default null
9505
+ *
9506
+ * @dtopt Option
9507
+ * @name DataTable.defaults.data
9508
+ *
9509
+ * @example
9510
+ * // Using a 2D array data source
9511
+ * $(document).ready( function () {
9512
+ * $('#example').dataTable( {
9513
+ * "data": [
9514
+ * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
9515
+ * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
9516
+ * ],
9517
+ * "columns": [
9518
+ * { "title": "Engine" },
9519
+ * { "title": "Browser" },
9520
+ * { "title": "Platform" },
9521
+ * { "title": "Version" },
9522
+ * { "title": "Grade" }
9523
+ * ]
9524
+ * } );
9525
+ * } );
9526
+ *
9527
+ * @example
9528
+ * // Using an array of objects as a data source (`data`)
9529
+ * $(document).ready( function () {
9530
+ * $('#example').dataTable( {
9531
+ * "data": [
9532
+ * {
9533
+ * "engine": "Trident",
9534
+ * "browser": "Internet Explorer 4.0",
9535
+ * "platform": "Win 95+",
9536
+ * "version": 4,
9537
+ * "grade": "X"
9538
+ * },
9539
+ * {
9540
+ * "engine": "Trident",
9541
+ * "browser": "Internet Explorer 5.0",
9542
+ * "platform": "Win 95+",
9543
+ * "version": 5,
9544
+ * "grade": "C"
9545
+ * }
9546
+ * ],
9547
+ * "columns": [
9548
+ * { "title": "Engine", "data": "engine" },
9549
+ * { "title": "Browser", "data": "browser" },
9550
+ * { "title": "Platform", "data": "platform" },
9551
+ * { "title": "Version", "data": "version" },
9552
+ * { "title": "Grade", "data": "grade" }
9553
+ * ]
9554
+ * } );
9555
+ * } );
9556
+ */
9557
+ "aaData": null,
9558
+
9559
+
9560
+ /**
9561
+ * If ordering is enabled, then DataTables will perform a first pass sort on
9562
+ * initialisation. You can define which column(s) the sort is performed
9563
+ * upon, and the sorting direction, with this variable. The `sorting` array
9564
+ * should contain an array for each column to be sorted initially containing
9565
+ * the column's index and a direction string ('asc' or 'desc').
9566
+ * @type array
9567
+ * @default [[0,'asc']]
9568
+ *
9569
+ * @dtopt Option
9570
+ * @name DataTable.defaults.order
9571
+ *
9572
+ * @example
9573
+ * // Sort by 3rd column first, and then 4th column
9574
+ * $(document).ready( function() {
9575
+ * $('#example').dataTable( {
9576
+ * "order": [[2,'asc'], [3,'desc']]
9577
+ * } );
9578
+ * } );
9579
+ *
9580
+ * // No initial sorting
9581
+ * $(document).ready( function() {
9582
+ * $('#example').dataTable( {
9583
+ * "order": []
9584
+ * } );
9585
+ * } );
9586
+ */
9587
+ "aaSorting": [[0,'asc']],
9588
+
9589
+
9590
+ /**
9591
+ * This parameter is basically identical to the `sorting` parameter, but
9592
+ * cannot be overridden by user interaction with the table. What this means
9593
+ * is that you could have a column (visible or hidden) which the sorting
9594
+ * will always be forced on first - any sorting after that (from the user)
9595
+ * will then be performed as required. This can be useful for grouping rows
9596
+ * together.
9597
+ * @type array
9598
+ * @default null
9599
+ *
9600
+ * @dtopt Option
9601
+ * @name DataTable.defaults.orderFixed
9602
+ *
9603
+ * @example
9604
+ * $(document).ready( function() {
9605
+ * $('#example').dataTable( {
9606
+ * "orderFixed": [[0,'asc']]
9607
+ * } );
9608
+ * } )
9609
+ */
9610
+ "aaSortingFixed": [],
9611
+
9612
+
9613
+ /**
9614
+ * DataTables can be instructed to load data to display in the table from a
9615
+ * Ajax source. This option defines how that Ajax call is made and where to.
9616
+ *
9617
+ * The `ajax` property has three different modes of operation, depending on
9618
+ * how it is defined. These are:
9619
+ *
9620
+ * * `string` - Set the URL from where the data should be loaded from.
9621
+ * * `object` - Define properties for `jQuery.ajax`.
9622
+ * * `function` - Custom data get function
9623
+ *
9624
+ * `string`
9625
+ * --------
9626
+ *
9627
+ * As a string, the `ajax` property simply defines the URL from which
9628
+ * DataTables will load data.
9629
+ *
9630
+ * `object`
9631
+ * --------
9632
+ *
9633
+ * As an object, the parameters in the object are passed to
9634
+ * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
9635
+ * of the Ajax request. DataTables has a number of default parameters which
9636
+ * you can override using this option. Please refer to the jQuery
9637
+ * documentation for a full description of the options available, although
9638
+ * the following parameters provide additional options in DataTables or
9639
+ * require special consideration:
9640
+ *
9641
+ * * `data` - As with jQuery, `data` can be provided as an object, but it
9642
+ * can also be used as a function to manipulate the data DataTables sends
9643
+ * to the server. The function takes a single parameter, an object of
9644
+ * parameters with the values that DataTables has readied for sending. An
9645
+ * object may be returned which will be merged into the DataTables
9646
+ * defaults, or you can add the items to the object that was passed in and
9647
+ * not return anything from the function. This supersedes `fnServerParams`
9648
+ * from DataTables 1.9-.
9649
+ *
9650
+ * * `dataSrc` - By default DataTables will look for the property `data` (or
9651
+ * `aaData` for compatibility with DataTables 1.9-) when obtaining data
9652
+ * from an Ajax source or for server-side processing - this parameter
9653
+ * allows that property to be changed. You can use Javascript dotted
9654
+ * object notation to get a data source for multiple levels of nesting, or
9655
+ * it my be used as a function. As a function it takes a single parameter,
9656
+ * the JSON returned from the server, which can be manipulated as
9657
+ * required, with the returned value being that used by DataTables as the
9658
+ * data source for the table. This supersedes `sAjaxDataProp` from
9659
+ * DataTables 1.9-.
9660
+ *
9661
+ * * `success` - Should not be overridden it is used internally in
9662
+ * DataTables. To manipulate / transform the data returned by the server
9663
+ * use `ajax.dataSrc`, or use `ajax` as a function (see below).
9664
+ *
9665
+ * `function`
9666
+ * ----------
9667
+ *
9668
+ * As a function, making the Ajax call is left up to yourself allowing
9669
+ * complete control of the Ajax request. Indeed, if desired, a method other
9670
+ * than Ajax could be used to obtain the required data, such as Web storage
9671
+ * or an AIR database.
9672
+ *
9673
+ * The function is given four parameters and no return is required. The
9674
+ * parameters are:
9675
+ *
9676
+ * 1. _object_ - Data to send to the server
9677
+ * 2. _function_ - Callback function that must be executed when the required
9678
+ * data has been obtained. That data should be passed into the callback
9679
+ * as the only parameter
9680
+ * 3. _object_ - DataTables settings object for the table
9681
+ *
9682
+ * Note that this supersedes `fnServerData` from DataTables 1.9-.
9683
+ *
9684
+ * @type string|object|function
9685
+ * @default null
9686
+ *
9687
+ * @dtopt Option
9688
+ * @name DataTable.defaults.ajax
9689
+ * @since 1.10.0
9690
+ *
9691
+ * @example
9692
+ * // Get JSON data from a file via Ajax.
9693
+ * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
9694
+ * $('#example').dataTable( {
9695
+ * "ajax": "data.json"
9696
+ * } );
9697
+ *
9698
+ * @example
9699
+ * // Get JSON data from a file via Ajax, using `dataSrc` to change
9700
+ * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
9701
+ * $('#example').dataTable( {
9702
+ * "ajax": {
9703
+ * "url": "data.json",
9704
+ * "dataSrc": "tableData"
9705
+ * }
9706
+ * } );
9707
+ *
9708
+ * @example
9709
+ * // Get JSON data from a file via Ajax, using `dataSrc` to read data
9710
+ * // from a plain array rather than an array in an object
9711
+ * $('#example').dataTable( {
9712
+ * "ajax": {
9713
+ * "url": "data.json",
9714
+ * "dataSrc": ""
9715
+ * }
9716
+ * } );
9717
+ *
9718
+ * @example
9719
+ * // Manipulate the data returned from the server - add a link to data
9720
+ * // (note this can, should, be done using `render` for the column - this
9721
+ * // is just a simple example of how the data can be manipulated).
9722
+ * $('#example').dataTable( {
9723
+ * "ajax": {
9724
+ * "url": "data.json",
9725
+ * "dataSrc": function ( json ) {
9726
+ * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
9727
+ * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
9728
+ * }
9729
+ * return json;
9730
+ * }
9731
+ * }
9732
+ * } );
9733
+ *
9734
+ * @example
9735
+ * // Add data to the request
9736
+ * $('#example').dataTable( {
9737
+ * "ajax": {
9738
+ * "url": "data.json",
9739
+ * "data": function ( d ) {
9740
+ * return {
9741
+ * "extra_search": $('#extra').val()
9742
+ * };
9743
+ * }
9744
+ * }
9745
+ * } );
9746
+ *
9747
+ * @example
9748
+ * // Send request as POST
9749
+ * $('#example').dataTable( {
9750
+ * "ajax": {
9751
+ * "url": "data.json",
9752
+ * "type": "POST"
9753
+ * }
9754
+ * } );
9755
+ *
9756
+ * @example
9757
+ * // Get the data from localStorage (could interface with a form for
9758
+ * // adding, editing and removing rows).
9759
+ * $('#example').dataTable( {
9760
+ * "ajax": function (data, callback, settings) {
9761
+ * callback(
9762
+ * JSON.parse( localStorage.getItem('dataTablesData') )
9763
+ * );
9764
+ * }
9765
+ * } );
9766
+ */
9767
+ "ajax": null,
9768
+
9769
+
9770
+ /**
9771
+ * This parameter allows you to readily specify the entries in the length drop
9772
+ * down menu that DataTables shows when pagination is enabled. It can be
9773
+ * either a 1D array of options which will be used for both the displayed
9774
+ * option and the value, or a 2D array which will use the array in the first
9775
+ * position as the value, and the array in the second position as the
9776
+ * displayed options (useful for language strings such as 'All').
9777
+ *
9778
+ * Note that the `pageLength` property will be automatically set to the
9779
+ * first value given in this array, unless `pageLength` is also provided.
9780
+ * @type array
9781
+ * @default [ 10, 25, 50, 100 ]
9782
+ *
9783
+ * @dtopt Option
9784
+ * @name DataTable.defaults.lengthMenu
9785
+ *
9786
+ * @example
9787
+ * $(document).ready( function() {
9788
+ * $('#example').dataTable( {
9789
+ * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
9790
+ * } );
9791
+ * } );
9792
+ */
9793
+ "aLengthMenu": [ 10, 25, 50, 100 ],
9794
+
9795
+
9796
+ /**
9797
+ * The `columns` option in the initialisation parameter allows you to define
9798
+ * details about the way individual columns behave. For a full list of
9799
+ * column options that can be set, please see
9800
+ * {@link DataTable.defaults.column}. Note that if you use `columns` to
9801
+ * define your columns, you must have an entry in the array for every single
9802
+ * column that you have in your table (these can be null if you don't which
9803
+ * to specify any options).
9804
+ * @member
9805
+ *
9806
+ * @name DataTable.defaults.column
9807
+ */
9808
+ "aoColumns": null,
9809
+
9810
+ /**
9811
+ * Very similar to `columns`, `columnDefs` allows you to target a specific
9812
+ * column, multiple columns, or all columns, using the `targets` property of
9813
+ * each object in the array. This allows great flexibility when creating
9814
+ * tables, as the `columnDefs` arrays can be of any length, targeting the
9815
+ * columns you specifically want. `columnDefs` may use any of the column
9816
+ * options available: {@link DataTable.defaults.column}, but it _must_
9817
+ * have `targets` defined in each object in the array. Values in the `targets`
9818
+ * array may be:
9819
+ * <ul>
9820
+ * <li>a string - class name will be matched on the TH for the column</li>
9821
+ * <li>0 or a positive integer - column index counting from the left</li>
9822
+ * <li>a negative integer - column index counting from the right</li>
9823
+ * <li>the string "_all" - all columns (i.e. assign a default)</li>
9824
+ * </ul>
9825
+ * @member
9826
+ *
9827
+ * @name DataTable.defaults.columnDefs
9828
+ */
9829
+ "aoColumnDefs": null,
9830
+
9831
+
9832
+ /**
9833
+ * Basically the same as `search`, this parameter defines the individual column
9834
+ * filtering state at initialisation time. The array must be of the same size
9835
+ * as the number of columns, and each element be an object with the parameters
9836
+ * `search` and `escapeRegex` (the latter is optional). 'null' is also
9837
+ * accepted and the default will be used.
9838
+ * @type array
9839
+ * @default []
9840
+ *
9841
+ * @dtopt Option
9842
+ * @name DataTable.defaults.searchCols
9843
+ *
9844
+ * @example
9845
+ * $(document).ready( function() {
9846
+ * $('#example').dataTable( {
9847
+ * "searchCols": [
9848
+ * null,
9849
+ * { "search": "My filter" },
9850
+ * null,
9851
+ * { "search": "^[0-9]", "escapeRegex": false }
9852
+ * ]
9853
+ * } );
9854
+ * } )
9855
+ */
9856
+ "aoSearchCols": [],
9857
+
9858
+
9859
+ /**
9860
+ * An array of CSS classes that should be applied to displayed rows. This
9861
+ * array may be of any length, and DataTables will apply each class
9862
+ * sequentially, looping when required.
9863
+ * @type array
9864
+ * @default null <i>Will take the values determined by the `oClasses.stripe*`
9865
+ * options</i>
9866
+ *
9867
+ * @dtopt Option
9868
+ * @name DataTable.defaults.stripeClasses
9869
+ *
9870
+ * @example
9871
+ * $(document).ready( function() {
9872
+ * $('#example').dataTable( {
9873
+ * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
9874
+ * } );
9875
+ * } )
9876
+ */
9877
+ "asStripeClasses": null,
9878
+
9879
+
9880
+ /**
9881
+ * Enable or disable automatic column width calculation. This can be disabled
9882
+ * as an optimisation (it takes some time to calculate the widths) if the
9883
+ * tables widths are passed in using `columns`.
9884
+ * @type boolean
9885
+ * @default true
9886
+ *
9887
+ * @dtopt Features
9888
+ * @name DataTable.defaults.autoWidth
9889
+ *
9890
+ * @example
9891
+ * $(document).ready( function () {
9892
+ * $('#example').dataTable( {
9893
+ * "autoWidth": false
9894
+ * } );
9895
+ * } );
9896
+ */
9897
+ "bAutoWidth": true,
9898
+
9899
+
9900
+ /**
9901
+ * Deferred rendering can provide DataTables with a huge speed boost when you
9902
+ * are using an Ajax or JS data source for the table. This option, when set to
9903
+ * true, will cause DataTables to defer the creation of the table elements for
9904
+ * each row until they are needed for a draw - saving a significant amount of
9905
+ * time.
9906
+ * @type boolean
9907
+ * @default false
9908
+ *
9909
+ * @dtopt Features
9910
+ * @name DataTable.defaults.deferRender
9911
+ *
9912
+ * @example
9913
+ * $(document).ready( function() {
9914
+ * $('#example').dataTable( {
9915
+ * "ajax": "sources/arrays.txt",
9916
+ * "deferRender": true
9917
+ * } );
9918
+ * } );
9919
+ */
9920
+ "bDeferRender": false,
9921
+
9922
+
9923
+ /**
9924
+ * Replace a DataTable which matches the given selector and replace it with
9925
+ * one which has the properties of the new initialisation object passed. If no
9926
+ * table matches the selector, then the new DataTable will be constructed as
9927
+ * per normal.
9928
+ * @type boolean
9929
+ * @default false
9930
+ *
9931
+ * @dtopt Options
9932
+ * @name DataTable.defaults.destroy
9933
+ *
9934
+ * @example
9935
+ * $(document).ready( function() {
9936
+ * $('#example').dataTable( {
9937
+ * "srollY": "200px",
9938
+ * "paginate": false
9939
+ * } );
9940
+ *
9941
+ * // Some time later....
9942
+ * $('#example').dataTable( {
9943
+ * "filter": false,
9944
+ * "destroy": true
9945
+ * } );
9946
+ * } );
9947
+ */
9948
+ "bDestroy": false,
9949
+
9950
+
9951
+ /**
9952
+ * Enable or disable filtering of data. Filtering in DataTables is "smart" in
9953
+ * that it allows the end user to input multiple words (space separated) and
9954
+ * will match a row containing those words, even if not in the order that was
9955
+ * specified (this allow matching across multiple columns). Note that if you
9956
+ * wish to use filtering in DataTables this must remain 'true' - to remove the
9957
+ * default filtering input box and retain filtering abilities, please use
9958
+ * {@link DataTable.defaults.dom}.
9959
+ * @type boolean
9960
+ * @default true
9961
+ *
9962
+ * @dtopt Features
9963
+ * @name DataTable.defaults.searching
9964
+ *
9965
+ * @example
9966
+ * $(document).ready( function () {
9967
+ * $('#example').dataTable( {
9968
+ * "searching": false
9969
+ * } );
9970
+ * } );
9971
+ */
9972
+ "bFilter": true,
9973
+
9974
+
9975
+ /**
9976
+ * Enable or disable the table information display. This shows information
9977
+ * about the data that is currently visible on the page, including information
9978
+ * about filtered data if that action is being performed.
9979
+ * @type boolean
9980
+ * @default true
9981
+ *
9982
+ * @dtopt Features
9983
+ * @name DataTable.defaults.info
9984
+ *
9985
+ * @example
9986
+ * $(document).ready( function () {
9987
+ * $('#example').dataTable( {
9988
+ * "info": false
9989
+ * } );
9990
+ * } );
9991
+ */
9992
+ "bInfo": true,
9993
+
9994
+
9995
+ /**
9996
+ * Enable jQuery UI ThemeRoller support (required as ThemeRoller requires some
9997
+ * slightly different and additional mark-up from what DataTables has
9998
+ * traditionally used).
9999
+ * @type boolean
10000
+ * @default false
10001
+ *
10002
+ * @dtopt Features
10003
+ * @name DataTable.defaults.jQueryUI
10004
+ *
10005
+ * @example
10006
+ * $(document).ready( function() {
10007
+ * $('#example').dataTable( {
10008
+ * "jQueryUI": true
10009
+ * } );
10010
+ * } );
10011
+ */
10012
+ "bJQueryUI": false,
10013
+
10014
+
10015
+ /**
10016
+ * Allows the end user to select the size of a formatted page from a select
10017
+ * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
10018
+ * @type boolean
10019
+ * @default true
10020
+ *
10021
+ * @dtopt Features
10022
+ * @name DataTable.defaults.lengthChange
10023
+ *
10024
+ * @example
10025
+ * $(document).ready( function () {
10026
+ * $('#example').dataTable( {
10027
+ * "lengthChange": false
10028
+ * } );
10029
+ * } );
10030
+ */
10031
+ "bLengthChange": true,
10032
+
10033
+
10034
+ /**
10035
+ * Enable or disable pagination.
10036
+ * @type boolean
10037
+ * @default true
10038
+ *
10039
+ * @dtopt Features
10040
+ * @name DataTable.defaults.paging
10041
+ *
10042
+ * @example
10043
+ * $(document).ready( function () {
10044
+ * $('#example').dataTable( {
10045
+ * "paging": false
10046
+ * } );
10047
+ * } );
10048
+ */
10049
+ "bPaginate": true,
10050
+
10051
+
10052
+ /**
10053
+ * Enable or disable the display of a 'processing' indicator when the table is
10054
+ * being processed (e.g. a sort). This is particularly useful for tables with
10055
+ * large amounts of data where it can take a noticeable amount of time to sort
10056
+ * the entries.
10057
+ * @type boolean
10058
+ * @default false
10059
+ *
10060
+ * @dtopt Features
10061
+ * @name DataTable.defaults.processing
10062
+ *
10063
+ * @example
10064
+ * $(document).ready( function () {
10065
+ * $('#example').dataTable( {
10066
+ * "processing": true
10067
+ * } );
10068
+ * } );
10069
+ */
10070
+ "bProcessing": false,
10071
+
10072
+
10073
+ /**
10074
+ * Retrieve the DataTables object for the given selector. Note that if the
10075
+ * table has already been initialised, this parameter will cause DataTables
10076
+ * to simply return the object that has already been set up - it will not take
10077
+ * account of any changes you might have made to the initialisation object
10078
+ * passed to DataTables (setting this parameter to true is an acknowledgement
10079
+ * that you understand this). `destroy` can be used to reinitialise a table if
10080
+ * you need.
10081
+ * @type boolean
10082
+ * @default false
10083
+ *
10084
+ * @dtopt Options
10085
+ * @name DataTable.defaults.retrieve
10086
+ *
10087
+ * @example
10088
+ * $(document).ready( function() {
10089
+ * initTable();
10090
+ * tableActions();
10091
+ * } );
10092
+ *
10093
+ * function initTable ()
10094
+ * {
10095
+ * return $('#example').dataTable( {
10096
+ * "scrollY": "200px",
10097
+ * "paginate": false,
10098
+ * "retrieve": true
10099
+ * } );
10100
+ * }
10101
+ *
10102
+ * function tableActions ()
10103
+ * {
10104
+ * var table = initTable();
10105
+ * // perform API operations with oTable
10106
+ * }
10107
+ */
10108
+ "bRetrieve": false,
10109
+
10110
+
10111
+ /**
10112
+ * When vertical (y) scrolling is enabled, DataTables will force the height of
10113
+ * the table's viewport to the given height at all times (useful for layout).
10114
+ * However, this can look odd when filtering data down to a small data set,
10115
+ * and the footer is left "floating" further down. This parameter (when
10116
+ * enabled) will cause DataTables to collapse the table's viewport down when
10117
+ * the result set will fit within the given Y height.
10118
+ * @type boolean
10119
+ * @default false
10120
+ *
10121
+ * @dtopt Options
10122
+ * @name DataTable.defaults.scrollCollapse
10123
+ *
10124
+ * @example
10125
+ * $(document).ready( function() {
10126
+ * $('#example').dataTable( {
10127
+ * "scrollY": "200",
10128
+ * "scrollCollapse": true
10129
+ * } );
10130
+ * } );
10131
+ */
10132
+ "bScrollCollapse": false,
10133
+
10134
+
10135
+ /**
10136
+ * Configure DataTables to use server-side processing. Note that the
10137
+ * `ajax` parameter must also be given in order to give DataTables a
10138
+ * source to obtain the required data for each draw.
10139
+ * @type boolean
10140
+ * @default false
10141
+ *
10142
+ * @dtopt Features
10143
+ * @dtopt Server-side
10144
+ * @name DataTable.defaults.serverSide
10145
+ *
10146
+ * @example
10147
+ * $(document).ready( function () {
10148
+ * $('#example').dataTable( {
10149
+ * "serverSide": true,
10150
+ * "ajax": "xhr.php"
10151
+ * } );
10152
+ * } );
10153
+ */
10154
+ "bServerSide": false,
10155
+
10156
+
10157
+ /**
10158
+ * Enable or disable sorting of columns. Sorting of individual columns can be
10159
+ * disabled by the `sortable` option for each column.
10160
+ * @type boolean
10161
+ * @default true
10162
+ *
10163
+ * @dtopt Features
10164
+ * @name DataTable.defaults.ordering
10165
+ *
10166
+ * @example
10167
+ * $(document).ready( function () {
10168
+ * $('#example').dataTable( {
10169
+ * "ordering": false
10170
+ * } );
10171
+ * } );
10172
+ */
10173
+ "bSort": true,
10174
+
10175
+
10176
+ /**
10177
+ * Enable or display DataTables' ability to sort multiple columns at the
10178
+ * same time (activated by shift-click by the user).
10179
+ * @type boolean
10180
+ * @default true
10181
+ *
10182
+ * @dtopt Options
10183
+ * @name DataTable.defaults.orderMulti
10184
+ *
10185
+ * @example
10186
+ * // Disable multiple column sorting ability
10187
+ * $(document).ready( function () {
10188
+ * $('#example').dataTable( {
10189
+ * "orderMulti": false
10190
+ * } );
10191
+ * } );
10192
+ */
10193
+ "bSortMulti": true,
10194
+
10195
+
10196
+ /**
10197
+ * Allows control over whether DataTables should use the top (true) unique
10198
+ * cell that is found for a single column, or the bottom (false - default).
10199
+ * This is useful when using complex headers.
10200
+ * @type boolean
10201
+ * @default false
10202
+ *
10203
+ * @dtopt Options
10204
+ * @name DataTable.defaults.orderCellsTop
10205
+ *
10206
+ * @example
10207
+ * $(document).ready( function() {
10208
+ * $('#example').dataTable( {
10209
+ * "orderCellsTop": true
10210
+ * } );
10211
+ * } );
10212
+ */
10213
+ "bSortCellsTop": false,
10214
+
10215
+
10216
+ /**
10217
+ * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
10218
+ * `sorting\_3` to the columns which are currently being sorted on. This is
10219
+ * presented as a feature switch as it can increase processing time (while
10220
+ * classes are removed and added) so for large data sets you might want to
10221
+ * turn this off.
10222
+ * @type boolean
10223
+ * @default true
10224
+ *
10225
+ * @dtopt Features
10226
+ * @name DataTable.defaults.orderClasses
10227
+ *
10228
+ * @example
10229
+ * $(document).ready( function () {
10230
+ * $('#example').dataTable( {
10231
+ * "orderClasses": false
10232
+ * } );
10233
+ * } );
10234
+ */
10235
+ "bSortClasses": true,
10236
+
10237
+
10238
+ /**
10239
+ * Enable or disable state saving. When enabled HTML5 `localStorage` will be
10240
+ * used to save table display information such as pagination information,
10241
+ * display length, filtering and sorting. As such when the end user reloads
10242
+ * the page the display display will match what thy had previously set up.
10243
+ *
10244
+ * Due to the use of `localStorage` the default state saving is not supported
10245
+ * in IE6 or 7. If state saving is required in those browsers, use
10246
+ * `stateSaveCallback` to provide a storage solution such as cookies.
10247
+ * @type boolean
10248
+ * @default false
10249
+ *
10250
+ * @dtopt Features
10251
+ * @name DataTable.defaults.stateSave
10252
+ *
10253
+ * @example
10254
+ * $(document).ready( function () {
10255
+ * $('#example').dataTable( {
10256
+ * "stateSave": true
10257
+ * } );
10258
+ * } );
10259
+ */
10260
+ "bStateSave": false,
10261
+
10262
+
10263
+ /**
10264
+ * This function is called when a TR element is created (and all TD child
10265
+ * elements have been inserted), or registered if using a DOM source, allowing
10266
+ * manipulation of the TR element (adding classes etc).
10267
+ * @type function
10268
+ * @param {node} row "TR" element for the current row
10269
+ * @param {array} data Raw data array for this row
10270
+ * @param {int} dataIndex The index of this row in the internal aoData array
10271
+ *
10272
+ * @dtopt Callbacks
10273
+ * @name DataTable.defaults.createdRow
10274
+ *
10275
+ * @example
10276
+ * $(document).ready( function() {
10277
+ * $('#example').dataTable( {
10278
+ * "createdRow": function( row, data, dataIndex ) {
10279
+ * // Bold the grade for all 'A' grade browsers
10280
+ * if ( data[4] == "A" )
10281
+ * {
10282
+ * $('td:eq(4)', row).html( '<b>A</b>' );
10283
+ * }
10284
+ * }
10285
+ * } );
10286
+ * } );
10287
+ */
10288
+ "fnCreatedRow": null,
10289
+
10290
+
10291
+ /**
10292
+ * This function is called on every 'draw' event, and allows you to
10293
+ * dynamically modify any aspect you want about the created DOM.
10294
+ * @type function
10295
+ * @param {object} settings DataTables settings object
10296
+ *
10297
+ * @dtopt Callbacks
10298
+ * @name DataTable.defaults.drawCallback
10299
+ *
10300
+ * @example
10301
+ * $(document).ready( function() {
10302
+ * $('#example').dataTable( {
10303
+ * "drawCallback": function( settings ) {
10304
+ * alert( 'DataTables has redrawn the table' );
10305
+ * }
10306
+ * } );
10307
+ * } );
10308
+ */
10309
+ "fnDrawCallback": null,
10310
+
10311
+
10312
+ /**
10313
+ * Identical to fnHeaderCallback() but for the table footer this function
10314
+ * allows you to modify the table footer on every 'draw' event.
10315
+ * @type function
10316
+ * @param {node} foot "TR" element for the footer
10317
+ * @param {array} data Full table data (as derived from the original HTML)
10318
+ * @param {int} start Index for the current display starting point in the
10319
+ * display array
10320
+ * @param {int} end Index for the current display ending point in the
10321
+ * display array
10322
+ * @param {array int} display Index array to translate the visual position
10323
+ * to the full data array
10324
+ *
10325
+ * @dtopt Callbacks
10326
+ * @name DataTable.defaults.footerCallback
10327
+ *
10328
+ * @example
10329
+ * $(document).ready( function() {
10330
+ * $('#example').dataTable( {
10331
+ * "footerCallback": function( tfoot, data, start, end, display ) {
10332
+ * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
10333
+ * }
10334
+ * } );
10335
+ * } )
10336
+ */
10337
+ "fnFooterCallback": null,
10338
+
10339
+
10340
+ /**
10341
+ * When rendering large numbers in the information element for the table
10342
+ * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
10343
+ * to have a comma separator for the 'thousands' units (e.g. 1 million is
10344
+ * rendered as "1,000,000") to help readability for the end user. This
10345
+ * function will override the default method DataTables uses.
10346
+ * @type function
10347
+ * @member
10348
+ * @param {int} toFormat number to be formatted
10349
+ * @returns {string} formatted string for DataTables to show the number
10350
+ *
10351
+ * @dtopt Callbacks
10352
+ * @name DataTable.defaults.formatNumber
10353
+ *
10354
+ * @example
10355
+ * // Format a number using a single quote for the separator (note that
10356
+ * // this can also be done with the language.thousands option)
10357
+ * $(document).ready( function() {
10358
+ * $('#example').dataTable( {
10359
+ * "formatNumber": function ( toFormat ) {
10360
+ * return toFormat.toString().replace(
10361
+ * /\B(?=(\d{3})+(?!\d))/g, "'"
10362
+ * );
10363
+ * };
10364
+ * } );
10365
+ * } );
10366
+ */
10367
+ "fnFormatNumber": function ( toFormat ) {
10368
+ return toFormat.toString().replace(
10369
+ /\B(?=(\d{3})+(?!\d))/g,
10370
+ this.oLanguage.sThousands
10371
+ );
10372
+ },
10373
+
10374
+
10375
+ /**
10376
+ * This function is called on every 'draw' event, and allows you to
10377
+ * dynamically modify the header row. This can be used to calculate and
10378
+ * display useful information about the table.
10379
+ * @type function
10380
+ * @param {node} head "TR" element for the header
10381
+ * @param {array} data Full table data (as derived from the original HTML)
10382
+ * @param {int} start Index for the current display starting point in the
10383
+ * display array
10384
+ * @param {int} end Index for the current display ending point in the
10385
+ * display array
10386
+ * @param {array int} display Index array to translate the visual position
10387
+ * to the full data array
10388
+ *
10389
+ * @dtopt Callbacks
10390
+ * @name DataTable.defaults.headerCallback
10391
+ *
10392
+ * @example
10393
+ * $(document).ready( function() {
10394
+ * $('#example').dataTable( {
10395
+ * "fheaderCallback": function( head, data, start, end, display ) {
10396
+ * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
10397
+ * }
10398
+ * } );
10399
+ * } )
10400
+ */
10401
+ "fnHeaderCallback": null,
10402
+
10403
+
10404
+ /**
10405
+ * The information element can be used to convey information about the current
10406
+ * state of the table. Although the internationalisation options presented by
10407
+ * DataTables are quite capable of dealing with most customisations, there may
10408
+ * be times where you wish to customise the string further. This callback
10409
+ * allows you to do exactly that.
10410
+ * @type function
10411
+ * @param {object} oSettings DataTables settings object
10412
+ * @param {int} start Starting position in data for the draw
10413
+ * @param {int} end End position in data for the draw
10414
+ * @param {int} max Total number of rows in the table (regardless of
10415
+ * filtering)
10416
+ * @param {int} total Total number of rows in the data set, after filtering
10417
+ * @param {string} pre The string that DataTables has formatted using it's
10418
+ * own rules
10419
+ * @returns {string} The string to be displayed in the information element.
10420
+ *
10421
+ * @dtopt Callbacks
10422
+ * @name DataTable.defaults.infoCallback
10423
+ *
10424
+ * @example
10425
+ * $('#example').dataTable( {
10426
+ * "infoCallback": function( settings, start, end, max, total, pre ) {
10427
+ * return start +" to "+ end;
10428
+ * }
10429
+ * } );
10430
+ */
10431
+ "fnInfoCallback": null,
10432
+
10433
+
10434
+ /**
10435
+ * Called when the table has been initialised. Normally DataTables will
10436
+ * initialise sequentially and there will be no need for this function,
10437
+ * however, this does not hold true when using external language information
10438
+ * since that is obtained using an async XHR call.
10439
+ * @type function
10440
+ * @param {object} settings DataTables settings object
10441
+ * @param {object} json The JSON object request from the server - only
10442
+ * present if client-side Ajax sourced data is used
10443
+ *
10444
+ * @dtopt Callbacks
10445
+ * @name DataTable.defaults.initComplete
10446
+ *
10447
+ * @example
10448
+ * $(document).ready( function() {
10449
+ * $('#example').dataTable( {
10450
+ * "initComplete": function(settings, json) {
10451
+ * alert( 'DataTables has finished its initialisation.' );
10452
+ * }
10453
+ * } );
10454
+ * } )
10455
+ */
10456
+ "fnInitComplete": null,
10457
+
10458
+
10459
+ /**
10460
+ * Called at the very start of each table draw and can be used to cancel the
10461
+ * draw by returning false, any other return (including undefined) results in
10462
+ * the full draw occurring).
10463
+ * @type function
10464
+ * @param {object} settings DataTables settings object
10465
+ * @returns {boolean} False will cancel the draw, anything else (including no
10466
+ * return) will allow it to complete.
10467
+ *
10468
+ * @dtopt Callbacks
10469
+ * @name DataTable.defaults.preDrawCallback
10470
+ *
10471
+ * @example
10472
+ * $(document).ready( function() {
10473
+ * $('#example').dataTable( {
10474
+ * "preDrawCallback": function( settings ) {
10475
+ * if ( $('#test').val() == 1 ) {
10476
+ * return false;
10477
+ * }
10478
+ * }
10479
+ * } );
10480
+ * } );
10481
+ */
10482
+ "fnPreDrawCallback": null,
10483
+
10484
+
10485
+ /**
10486
+ * This function allows you to 'post process' each row after it have been
10487
+ * generated for each table draw, but before it is rendered on screen. This
10488
+ * function might be used for setting the row class name etc.
10489
+ * @type function
10490
+ * @param {node} row "TR" element for the current row
10491
+ * @param {array} data Raw data array for this row
10492
+ * @param {int} displayIndex The display index for the current table draw
10493
+ * @param {int} displayIndexFull The index of the data in the full list of
10494
+ * rows (after filtering)
10495
+ *
10496
+ * @dtopt Callbacks
10497
+ * @name DataTable.defaults.rowCallback
10498
+ *
10499
+ * @example
10500
+ * $(document).ready( function() {
10501
+ * $('#example').dataTable( {
10502
+ * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
10503
+ * // Bold the grade for all 'A' grade browsers
10504
+ * if ( data[4] == "A" ) {
10505
+ * $('td:eq(4)', row).html( '<b>A</b>' );
10506
+ * }
10507
+ * }
10508
+ * } );
10509
+ * } );
10510
+ */
10511
+ "fnRowCallback": null,
10512
+
10513
+
10514
+ /**
10515
+ * __Deprecated__ The functionality provided by this parameter has now been
10516
+ * superseded by that provided through `ajax`, which should be used instead.
10517
+ *
10518
+ * This parameter allows you to override the default function which obtains
10519
+ * the data from the server so something more suitable for your application.
10520
+ * For example you could use POST data, or pull information from a Gears or
10521
+ * AIR database.
10522
+ * @type function
10523
+ * @member
10524
+ * @param {string} source HTTP source to obtain the data from (`ajax`)
10525
+ * @param {array} data A key/value pair object containing the data to send
10526
+ * to the server
10527
+ * @param {function} callback to be called on completion of the data get
10528
+ * process that will draw the data on the page.
10529
+ * @param {object} settings DataTables settings object
10530
+ *
10531
+ * @dtopt Callbacks
10532
+ * @dtopt Server-side
10533
+ * @name DataTable.defaults.serverData
10534
+ *
10535
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
10536
+ */
10537
+ "fnServerData": null,
10538
+
10539
+
10540
+ /**
10541
+ * __Deprecated__ The functionality provided by this parameter has now been
10542
+ * superseded by that provided through `ajax`, which should be used instead.
10543
+ *
10544
+ * It is often useful to send extra data to the server when making an Ajax
10545
+ * request - for example custom filtering information, and this callback
10546
+ * function makes it trivial to send extra information to the server. The
10547
+ * passed in parameter is the data set that has been constructed by
10548
+ * DataTables, and you can add to this or modify it as you require.
10549
+ * @type function
10550
+ * @param {array} data Data array (array of objects which are name/value
10551
+ * pairs) that has been constructed by DataTables and will be sent to the
10552
+ * server. In the case of Ajax sourced data with server-side processing
10553
+ * this will be an empty array, for server-side processing there will be a
10554
+ * significant number of parameters!
10555
+ * @returns {undefined} Ensure that you modify the data array passed in,
10556
+ * as this is passed by reference.
10557
+ *
10558
+ * @dtopt Callbacks
10559
+ * @dtopt Server-side
10560
+ * @name DataTable.defaults.serverParams
10561
+ *
10562
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
10563
+ */
10564
+ "fnServerParams": null,
10565
+
10566
+
10567
+ /**
10568
+ * Load the table state. With this function you can define from where, and how, the
10569
+ * state of a table is loaded. By default DataTables will load from `localStorage`
10570
+ * but you might wish to use a server-side database or cookies.
10571
+ * @type function
10572
+ * @member
10573
+ * @param {object} settings DataTables settings object
10574
+ * @return {object} The DataTables state object to be loaded
10575
+ *
10576
+ * @dtopt Callbacks
10577
+ * @name DataTable.defaults.stateLoadCallback
10578
+ *
10579
+ * @example
10580
+ * $(document).ready( function() {
10581
+ * $('#example').dataTable( {
10582
+ * "stateSave": true,
10583
+ * "stateLoadCallback": function (settings) {
10584
+ * var o;
10585
+ *
10586
+ * // Send an Ajax request to the server to get the data. Note that
10587
+ * // this is a synchronous request.
10588
+ * $.ajax( {
10589
+ * "url": "/state_load",
10590
+ * "async": false,
10591
+ * "dataType": "json",
10592
+ * "success": function (json) {
10593
+ * o = json;
10594
+ * }
10595
+ * } );
10596
+ *
10597
+ * return o;
10598
+ * }
10599
+ * } );
10600
+ * } );
10601
+ */
10602
+ "fnStateLoadCallback": function ( settings ) {
10603
+ try {
10604
+ return JSON.parse(
10605
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
10606
+ 'DataTables_'+settings.sInstance+'_'+location.pathname
10607
+ )
10608
+ );
10609
+ } catch (e) {}
10610
+ },
10611
+
10612
+
10613
+ /**
10614
+ * Callback which allows modification of the saved state prior to loading that state.
10615
+ * This callback is called when the table is loading state from the stored data, but
10616
+ * prior to the settings object being modified by the saved state. Note that for
10617
+ * plug-in authors, you should use the `stateLoadParams` event to load parameters for
10618
+ * a plug-in.
10619
+ * @type function
10620
+ * @param {object} settings DataTables settings object
10621
+ * @param {object} data The state object that is to be loaded
10622
+ *
10623
+ * @dtopt Callbacks
10624
+ * @name DataTable.defaults.stateLoadParams
10625
+ *
10626
+ * @example
10627
+ * // Remove a saved filter, so filtering is never loaded
10628
+ * $(document).ready( function() {
10629
+ * $('#example').dataTable( {
10630
+ * "stateSave": true,
10631
+ * "stateLoadParams": function (settings, data) {
10632
+ * data.oSearch.sSearch = "";
10633
+ * }
10634
+ * } );
10635
+ * } );
10636
+ *
10637
+ * @example
10638
+ * // Disallow state loading by returning false
10639
+ * $(document).ready( function() {
10640
+ * $('#example').dataTable( {
10641
+ * "stateSave": true,
10642
+ * "stateLoadParams": function (settings, data) {
10643
+ * return false;
10644
+ * }
10645
+ * } );
10646
+ * } );
10647
+ */
10648
+ "fnStateLoadParams": null,
10649
+
10650
+
10651
+ /**
10652
+ * Callback that is called when the state has been loaded from the state saving method
10653
+ * and the DataTables settings object has been modified as a result of the loaded state.
10654
+ * @type function
10655
+ * @param {object} settings DataTables settings object
10656
+ * @param {object} data The state object that was loaded
10657
+ *
10658
+ * @dtopt Callbacks
10659
+ * @name DataTable.defaults.stateLoaded
10660
+ *
10661
+ * @example
10662
+ * // Show an alert with the filtering value that was saved
10663
+ * $(document).ready( function() {
10664
+ * $('#example').dataTable( {
10665
+ * "stateSave": true,
10666
+ * "stateLoaded": function (settings, data) {
10667
+ * alert( 'Saved filter was: '+data.oSearch.sSearch );
10668
+ * }
10669
+ * } );
10670
+ * } );
10671
+ */
10672
+ "fnStateLoaded": null,
10673
+
10674
+
10675
+ /**
10676
+ * Save the table state. This function allows you to define where and how the state
10677
+ * information for the table is stored By default DataTables will use `localStorage`
10678
+ * but you might wish to use a server-side database or cookies.
10679
+ * @type function
10680
+ * @member
10681
+ * @param {object} settings DataTables settings object
10682
+ * @param {object} data The state object to be saved
10683
+ *
10684
+ * @dtopt Callbacks
10685
+ * @name DataTable.defaults.stateSaveCallback
10686
+ *
10687
+ * @example
10688
+ * $(document).ready( function() {
10689
+ * $('#example').dataTable( {
10690
+ * "stateSave": true,
10691
+ * "stateSaveCallback": function (settings, data) {
10692
+ * // Send an Ajax request to the server with the state object
10693
+ * $.ajax( {
10694
+ * "url": "/state_save",
10695
+ * "data": data,
10696
+ * "dataType": "json",
10697
+ * "method": "POST"
10698
+ * "success": function () {}
10699
+ * } );
10700
+ * }
10701
+ * } );
10702
+ * } );
10703
+ */
10704
+ "fnStateSaveCallback": function ( settings, data ) {
10705
+ try {
10706
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
10707
+ 'DataTables_'+settings.sInstance+'_'+location.pathname,
10708
+ JSON.stringify( data )
10709
+ );
10710
+ } catch (e) {}
10711
+ },
10712
+
10713
+
10714
+ /**
10715
+ * Callback which allows modification of the state to be saved. Called when the table
10716
+ * has changed state a new state save is required. This method allows modification of
10717
+ * the state saving object prior to actually doing the save, including addition or
10718
+ * other state properties or modification. Note that for plug-in authors, you should
10719
+ * use the `stateSaveParams` event to save parameters for a plug-in.
10720
+ * @type function
10721
+ * @param {object} settings DataTables settings object
10722
+ * @param {object} data The state object to be saved
10723
+ *
10724
+ * @dtopt Callbacks
10725
+ * @name DataTable.defaults.stateSaveParams
10726
+ *
10727
+ * @example
10728
+ * // Remove a saved filter, so filtering is never saved
10729
+ * $(document).ready( function() {
10730
+ * $('#example').dataTable( {
10731
+ * "stateSave": true,
10732
+ * "stateSaveParams": function (settings, data) {
10733
+ * data.oSearch.sSearch = "";
10734
+ * }
10735
+ * } );
10736
+ * } );
10737
+ */
10738
+ "fnStateSaveParams": null,
10739
+
10740
+
10741
+ /**
10742
+ * Duration for which the saved state information is considered valid. After this period
10743
+ * has elapsed the state will be returned to the default.
10744
+ * Value is given in seconds.
10745
+ * @type int
10746
+ * @default 7200 <i>(2 hours)</i>
10747
+ *
10748
+ * @dtopt Options
10749
+ * @name DataTable.defaults.stateDuration
10750
+ *
10751
+ * @example
10752
+ * $(document).ready( function() {
10753
+ * $('#example').dataTable( {
10754
+ * "stateDuration": 60*60*24; // 1 day
10755
+ * } );
10756
+ * } )
10757
+ */
10758
+ "iStateDuration": 7200,
10759
+
10760
+
10761
+ /**
10762
+ * When enabled DataTables will not make a request to the server for the first
10763
+ * page draw - rather it will use the data already on the page (no sorting etc
10764
+ * will be applied to it), thus saving on an XHR at load time. `deferLoading`
10765
+ * is used to indicate that deferred loading is required, but it is also used
10766
+ * to tell DataTables how many records there are in the full table (allowing
10767
+ * the information element and pagination to be displayed correctly). In the case
10768
+ * where a filtering is applied to the table on initial load, this can be
10769
+ * indicated by giving the parameter as an array, where the first element is
10770
+ * the number of records available after filtering and the second element is the
10771
+ * number of records without filtering (allowing the table information element
10772
+ * to be shown correctly).
10773
+ * @type int | array
10774
+ * @default null
10775
+ *
10776
+ * @dtopt Options
10777
+ * @name DataTable.defaults.deferLoading
10778
+ *
10779
+ * @example
10780
+ * // 57 records available in the table, no filtering applied
10781
+ * $(document).ready( function() {
10782
+ * $('#example').dataTable( {
10783
+ * "serverSide": true,
10784
+ * "ajax": "scripts/server_processing.php",
10785
+ * "deferLoading": 57
10786
+ * } );
10787
+ * } );
10788
+ *
10789
+ * @example
10790
+ * // 57 records after filtering, 100 without filtering (an initial filter applied)
10791
+ * $(document).ready( function() {
10792
+ * $('#example').dataTable( {
10793
+ * "serverSide": true,
10794
+ * "ajax": "scripts/server_processing.php",
10795
+ * "deferLoading": [ 57, 100 ],
10796
+ * "search": {
10797
+ * "search": "my_filter"
10798
+ * }
10799
+ * } );
10800
+ * } );
10801
+ */
10802
+ "iDeferLoading": null,
10803
+
10804
+
10805
+ /**
10806
+ * Number of rows to display on a single page when using pagination. If
10807
+ * feature enabled (`lengthChange`) then the end user will be able to override
10808
+ * this to a custom setting using a pop-up menu.
10809
+ * @type int
10810
+ * @default 10
10811
+ *
10812
+ * @dtopt Options
10813
+ * @name DataTable.defaults.pageLength
10814
+ *
10815
+ * @example
10816
+ * $(document).ready( function() {
10817
+ * $('#example').dataTable( {
10818
+ * "pageLength": 50
10819
+ * } );
10820
+ * } )
10821
+ */
10822
+ "iDisplayLength": 10,
10823
+
10824
+
10825
+ /**
10826
+ * Define the starting point for data display when using DataTables with
10827
+ * pagination. Note that this parameter is the number of records, rather than
10828
+ * the page number, so if you have 10 records per page and want to start on
10829
+ * the third page, it should be "20".
10830
+ * @type int
10831
+ * @default 0
10832
+ *
10833
+ * @dtopt Options
10834
+ * @name DataTable.defaults.displayStart
10835
+ *
10836
+ * @example
10837
+ * $(document).ready( function() {
10838
+ * $('#example').dataTable( {
10839
+ * "displayStart": 20
10840
+ * } );
10841
+ * } )
10842
+ */
10843
+ "iDisplayStart": 0,
10844
+
10845
+
10846
+ /**
10847
+ * By default DataTables allows keyboard navigation of the table (sorting, paging,
10848
+ * and filtering) by adding a `tabindex` attribute to the required elements. This
10849
+ * allows you to tab through the controls and press the enter key to activate them.
10850
+ * The tabindex is default 0, meaning that the tab follows the flow of the document.
10851
+ * You can overrule this using this parameter if you wish. Use a value of -1 to
10852
+ * disable built-in keyboard navigation.
10853
+ * @type int
10854
+ * @default 0
10855
+ *
10856
+ * @dtopt Options
10857
+ * @name DataTable.defaults.tabIndex
10858
+ *
10859
+ * @example
10860
+ * $(document).ready( function() {
10861
+ * $('#example').dataTable( {
10862
+ * "tabIndex": 1
10863
+ * } );
10864
+ * } );
10865
+ */
10866
+ "iTabIndex": 0,
10867
+
10868
+
10869
+ /**
10870
+ * Classes that DataTables assigns to the various components and features
10871
+ * that it adds to the HTML table. This allows classes to be configured
10872
+ * during initialisation in addition to through the static
10873
+ * {@link DataTable.ext.oStdClasses} object).
10874
+ * @namespace
10875
+ * @name DataTable.defaults.classes
10876
+ */
10877
+ "oClasses": {},
10878
+
10879
+
10880
+ /**
10881
+ * All strings that DataTables uses in the user interface that it creates
10882
+ * are defined in this object, allowing you to modified them individually or
10883
+ * completely replace them all as required.
10884
+ * @namespace
10885
+ * @name DataTable.defaults.language
10886
+ */
10887
+ "oLanguage": {
10888
+ /**
10889
+ * Strings that are used for WAI-ARIA labels and controls only (these are not
10890
+ * actually visible on the page, but will be read by screenreaders, and thus
10891
+ * must be internationalised as well).
10892
+ * @namespace
10893
+ * @name DataTable.defaults.language.aria
10894
+ */
10895
+ "oAria": {
10896
+ /**
10897
+ * ARIA label that is added to the table headers when the column may be
10898
+ * sorted ascending by activing the column (click or return when focused).
10899
+ * Note that the column header is prefixed to this string.
10900
+ * @type string
10901
+ * @default : activate to sort column ascending
10902
+ *
10903
+ * @dtopt Language
10904
+ * @name DataTable.defaults.language.aria.sortAscending
10905
+ *
10906
+ * @example
10907
+ * $(document).ready( function() {
10908
+ * $('#example').dataTable( {
10909
+ * "language": {
10910
+ * "aria": {
10911
+ * "sortAscending": " - click/return to sort ascending"
10912
+ * }
10913
+ * }
10914
+ * } );
10915
+ * } );
10916
+ */
10917
+ "sSortAscending": ": activate to sort column ascending",
10918
+
10919
+ /**
10920
+ * ARIA label that is added to the table headers when the column may be
10921
+ * sorted descending by activing the column (click or return when focused).
10922
+ * Note that the column header is prefixed to this string.
10923
+ * @type string
10924
+ * @default : activate to sort column ascending
10925
+ *
10926
+ * @dtopt Language
10927
+ * @name DataTable.defaults.language.aria.sortDescending
10928
+ *
10929
+ * @example
10930
+ * $(document).ready( function() {
10931
+ * $('#example').dataTable( {
10932
+ * "language": {
10933
+ * "aria": {
10934
+ * "sortDescending": " - click/return to sort descending"
10935
+ * }
10936
+ * }
10937
+ * } );
10938
+ * } );
10939
+ */
10940
+ "sSortDescending": ": activate to sort column descending"
10941
+ },
10942
+
10943
+ /**
10944
+ * Pagination string used by DataTables for the built-in pagination
10945
+ * control types.
10946
+ * @namespace
10947
+ * @name DataTable.defaults.language.paginate
10948
+ */
10949
+ "oPaginate": {
10950
+ /**
10951
+ * Text to use when using the 'full_numbers' type of pagination for the
10952
+ * button to take the user to the first page.
10953
+ * @type string
10954
+ * @default First
10955
+ *
10956
+ * @dtopt Language
10957
+ * @name DataTable.defaults.language.paginate.first
10958
+ *
10959
+ * @example
10960
+ * $(document).ready( function() {
10961
+ * $('#example').dataTable( {
10962
+ * "language": {
10963
+ * "paginate": {
10964
+ * "first": "First page"
10965
+ * }
10966
+ * }
10967
+ * } );
10968
+ * } );
10969
+ */
10970
+ "sFirst": "First",
10971
+
10972
+
10973
+ /**
10974
+ * Text to use when using the 'full_numbers' type of pagination for the
10975
+ * button to take the user to the last page.
10976
+ * @type string
10977
+ * @default Last
10978
+ *
10979
+ * @dtopt Language
10980
+ * @name DataTable.defaults.language.paginate.last
10981
+ *
10982
+ * @example
10983
+ * $(document).ready( function() {
10984
+ * $('#example').dataTable( {
10985
+ * "language": {
10986
+ * "paginate": {
10987
+ * "last": "Last page"
10988
+ * }
10989
+ * }
10990
+ * } );
10991
+ * } );
10992
+ */
10993
+ "sLast": "Last",
10994
+
10995
+
10996
+ /**
10997
+ * Text to use for the 'next' pagination button (to take the user to the
10998
+ * next page).
10999
+ * @type string
11000
+ * @default Next
11001
+ *
11002
+ * @dtopt Language
11003
+ * @name DataTable.defaults.language.paginate.next
11004
+ *
11005
+ * @example
11006
+ * $(document).ready( function() {
11007
+ * $('#example').dataTable( {
11008
+ * "language": {
11009
+ * "paginate": {
11010
+ * "next": "Next page"
11011
+ * }
11012
+ * }
11013
+ * } );
11014
+ * } );
11015
+ */
11016
+ "sNext": "Next",
11017
+
11018
+
11019
+ /**
11020
+ * Text to use for the 'previous' pagination button (to take the user to
11021
+ * the previous page).
11022
+ * @type string
11023
+ * @default Previous
11024
+ *
11025
+ * @dtopt Language
11026
+ * @name DataTable.defaults.language.paginate.previous
11027
+ *
11028
+ * @example
11029
+ * $(document).ready( function() {
11030
+ * $('#example').dataTable( {
11031
+ * "language": {
11032
+ * "paginate": {
11033
+ * "previous": "Previous page"
11034
+ * }
11035
+ * }
11036
+ * } );
11037
+ * } );
11038
+ */
11039
+ "sPrevious": "Previous"
11040
+ },
11041
+
11042
+ /**
11043
+ * This string is shown in preference to `zeroRecords` when the table is
11044
+ * empty of data (regardless of filtering). Note that this is an optional
11045
+ * parameter - if it is not given, the value of `zeroRecords` will be used
11046
+ * instead (either the default or given value).
11047
+ * @type string
11048
+ * @default No data available in table
11049
+ *
11050
+ * @dtopt Language
11051
+ * @name DataTable.defaults.language.emptyTable
11052
+ *
11053
+ * @example
11054
+ * $(document).ready( function() {
11055
+ * $('#example').dataTable( {
11056
+ * "language": {
11057
+ * "emptyTable": "No data available in table"
11058
+ * }
11059
+ * } );
11060
+ * } );
11061
+ */
11062
+ "sEmptyTable": "No data available in table",
11063
+
11064
+
11065
+ /**
11066
+ * This string gives information to the end user about the information
11067
+ * that is current on display on the page. The following tokens can be
11068
+ * used in the string and will be dynamically replaced as the table
11069
+ * display updates. This tokens can be placed anywhere in the string, or
11070
+ * removed as needed by the language requires:
11071
+ *
11072
+ * * `\_START\_` - Display index of the first record on the current page
11073
+ * * `\_END\_` - Display index of the last record on the current page
11074
+ * * `\_TOTAL\_` - Number of records in the table after filtering
11075
+ * * `\_MAX\_` - Number of records in the table without filtering
11076
+ * * `\_PAGE\_` - Current page number
11077
+ * * `\_PAGES\_` - Total number of pages of data in the table
11078
+ *
11079
+ * @type string
11080
+ * @default Showing _START_ to _END_ of _TOTAL_ entries
11081
+ *
11082
+ * @dtopt Language
11083
+ * @name DataTable.defaults.language.info
11084
+ *
11085
+ * @example
11086
+ * $(document).ready( function() {
11087
+ * $('#example').dataTable( {
11088
+ * "language": {
11089
+ * "info": "Showing page _PAGE_ of _PAGES_"
11090
+ * }
11091
+ * } );
11092
+ * } );
11093
+ */
11094
+ "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
11095
+
11096
+
11097
+ /**
11098
+ * Display information string for when the table is empty. Typically the
11099
+ * format of this string should match `info`.
11100
+ * @type string
11101
+ * @default Showing 0 to 0 of 0 entries
11102
+ *
11103
+ * @dtopt Language
11104
+ * @name DataTable.defaults.language.infoEmpty
11105
+ *
11106
+ * @example
11107
+ * $(document).ready( function() {
11108
+ * $('#example').dataTable( {
11109
+ * "language": {
11110
+ * "infoEmpty": "No entries to show"
11111
+ * }
11112
+ * } );
11113
+ * } );
11114
+ */
11115
+ "sInfoEmpty": "Showing 0 to 0 of 0 entries",
11116
+
11117
+
11118
+ /**
11119
+ * When a user filters the information in a table, this string is appended
11120
+ * to the information (`info`) to give an idea of how strong the filtering
11121
+ * is. The variable _MAX_ is dynamically updated.
11122
+ * @type string
11123
+ * @default (filtered from _MAX_ total entries)
11124
+ *
11125
+ * @dtopt Language
11126
+ * @name DataTable.defaults.language.infoFiltered
11127
+ *
11128
+ * @example
11129
+ * $(document).ready( function() {
11130
+ * $('#example').dataTable( {
11131
+ * "language": {
11132
+ * "infoFiltered": " - filtering from _MAX_ records"
11133
+ * }
11134
+ * } );
11135
+ * } );
11136
+ */
11137
+ "sInfoFiltered": "(filtered from _MAX_ total entries)",
11138
+
11139
+
11140
+ /**
11141
+ * If can be useful to append extra information to the info string at times,
11142
+ * and this variable does exactly that. This information will be appended to
11143
+ * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
11144
+ * being used) at all times.
11145
+ * @type string
11146
+ * @default <i>Empty string</i>
11147
+ *
11148
+ * @dtopt Language
11149
+ * @name DataTable.defaults.language.infoPostFix
11150
+ *
11151
+ * @example
11152
+ * $(document).ready( function() {
11153
+ * $('#example').dataTable( {
11154
+ * "language": {
11155
+ * "infoPostFix": "All records shown are derived from real information."
11156
+ * }
11157
+ * } );
11158
+ * } );
11159
+ */
11160
+ "sInfoPostFix": "",
11161
+
11162
+
11163
+ /**
11164
+ * This decimal place operator is a little different from the other
11165
+ * language options since DataTables doesn't output floating point
11166
+ * numbers, so it won't ever use this for display of a number. Rather,
11167
+ * what this parameter does is modify the sort methods of the table so
11168
+ * that numbers which are in a format which has a character other than
11169
+ * a period (`.`) as a decimal place will be sorted numerically.
11170
+ *
11171
+ * Note that numbers with different decimal places cannot be shown in
11172
+ * the same table and still be sortable, the table must be consistent.
11173
+ * However, multiple different tables on the page can use different
11174
+ * decimal place characters.
11175
+ * @type string
11176
+ * @default
11177
+ *
11178
+ * @dtopt Language
11179
+ * @name DataTable.defaults.language.decimal
11180
+ *
11181
+ * @example
11182
+ * $(document).ready( function() {
11183
+ * $('#example').dataTable( {
11184
+ * "language": {
11185
+ * "decimal": ","
11186
+ * "thousands": "."
11187
+ * }
11188
+ * } );
11189
+ * } );
11190
+ */
11191
+ "sDecimal": "",
11192
+
11193
+
11194
+ /**
11195
+ * DataTables has a build in number formatter (`formatNumber`) which is
11196
+ * used to format large numbers that are used in the table information.
11197
+ * By default a comma is used, but this can be trivially changed to any
11198
+ * character you wish with this parameter.
11199
+ * @type string
11200
+ * @default ,
11201
+ *
11202
+ * @dtopt Language
11203
+ * @name DataTable.defaults.language.thousands
11204
+ *
11205
+ * @example
11206
+ * $(document).ready( function() {
11207
+ * $('#example').dataTable( {
11208
+ * "language": {
11209
+ * "thousands": "'"
11210
+ * }
11211
+ * } );
11212
+ * } );
11213
+ */
11214
+ "sThousands": ",",
11215
+
11216
+
11217
+ /**
11218
+ * Detail the action that will be taken when the drop down menu for the
11219
+ * pagination length option is changed. The '_MENU_' variable is replaced
11220
+ * with a default select list of 10, 25, 50 and 100, and can be replaced
11221
+ * with a custom select box if required.
11222
+ * @type string
11223
+ * @default Show _MENU_ entries
11224
+ *
11225
+ * @dtopt Language
11226
+ * @name DataTable.defaults.language.lengthMenu
11227
+ *
11228
+ * @example
11229
+ * // Language change only
11230
+ * $(document).ready( function() {
11231
+ * $('#example').dataTable( {
11232
+ * "language": {
11233
+ * "lengthMenu": "Display _MENU_ records"
11234
+ * }
11235
+ * } );
11236
+ * } );
11237
+ *
11238
+ * @example
11239
+ * // Language and options change
11240
+ * $(document).ready( function() {
11241
+ * $('#example').dataTable( {
11242
+ * "language": {
11243
+ * "lengthMenu": 'Display <select>'+
11244
+ * '<option value="10">10</option>'+
11245
+ * '<option value="20">20</option>'+
11246
+ * '<option value="30">30</option>'+
11247
+ * '<option value="40">40</option>'+
11248
+ * '<option value="50">50</option>'+
11249
+ * '<option value="-1">All</option>'+
11250
+ * '</select> records'
11251
+ * }
11252
+ * } );
11253
+ * } );
11254
+ */
11255
+ "sLengthMenu": "Show _MENU_ entries",
11256
+
11257
+
11258
+ /**
11259
+ * When using Ajax sourced data and during the first draw when DataTables is
11260
+ * gathering the data, this message is shown in an empty row in the table to
11261
+ * indicate to the end user the the data is being loaded. Note that this
11262
+ * parameter is not used when loading data by server-side processing, just
11263
+ * Ajax sourced data with client-side processing.
11264
+ * @type string
11265
+ * @default Loading...
11266
+ *
11267
+ * @dtopt Language
11268
+ * @name DataTable.defaults.language.loadingRecords
11269
+ *
11270
+ * @example
11271
+ * $(document).ready( function() {
11272
+ * $('#example').dataTable( {
11273
+ * "language": {
11274
+ * "loadingRecords": "Please wait - loading..."
11275
+ * }
11276
+ * } );
11277
+ * } );
11278
+ */
11279
+ "sLoadingRecords": "Loading...",
11280
+
11281
+
11282
+ /**
11283
+ * Text which is displayed when the table is processing a user action
11284
+ * (usually a sort command or similar).
11285
+ * @type string
11286
+ * @default Processing...
11287
+ *
11288
+ * @dtopt Language
11289
+ * @name DataTable.defaults.language.processing
11290
+ *
11291
+ * @example
11292
+ * $(document).ready( function() {
11293
+ * $('#example').dataTable( {
11294
+ * "language": {
11295
+ * "processing": "DataTables is currently busy"
11296
+ * }
11297
+ * } );
11298
+ * } );
11299
+ */
11300
+ "sProcessing": "Processing...",
11301
+
11302
+
11303
+ /**
11304
+ * Details the actions that will be taken when the user types into the
11305
+ * filtering input text box. The variable "_INPUT_", if used in the string,
11306
+ * is replaced with the HTML text box for the filtering input allowing
11307
+ * control over where it appears in the string. If "_INPUT_" is not given
11308
+ * then the input box is appended to the string automatically.
11309
+ * @type string
11310
+ * @default Search:
11311
+ *
11312
+ * @dtopt Language
11313
+ * @name DataTable.defaults.language.search
11314
+ *
11315
+ * @example
11316
+ * // Input text box will be appended at the end automatically
11317
+ * $(document).ready( function() {
11318
+ * $('#example').dataTable( {
11319
+ * "language": {
11320
+ * "search": "Filter records:"
11321
+ * }
11322
+ * } );
11323
+ * } );
11324
+ *
11325
+ * @example
11326
+ * // Specify where the filter should appear
11327
+ * $(document).ready( function() {
11328
+ * $('#example').dataTable( {
11329
+ * "language": {
11330
+ * "search": "Apply filter _INPUT_ to table"
11331
+ * }
11332
+ * } );
11333
+ * } );
11334
+ */
11335
+ "sSearch": "Search:",
11336
+
11337
+
11338
+ /**
11339
+ * Assign a `placeholder` attribute to the search `input` element
11340
+ * @type string
11341
+ * @default
11342
+ *
11343
+ * @dtopt Language
11344
+ * @name DataTable.defaults.language.searchPlaceholder
11345
+ */
11346
+ "sSearchPlaceholder": "",
11347
+
11348
+
11349
+ /**
11350
+ * All of the language information can be stored in a file on the
11351
+ * server-side, which DataTables will look up if this parameter is passed.
11352
+ * It must store the URL of the language file, which is in a JSON format,
11353
+ * and the object has the same properties as the oLanguage object in the
11354
+ * initialiser object (i.e. the above parameters). Please refer to one of
11355
+ * the example language files to see how this works in action.
11356
+ * @type string
11357
+ * @default <i>Empty string - i.e. disabled</i>
11358
+ *
11359
+ * @dtopt Language
11360
+ * @name DataTable.defaults.language.url
11361
+ *
11362
+ * @example
11363
+ * $(document).ready( function() {
11364
+ * $('#example').dataTable( {
11365
+ * "language": {
11366
+ * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
11367
+ * }
11368
+ * } );
11369
+ * } );
11370
+ */
11371
+ "sUrl": "",
11372
+
11373
+
11374
+ /**
11375
+ * Text shown inside the table records when the is no information to be
11376
+ * displayed after filtering. `emptyTable` is shown when there is simply no
11377
+ * information in the table at all (regardless of filtering).
11378
+ * @type string
11379
+ * @default No matching records found
11380
+ *
11381
+ * @dtopt Language
11382
+ * @name DataTable.defaults.language.zeroRecords
11383
+ *
11384
+ * @example
11385
+ * $(document).ready( function() {
11386
+ * $('#example').dataTable( {
11387
+ * "language": {
11388
+ * "zeroRecords": "No records to display"
11389
+ * }
11390
+ * } );
11391
+ * } );
11392
+ */
11393
+ "sZeroRecords": "No matching records found"
11394
+ },
11395
+
11396
+
11397
+ /**
11398
+ * This parameter allows you to have define the global filtering state at
11399
+ * initialisation time. As an object the `search` parameter must be
11400
+ * defined, but all other parameters are optional. When `regex` is true,
11401
+ * the search string will be treated as a regular expression, when false
11402
+ * (default) it will be treated as a straight string. When `smart`
11403
+ * DataTables will use it's smart filtering methods (to word match at
11404
+ * any point in the data), when false this will not be done.
11405
+ * @namespace
11406
+ * @extends DataTable.models.oSearch
11407
+ *
11408
+ * @dtopt Options
11409
+ * @name DataTable.defaults.search
11410
+ *
11411
+ * @example
11412
+ * $(document).ready( function() {
11413
+ * $('#example').dataTable( {
11414
+ * "search": {"search": "Initial search"}
11415
+ * } );
11416
+ * } )
11417
+ */
11418
+ "oSearch": $.extend( {}, DataTable.models.oSearch ),
11419
+
11420
+
11421
+ /**
11422
+ * __Deprecated__ The functionality provided by this parameter has now been
11423
+ * superseded by that provided through `ajax`, which should be used instead.
11424
+ *
11425
+ * By default DataTables will look for the property `data` (or `aaData` for
11426
+ * compatibility with DataTables 1.9-) when obtaining data from an Ajax
11427
+ * source or for server-side processing - this parameter allows that
11428
+ * property to be changed. You can use Javascript dotted object notation to
11429
+ * get a data source for multiple levels of nesting.
11430
+ * @type string
11431
+ * @default data
11432
+ *
11433
+ * @dtopt Options
11434
+ * @dtopt Server-side
11435
+ * @name DataTable.defaults.ajaxDataProp
11436
+ *
11437
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11438
+ */
11439
+ "sAjaxDataProp": "data",
11440
+
11441
+
11442
+ /**
11443
+ * __Deprecated__ The functionality provided by this parameter has now been
11444
+ * superseded by that provided through `ajax`, which should be used instead.
11445
+ *
11446
+ * You can instruct DataTables to load data from an external
11447
+ * source using this parameter (use aData if you want to pass data in you
11448
+ * already have). Simply provide a url a JSON object can be obtained from.
11449
+ * @type string
11450
+ * @default null
11451
+ *
11452
+ * @dtopt Options
11453
+ * @dtopt Server-side
11454
+ * @name DataTable.defaults.ajaxSource
11455
+ *
11456
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11457
+ */
11458
+ "sAjaxSource": null,
11459
+
11460
+
11461
+ /**
11462
+ * This initialisation variable allows you to specify exactly where in the
11463
+ * DOM you want DataTables to inject the various controls it adds to the page
11464
+ * (for example you might want the pagination controls at the top of the
11465
+ * table). DIV elements (with or without a custom class) can also be added to
11466
+ * aid styling. The follow syntax is used:
11467
+ * <ul>
11468
+ * <li>The following options are allowed:
11469
+ * <ul>
11470
+ * <li>'l' - Length changing</li>
11471
+ * <li>'f' - Filtering input</li>
11472
+ * <li>'t' - The table!</li>
11473
+ * <li>'i' - Information</li>
11474
+ * <li>'p' - Pagination</li>
11475
+ * <li>'r' - pRocessing</li>
11476
+ * </ul>
11477
+ * </li>
11478
+ * <li>The following constants are allowed:
11479
+ * <ul>
11480
+ * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
11481
+ * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
11482
+ * </ul>
11483
+ * </li>
11484
+ * <li>The following syntax is expected:
11485
+ * <ul>
11486
+ * <li>'&lt;' and '&gt;' - div elements</li>
11487
+ * <li>'&lt;"class" and '&gt;' - div with a class</li>
11488
+ * <li>'&lt;"#id" and '&gt;' - div with an ID</li>
11489
+ * </ul>
11490
+ * </li>
11491
+ * <li>Examples:
11492
+ * <ul>
11493
+ * <li>'&lt;"wrapper"flipt&gt;'</li>
11494
+ * <li>'&lt;lf&lt;t&gt;ip&gt;'</li>
11495
+ * </ul>
11496
+ * </li>
11497
+ * </ul>
11498
+ * @type string
11499
+ * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
11500
+ * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
11501
+ *
11502
+ * @dtopt Options
11503
+ * @name DataTable.defaults.dom
11504
+ *
11505
+ * @example
11506
+ * $(document).ready( function() {
11507
+ * $('#example').dataTable( {
11508
+ * "dom": '&lt;"top"i&gt;rt&lt;"bottom"flp&gt;&lt;"clear"&gt;'
11509
+ * } );
11510
+ * } );
11511
+ */
11512
+ "sDom": "lfrtip",
11513
+
11514
+
11515
+ /**
11516
+ * Search delay option. This will throttle full table searches that use the
11517
+ * DataTables provided search input element (it does not effect calls to
11518
+ * `dt-api search()`, providing a delay before the search is made.
11519
+ * @type integer
11520
+ * @default 0
11521
+ *
11522
+ * @dtopt Options
11523
+ * @name DataTable.defaults.searchDelay
11524
+ *
11525
+ * @example
11526
+ * $(document).ready( function() {
11527
+ * $('#example').dataTable( {
11528
+ * "searchDelay": 200
11529
+ * } );
11530
+ * } )
11531
+ */
11532
+ "searchDelay": null,
11533
+
11534
+
11535
+ /**
11536
+ * DataTables features four different built-in options for the buttons to
11537
+ * display for pagination control:
11538
+ *
11539
+ * * `simple` - 'Previous' and 'Next' buttons only
11540
+ * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
11541
+ * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
11542
+ * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus
11543
+ * page numbers
11544
+ *
11545
+ * Further methods can be added using {@link DataTable.ext.oPagination}.
11546
+ * @type string
11547
+ * @default simple_numbers
11548
+ *
11549
+ * @dtopt Options
11550
+ * @name DataTable.defaults.pagingType
11551
+ *
11552
+ * @example
11553
+ * $(document).ready( function() {
11554
+ * $('#example').dataTable( {
11555
+ * "pagingType": "full_numbers"
11556
+ * } );
11557
+ * } )
11558
+ */
11559
+ "sPaginationType": "simple_numbers",
11560
+
11561
+
11562
+ /**
11563
+ * Enable horizontal scrolling. When a table is too wide to fit into a
11564
+ * certain layout, or you have a large number of columns in the table, you
11565
+ * can enable x-scrolling to show the table in a viewport, which can be
11566
+ * scrolled. This property can be `true` which will allow the table to
11567
+ * scroll horizontally when needed, or any CSS unit, or a number (in which
11568
+ * case it will be treated as a pixel measurement). Setting as simply `true`
11569
+ * is recommended.
11570
+ * @type boolean|string
11571
+ * @default <i>blank string - i.e. disabled</i>
11572
+ *
11573
+ * @dtopt Features
11574
+ * @name DataTable.defaults.scrollX
11575
+ *
11576
+ * @example
11577
+ * $(document).ready( function() {
11578
+ * $('#example').dataTable( {
11579
+ * "scrollX": true,
11580
+ * "scrollCollapse": true
11581
+ * } );
11582
+ * } );
11583
+ */
11584
+ "sScrollX": "",
11585
+
11586
+
11587
+ /**
11588
+ * This property can be used to force a DataTable to use more width than it
11589
+ * might otherwise do when x-scrolling is enabled. For example if you have a
11590
+ * table which requires to be well spaced, this parameter is useful for
11591
+ * "over-sizing" the table, and thus forcing scrolling. This property can by
11592
+ * any CSS unit, or a number (in which case it will be treated as a pixel
11593
+ * measurement).
11594
+ * @type string
11595
+ * @default <i>blank string - i.e. disabled</i>
11596
+ *
11597
+ * @dtopt Options
11598
+ * @name DataTable.defaults.scrollXInner
11599
+ *
11600
+ * @example
11601
+ * $(document).ready( function() {
11602
+ * $('#example').dataTable( {
11603
+ * "scrollX": "100%",
11604
+ * "scrollXInner": "110%"
11605
+ * } );
11606
+ * } );
11607
+ */
11608
+ "sScrollXInner": "",
11609
+
11610
+
11611
+ /**
11612
+ * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
11613
+ * to the given height, and enable scrolling for any data which overflows the
11614
+ * current viewport. This can be used as an alternative to paging to display
11615
+ * a lot of data in a small area (although paging and scrolling can both be
11616
+ * enabled at the same time). This property can be any CSS unit, or a number
11617
+ * (in which case it will be treated as a pixel measurement).
11618
+ * @type string
11619
+ * @default <i>blank string - i.e. disabled</i>
11620
+ *
11621
+ * @dtopt Features
11622
+ * @name DataTable.defaults.scrollY
11623
+ *
11624
+ * @example
11625
+ * $(document).ready( function() {
11626
+ * $('#example').dataTable( {
11627
+ * "scrollY": "200px",
11628
+ * "paginate": false
11629
+ * } );
11630
+ * } );
11631
+ */
11632
+ "sScrollY": "",
11633
+
11634
+
11635
+ /**
11636
+ * __Deprecated__ The functionality provided by this parameter has now been
11637
+ * superseded by that provided through `ajax`, which should be used instead.
11638
+ *
11639
+ * Set the HTTP method that is used to make the Ajax call for server-side
11640
+ * processing or Ajax sourced data.
11641
+ * @type string
11642
+ * @default GET
11643
+ *
11644
+ * @dtopt Options
11645
+ * @dtopt Server-side
11646
+ * @name DataTable.defaults.serverMethod
11647
+ *
11648
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
11649
+ */
11650
+ "sServerMethod": "GET",
11651
+
11652
+
11653
+ /**
11654
+ * DataTables makes use of renderers when displaying HTML elements for
11655
+ * a table. These renderers can be added or modified by plug-ins to
11656
+ * generate suitable mark-up for a site. For example the Bootstrap
11657
+ * integration plug-in for DataTables uses a paging button renderer to
11658
+ * display pagination buttons in the mark-up required by Bootstrap.
11659
+ *
11660
+ * For further information about the renderers available see
11661
+ * DataTable.ext.renderer
11662
+ * @type string|object
11663
+ * @default null
11664
+ *
11665
+ * @name DataTable.defaults.renderer
11666
+ *
11667
+ */
11668
+ "renderer": null
11669
+ };
11670
+
11671
+ _fnHungarianMap( DataTable.defaults );
11672
+
11673
+
11674
+
11675
+ /*
11676
+ * Developer note - See note in model.defaults.js about the use of Hungarian
11677
+ * notation and camel case.
11678
+ */
11679
+
11680
+ /**
11681
+ * Column options that can be given to DataTables at initialisation time.
11682
+ * @namespace
11683
+ */
11684
+ DataTable.defaults.column = {
11685
+ /**
11686
+ * Define which column(s) an order will occur on for this column. This
11687
+ * allows a column's ordering to take multiple columns into account when
11688
+ * doing a sort or use the data from a different column. For example first
11689
+ * name / last name columns make sense to do a multi-column sort over the
11690
+ * two columns.
11691
+ * @type array|int
11692
+ * @default null <i>Takes the value of the column index automatically</i>
11693
+ *
11694
+ * @name DataTable.defaults.column.orderData
11695
+ * @dtopt Columns
11696
+ *
11697
+ * @example
11698
+ * // Using `columnDefs`
11699
+ * $(document).ready( function() {
11700
+ * $('#example').dataTable( {
11701
+ * "columnDefs": [
11702
+ * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
11703
+ * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
11704
+ * { "orderData": 2, "targets": [ 2 ] }
11705
+ * ]
11706
+ * } );
11707
+ * } );
11708
+ *
11709
+ * @example
11710
+ * // Using `columns`
11711
+ * $(document).ready( function() {
11712
+ * $('#example').dataTable( {
11713
+ * "columns": [
11714
+ * { "orderData": [ 0, 1 ] },
11715
+ * { "orderData": [ 1, 0 ] },
11716
+ * { "orderData": 2 },
11717
+ * null,
11718
+ * null
11719
+ * ]
11720
+ * } );
11721
+ * } );
11722
+ */
11723
+ "aDataSort": null,
11724
+ "iDataSort": -1,
11725
+
11726
+
11727
+ /**
11728
+ * You can control the default ordering direction, and even alter the
11729
+ * behaviour of the sort handler (i.e. only allow ascending ordering etc)
11730
+ * using this parameter.
11731
+ * @type array
11732
+ * @default [ 'asc', 'desc' ]
11733
+ *
11734
+ * @name DataTable.defaults.column.orderSequence
11735
+ * @dtopt Columns
11736
+ *
11737
+ * @example
11738
+ * // Using `columnDefs`
11739
+ * $(document).ready( function() {
11740
+ * $('#example').dataTable( {
11741
+ * "columnDefs": [
11742
+ * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
11743
+ * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
11744
+ * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
11745
+ * ]
11746
+ * } );
11747
+ * } );
11748
+ *
11749
+ * @example
11750
+ * // Using `columns`
11751
+ * $(document).ready( function() {
11752
+ * $('#example').dataTable( {
11753
+ * "columns": [
11754
+ * null,
11755
+ * { "orderSequence": [ "asc" ] },
11756
+ * { "orderSequence": [ "desc", "asc", "asc" ] },
11757
+ * { "orderSequence": [ "desc" ] },
11758
+ * null
11759
+ * ]
11760
+ * } );
11761
+ * } );
11762
+ */
11763
+ "asSorting": [ 'asc', 'desc' ],
11764
+
11765
+
11766
+ /**
11767
+ * Enable or disable filtering on the data in this column.
11768
+ * @type boolean
11769
+ * @default true
11770
+ *
11771
+ * @name DataTable.defaults.column.searchable
11772
+ * @dtopt Columns
11773
+ *
11774
+ * @example
11775
+ * // Using `columnDefs`
11776
+ * $(document).ready( function() {
11777
+ * $('#example').dataTable( {
11778
+ * "columnDefs": [
11779
+ * { "searchable": false, "targets": [ 0 ] }
11780
+ * ] } );
11781
+ * } );
11782
+ *
11783
+ * @example
11784
+ * // Using `columns`
11785
+ * $(document).ready( function() {
11786
+ * $('#example').dataTable( {
11787
+ * "columns": [
11788
+ * { "searchable": false },
11789
+ * null,
11790
+ * null,
11791
+ * null,
11792
+ * null
11793
+ * ] } );
11794
+ * } );
11795
+ */
11796
+ "bSearchable": true,
11797
+
11798
+
11799
+ /**
11800
+ * Enable or disable ordering on this column.
11801
+ * @type boolean
11802
+ * @default true
11803
+ *
11804
+ * @name DataTable.defaults.column.orderable
11805
+ * @dtopt Columns
11806
+ *
11807
+ * @example
11808
+ * // Using `columnDefs`
11809
+ * $(document).ready( function() {
11810
+ * $('#example').dataTable( {
11811
+ * "columnDefs": [
11812
+ * { "orderable": false, "targets": [ 0 ] }
11813
+ * ] } );
11814
+ * } );
11815
+ *
11816
+ * @example
11817
+ * // Using `columns`
11818
+ * $(document).ready( function() {
11819
+ * $('#example').dataTable( {
11820
+ * "columns": [
11821
+ * { "orderable": false },
11822
+ * null,
11823
+ * null,
11824
+ * null,
11825
+ * null
11826
+ * ] } );
11827
+ * } );
11828
+ */
11829
+ "bSortable": true,
11830
+
11831
+
11832
+ /**
11833
+ * Enable or disable the display of this column.
11834
+ * @type boolean
11835
+ * @default true
11836
+ *
11837
+ * @name DataTable.defaults.column.visible
11838
+ * @dtopt Columns
11839
+ *
11840
+ * @example
11841
+ * // Using `columnDefs`
11842
+ * $(document).ready( function() {
11843
+ * $('#example').dataTable( {
11844
+ * "columnDefs": [
11845
+ * { "visible": false, "targets": [ 0 ] }
11846
+ * ] } );
11847
+ * } );
11848
+ *
11849
+ * @example
11850
+ * // Using `columns`
11851
+ * $(document).ready( function() {
11852
+ * $('#example').dataTable( {
11853
+ * "columns": [
11854
+ * { "visible": false },
11855
+ * null,
11856
+ * null,
11857
+ * null,
11858
+ * null
11859
+ * ] } );
11860
+ * } );
11861
+ */
11862
+ "bVisible": true,
11863
+
11864
+
11865
+ /**
11866
+ * Developer definable function that is called whenever a cell is created (Ajax source,
11867
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
11868
+ * allowing you to modify the DOM element (add background colour for example) when the
11869
+ * element is available.
11870
+ * @type function
11871
+ * @param {element} td The TD node that has been created
11872
+ * @param {*} cellData The Data for the cell
11873
+ * @param {array|object} rowData The data for the whole row
11874
+ * @param {int} row The row index for the aoData data store
11875
+ * @param {int} col The column index for aoColumns
11876
+ *
11877
+ * @name DataTable.defaults.column.createdCell
11878
+ * @dtopt Columns
11879
+ *
11880
+ * @example
11881
+ * $(document).ready( function() {
11882
+ * $('#example').dataTable( {
11883
+ * "columnDefs": [ {
11884
+ * "targets": [3],
11885
+ * "createdCell": function (td, cellData, rowData, row, col) {
11886
+ * if ( cellData == "1.7" ) {
11887
+ * $(td).css('color', 'blue')
11888
+ * }
11889
+ * }
11890
+ * } ]
11891
+ * });
11892
+ * } );
11893
+ */
11894
+ "fnCreatedCell": null,
11895
+
11896
+
11897
+ /**
11898
+ * This parameter has been replaced by `data` in DataTables to ensure naming
11899
+ * consistency. `dataProp` can still be used, as there is backwards
11900
+ * compatibility in DataTables for this option, but it is strongly
11901
+ * recommended that you use `data` in preference to `dataProp`.
11902
+ * @name DataTable.defaults.column.dataProp
11903
+ */
11904
+
11905
+
11906
+ /**
11907
+ * This property can be used to read data from any data source property,
11908
+ * including deeply nested objects / properties. `data` can be given in a
11909
+ * number of different ways which effect its behaviour:
11910
+ *
11911
+ * * `integer` - treated as an array index for the data source. This is the
11912
+ * default that DataTables uses (incrementally increased for each column).
11913
+ * * `string` - read an object property from the data source. There are
11914
+ * three 'special' options that can be used in the string to alter how
11915
+ * DataTables reads the data from the source object:
11916
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
11917
+ * Javascript to read from nested objects, so to can the options
11918
+ * specified in `data`. For example: `browser.version` or
11919
+ * `browser.name`. If your object parameter name contains a period, use
11920
+ * `\\` to escape it - i.e. `first\\.name`.
11921
+ * * `[]` - Array notation. DataTables can automatically combine data
11922
+ * from and array source, joining the data with the characters provided
11923
+ * between the two brackets. For example: `name[, ]` would provide a
11924
+ * comma-space separated list from the source array. If no characters
11925
+ * are provided between the brackets, the original array source is
11926
+ * returned.
11927
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
11928
+ * execute a function of the name given. For example: `browser()` for a
11929
+ * simple function on the data source, `browser.version()` for a
11930
+ * function in a nested property or even `browser().version` to get an
11931
+ * object property if the function called returns an object. Note that
11932
+ * function notation is recommended for use in `render` rather than
11933
+ * `data` as it is much simpler to use as a renderer.
11934
+ * * `null` - use the original data source for the row rather than plucking
11935
+ * data directly from it. This action has effects on two other
11936
+ * initialisation options:
11937
+ * * `defaultContent` - When null is given as the `data` option and
11938
+ * `defaultContent` is specified for the column, the value defined by
11939
+ * `defaultContent` will be used for the cell.
11940
+ * * `render` - When null is used for the `data` option and the `render`
11941
+ * option is specified for the column, the whole data source for the
11942
+ * row is used for the renderer.
11943
+ * * `function` - the function given will be executed whenever DataTables
11944
+ * needs to set or get the data for a cell in the column. The function
11945
+ * takes three parameters:
11946
+ * * Parameters:
11947
+ * * `{array|object}` The data source for the row
11948
+ * * `{string}` The type call data requested - this will be 'set' when
11949
+ * setting data or 'filter', 'display', 'type', 'sort' or undefined
11950
+ * when gathering data. Note that when `undefined` is given for the
11951
+ * type DataTables expects to get the raw data for the object back<
11952
+ * * `{*}` Data to set when the second parameter is 'set'.
11953
+ * * Return:
11954
+ * * The return value from the function is not required when 'set' is
11955
+ * the type of call, but otherwise the return is what will be used
11956
+ * for the data requested.
11957
+ *
11958
+ * Note that `data` is a getter and setter option. If you just require
11959
+ * formatting of data for output, you will likely want to use `render` which
11960
+ * is simply a getter and thus simpler to use.
11961
+ *
11962
+ * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
11963
+ * name change reflects the flexibility of this property and is consistent
11964
+ * with the naming of mRender. If 'mDataProp' is given, then it will still
11965
+ * be used by DataTables, as it automatically maps the old name to the new
11966
+ * if required.
11967
+ *
11968
+ * @type string|int|function|null
11969
+ * @default null <i>Use automatically calculated column index</i>
11970
+ *
11971
+ * @name DataTable.defaults.column.data
11972
+ * @dtopt Columns
11973
+ *
11974
+ * @example
11975
+ * // Read table data from objects
11976
+ * // JSON structure for each row:
11977
+ * // {
11978
+ * // "engine": {value},
11979
+ * // "browser": {value},
11980
+ * // "platform": {value},
11981
+ * // "version": {value},
11982
+ * // "grade": {value}
11983
+ * // }
11984
+ * $(document).ready( function() {
11985
+ * $('#example').dataTable( {
11986
+ * "ajaxSource": "sources/objects.txt",
11987
+ * "columns": [
11988
+ * { "data": "engine" },
11989
+ * { "data": "browser" },
11990
+ * { "data": "platform" },
11991
+ * { "data": "version" },
11992
+ * { "data": "grade" }
11993
+ * ]
11994
+ * } );
11995
+ * } );
11996
+ *
11997
+ * @example
11998
+ * // Read information from deeply nested objects
11999
+ * // JSON structure for each row:
12000
+ * // {
12001
+ * // "engine": {value},
12002
+ * // "browser": {value},
12003
+ * // "platform": {
12004
+ * // "inner": {value}
12005
+ * // },
12006
+ * // "details": [
12007
+ * // {value}, {value}
12008
+ * // ]
12009
+ * // }
12010
+ * $(document).ready( function() {
12011
+ * $('#example').dataTable( {
12012
+ * "ajaxSource": "sources/deep.txt",
12013
+ * "columns": [
12014
+ * { "data": "engine" },
12015
+ * { "data": "browser" },
12016
+ * { "data": "platform.inner" },
12017
+ * { "data": "platform.details.0" },
12018
+ * { "data": "platform.details.1" }
12019
+ * ]
12020
+ * } );
12021
+ * } );
12022
+ *
12023
+ * @example
12024
+ * // Using `data` as a function to provide different information for
12025
+ * // sorting, filtering and display. In this case, currency (price)
12026
+ * $(document).ready( function() {
12027
+ * $('#example').dataTable( {
12028
+ * "columnDefs": [ {
12029
+ * "targets": [ 0 ],
12030
+ * "data": function ( source, type, val ) {
12031
+ * if (type === 'set') {
12032
+ * source.price = val;
12033
+ * // Store the computed dislay and filter values for efficiency
12034
+ * source.price_display = val=="" ? "" : "$"+numberFormat(val);
12035
+ * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
12036
+ * return;
12037
+ * }
12038
+ * else if (type === 'display') {
12039
+ * return source.price_display;
12040
+ * }
12041
+ * else if (type === 'filter') {
12042
+ * return source.price_filter;
12043
+ * }
12044
+ * // 'sort', 'type' and undefined all just use the integer
12045
+ * return source.price;
12046
+ * }
12047
+ * } ]
12048
+ * } );
12049
+ * } );
12050
+ *
12051
+ * @example
12052
+ * // Using default content
12053
+ * $(document).ready( function() {
12054
+ * $('#example').dataTable( {
12055
+ * "columnDefs": [ {
12056
+ * "targets": [ 0 ],
12057
+ * "data": null,
12058
+ * "defaultContent": "Click to edit"
12059
+ * } ]
12060
+ * } );
12061
+ * } );
12062
+ *
12063
+ * @example
12064
+ * // Using array notation - outputting a list from an array
12065
+ * $(document).ready( function() {
12066
+ * $('#example').dataTable( {
12067
+ * "columnDefs": [ {
12068
+ * "targets": [ 0 ],
12069
+ * "data": "name[, ]"
12070
+ * } ]
12071
+ * } );
12072
+ * } );
12073
+ *
12074
+ */
12075
+ "mData": null,
12076
+
12077
+
12078
+ /**
12079
+ * This property is the rendering partner to `data` and it is suggested that
12080
+ * when you want to manipulate data for display (including filtering,
12081
+ * sorting etc) without altering the underlying data for the table, use this
12082
+ * property. `render` can be considered to be the the read only companion to
12083
+ * `data` which is read / write (then as such more complex). Like `data`
12084
+ * this option can be given in a number of different ways to effect its
12085
+ * behaviour:
12086
+ *
12087
+ * * `integer` - treated as an array index for the data source. This is the
12088
+ * default that DataTables uses (incrementally increased for each column).
12089
+ * * `string` - read an object property from the data source. There are
12090
+ * three 'special' options that can be used in the string to alter how
12091
+ * DataTables reads the data from the source object:
12092
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
12093
+ * Javascript to read from nested objects, so to can the options
12094
+ * specified in `data`. For example: `browser.version` or
12095
+ * `browser.name`. If your object parameter name contains a period, use
12096
+ * `\\` to escape it - i.e. `first\\.name`.
12097
+ * * `[]` - Array notation. DataTables can automatically combine data
12098
+ * from and array source, joining the data with the characters provided
12099
+ * between the two brackets. For example: `name[, ]` would provide a
12100
+ * comma-space separated list from the source array. If no characters
12101
+ * are provided between the brackets, the original array source is
12102
+ * returned.
12103
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
12104
+ * execute a function of the name given. For example: `browser()` for a
12105
+ * simple function on the data source, `browser.version()` for a
12106
+ * function in a nested property or even `browser().version` to get an
12107
+ * object property if the function called returns an object.
12108
+ * * `object` - use different data for the different data types requested by
12109
+ * DataTables ('filter', 'display', 'type' or 'sort'). The property names
12110
+ * of the object is the data type the property refers to and the value can
12111
+ * defined using an integer, string or function using the same rules as
12112
+ * `render` normally does. Note that an `_` option _must_ be specified.
12113
+ * This is the default value to use if you haven't specified a value for
12114
+ * the data type requested by DataTables.
12115
+ * * `function` - the function given will be executed whenever DataTables
12116
+ * needs to set or get the data for a cell in the column. The function
12117
+ * takes three parameters:
12118
+ * * Parameters:
12119
+ * * {array|object} The data source for the row (based on `data`)
12120
+ * * {string} The type call data requested - this will be 'filter',
12121
+ * 'display', 'type' or 'sort'.
12122
+ * * {array|object} The full data source for the row (not based on
12123
+ * `data`)
12124
+ * * Return:
12125
+ * * The return value from the function is what will be used for the
12126
+ * data requested.
12127
+ *
12128
+ * @type string|int|function|object|null
12129
+ * @default null Use the data source value.
12130
+ *
12131
+ * @name DataTable.defaults.column.render
12132
+ * @dtopt Columns
12133
+ *
12134
+ * @example
12135
+ * // Create a comma separated list from an array of objects
12136
+ * $(document).ready( function() {
12137
+ * $('#example').dataTable( {
12138
+ * "ajaxSource": "sources/deep.txt",
12139
+ * "columns": [
12140
+ * { "data": "engine" },
12141
+ * { "data": "browser" },
12142
+ * {
12143
+ * "data": "platform",
12144
+ * "render": "[, ].name"
12145
+ * }
12146
+ * ]
12147
+ * } );
12148
+ * } );
12149
+ *
12150
+ * @example
12151
+ * // Execute a function to obtain data
12152
+ * $(document).ready( function() {
12153
+ * $('#example').dataTable( {
12154
+ * "columnDefs": [ {
12155
+ * "targets": [ 0 ],
12156
+ * "data": null, // Use the full data source object for the renderer's source
12157
+ * "render": "browserName()"
12158
+ * } ]
12159
+ * } );
12160
+ * } );
12161
+ *
12162
+ * @example
12163
+ * // As an object, extracting different data for the different types
12164
+ * // This would be used with a data source such as:
12165
+ * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
12166
+ * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
12167
+ * // (which has both forms) is used for filtering for if a user inputs either format, while
12168
+ * // the formatted phone number is the one that is shown in the table.
12169
+ * $(document).ready( function() {
12170
+ * $('#example').dataTable( {
12171
+ * "columnDefs": [ {
12172
+ * "targets": [ 0 ],
12173
+ * "data": null, // Use the full data source object for the renderer's source
12174
+ * "render": {
12175
+ * "_": "phone",
12176
+ * "filter": "phone_filter",
12177
+ * "display": "phone_display"
12178
+ * }
12179
+ * } ]
12180
+ * } );
12181
+ * } );
12182
+ *
12183
+ * @example
12184
+ * // Use as a function to create a link from the data source
12185
+ * $(document).ready( function() {
12186
+ * $('#example').dataTable( {
12187
+ * "columnDefs": [ {
12188
+ * "targets": [ 0 ],
12189
+ * "data": "download_link",
12190
+ * "render": function ( data, type, full ) {
12191
+ * return '<a href="'+data+'">Download</a>';
12192
+ * }
12193
+ * } ]
12194
+ * } );
12195
+ * } );
12196
+ */
12197
+ "mRender": null,
12198
+
12199
+
12200
+ /**
12201
+ * Change the cell type created for the column - either TD cells or TH cells. This
12202
+ * can be useful as TH cells have semantic meaning in the table body, allowing them
12203
+ * to act as a header for a row (you may wish to add scope='row' to the TH elements).
12204
+ * @type string
12205
+ * @default td
12206
+ *
12207
+ * @name DataTable.defaults.column.cellType
12208
+ * @dtopt Columns
12209
+ *
12210
+ * @example
12211
+ * // Make the first column use TH cells
12212
+ * $(document).ready( function() {
12213
+ * $('#example').dataTable( {
12214
+ * "columnDefs": [ {
12215
+ * "targets": [ 0 ],
12216
+ * "cellType": "th"
12217
+ * } ]
12218
+ * } );
12219
+ * } );
12220
+ */
12221
+ "sCellType": "td",
12222
+
12223
+
12224
+ /**
12225
+ * Class to give to each cell in this column.
12226
+ * @type string
12227
+ * @default <i>Empty string</i>
12228
+ *
12229
+ * @name DataTable.defaults.column.class
12230
+ * @dtopt Columns
12231
+ *
12232
+ * @example
12233
+ * // Using `columnDefs`
12234
+ * $(document).ready( function() {
12235
+ * $('#example').dataTable( {
12236
+ * "columnDefs": [
12237
+ * { "class": "my_class", "targets": [ 0 ] }
12238
+ * ]
12239
+ * } );
12240
+ * } );
12241
+ *
12242
+ * @example
12243
+ * // Using `columns`
12244
+ * $(document).ready( function() {
12245
+ * $('#example').dataTable( {
12246
+ * "columns": [
12247
+ * { "class": "my_class" },
12248
+ * null,
12249
+ * null,
12250
+ * null,
12251
+ * null
12252
+ * ]
12253
+ * } );
12254
+ * } );
12255
+ */
12256
+ "sClass": "",
12257
+
12258
+ /**
12259
+ * When DataTables calculates the column widths to assign to each column,
12260
+ * it finds the longest string in each column and then constructs a
12261
+ * temporary table and reads the widths from that. The problem with this
12262
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
12263
+ * string - thus the calculation can go wrong (doing it properly and putting
12264
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
12265
+ * a "work around" we provide this option. It will append its value to the
12266
+ * text that is found to be the longest string for the column - i.e. padding.
12267
+ * Generally you shouldn't need this!
12268
+ * @type string
12269
+ * @default <i>Empty string<i>
12270
+ *
12271
+ * @name DataTable.defaults.column.contentPadding
12272
+ * @dtopt Columns
12273
+ *
12274
+ * @example
12275
+ * // Using `columns`
12276
+ * $(document).ready( function() {
12277
+ * $('#example').dataTable( {
12278
+ * "columns": [
12279
+ * null,
12280
+ * null,
12281
+ * null,
12282
+ * {
12283
+ * "contentPadding": "mmm"
12284
+ * }
12285
+ * ]
12286
+ * } );
12287
+ * } );
12288
+ */
12289
+ "sContentPadding": "",
12290
+
12291
+
12292
+ /**
12293
+ * Allows a default value to be given for a column's data, and will be used
12294
+ * whenever a null data source is encountered (this can be because `data`
12295
+ * is set to null, or because the data source itself is null).
12296
+ * @type string
12297
+ * @default null
12298
+ *
12299
+ * @name DataTable.defaults.column.defaultContent
12300
+ * @dtopt Columns
12301
+ *
12302
+ * @example
12303
+ * // Using `columnDefs`
12304
+ * $(document).ready( function() {
12305
+ * $('#example').dataTable( {
12306
+ * "columnDefs": [
12307
+ * {
12308
+ * "data": null,
12309
+ * "defaultContent": "Edit",
12310
+ * "targets": [ -1 ]
12311
+ * }
12312
+ * ]
12313
+ * } );
12314
+ * } );
12315
+ *
12316
+ * @example
12317
+ * // Using `columns`
12318
+ * $(document).ready( function() {
12319
+ * $('#example').dataTable( {
12320
+ * "columns": [
12321
+ * null,
12322
+ * null,
12323
+ * null,
12324
+ * {
12325
+ * "data": null,
12326
+ * "defaultContent": "Edit"
12327
+ * }
12328
+ * ]
12329
+ * } );
12330
+ * } );
12331
+ */
12332
+ "sDefaultContent": null,
12333
+
12334
+
12335
+ /**
12336
+ * This parameter is only used in DataTables' server-side processing. It can
12337
+ * be exceptionally useful to know what columns are being displayed on the
12338
+ * client side, and to map these to database fields. When defined, the names
12339
+ * also allow DataTables to reorder information from the server if it comes
12340
+ * back in an unexpected order (i.e. if you switch your columns around on the
12341
+ * client-side, your server-side code does not also need updating).
12342
+ * @type string
12343
+ * @default <i>Empty string</i>
12344
+ *
12345
+ * @name DataTable.defaults.column.name
12346
+ * @dtopt Columns
12347
+ *
12348
+ * @example
12349
+ * // Using `columnDefs`
12350
+ * $(document).ready( function() {
12351
+ * $('#example').dataTable( {
12352
+ * "columnDefs": [
12353
+ * { "name": "engine", "targets": [ 0 ] },
12354
+ * { "name": "browser", "targets": [ 1 ] },
12355
+ * { "name": "platform", "targets": [ 2 ] },
12356
+ * { "name": "version", "targets": [ 3 ] },
12357
+ * { "name": "grade", "targets": [ 4 ] }
12358
+ * ]
12359
+ * } );
12360
+ * } );
12361
+ *
12362
+ * @example
12363
+ * // Using `columns`
12364
+ * $(document).ready( function() {
12365
+ * $('#example').dataTable( {
12366
+ * "columns": [
12367
+ * { "name": "engine" },
12368
+ * { "name": "browser" },
12369
+ * { "name": "platform" },
12370
+ * { "name": "version" },
12371
+ * { "name": "grade" }
12372
+ * ]
12373
+ * } );
12374
+ * } );
12375
+ */
12376
+ "sName": "",
12377
+
12378
+
12379
+ /**
12380
+ * Defines a data source type for the ordering which can be used to read
12381
+ * real-time information from the table (updating the internally cached
12382
+ * version) prior to ordering. This allows ordering to occur on user
12383
+ * editable elements such as form inputs.
12384
+ * @type string
12385
+ * @default std
12386
+ *
12387
+ * @name DataTable.defaults.column.orderDataType
12388
+ * @dtopt Columns
12389
+ *
12390
+ * @example
12391
+ * // Using `columnDefs`
12392
+ * $(document).ready( function() {
12393
+ * $('#example').dataTable( {
12394
+ * "columnDefs": [
12395
+ * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
12396
+ * { "type": "numeric", "targets": [ 3 ] },
12397
+ * { "orderDataType": "dom-select", "targets": [ 4 ] },
12398
+ * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
12399
+ * ]
12400
+ * } );
12401
+ * } );
12402
+ *
12403
+ * @example
12404
+ * // Using `columns`
12405
+ * $(document).ready( function() {
12406
+ * $('#example').dataTable( {
12407
+ * "columns": [
12408
+ * null,
12409
+ * null,
12410
+ * { "orderDataType": "dom-text" },
12411
+ * { "orderDataType": "dom-text", "type": "numeric" },
12412
+ * { "orderDataType": "dom-select" },
12413
+ * { "orderDataType": "dom-checkbox" }
12414
+ * ]
12415
+ * } );
12416
+ * } );
12417
+ */
12418
+ "sSortDataType": "std",
12419
+
12420
+
12421
+ /**
12422
+ * The title of this column.
12423
+ * @type string
12424
+ * @default null <i>Derived from the 'TH' value for this column in the
12425
+ * original HTML table.</i>
12426
+ *
12427
+ * @name DataTable.defaults.column.title
12428
+ * @dtopt Columns
12429
+ *
12430
+ * @example
12431
+ * // Using `columnDefs`
12432
+ * $(document).ready( function() {
12433
+ * $('#example').dataTable( {
12434
+ * "columnDefs": [
12435
+ * { "title": "My column title", "targets": [ 0 ] }
12436
+ * ]
12437
+ * } );
12438
+ * } );
12439
+ *
12440
+ * @example
12441
+ * // Using `columns`
12442
+ * $(document).ready( function() {
12443
+ * $('#example').dataTable( {
12444
+ * "columns": [
12445
+ * { "title": "My column title" },
12446
+ * null,
12447
+ * null,
12448
+ * null,
12449
+ * null
12450
+ * ]
12451
+ * } );
12452
+ * } );
12453
+ */
12454
+ "sTitle": null,
12455
+
12456
+
12457
+ /**
12458
+ * The type allows you to specify how the data for this column will be
12459
+ * ordered. Four types (string, numeric, date and html (which will strip
12460
+ * HTML tags before ordering)) are currently available. Note that only date
12461
+ * formats understood by Javascript's Date() object will be accepted as type
12462
+ * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
12463
+ * 'numeric', 'date' or 'html' (by default). Further types can be adding
12464
+ * through plug-ins.
12465
+ * @type string
12466
+ * @default null <i>Auto-detected from raw data</i>
12467
+ *
12468
+ * @name DataTable.defaults.column.type
12469
+ * @dtopt Columns
12470
+ *
12471
+ * @example
12472
+ * // Using `columnDefs`
12473
+ * $(document).ready( function() {
12474
+ * $('#example').dataTable( {
12475
+ * "columnDefs": [
12476
+ * { "type": "html", "targets": [ 0 ] }
12477
+ * ]
12478
+ * } );
12479
+ * } );
12480
+ *
12481
+ * @example
12482
+ * // Using `columns`
12483
+ * $(document).ready( function() {
12484
+ * $('#example').dataTable( {
12485
+ * "columns": [
12486
+ * { "type": "html" },
12487
+ * null,
12488
+ * null,
12489
+ * null,
12490
+ * null
12491
+ * ]
12492
+ * } );
12493
+ * } );
12494
+ */
12495
+ "sType": null,
12496
+
12497
+
12498
+ /**
12499
+ * Defining the width of the column, this parameter may take any CSS value
12500
+ * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
12501
+ * been given a specific width through this interface ensuring that the table
12502
+ * remains readable.
12503
+ * @type string
12504
+ * @default null <i>Automatic</i>
12505
+ *
12506
+ * @name DataTable.defaults.column.width
12507
+ * @dtopt Columns
12508
+ *
12509
+ * @example
12510
+ * // Using `columnDefs`
12511
+ * $(document).ready( function() {
12512
+ * $('#example').dataTable( {
12513
+ * "columnDefs": [
12514
+ * { "width": "20%", "targets": [ 0 ] }
12515
+ * ]
12516
+ * } );
12517
+ * } );
12518
+ *
12519
+ * @example
12520
+ * // Using `columns`
12521
+ * $(document).ready( function() {
12522
+ * $('#example').dataTable( {
12523
+ * "columns": [
12524
+ * { "width": "20%" },
12525
+ * null,
12526
+ * null,
12527
+ * null,
12528
+ * null
12529
+ * ]
12530
+ * } );
12531
+ * } );
12532
+ */
12533
+ "sWidth": null
12534
+ };
12535
+
12536
+ _fnHungarianMap( DataTable.defaults.column );
12537
+
12538
+
12539
+
12540
+ /**
12541
+ * DataTables settings object - this holds all the information needed for a
12542
+ * given table, including configuration, data and current application of the
12543
+ * table options. DataTables does not have a single instance for each DataTable
12544
+ * with the settings attached to that instance, but rather instances of the
12545
+ * DataTable "class" are created on-the-fly as needed (typically by a
12546
+ * $().dataTable() call) and the settings object is then applied to that
12547
+ * instance.
12548
+ *
12549
+ * Note that this object is related to {@link DataTable.defaults} but this
12550
+ * one is the internal data store for DataTables's cache of columns. It should
12551
+ * NOT be manipulated outside of DataTables. Any configuration should be done
12552
+ * through the initialisation options.
12553
+ * @namespace
12554
+ * @todo Really should attach the settings object to individual instances so we
12555
+ * don't need to create new instances on each $().dataTable() call (if the
12556
+ * table already exists). It would also save passing oSettings around and
12557
+ * into every single function. However, this is a very significant
12558
+ * architecture change for DataTables and will almost certainly break
12559
+ * backwards compatibility with older installations. This is something that
12560
+ * will be done in 2.0.
12561
+ */
12562
+ DataTable.models.oSettings = {
12563
+ /**
12564
+ * Primary features of DataTables and their enablement state.
12565
+ * @namespace
12566
+ */
12567
+ "oFeatures": {
12568
+
12569
+ /**
12570
+ * Flag to say if DataTables should automatically try to calculate the
12571
+ * optimum table and columns widths (true) or not (false).
12572
+ * Note that this parameter will be set by the initialisation routine. To
12573
+ * set a default use {@link DataTable.defaults}.
12574
+ * @type boolean
12575
+ */
12576
+ "bAutoWidth": null,
12577
+
12578
+ /**
12579
+ * Delay the creation of TR and TD elements until they are actually
12580
+ * needed by a driven page draw. This can give a significant speed
12581
+ * increase for Ajax source and Javascript source data, but makes no
12582
+ * difference at all fro DOM and server-side processing tables.
12583
+ * Note that this parameter will be set by the initialisation routine. To
12584
+ * set a default use {@link DataTable.defaults}.
12585
+ * @type boolean
12586
+ */
12587
+ "bDeferRender": null,
12588
+
12589
+ /**
12590
+ * Enable filtering on the table or not. Note that if this is disabled
12591
+ * then there is no filtering at all on the table, including fnFilter.
12592
+ * To just remove the filtering input use sDom and remove the 'f' option.
12593
+ * Note that this parameter will be set by the initialisation routine. To
12594
+ * set a default use {@link DataTable.defaults}.
12595
+ * @type boolean
12596
+ */
12597
+ "bFilter": null,
12598
+
12599
+ /**
12600
+ * Table information element (the 'Showing x of y records' div) enable
12601
+ * flag.
12602
+ * Note that this parameter will be set by the initialisation routine. To
12603
+ * set a default use {@link DataTable.defaults}.
12604
+ * @type boolean
12605
+ */
12606
+ "bInfo": null,
12607
+
12608
+ /**
12609
+ * Present a user control allowing the end user to change the page size
12610
+ * when pagination is enabled.
12611
+ * Note that this parameter will be set by the initialisation routine. To
12612
+ * set a default use {@link DataTable.defaults}.
12613
+ * @type boolean
12614
+ */
12615
+ "bLengthChange": null,
12616
+
12617
+ /**
12618
+ * Pagination enabled or not. Note that if this is disabled then length
12619
+ * changing must also be disabled.
12620
+ * Note that this parameter will be set by the initialisation routine. To
12621
+ * set a default use {@link DataTable.defaults}.
12622
+ * @type boolean
12623
+ */
12624
+ "bPaginate": null,
12625
+
12626
+ /**
12627
+ * Processing indicator enable flag whenever DataTables is enacting a
12628
+ * user request - typically an Ajax request for server-side processing.
12629
+ * Note that this parameter will be set by the initialisation routine. To
12630
+ * set a default use {@link DataTable.defaults}.
12631
+ * @type boolean
12632
+ */
12633
+ "bProcessing": null,
12634
+
12635
+ /**
12636
+ * Server-side processing enabled flag - when enabled DataTables will
12637
+ * get all data from the server for every draw - there is no filtering,
12638
+ * sorting or paging done on the client-side.
12639
+ * Note that this parameter will be set by the initialisation routine. To
12640
+ * set a default use {@link DataTable.defaults}.
12641
+ * @type boolean
12642
+ */
12643
+ "bServerSide": null,
12644
+
12645
+ /**
12646
+ * Sorting enablement flag.
12647
+ * Note that this parameter will be set by the initialisation routine. To
12648
+ * set a default use {@link DataTable.defaults}.
12649
+ * @type boolean
12650
+ */
12651
+ "bSort": null,
12652
+
12653
+ /**
12654
+ * Multi-column sorting
12655
+ * Note that this parameter will be set by the initialisation routine. To
12656
+ * set a default use {@link DataTable.defaults}.
12657
+ * @type boolean
12658
+ */
12659
+ "bSortMulti": null,
12660
+
12661
+ /**
12662
+ * Apply a class to the columns which are being sorted to provide a
12663
+ * visual highlight or not. This can slow things down when enabled since
12664
+ * there is a lot of DOM interaction.
12665
+ * Note that this parameter will be set by the initialisation routine. To
12666
+ * set a default use {@link DataTable.defaults}.
12667
+ * @type boolean
12668
+ */
12669
+ "bSortClasses": null,
12670
+
12671
+ /**
12672
+ * State saving enablement flag.
12673
+ * Note that this parameter will be set by the initialisation routine. To
12674
+ * set a default use {@link DataTable.defaults}.
12675
+ * @type boolean
12676
+ */
12677
+ "bStateSave": null
12678
+ },
12679
+
12680
+
12681
+ /**
12682
+ * Scrolling settings for a table.
12683
+ * @namespace
12684
+ */
12685
+ "oScroll": {
12686
+ /**
12687
+ * When the table is shorter in height than sScrollY, collapse the
12688
+ * table container down to the height of the table (when true).
12689
+ * Note that this parameter will be set by the initialisation routine. To
12690
+ * set a default use {@link DataTable.defaults}.
12691
+ * @type boolean
12692
+ */
12693
+ "bCollapse": null,
12694
+
12695
+ /**
12696
+ * Width of the scrollbar for the web-browser's platform. Calculated
12697
+ * during table initialisation.
12698
+ * @type int
12699
+ * @default 0
12700
+ */
12701
+ "iBarWidth": 0,
12702
+
12703
+ /**
12704
+ * Viewport width for horizontal scrolling. Horizontal scrolling is
12705
+ * disabled if an empty string.
12706
+ * Note that this parameter will be set by the initialisation routine. To
12707
+ * set a default use {@link DataTable.defaults}.
12708
+ * @type string
12709
+ */
12710
+ "sX": null,
12711
+
12712
+ /**
12713
+ * Width to expand the table to when using x-scrolling. Typically you
12714
+ * should not need to use this.
12715
+ * Note that this parameter will be set by the initialisation routine. To
12716
+ * set a default use {@link DataTable.defaults}.
12717
+ * @type string
12718
+ * @deprecated
12719
+ */
12720
+ "sXInner": null,
12721
+
12722
+ /**
12723
+ * Viewport height for vertical scrolling. Vertical scrolling is disabled
12724
+ * if an empty string.
12725
+ * Note that this parameter will be set by the initialisation routine. To
12726
+ * set a default use {@link DataTable.defaults}.
12727
+ * @type string
12728
+ */
12729
+ "sY": null
12730
+ },
12731
+
12732
+ /**
12733
+ * Language information for the table.
12734
+ * @namespace
12735
+ * @extends DataTable.defaults.oLanguage
12736
+ */
12737
+ "oLanguage": {
12738
+ /**
12739
+ * Information callback function. See
12740
+ * {@link DataTable.defaults.fnInfoCallback}
12741
+ * @type function
12742
+ * @default null
12743
+ */
12744
+ "fnInfoCallback": null
12745
+ },
12746
+
12747
+ /**
12748
+ * Browser support parameters
12749
+ * @namespace
12750
+ */
12751
+ "oBrowser": {
12752
+ /**
12753
+ * Indicate if the browser incorrectly calculates width:100% inside a
12754
+ * scrolling element (IE6/7)
12755
+ * @type boolean
12756
+ * @default false
12757
+ */
12758
+ "bScrollOversize": false,
12759
+
12760
+ /**
12761
+ * Determine if the vertical scrollbar is on the right or left of the
12762
+ * scrolling container - needed for rtl language layout, although not
12763
+ * all browsers move the scrollbar (Safari).
12764
+ * @type boolean
12765
+ * @default false
12766
+ */
12767
+ "bScrollbarLeft": false
12768
+ },
12769
+
12770
+
12771
+ "ajax": null,
12772
+
12773
+
12774
+ /**
12775
+ * Array referencing the nodes which are used for the features. The
12776
+ * parameters of this object match what is allowed by sDom - i.e.
12777
+ * <ul>
12778
+ * <li>'l' - Length changing</li>
12779
+ * <li>'f' - Filtering input</li>
12780
+ * <li>'t' - The table!</li>
12781
+ * <li>'i' - Information</li>
12782
+ * <li>'p' - Pagination</li>
12783
+ * <li>'r' - pRocessing</li>
12784
+ * </ul>
12785
+ * @type array
12786
+ * @default []
12787
+ */
12788
+ "aanFeatures": [],
12789
+
12790
+ /**
12791
+ * Store data information - see {@link DataTable.models.oRow} for detailed
12792
+ * information.
12793
+ * @type array
12794
+ * @default []
12795
+ */
12796
+ "aoData": [],
12797
+
12798
+ /**
12799
+ * Array of indexes which are in the current display (after filtering etc)
12800
+ * @type array
12801
+ * @default []
12802
+ */
12803
+ "aiDisplay": [],
12804
+
12805
+ /**
12806
+ * Array of indexes for display - no filtering
12807
+ * @type array
12808
+ * @default []
12809
+ */
12810
+ "aiDisplayMaster": [],
12811
+
12812
+ /**
12813
+ * Store information about each column that is in use
12814
+ * @type array
12815
+ * @default []
12816
+ */
12817
+ "aoColumns": [],
12818
+
12819
+ /**
12820
+ * Store information about the table's header
12821
+ * @type array
12822
+ * @default []
12823
+ */
12824
+ "aoHeader": [],
12825
+
12826
+ /**
12827
+ * Store information about the table's footer
12828
+ * @type array
12829
+ * @default []
12830
+ */
12831
+ "aoFooter": [],
12832
+
12833
+ /**
12834
+ * Store the applied global search information in case we want to force a
12835
+ * research or compare the old search to a new one.
12836
+ * Note that this parameter will be set by the initialisation routine. To
12837
+ * set a default use {@link DataTable.defaults}.
12838
+ * @namespace
12839
+ * @extends DataTable.models.oSearch
12840
+ */
12841
+ "oPreviousSearch": {},
12842
+
12843
+ /**
12844
+ * Store the applied search for each column - see
12845
+ * {@link DataTable.models.oSearch} for the format that is used for the
12846
+ * filtering information for each column.
12847
+ * @type array
12848
+ * @default []
12849
+ */
12850
+ "aoPreSearchCols": [],
12851
+
12852
+ /**
12853
+ * Sorting that is applied to the table. Note that the inner arrays are
12854
+ * used in the following manner:
12855
+ * <ul>
12856
+ * <li>Index 0 - column number</li>
12857
+ * <li>Index 1 - current sorting direction</li>
12858
+ * </ul>
12859
+ * Note that this parameter will be set by the initialisation routine. To
12860
+ * set a default use {@link DataTable.defaults}.
12861
+ * @type array
12862
+ * @todo These inner arrays should really be objects
12863
+ */
12864
+ "aaSorting": null,
12865
+
12866
+ /**
12867
+ * Sorting that is always applied to the table (i.e. prefixed in front of
12868
+ * aaSorting).
12869
+ * Note that this parameter will be set by the initialisation routine. To
12870
+ * set a default use {@link DataTable.defaults}.
12871
+ * @type array
12872
+ * @default []
12873
+ */
12874
+ "aaSortingFixed": [],
12875
+
12876
+ /**
12877
+ * Classes to use for the striping of a table.
12878
+ * Note that this parameter will be set by the initialisation routine. To
12879
+ * set a default use {@link DataTable.defaults}.
12880
+ * @type array
12881
+ * @default []
12882
+ */
12883
+ "asStripeClasses": null,
12884
+
12885
+ /**
12886
+ * If restoring a table - we should restore its striping classes as well
12887
+ * @type array
12888
+ * @default []
12889
+ */
12890
+ "asDestroyStripes": [],
12891
+
12892
+ /**
12893
+ * If restoring a table - we should restore its width
12894
+ * @type int
12895
+ * @default 0
12896
+ */
12897
+ "sDestroyWidth": 0,
12898
+
12899
+ /**
12900
+ * Callback functions array for every time a row is inserted (i.e. on a draw).
12901
+ * @type array
12902
+ * @default []
12903
+ */
12904
+ "aoRowCallback": [],
12905
+
12906
+ /**
12907
+ * Callback functions for the header on each draw.
12908
+ * @type array
12909
+ * @default []
12910
+ */
12911
+ "aoHeaderCallback": [],
12912
+
12913
+ /**
12914
+ * Callback function for the footer on each draw.
12915
+ * @type array
12916
+ * @default []
12917
+ */
12918
+ "aoFooterCallback": [],
12919
+
12920
+ /**
12921
+ * Array of callback functions for draw callback functions
12922
+ * @type array
12923
+ * @default []
12924
+ */
12925
+ "aoDrawCallback": [],
12926
+
12927
+ /**
12928
+ * Array of callback functions for row created function
12929
+ * @type array
12930
+ * @default []
12931
+ */
12932
+ "aoRowCreatedCallback": [],
12933
+
12934
+ /**
12935
+ * Callback functions for just before the table is redrawn. A return of
12936
+ * false will be used to cancel the draw.
12937
+ * @type array
12938
+ * @default []
12939
+ */
12940
+ "aoPreDrawCallback": [],
12941
+
12942
+ /**
12943
+ * Callback functions for when the table has been initialised.
12944
+ * @type array
12945
+ * @default []
12946
+ */
12947
+ "aoInitComplete": [],
12948
+
12949
+
12950
+ /**
12951
+ * Callbacks for modifying the settings to be stored for state saving, prior to
12952
+ * saving state.
12953
+ * @type array
12954
+ * @default []
12955
+ */
12956
+ "aoStateSaveParams": [],
12957
+
12958
+ /**
12959
+ * Callbacks for modifying the settings that have been stored for state saving
12960
+ * prior to using the stored values to restore the state.
12961
+ * @type array
12962
+ * @default []
12963
+ */
12964
+ "aoStateLoadParams": [],
12965
+
12966
+ /**
12967
+ * Callbacks for operating on the settings object once the saved state has been
12968
+ * loaded
12969
+ * @type array
12970
+ * @default []
12971
+ */
12972
+ "aoStateLoaded": [],
12973
+
12974
+ /**
12975
+ * Cache the table ID for quick access
12976
+ * @type string
12977
+ * @default <i>Empty string</i>
12978
+ */
12979
+ "sTableId": "",
12980
+
12981
+ /**
12982
+ * The TABLE node for the main table
12983
+ * @type node
12984
+ * @default null
12985
+ */
12986
+ "nTable": null,
12987
+
12988
+ /**
12989
+ * Permanent ref to the thead element
12990
+ * @type node
12991
+ * @default null
12992
+ */
12993
+ "nTHead": null,
12994
+
12995
+ /**
12996
+ * Permanent ref to the tfoot element - if it exists
12997
+ * @type node
12998
+ * @default null
12999
+ */
13000
+ "nTFoot": null,
13001
+
13002
+ /**
13003
+ * Permanent ref to the tbody element
13004
+ * @type node
13005
+ * @default null
13006
+ */
13007
+ "nTBody": null,
13008
+
13009
+ /**
13010
+ * Cache the wrapper node (contains all DataTables controlled elements)
13011
+ * @type node
13012
+ * @default null
13013
+ */
13014
+ "nTableWrapper": null,
13015
+
13016
+ /**
13017
+ * Indicate if when using server-side processing the loading of data
13018
+ * should be deferred until the second draw.
13019
+ * Note that this parameter will be set by the initialisation routine. To
13020
+ * set a default use {@link DataTable.defaults}.
13021
+ * @type boolean
13022
+ * @default false
13023
+ */
13024
+ "bDeferLoading": false,
13025
+
13026
+ /**
13027
+ * Indicate if all required information has been read in
13028
+ * @type boolean
13029
+ * @default false
13030
+ */
13031
+ "bInitialised": false,
13032
+
13033
+ /**
13034
+ * Information about open rows. Each object in the array has the parameters
13035
+ * 'nTr' and 'nParent'
13036
+ * @type array
13037
+ * @default []
13038
+ */
13039
+ "aoOpenRows": [],
13040
+
13041
+ /**
13042
+ * Dictate the positioning of DataTables' control elements - see
13043
+ * {@link DataTable.model.oInit.sDom}.
13044
+ * Note that this parameter will be set by the initialisation routine. To
13045
+ * set a default use {@link DataTable.defaults}.
13046
+ * @type string
13047
+ * @default null
13048
+ */
13049
+ "sDom": null,
13050
+
13051
+ /**
13052
+ * Search delay (in mS)
13053
+ * @type integer
13054
+ * @default null
13055
+ */
13056
+ "searchDelay": null,
13057
+
13058
+ /**
13059
+ * Which type of pagination should be used.
13060
+ * Note that this parameter will be set by the initialisation routine. To
13061
+ * set a default use {@link DataTable.defaults}.
13062
+ * @type string
13063
+ * @default two_button
13064
+ */
13065
+ "sPaginationType": "two_button",
13066
+
13067
+ /**
13068
+ * The state duration (for `stateSave`) in seconds.
13069
+ * Note that this parameter will be set by the initialisation routine. To
13070
+ * set a default use {@link DataTable.defaults}.
13071
+ * @type int
13072
+ * @default 0
13073
+ */
13074
+ "iStateDuration": 0,
13075
+
13076
+ /**
13077
+ * Array of callback functions for state saving. Each array element is an
13078
+ * object with the following parameters:
13079
+ * <ul>
13080
+ * <li>function:fn - function to call. Takes two parameters, oSettings
13081
+ * and the JSON string to save that has been thus far created. Returns
13082
+ * a JSON string to be inserted into a json object
13083
+ * (i.e. '"param": [ 0, 1, 2]')</li>
13084
+ * <li>string:sName - name of callback</li>
13085
+ * </ul>
13086
+ * @type array
13087
+ * @default []
13088
+ */
13089
+ "aoStateSave": [],
13090
+
13091
+ /**
13092
+ * Array of callback functions for state loading. Each array element is an
13093
+ * object with the following parameters:
13094
+ * <ul>
13095
+ * <li>function:fn - function to call. Takes two parameters, oSettings
13096
+ * and the object stored. May return false to cancel state loading</li>
13097
+ * <li>string:sName - name of callback</li>
13098
+ * </ul>
13099
+ * @type array
13100
+ * @default []
13101
+ */
13102
+ "aoStateLoad": [],
13103
+
13104
+ /**
13105
+ * State that was saved. Useful for back reference
13106
+ * @type object
13107
+ * @default null
13108
+ */
13109
+ "oSavedState": null,
13110
+
13111
+ /**
13112
+ * State that was loaded. Useful for back reference
13113
+ * @type object
13114
+ * @default null
13115
+ */
13116
+ "oLoadedState": null,
13117
+
13118
+ /**
13119
+ * Source url for AJAX data for the table.
13120
+ * Note that this parameter will be set by the initialisation routine. To
13121
+ * set a default use {@link DataTable.defaults}.
13122
+ * @type string
13123
+ * @default null
13124
+ */
13125
+ "sAjaxSource": null,
13126
+
13127
+ /**
13128
+ * Property from a given object from which to read the table data from. This
13129
+ * can be an empty string (when not server-side processing), in which case
13130
+ * it is assumed an an array is given directly.
13131
+ * Note that this parameter will be set by the initialisation routine. To
13132
+ * set a default use {@link DataTable.defaults}.
13133
+ * @type string
13134
+ */
13135
+ "sAjaxDataProp": null,
13136
+
13137
+ /**
13138
+ * Note if draw should be blocked while getting data
13139
+ * @type boolean
13140
+ * @default true
13141
+ */
13142
+ "bAjaxDataGet": true,
13143
+
13144
+ /**
13145
+ * The last jQuery XHR object that was used for server-side data gathering.
13146
+ * This can be used for working with the XHR information in one of the
13147
+ * callbacks
13148
+ * @type object
13149
+ * @default null
13150
+ */
13151
+ "jqXHR": null,
13152
+
13153
+ /**
13154
+ * JSON returned from the server in the last Ajax request
13155
+ * @type object
13156
+ * @default undefined
13157
+ */
13158
+ "json": undefined,
13159
+
13160
+ /**
13161
+ * Data submitted as part of the last Ajax request
13162
+ * @type object
13163
+ * @default undefined
13164
+ */
13165
+ "oAjaxData": undefined,
13166
+
13167
+ /**
13168
+ * Function to get the server-side data.
13169
+ * Note that this parameter will be set by the initialisation routine. To
13170
+ * set a default use {@link DataTable.defaults}.
13171
+ * @type function
13172
+ */
13173
+ "fnServerData": null,
13174
+
13175
+ /**
13176
+ * Functions which are called prior to sending an Ajax request so extra
13177
+ * parameters can easily be sent to the server
13178
+ * @type array
13179
+ * @default []
13180
+ */
13181
+ "aoServerParams": [],
13182
+
13183
+ /**
13184
+ * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
13185
+ * required).
13186
+ * Note that this parameter will be set by the initialisation routine. To
13187
+ * set a default use {@link DataTable.defaults}.
13188
+ * @type string
13189
+ */
13190
+ "sServerMethod": null,
13191
+
13192
+ /**
13193
+ * Format numbers for display.
13194
+ * Note that this parameter will be set by the initialisation routine. To
13195
+ * set a default use {@link DataTable.defaults}.
13196
+ * @type function
13197
+ */
13198
+ "fnFormatNumber": null,
13199
+
13200
+ /**
13201
+ * List of options that can be used for the user selectable length menu.
13202
+ * Note that this parameter will be set by the initialisation routine. To
13203
+ * set a default use {@link DataTable.defaults}.
13204
+ * @type array
13205
+ * @default []
13206
+ */
13207
+ "aLengthMenu": null,
13208
+
13209
+ /**
13210
+ * Counter for the draws that the table does. Also used as a tracker for
13211
+ * server-side processing
13212
+ * @type int
13213
+ * @default 0
13214
+ */
13215
+ "iDraw": 0,
13216
+
13217
+ /**
13218
+ * Indicate if a redraw is being done - useful for Ajax
13219
+ * @type boolean
13220
+ * @default false
13221
+ */
13222
+ "bDrawing": false,
13223
+
13224
+ /**
13225
+ * Draw index (iDraw) of the last error when parsing the returned data
13226
+ * @type int
13227
+ * @default -1
13228
+ */
13229
+ "iDrawError": -1,
13230
+
13231
+ /**
13232
+ * Paging display length
13233
+ * @type int
13234
+ * @default 10
13235
+ */
13236
+ "_iDisplayLength": 10,
13237
+
13238
+ /**
13239
+ * Paging start point - aiDisplay index
13240
+ * @type int
13241
+ * @default 0
13242
+ */
13243
+ "_iDisplayStart": 0,
13244
+
13245
+ /**
13246
+ * Server-side processing - number of records in the result set
13247
+ * (i.e. before filtering), Use fnRecordsTotal rather than
13248
+ * this property to get the value of the number of records, regardless of
13249
+ * the server-side processing setting.
13250
+ * @type int
13251
+ * @default 0
13252
+ * @private
13253
+ */
13254
+ "_iRecordsTotal": 0,
13255
+
13256
+ /**
13257
+ * Server-side processing - number of records in the current display set
13258
+ * (i.e. after filtering). Use fnRecordsDisplay rather than
13259
+ * this property to get the value of the number of records, regardless of
13260
+ * the server-side processing setting.
13261
+ * @type boolean
13262
+ * @default 0
13263
+ * @private
13264
+ */
13265
+ "_iRecordsDisplay": 0,
13266
+
13267
+ /**
13268
+ * Flag to indicate if jQuery UI marking and classes should be used.
13269
+ * Note that this parameter will be set by the initialisation routine. To
13270
+ * set a default use {@link DataTable.defaults}.
13271
+ * @type boolean
13272
+ */
13273
+ "bJUI": null,
13274
+
13275
+ /**
13276
+ * The classes to use for the table
13277
+ * @type object
13278
+ * @default {}
13279
+ */
13280
+ "oClasses": {},
13281
+
13282
+ /**
13283
+ * Flag attached to the settings object so you can check in the draw
13284
+ * callback if filtering has been done in the draw. Deprecated in favour of
13285
+ * events.
13286
+ * @type boolean
13287
+ * @default false
13288
+ * @deprecated
13289
+ */
13290
+ "bFiltered": false,
13291
+
13292
+ /**
13293
+ * Flag attached to the settings object so you can check in the draw
13294
+ * callback if sorting has been done in the draw. Deprecated in favour of
13295
+ * events.
13296
+ * @type boolean
13297
+ * @default false
13298
+ * @deprecated
13299
+ */
13300
+ "bSorted": false,
13301
+
13302
+ /**
13303
+ * Indicate that if multiple rows are in the header and there is more than
13304
+ * one unique cell per column, if the top one (true) or bottom one (false)
13305
+ * should be used for sorting / title by DataTables.
13306
+ * Note that this parameter will be set by the initialisation routine. To
13307
+ * set a default use {@link DataTable.defaults}.
13308
+ * @type boolean
13309
+ */
13310
+ "bSortCellsTop": null,
13311
+
13312
+ /**
13313
+ * Initialisation object that is used for the table
13314
+ * @type object
13315
+ * @default null
13316
+ */
13317
+ "oInit": null,
13318
+
13319
+ /**
13320
+ * Destroy callback functions - for plug-ins to attach themselves to the
13321
+ * destroy so they can clean up markup and events.
13322
+ * @type array
13323
+ * @default []
13324
+ */
13325
+ "aoDestroyCallback": [],
13326
+
13327
+
13328
+ /**
13329
+ * Get the number of records in the current record set, before filtering
13330
+ * @type function
13331
+ */
13332
+ "fnRecordsTotal": function ()
13333
+ {
13334
+ return _fnDataSource( this ) == 'ssp' ?
13335
+ this._iRecordsTotal * 1 :
13336
+ this.aiDisplayMaster.length;
13337
+ },
13338
+
13339
+ /**
13340
+ * Get the number of records in the current record set, after filtering
13341
+ * @type function
13342
+ */
13343
+ "fnRecordsDisplay": function ()
13344
+ {
13345
+ return _fnDataSource( this ) == 'ssp' ?
13346
+ this._iRecordsDisplay * 1 :
13347
+ this.aiDisplay.length;
13348
+ },
13349
+
13350
+ /**
13351
+ * Get the display end point - aiDisplay index
13352
+ * @type function
13353
+ */
13354
+ "fnDisplayEnd": function ()
13355
+ {
13356
+ var
13357
+ len = this._iDisplayLength,
13358
+ start = this._iDisplayStart,
13359
+ calc = start + len,
13360
+ records = this.aiDisplay.length,
13361
+ features = this.oFeatures,
13362
+ paginate = features.bPaginate;
13363
+
13364
+ if ( features.bServerSide ) {
13365
+ return paginate === false || len === -1 ?
13366
+ start + records :
13367
+ Math.min( start+len, this._iRecordsDisplay );
13368
+ }
13369
+ else {
13370
+ return ! paginate || calc>records || len===-1 ?
13371
+ records :
13372
+ calc;
13373
+ }
13374
+ },
13375
+
13376
+ /**
13377
+ * The DataTables object for this table
13378
+ * @type object
13379
+ * @default null
13380
+ */
13381
+ "oInstance": null,
13382
+
13383
+ /**
13384
+ * Unique identifier for each instance of the DataTables object. If there
13385
+ * is an ID on the table node, then it takes that value, otherwise an
13386
+ * incrementing internal counter is used.
13387
+ * @type string
13388
+ * @default null
13389
+ */
13390
+ "sInstance": null,
13391
+
13392
+ /**
13393
+ * tabindex attribute value that is added to DataTables control elements, allowing
13394
+ * keyboard navigation of the table and its controls.
13395
+ */
13396
+ "iTabIndex": 0,
13397
+
13398
+ /**
13399
+ * DIV container for the footer scrolling table if scrolling
13400
+ */
13401
+ "nScrollHead": null,
13402
+
13403
+ /**
13404
+ * DIV container for the footer scrolling table if scrolling
13405
+ */
13406
+ "nScrollFoot": null,
13407
+
13408
+ /**
13409
+ * Last applied sort
13410
+ * @type array
13411
+ * @default []
13412
+ */
13413
+ "aLastSort": [],
13414
+
13415
+ /**
13416
+ * Stored plug-in instances
13417
+ * @type object
13418
+ * @default {}
13419
+ */
13420
+ "oPlugins": {}
13421
+ };
13422
+
13423
+ /**
13424
+ * Extension object for DataTables that is used to provide all extension
13425
+ * options.
13426
+ *
13427
+ * Note that the `DataTable.ext` object is available through
13428
+ * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
13429
+ * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
13430
+ * @namespace
13431
+ * @extends DataTable.models.ext
13432
+ */
13433
+
13434
+
13435
+ /**
13436
+ * DataTables extensions
13437
+ *
13438
+ * This namespace acts as a collection area for plug-ins that can be used to
13439
+ * extend DataTables capabilities. Indeed many of the build in methods
13440
+ * use this method to provide their own capabilities (sorting methods for
13441
+ * example).
13442
+ *
13443
+ * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
13444
+ * reasons
13445
+ *
13446
+ * @namespace
13447
+ */
13448
+ DataTable.ext = _ext = {
13449
+ /**
13450
+ * Element class names
13451
+ *
13452
+ * @type object
13453
+ * @default {}
13454
+ */
13455
+ classes: {},
13456
+
13457
+
13458
+ /**
13459
+ * Error reporting.
13460
+ *
13461
+ * How should DataTables report an error. Can take the value 'alert' or
13462
+ * 'throw'
13463
+ *
13464
+ * @type string
13465
+ * @default alert
13466
+ */
13467
+ errMode: "alert",
13468
+
13469
+
13470
+ /**
13471
+ * Feature plug-ins.
13472
+ *
13473
+ * This is an array of objects which describe the feature plug-ins that are
13474
+ * available to DataTables. These feature plug-ins are then available for
13475
+ * use through the `dom` initialisation option.
13476
+ *
13477
+ * Each feature plug-in is described by an object which must have the
13478
+ * following properties:
13479
+ *
13480
+ * * `fnInit` - function that is used to initialise the plug-in,
13481
+ * * `cFeature` - a character so the feature can be enabled by the `dom`
13482
+ * instillation option. This is case sensitive.
13483
+ *
13484
+ * The `fnInit` function has the following input parameters:
13485
+ *
13486
+ * 1. `{object}` DataTables settings object: see
13487
+ * {@link DataTable.models.oSettings}
13488
+ *
13489
+ * And the following return is expected:
13490
+ *
13491
+ * * {node|null} The element which contains your feature. Note that the
13492
+ * return may also be void if your plug-in does not require to inject any
13493
+ * DOM elements into DataTables control (`dom`) - for example this might
13494
+ * be useful when developing a plug-in which allows table control via
13495
+ * keyboard entry
13496
+ *
13497
+ * @type array
13498
+ *
13499
+ * @example
13500
+ * $.fn.dataTable.ext.features.push( {
13501
+ * "fnInit": function( oSettings ) {
13502
+ * return new TableTools( { "oDTSettings": oSettings } );
13503
+ * },
13504
+ * "cFeature": "T"
13505
+ * } );
13506
+ */
13507
+ feature: [],
13508
+
13509
+
13510
+ /**
13511
+ * Row searching.
13512
+ *
13513
+ * This method of searching is complimentary to the default type based
13514
+ * searching, and a lot more comprehensive as it allows you complete control
13515
+ * over the searching logic. Each element in this array is a function
13516
+ * (parameters described below) that is called for every row in the table,
13517
+ * and your logic decides if it should be included in the searching data set
13518
+ * or not.
13519
+ *
13520
+ * Searching functions have the following input parameters:
13521
+ *
13522
+ * 1. `{object}` DataTables settings object: see
13523
+ * {@link DataTable.models.oSettings}
13524
+ * 2. `{array|object}` Data for the row to be processed (same as the
13525
+ * original format that was passed in as the data source, or an array
13526
+ * from a DOM data source
13527
+ * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
13528
+ * can be useful to retrieve the `TR` element if you need DOM interaction.
13529
+ *
13530
+ * And the following return is expected:
13531
+ *
13532
+ * * {boolean} Include the row in the searched result set (true) or not
13533
+ * (false)
13534
+ *
13535
+ * Note that as with the main search ability in DataTables, technically this
13536
+ * is "filtering", since it is subtractive. However, for consistency in
13537
+ * naming we call it searching here.
13538
+ *
13539
+ * @type array
13540
+ * @default []
13541
+ *
13542
+ * @example
13543
+ * // The following example shows custom search being applied to the
13544
+ * // fourth column (i.e. the data[3] index) based on two input values
13545
+ * // from the end-user, matching the data in a certain range.
13546
+ * $.fn.dataTable.ext.search.push(
13547
+ * function( settings, data, dataIndex ) {
13548
+ * var min = document.getElementById('min').value * 1;
13549
+ * var max = document.getElementById('max').value * 1;
13550
+ * var version = data[3] == "-" ? 0 : data[3]*1;
13551
+ *
13552
+ * if ( min == "" && max == "" ) {
13553
+ * return true;
13554
+ * }
13555
+ * else if ( min == "" && version < max ) {
13556
+ * return true;
13557
+ * }
13558
+ * else if ( min < version && "" == max ) {
13559
+ * return true;
13560
+ * }
13561
+ * else if ( min < version && version < max ) {
13562
+ * return true;
13563
+ * }
13564
+ * return false;
13565
+ * }
13566
+ * );
13567
+ */
13568
+ search: [],
13569
+
13570
+
13571
+ /**
13572
+ * Internal functions, exposed for used in plug-ins.
13573
+ *
13574
+ * Please note that you should not need to use the internal methods for
13575
+ * anything other than a plug-in (and even then, try to avoid if possible).
13576
+ * The internal function may change between releases.
13577
+ *
13578
+ * @type object
13579
+ * @default {}
13580
+ */
13581
+ internal: {},
13582
+
13583
+
13584
+ /**
13585
+ * Legacy configuration options. Enable and disable legacy options that
13586
+ * are available in DataTables.
13587
+ *
13588
+ * @type object
13589
+ */
13590
+ legacy: {
13591
+ /**
13592
+ * Enable / disable DataTables 1.9 compatible server-side processing
13593
+ * requests
13594
+ *
13595
+ * @type boolean
13596
+ * @default null
13597
+ */
13598
+ ajax: null
13599
+ },
13600
+
13601
+
13602
+ /**
13603
+ * Pagination plug-in methods.
13604
+ *
13605
+ * Each entry in this object is a function and defines which buttons should
13606
+ * be shown by the pagination rendering method that is used for the table:
13607
+ * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
13608
+ * buttons are displayed in the document, while the functions here tell it
13609
+ * what buttons to display. This is done by returning an array of button
13610
+ * descriptions (what each button will do).
13611
+ *
13612
+ * Pagination types (the four built in options and any additional plug-in
13613
+ * options defined here) can be used through the `paginationType`
13614
+ * initialisation parameter.
13615
+ *
13616
+ * The functions defined take two parameters:
13617
+ *
13618
+ * 1. `{int} page` The current page index
13619
+ * 2. `{int} pages` The number of pages in the table
13620
+ *
13621
+ * Each function is expected to return an array where each element of the
13622
+ * array can be one of:
13623
+ *
13624
+ * * `first` - Jump to first page when activated
13625
+ * * `last` - Jump to last page when activated
13626
+ * * `previous` - Show previous page when activated
13627
+ * * `next` - Show next page when activated
13628
+ * * `{int}` - Show page of the index given
13629
+ * * `{array}` - A nested array containing the above elements to add a
13630
+ * containing 'DIV' element (might be useful for styling).
13631
+ *
13632
+ * Note that DataTables v1.9- used this object slightly differently whereby
13633
+ * an object with two functions would be defined for each plug-in. That
13634
+ * ability is still supported by DataTables 1.10+ to provide backwards
13635
+ * compatibility, but this option of use is now decremented and no longer
13636
+ * documented in DataTables 1.10+.
13637
+ *
13638
+ * @type object
13639
+ * @default {}
13640
+ *
13641
+ * @example
13642
+ * // Show previous, next and current page buttons only
13643
+ * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
13644
+ * return [ 'previous', page, 'next' ];
13645
+ * };
13646
+ */
13647
+ pager: {},
13648
+
13649
+
13650
+ renderer: {
13651
+ pageButton: {},
13652
+ header: {}
13653
+ },
13654
+
13655
+
13656
+ /**
13657
+ * Ordering plug-ins - custom data source
13658
+ *
13659
+ * The extension options for ordering of data available here is complimentary
13660
+ * to the default type based ordering that DataTables typically uses. It
13661
+ * allows much greater control over the the data that is being used to
13662
+ * order a column, but is necessarily therefore more complex.
13663
+ *
13664
+ * This type of ordering is useful if you want to do ordering based on data
13665
+ * live from the DOM (for example the contents of an 'input' element) rather
13666
+ * than just the static string that DataTables knows of.
13667
+ *
13668
+ * The way these plug-ins work is that you create an array of the values you
13669
+ * wish to be ordering for the column in question and then return that
13670
+ * array. The data in the array much be in the index order of the rows in
13671
+ * the table (not the currently ordering order!). Which order data gathering
13672
+ * function is run here depends on the `dt-init columns.orderDataType`
13673
+ * parameter that is used for the column (if any).
13674
+ *
13675
+ * The functions defined take two parameters:
13676
+ *
13677
+ * 1. `{object}` DataTables settings object: see
13678
+ * {@link DataTable.models.oSettings}
13679
+ * 2. `{int}` Target column index
13680
+ *
13681
+ * Each function is expected to return an array:
13682
+ *
13683
+ * * `{array}` Data for the column to be ordering upon
13684
+ *
13685
+ * @type array
13686
+ *
13687
+ * @example
13688
+ * // Ordering using `input` node values
13689
+ * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
13690
+ * {
13691
+ * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
13692
+ * return $('input', td).val();
13693
+ * } );
13694
+ * }
13695
+ */
13696
+ order: {},
13697
+
13698
+
13699
+ /**
13700
+ * Type based plug-ins.
13701
+ *
13702
+ * Each column in DataTables has a type assigned to it, either by automatic
13703
+ * detection or by direct assignment using the `type` option for the column.
13704
+ * The type of a column will effect how it is ordering and search (plug-ins
13705
+ * can also make use of the column type if required).
13706
+ *
13707
+ * @namespace
13708
+ */
13709
+ type: {
13710
+ /**
13711
+ * Type detection functions.
13712
+ *
13713
+ * The functions defined in this object are used to automatically detect
13714
+ * a column's type, making initialisation of DataTables super easy, even
13715
+ * when complex data is in the table.
13716
+ *
13717
+ * The functions defined take two parameters:
13718
+ *
13719
+ * 1. `{*}` Data from the column cell to be analysed
13720
+ * 2. `{settings}` DataTables settings object. This can be used to
13721
+ * perform context specific type detection - for example detection
13722
+ * based on language settings such as using a comma for a decimal
13723
+ * place. Generally speaking the options from the settings will not
13724
+ * be required
13725
+ *
13726
+ * Each function is expected to return:
13727
+ *
13728
+ * * `{string|null}` Data type detected, or null if unknown (and thus
13729
+ * pass it on to the other type detection functions.
13730
+ *
13731
+ * @type array
13732
+ *
13733
+ * @example
13734
+ * // Currency type detection plug-in:
13735
+ * $.fn.dataTable.ext.type.detect.push(
13736
+ * function ( data, settings ) {
13737
+ * // Check the numeric part
13738
+ * if ( ! $.isNumeric( data.substring(1) ) ) {
13739
+ * return null;
13740
+ * }
13741
+ *
13742
+ * // Check prefixed by currency
13743
+ * if ( data.charAt(0) == '$' || data.charAt(0) == '&pound;' ) {
13744
+ * return 'currency';
13745
+ * }
13746
+ * return null;
13747
+ * }
13748
+ * );
13749
+ */
13750
+ detect: [],
13751
+
13752
+
13753
+ /**
13754
+ * Type based search formatting.
13755
+ *
13756
+ * The type based searching functions can be used to pre-format the
13757
+ * data to be search on. For example, it can be used to strip HTML
13758
+ * tags or to de-format telephone numbers for numeric only searching.
13759
+ *
13760
+ * Note that is a search is not defined for a column of a given type,
13761
+ * no search formatting will be performed.
13762
+ *
13763
+ * Pre-processing of searching data plug-ins - When you assign the sType
13764
+ * for a column (or have it automatically detected for you by DataTables
13765
+ * or a type detection plug-in), you will typically be using this for
13766
+ * custom sorting, but it can also be used to provide custom searching
13767
+ * by allowing you to pre-processing the data and returning the data in
13768
+ * the format that should be searched upon. This is done by adding
13769
+ * functions this object with a parameter name which matches the sType
13770
+ * for that target column. This is the corollary of <i>afnSortData</i>
13771
+ * for searching data.
13772
+ *
13773
+ * The functions defined take a single parameter:
13774
+ *
13775
+ * 1. `{*}` Data from the column cell to be prepared for searching
13776
+ *
13777
+ * Each function is expected to return:
13778
+ *
13779
+ * * `{string|null}` Formatted string that will be used for the searching.
13780
+ *
13781
+ * @type object
13782
+ * @default {}
13783
+ *
13784
+ * @example
13785
+ * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
13786
+ * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
13787
+ * }
13788
+ */
13789
+ search: {},
13790
+
13791
+
13792
+ /**
13793
+ * Type based ordering.
13794
+ *
13795
+ * The column type tells DataTables what ordering to apply to the table
13796
+ * when a column is sorted upon. The order for each type that is defined,
13797
+ * is defined by the functions available in this object.
13798
+ *
13799
+ * Each ordering option can be described by three properties added to
13800
+ * this object:
13801
+ *
13802
+ * * `{type}-pre` - Pre-formatting function
13803
+ * * `{type}-asc` - Ascending order function
13804
+ * * `{type}-desc` - Descending order function
13805
+ *
13806
+ * All three can be used together, only `{type}-pre` or only
13807
+ * `{type}-asc` and `{type}-desc` together. It is generally recommended
13808
+ * that only `{type}-pre` is used, as this provides the optimal
13809
+ * implementation in terms of speed, although the others are provided
13810
+ * for compatibility with existing Javascript sort functions.
13811
+ *
13812
+ * `{type}-pre`: Functions defined take a single parameter:
13813
+ *
13814
+ * 1. `{*}` Data from the column cell to be prepared for ordering
13815
+ *
13816
+ * And return:
13817
+ *
13818
+ * * `{*}` Data to be sorted upon
13819
+ *
13820
+ * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
13821
+ * functions, taking two parameters:
13822
+ *
13823
+ * 1. `{*}` Data to compare to the second parameter
13824
+ * 2. `{*}` Data to compare to the first parameter
13825
+ *
13826
+ * And returning:
13827
+ *
13828
+ * * `{*}` Ordering match: <0 if first parameter should be sorted lower
13829
+ * than the second parameter, ===0 if the two parameters are equal and
13830
+ * >0 if the first parameter should be sorted height than the second
13831
+ * parameter.
13832
+ *
13833
+ * @type object
13834
+ * @default {}
13835
+ *
13836
+ * @example
13837
+ * // Numeric ordering of formatted numbers with a pre-formatter
13838
+ * $.extend( $.fn.dataTable.ext.type.order, {
13839
+ * "string-pre": function(x) {
13840
+ * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
13841
+ * return parseFloat( a );
13842
+ * }
13843
+ * } );
13844
+ *
13845
+ * @example
13846
+ * // Case-sensitive string ordering, with no pre-formatting method
13847
+ * $.extend( $.fn.dataTable.ext.order, {
13848
+ * "string-case-asc": function(x,y) {
13849
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
13850
+ * },
13851
+ * "string-case-desc": function(x,y) {
13852
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
13853
+ * }
13854
+ * } );
13855
+ */
13856
+ order: {}
13857
+ },
13858
+
13859
+ /**
13860
+ * Unique DataTables instance counter
13861
+ *
13862
+ * @type int
13863
+ * @private
13864
+ */
13865
+ _unique: 0,
13866
+
13867
+
13868
+ //
13869
+ // Depreciated
13870
+ // The following properties are retained for backwards compatiblity only.
13871
+ // The should not be used in new projects and will be removed in a future
13872
+ // version
13873
+ //
13874
+
13875
+ /**
13876
+ * Version check function.
13877
+ * @type function
13878
+ * @depreciated Since 1.10
13879
+ */
13880
+ fnVersionCheck: DataTable.fnVersionCheck,
13881
+
13882
+
13883
+ /**
13884
+ * Index for what 'this' index API functions should use
13885
+ * @type int
13886
+ * @deprecated Since v1.10
13887
+ */
13888
+ iApiIndex: 0,
13889
+
13890
+
13891
+ /**
13892
+ * jQuery UI class container
13893
+ * @type object
13894
+ * @deprecated Since v1.10
13895
+ */
13896
+ oJUIClasses: {},
13897
+
13898
+
13899
+ /**
13900
+ * Software version
13901
+ * @type string
13902
+ * @deprecated Since v1.10
13903
+ */
13904
+ sVersion: DataTable.version
13905
+ };
13906
+
13907
+
13908
+ //
13909
+ // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
13910
+ //
13911
+ $.extend( _ext, {
13912
+ afnFiltering: _ext.search,
13913
+ aTypes: _ext.type.detect,
13914
+ ofnSearch: _ext.type.search,
13915
+ oSort: _ext.type.order,
13916
+ afnSortData: _ext.order,
13917
+ aoFeatures: _ext.feature,
13918
+ oApi: _ext.internal,
13919
+ oStdClasses: _ext.classes,
13920
+ oPagination: _ext.pager
13921
+ } );
13922
+
13923
+
13924
+ $.extend( DataTable.ext.classes, {
13925
+ "sTable": "dataTable",
13926
+ "sNoFooter": "no-footer",
13927
+
13928
+ /* Paging buttons */
13929
+ "sPageButton": "paginate_button",
13930
+ "sPageButtonActive": "current",
13931
+ "sPageButtonDisabled": "disabled",
13932
+
13933
+ /* Striping classes */
13934
+ "sStripeOdd": "odd",
13935
+ "sStripeEven": "even",
13936
+
13937
+ /* Empty row */
13938
+ "sRowEmpty": "dataTables_empty",
13939
+
13940
+ /* Features */
13941
+ "sWrapper": "dataTables_wrapper",
13942
+ "sFilter": "dataTables_filter",
13943
+ "sInfo": "dataTables_info",
13944
+ "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
13945
+ "sLength": "dataTables_length",
13946
+ "sProcessing": "dataTables_processing",
13947
+
13948
+ /* Sorting */
13949
+ "sSortAsc": "sorting_asc",
13950
+ "sSortDesc": "sorting_desc",
13951
+ "sSortable": "sorting", /* Sortable in both directions */
13952
+ "sSortableAsc": "sorting_asc_disabled",
13953
+ "sSortableDesc": "sorting_desc_disabled",
13954
+ "sSortableNone": "sorting_disabled",
13955
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
13956
+
13957
+ /* Filtering */
13958
+ "sFilterInput": "",
13959
+
13960
+ /* Page length */
13961
+ "sLengthSelect": "",
13962
+
13963
+ /* Scrolling */
13964
+ "sScrollWrapper": "dataTables_scroll",
13965
+ "sScrollHead": "dataTables_scrollHead",
13966
+ "sScrollHeadInner": "dataTables_scrollHeadInner",
13967
+ "sScrollBody": "dataTables_scrollBody",
13968
+ "sScrollFoot": "dataTables_scrollFoot",
13969
+ "sScrollFootInner": "dataTables_scrollFootInner",
13970
+
13971
+ /* Misc */
13972
+ "sHeaderTH": "",
13973
+ "sFooterTH": "",
13974
+
13975
+ // Deprecated
13976
+ "sSortJUIAsc": "",
13977
+ "sSortJUIDesc": "",
13978
+ "sSortJUI": "",
13979
+ "sSortJUIAscAllowed": "",
13980
+ "sSortJUIDescAllowed": "",
13981
+ "sSortJUIWrapper": "",
13982
+ "sSortIcon": "",
13983
+ "sJUIHeader": "",
13984
+ "sJUIFooter": ""
13985
+ } );
13986
+
13987
+
13988
+ (function() {
13989
+
13990
+ // Reused strings for better compression. Closure compiler appears to have a
13991
+ // weird edge case where it is trying to expand strings rather than use the
13992
+ // variable version. This results in about 200 bytes being added, for very
13993
+ // little preference benefit since it this run on script load only.
13994
+ var _empty = '';
13995
+ _empty = '';
13996
+
13997
+ var _stateDefault = _empty + 'ui-state-default';
13998
+ var _sortIcon = _empty + 'css_right ui-icon ui-icon-';
13999
+ var _headerFooter = _empty + 'fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix';
14000
+
14001
+ $.extend( DataTable.ext.oJUIClasses, DataTable.ext.classes, {
14002
+ /* Full numbers paging buttons */
14003
+ "sPageButton": "fg-button ui-button "+_stateDefault,
14004
+ "sPageButtonActive": "ui-state-disabled",
14005
+ "sPageButtonDisabled": "ui-state-disabled",
14006
+
14007
+ /* Features */
14008
+ "sPaging": "dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi "+
14009
+ "ui-buttonset-multi paging_", /* Note that the type is postfixed */
14010
+
14011
+ /* Sorting */
14012
+ "sSortAsc": _stateDefault+" sorting_asc",
14013
+ "sSortDesc": _stateDefault+" sorting_desc",
14014
+ "sSortable": _stateDefault+" sorting",
14015
+ "sSortableAsc": _stateDefault+" sorting_asc_disabled",
14016
+ "sSortableDesc": _stateDefault+" sorting_desc_disabled",
14017
+ "sSortableNone": _stateDefault+" sorting_disabled",
14018
+ "sSortJUIAsc": _sortIcon+"triangle-1-n",
14019
+ "sSortJUIDesc": _sortIcon+"triangle-1-s",
14020
+ "sSortJUI": _sortIcon+"carat-2-n-s",
14021
+ "sSortJUIAscAllowed": _sortIcon+"carat-1-n",
14022
+ "sSortJUIDescAllowed": _sortIcon+"carat-1-s",
14023
+ "sSortJUIWrapper": "DataTables_sort_wrapper",
14024
+ "sSortIcon": "DataTables_sort_icon",
14025
+
14026
+ /* Scrolling */
14027
+ "sScrollHead": "dataTables_scrollHead "+_stateDefault,
14028
+ "sScrollFoot": "dataTables_scrollFoot "+_stateDefault,
14029
+
14030
+ /* Misc */
14031
+ "sHeaderTH": _stateDefault,
14032
+ "sFooterTH": _stateDefault,
14033
+ "sJUIHeader": _headerFooter+" ui-corner-tl ui-corner-tr",
14034
+ "sJUIFooter": _headerFooter+" ui-corner-bl ui-corner-br"
14035
+ } );
14036
+
14037
+ }());
14038
+
14039
+
14040
+
14041
+ var extPagination = DataTable.ext.pager;
14042
+
14043
+ function _numbers ( page, pages ) {
14044
+ var
14045
+ numbers = [],
14046
+ buttons = extPagination.numbers_length,
14047
+ half = Math.floor( buttons / 2 ),
14048
+ i = 1;
14049
+
14050
+ if ( pages <= buttons ) {
14051
+ numbers = _range( 0, pages );
14052
+ }
14053
+ else if ( page <= half ) {
14054
+ numbers = _range( 0, buttons-2 );
14055
+ numbers.push( 'ellipsis' );
14056
+ numbers.push( pages-1 );
14057
+ }
14058
+ else if ( page >= pages - 1 - half ) {
14059
+ numbers = _range( pages-(buttons-2), pages );
14060
+ numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
14061
+ numbers.splice( 0, 0, 0 );
14062
+ }
14063
+ else {
14064
+ numbers = _range( page-1, page+2 );
14065
+ numbers.push( 'ellipsis' );
14066
+ numbers.push( pages-1 );
14067
+ numbers.splice( 0, 0, 'ellipsis' );
14068
+ numbers.splice( 0, 0, 0 );
14069
+ }
14070
+
14071
+ numbers.DT_el = 'span';
14072
+ return numbers;
14073
+ }
14074
+
14075
+
14076
+ $.extend( extPagination, {
14077
+ simple: function ( page, pages ) {
14078
+ return [ 'previous', 'next' ];
14079
+ },
14080
+
14081
+ full: function ( page, pages ) {
14082
+ return [ 'first', 'previous', 'next', 'last' ];
14083
+ },
14084
+
14085
+ simple_numbers: function ( page, pages ) {
14086
+ return [ 'previous', _numbers(page, pages), 'next' ];
14087
+ },
14088
+
14089
+ full_numbers: function ( page, pages ) {
14090
+ return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
14091
+ },
14092
+
14093
+ // For testing and plug-ins to use
14094
+ _numbers: _numbers,
14095
+ numbers_length: 7
14096
+ } );
14097
+
14098
+
14099
+ $.extend( true, DataTable.ext.renderer, {
14100
+ pageButton: {
14101
+ _: function ( settings, host, idx, buttons, page, pages ) {
14102
+ var classes = settings.oClasses;
14103
+ var lang = settings.oLanguage.oPaginate;
14104
+ var btnDisplay, btnClass, counter=0;
14105
+
14106
+ var attach = function( container, buttons ) {
14107
+ var i, ien, node, button;
14108
+ var clickHandler = function ( e ) {
14109
+ _fnPageChange( settings, e.data.action, true );
14110
+ };
14111
+
14112
+ for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
14113
+ button = buttons[i];
14114
+
14115
+ if ( $.isArray( button ) ) {
14116
+ var inner = $( '<'+(button.DT_el || 'div')+'/>' )
14117
+ .appendTo( container );
14118
+ attach( inner, button );
14119
+ }
14120
+ else {
14121
+ btnDisplay = '';
14122
+ btnClass = '';
14123
+
14124
+ switch ( button ) {
14125
+ case 'ellipsis':
14126
+ container.append('<span>&hellip;</span>');
14127
+ break;
14128
+
14129
+ case 'first':
14130
+ btnDisplay = lang.sFirst;
14131
+ btnClass = button + (page > 0 ?
14132
+ '' : ' '+classes.sPageButtonDisabled);
14133
+ break;
14134
+
14135
+ case 'previous':
14136
+ btnDisplay = lang.sPrevious;
14137
+ btnClass = button + (page > 0 ?
14138
+ '' : ' '+classes.sPageButtonDisabled);
14139
+ break;
14140
+
14141
+ case 'next':
14142
+ btnDisplay = lang.sNext;
14143
+ btnClass = button + (page < pages-1 ?
14144
+ '' : ' '+classes.sPageButtonDisabled);
14145
+ break;
14146
+
14147
+ case 'last':
14148
+ btnDisplay = lang.sLast;
14149
+ btnClass = button + (page < pages-1 ?
14150
+ '' : ' '+classes.sPageButtonDisabled);
14151
+ break;
14152
+
14153
+ default:
14154
+ btnDisplay = button + 1;
14155
+ btnClass = page === button ?
14156
+ classes.sPageButtonActive : '';
14157
+ break;
14158
+ }
14159
+
14160
+ if ( btnDisplay ) {
14161
+ node = $('<a>', {
14162
+ 'class': classes.sPageButton+' '+btnClass,
14163
+ 'aria-controls': settings.sTableId,
14164
+ 'data-dt-idx': counter,
14165
+ 'tabindex': settings.iTabIndex,
14166
+ 'id': idx === 0 && typeof button === 'string' ?
14167
+ settings.sTableId +'_'+ button :
14168
+ null
14169
+ } )
14170
+ .html( btnDisplay )
14171
+ .appendTo( container );
14172
+
14173
+ _fnBindAction(
14174
+ node, {action: button}, clickHandler
14175
+ );
14176
+
14177
+ counter++;
14178
+ }
14179
+ }
14180
+ }
14181
+ };
14182
+
14183
+ // IE9 throws an 'unknown error' if document.activeElement is used
14184
+ // inside an iframe or frame. Try / catch the error. Not good for
14185
+ // accessibility, but neither are frames.
14186
+ try {
14187
+ // Because this approach is destroying and recreating the paging
14188
+ // elements, focus is lost on the select button which is bad for
14189
+ // accessibility. So we want to restore focus once the draw has
14190
+ // completed
14191
+ var activeEl = $(document.activeElement).data('dt-idx');
14192
+
14193
+ attach( $(host).empty(), buttons );
14194
+
14195
+ if ( activeEl !== null ) {
14196
+ $(host).find( '[data-dt-idx='+activeEl+']' ).focus();
14197
+ }
14198
+ }
14199
+ catch (e) {}
14200
+ }
14201
+ }
14202
+ } );
14203
+
14204
+
14205
+
14206
+ // Built in type detection. See model.ext.aTypes for information about
14207
+ // what is required from this methods.
14208
+ $.extend( DataTable.ext.type.detect, [
14209
+ // Plain numbers - first since V8 detects some plain numbers as dates
14210
+ // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
14211
+ function ( d, settings )
14212
+ {
14213
+ var decimal = settings.oLanguage.sDecimal;
14214
+ return _isNumber( d, decimal ) ? 'num'+decimal : null;
14215
+ },
14216
+
14217
+ // Dates (only those recognised by the browser's Date.parse)
14218
+ function ( d, settings )
14219
+ {
14220
+ // V8 will remove any unknown characters at the start and end of the
14221
+ // expression, leading to false matches such as `$245.12` or `10%` being
14222
+ // a valid date. See forum thread 18941 for detail.
14223
+ if ( d && !(d instanceof Date) && ( ! _re_date_start.test(d) || ! _re_date_end.test(d) ) ) {
14224
+ return null;
14225
+ }
14226
+ var parsed = Date.parse(d);
14227
+ return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
14228
+ },
14229
+
14230
+ // Formatted numbers
14231
+ function ( d, settings )
14232
+ {
14233
+ var decimal = settings.oLanguage.sDecimal;
14234
+ return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
14235
+ },
14236
+
14237
+ // HTML numeric
14238
+ function ( d, settings )
14239
+ {
14240
+ var decimal = settings.oLanguage.sDecimal;
14241
+ return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
14242
+ },
14243
+
14244
+ // HTML numeric, formatted
14245
+ function ( d, settings )
14246
+ {
14247
+ var decimal = settings.oLanguage.sDecimal;
14248
+ return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
14249
+ },
14250
+
14251
+ // HTML (this is strict checking - there must be html)
14252
+ function ( d, settings )
14253
+ {
14254
+ return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
14255
+ 'html' : null;
14256
+ }
14257
+ ] );
14258
+
14259
+
14260
+
14261
+ // Filter formatting functions. See model.ext.ofnSearch for information about
14262
+ // what is required from these methods.
14263
+ //
14264
+ // Note that additional search methods are added for the html numbers and
14265
+ // html formatted numbers by `_addNumericSort()` when we know what the decimal
14266
+ // place is
14267
+
14268
+
14269
+ $.extend( DataTable.ext.type.search, {
14270
+ html: function ( data ) {
14271
+ return _empty(data) ?
14272
+ data :
14273
+ typeof data === 'string' ?
14274
+ data
14275
+ .replace( _re_new_lines, " " )
14276
+ .replace( _re_html, "" ) :
14277
+ '';
14278
+ },
14279
+
14280
+ string: function ( data ) {
14281
+ return _empty(data) ?
14282
+ data :
14283
+ typeof data === 'string' ?
14284
+ data.replace( _re_new_lines, " " ) :
14285
+ data;
14286
+ }
14287
+ } );
14288
+
14289
+
14290
+
14291
+ var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
14292
+ if ( d !== 0 && (!d || d === '-') ) {
14293
+ return -Infinity;
14294
+ }
14295
+
14296
+ // If a decimal place other than `.` is used, it needs to be given to the
14297
+ // function so we can detect it and replace with a `.` which is the only
14298
+ // decimal place Javascript recognises - it is not locale aware.
14299
+ if ( decimalPlace ) {
14300
+ d = _numToDecimal( d, decimalPlace );
14301
+ }
14302
+
14303
+ if ( d.replace ) {
14304
+ if ( re1 ) {
14305
+ d = d.replace( re1, '' );
14306
+ }
14307
+
14308
+ if ( re2 ) {
14309
+ d = d.replace( re2, '' );
14310
+ }
14311
+ }
14312
+
14313
+ return d * 1;
14314
+ };
14315
+
14316
+
14317
+ // Add the numeric 'deformatting' functions for sorting and search. This is done
14318
+ // in a function to provide an easy ability for the language options to add
14319
+ // additional methods if a non-period decimal place is used.
14320
+ function _addNumericSort ( decimalPlace ) {
14321
+ $.each(
14322
+ {
14323
+ // Plain numbers
14324
+ "num": function ( d ) {
14325
+ return __numericReplace( d, decimalPlace );
14326
+ },
14327
+
14328
+ // Formatted numbers
14329
+ "num-fmt": function ( d ) {
14330
+ return __numericReplace( d, decimalPlace, _re_formatted_numeric );
14331
+ },
14332
+
14333
+ // HTML numeric
14334
+ "html-num": function ( d ) {
14335
+ return __numericReplace( d, decimalPlace, _re_html );
14336
+ },
14337
+
14338
+ // HTML numeric, formatted
14339
+ "html-num-fmt": function ( d ) {
14340
+ return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
14341
+ }
14342
+ },
14343
+ function ( key, fn ) {
14344
+ // Add the ordering method
14345
+ _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
14346
+
14347
+ // For HTML types add a search formatter that will strip the HTML
14348
+ if ( key.match(/^html\-/) ) {
14349
+ _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
14350
+ }
14351
+ }
14352
+ );
14353
+ }
14354
+
14355
+
14356
+ // Default sort methods
14357
+ $.extend( _ext.type.order, {
14358
+ // Dates
14359
+ "date-pre": function ( d ) {
14360
+ return Date.parse( d ) || 0;
14361
+ },
14362
+
14363
+ // html
14364
+ "html-pre": function ( a ) {
14365
+ return _empty(a) ?
14366
+ '' :
14367
+ a.replace ?
14368
+ a.replace( /<.*?>/g, "" ).toLowerCase() :
14369
+ a+'';
14370
+ },
14371
+
14372
+ // string
14373
+ "string-pre": function ( a ) {
14374
+ // This is a little complex, but faster than always calling toString,
14375
+ // http://jsperf.com/tostring-v-check
14376
+ return _empty(a) ?
14377
+ '' :
14378
+ typeof a === 'string' ?
14379
+ a.toLowerCase() :
14380
+ ! a.toString ?
14381
+ '' :
14382
+ a.toString();
14383
+ },
14384
+
14385
+ // string-asc and -desc are retained only for compatibility with the old
14386
+ // sort methods
14387
+ "string-asc": function ( x, y ) {
14388
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
14389
+ },
14390
+
14391
+ "string-desc": function ( x, y ) {
14392
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
14393
+ }
14394
+ } );
14395
+
14396
+
14397
+ // Numeric sorting types - order doesn't matter here
14398
+ _addNumericSort( '' );
14399
+
14400
+
14401
+ $.extend( true, DataTable.ext.renderer, {
14402
+ header: {
14403
+ _: function ( settings, cell, column, classes ) {
14404
+ // No additional mark-up required
14405
+ // Attach a sort listener to update on sort - note that using the
14406
+ // `DT` namespace will allow the event to be removed automatically
14407
+ // on destroy, while the `dt` namespaced event is the one we are
14408
+ // listening for
14409
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14410
+ if ( settings !== ctx ) { // need to check this this is the host
14411
+ return; // table, not a nested one
14412
+ }
14413
+
14414
+ var colIdx = column.idx;
14415
+
14416
+ cell
14417
+ .removeClass(
14418
+ column.sSortingClass +' '+
14419
+ classes.sSortAsc +' '+
14420
+ classes.sSortDesc
14421
+ )
14422
+ .addClass( columns[ colIdx ] == 'asc' ?
14423
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14424
+ classes.sSortDesc :
14425
+ column.sSortingClass
14426
+ );
14427
+ } );
14428
+ },
14429
+
14430
+ jqueryui: function ( settings, cell, column, classes ) {
14431
+ $('<div/>')
14432
+ .addClass( classes.sSortJUIWrapper )
14433
+ .append( cell.contents() )
14434
+ .append( $('<span/>')
14435
+ .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
14436
+ )
14437
+ .appendTo( cell );
14438
+
14439
+ // Attach a sort listener to update on sort
14440
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
14441
+ if ( settings !== ctx ) {
14442
+ return;
14443
+ }
14444
+
14445
+ var colIdx = column.idx;
14446
+
14447
+ cell
14448
+ .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
14449
+ .addClass( columns[ colIdx ] == 'asc' ?
14450
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
14451
+ classes.sSortDesc :
14452
+ column.sSortingClass
14453
+ );
14454
+
14455
+ cell
14456
+ .find( 'span.'+classes.sSortIcon )
14457
+ .removeClass(
14458
+ classes.sSortJUIAsc +" "+
14459
+ classes.sSortJUIDesc +" "+
14460
+ classes.sSortJUI +" "+
14461
+ classes.sSortJUIAscAllowed +" "+
14462
+ classes.sSortJUIDescAllowed
14463
+ )
14464
+ .addClass( columns[ colIdx ] == 'asc' ?
14465
+ classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
14466
+ classes.sSortJUIDesc :
14467
+ column.sSortingClassJUI
14468
+ );
14469
+ } );
14470
+ }
14471
+ }
14472
+ } );
14473
+
14474
+ /*
14475
+ * Public helper functions. These aren't used internally by DataTables, or
14476
+ * called by any of the options passed into DataTables, but they can be used
14477
+ * externally by developers working with DataTables. They are helper functions
14478
+ * to make working with DataTables a little bit easier.
14479
+ */
14480
+
14481
+ /**
14482
+ * Helpers for `columns.render`.
14483
+ *
14484
+ * The options defined here can be used with the `columns.render` initialisation
14485
+ * option to provide a display renderer. The following functions are defined:
14486
+ *
14487
+ * * `number` - Will format numeric data (defined by `columns.data`) for
14488
+ * display, retaining the original unformatted data for sorting and filtering.
14489
+ * It takes 4 parameters:
14490
+ * * `string` - Thousands grouping separator
14491
+ * * `string` - Decimal point indicator
14492
+ * * `integer` - Number of decimal points to show
14493
+ * * `string` (optional) - Prefix.
14494
+ *
14495
+ * @example
14496
+ * // Column definition using the number renderer
14497
+ * {
14498
+ * data: "salary",
14499
+ * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
14500
+ * }
14501
+ *
14502
+ * @namespace
14503
+ */
14504
+ DataTable.render = {
14505
+ number: function ( thousands, decimal, precision, prefix ) {
14506
+ return {
14507
+ display: function ( d ) {
14508
+ var negative = d < 0 ? '-' : '';
14509
+ d = Math.abs( parseFloat( d ) );
14510
+
14511
+ var intPart = parseInt( d, 10 );
14512
+ var floatPart = precision ?
14513
+ decimal+(d - intPart).toFixed( precision ).substring( 2 ):
14514
+ '';
14515
+
14516
+ return negative + (prefix||'') +
14517
+ intPart.toString().replace(
14518
+ /\B(?=(\d{3})+(?!\d))/g, thousands
14519
+ ) +
14520
+ floatPart;
14521
+ }
14522
+ };
14523
+ }
14524
+ };
14525
+
14526
+
14527
+ /*
14528
+ * This is really a good bit rubbish this method of exposing the internal methods
14529
+ * publicly... - To be fixed in 2.0 using methods on the prototype
14530
+ */
14531
+
14532
+
14533
+ /**
14534
+ * Create a wrapper function for exporting an internal functions to an external API.
14535
+ * @param {string} fn API function name
14536
+ * @returns {function} wrapped function
14537
+ * @memberof DataTable#internal
14538
+ */
14539
+ function _fnExternApiFunc (fn)
14540
+ {
14541
+ return function() {
14542
+ var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
14543
+ Array.prototype.slice.call(arguments)
14544
+ );
14545
+ return DataTable.ext.internal[fn].apply( this, args );
14546
+ };
14547
+ }
14548
+
14549
+
14550
+ /**
14551
+ * Reference to internal functions for use by plug-in developers. Note that
14552
+ * these methods are references to internal functions and are considered to be
14553
+ * private. If you use these methods, be aware that they are liable to change
14554
+ * between versions.
14555
+ * @namespace
14556
+ */
14557
+ $.extend( DataTable.ext.internal, {
14558
+ _fnExternApiFunc: _fnExternApiFunc,
14559
+ _fnBuildAjax: _fnBuildAjax,
14560
+ _fnAjaxUpdate: _fnAjaxUpdate,
14561
+ _fnAjaxParameters: _fnAjaxParameters,
14562
+ _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
14563
+ _fnAjaxDataSrc: _fnAjaxDataSrc,
14564
+ _fnAddColumn: _fnAddColumn,
14565
+ _fnColumnOptions: _fnColumnOptions,
14566
+ _fnAdjustColumnSizing: _fnAdjustColumnSizing,
14567
+ _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
14568
+ _fnColumnIndexToVisible: _fnColumnIndexToVisible,
14569
+ _fnVisbleColumns: _fnVisbleColumns,
14570
+ _fnGetColumns: _fnGetColumns,
14571
+ _fnColumnTypes: _fnColumnTypes,
14572
+ _fnApplyColumnDefs: _fnApplyColumnDefs,
14573
+ _fnHungarianMap: _fnHungarianMap,
14574
+ _fnCamelToHungarian: _fnCamelToHungarian,
14575
+ _fnLanguageCompat: _fnLanguageCompat,
14576
+ _fnBrowserDetect: _fnBrowserDetect,
14577
+ _fnAddData: _fnAddData,
14578
+ _fnAddTr: _fnAddTr,
14579
+ _fnNodeToDataIndex: _fnNodeToDataIndex,
14580
+ _fnNodeToColumnIndex: _fnNodeToColumnIndex,
14581
+ _fnGetCellData: _fnGetCellData,
14582
+ _fnSetCellData: _fnSetCellData,
14583
+ _fnSplitObjNotation: _fnSplitObjNotation,
14584
+ _fnGetObjectDataFn: _fnGetObjectDataFn,
14585
+ _fnSetObjectDataFn: _fnSetObjectDataFn,
14586
+ _fnGetDataMaster: _fnGetDataMaster,
14587
+ _fnClearTable: _fnClearTable,
14588
+ _fnDeleteIndex: _fnDeleteIndex,
14589
+ _fnInvalidate: _fnInvalidate,
14590
+ _fnGetRowElements: _fnGetRowElements,
14591
+ _fnCreateTr: _fnCreateTr,
14592
+ _fnBuildHead: _fnBuildHead,
14593
+ _fnDrawHead: _fnDrawHead,
14594
+ _fnDraw: _fnDraw,
14595
+ _fnReDraw: _fnReDraw,
14596
+ _fnAddOptionsHtml: _fnAddOptionsHtml,
14597
+ _fnDetectHeader: _fnDetectHeader,
14598
+ _fnGetUniqueThs: _fnGetUniqueThs,
14599
+ _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
14600
+ _fnFilterComplete: _fnFilterComplete,
14601
+ _fnFilterCustom: _fnFilterCustom,
14602
+ _fnFilterColumn: _fnFilterColumn,
14603
+ _fnFilter: _fnFilter,
14604
+ _fnFilterCreateSearch: _fnFilterCreateSearch,
14605
+ _fnEscapeRegex: _fnEscapeRegex,
14606
+ _fnFilterData: _fnFilterData,
14607
+ _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
14608
+ _fnUpdateInfo: _fnUpdateInfo,
14609
+ _fnInfoMacros: _fnInfoMacros,
14610
+ _fnInitialise: _fnInitialise,
14611
+ _fnInitComplete: _fnInitComplete,
14612
+ _fnLengthChange: _fnLengthChange,
14613
+ _fnFeatureHtmlLength: _fnFeatureHtmlLength,
14614
+ _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
14615
+ _fnPageChange: _fnPageChange,
14616
+ _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
14617
+ _fnProcessingDisplay: _fnProcessingDisplay,
14618
+ _fnFeatureHtmlTable: _fnFeatureHtmlTable,
14619
+ _fnScrollDraw: _fnScrollDraw,
14620
+ _fnApplyToChildren: _fnApplyToChildren,
14621
+ _fnCalculateColumnWidths: _fnCalculateColumnWidths,
14622
+ _fnThrottle: _fnThrottle,
14623
+ _fnConvertToWidth: _fnConvertToWidth,
14624
+ _fnScrollingWidthAdjust: _fnScrollingWidthAdjust,
14625
+ _fnGetWidestNode: _fnGetWidestNode,
14626
+ _fnGetMaxLenString: _fnGetMaxLenString,
14627
+ _fnStringToCss: _fnStringToCss,
14628
+ _fnScrollBarWidth: _fnScrollBarWidth,
14629
+ _fnSortFlatten: _fnSortFlatten,
14630
+ _fnSort: _fnSort,
14631
+ _fnSortAria: _fnSortAria,
14632
+ _fnSortListener: _fnSortListener,
14633
+ _fnSortAttachListener: _fnSortAttachListener,
14634
+ _fnSortingClasses: _fnSortingClasses,
14635
+ _fnSortData: _fnSortData,
14636
+ _fnSaveState: _fnSaveState,
14637
+ _fnLoadState: _fnLoadState,
14638
+ _fnSettingsFromNode: _fnSettingsFromNode,
14639
+ _fnLog: _fnLog,
14640
+ _fnMap: _fnMap,
14641
+ _fnBindAction: _fnBindAction,
14642
+ _fnCallbackReg: _fnCallbackReg,
14643
+ _fnCallbackFire: _fnCallbackFire,
14644
+ _fnLengthOverflow: _fnLengthOverflow,
14645
+ _fnRenderer: _fnRenderer,
14646
+ _fnDataSource: _fnDataSource,
14647
+ _fnRowAttributes: _fnRowAttributes,
14648
+ _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
14649
+ // in 1.10, so this dead-end function is
14650
+ // added to prevent errors
14651
+ } );
14652
+
14653
+
14654
+ // jQuery access
14655
+ $.fn.dataTable = DataTable;
14656
+
14657
+ // Legacy aliases
14658
+ $.fn.dataTableSettings = DataTable.settings;
14659
+ $.fn.dataTableExt = DataTable.ext;
14660
+
14661
+ // With a capital `D` we return a DataTables API instance rather than a
14662
+ // jQuery object
14663
+ $.fn.DataTable = function ( opts ) {
14664
+ return $(this).dataTable( opts ).api();
14665
+ };
14666
+
14667
+ // All properties that are available to $.fn.dataTable should also be
14668
+ // available on $.fn.DataTable
14669
+ $.each( DataTable, function ( prop, val ) {
14670
+ $.fn.DataTable[ prop ] = val;
14671
+ } );
14672
+
14673
+
14674
+ // Information about events fired by DataTables - for documentation.
14675
+ /**
14676
+ * Draw event, fired whenever the table is redrawn on the page, at the same
14677
+ * point as fnDrawCallback. This may be useful for binding events or
14678
+ * performing calculations when the table is altered at all.
14679
+ * @name DataTable#draw.dt
14680
+ * @event
14681
+ * @param {event} e jQuery event object
14682
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14683
+ */
14684
+
14685
+ /**
14686
+ * Search event, fired when the searching applied to the table (using the
14687
+ * built-in global search, or column filters) is altered.
14688
+ * @name DataTable#search.dt
14689
+ * @event
14690
+ * @param {event} e jQuery event object
14691
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14692
+ */
14693
+
14694
+ /**
14695
+ * Page change event, fired when the paging of the table is altered.
14696
+ * @name DataTable#page.dt
14697
+ * @event
14698
+ * @param {event} e jQuery event object
14699
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14700
+ */
14701
+
14702
+ /**
14703
+ * Order event, fired when the ordering applied to the table is altered.
14704
+ * @name DataTable#order.dt
14705
+ * @event
14706
+ * @param {event} e jQuery event object
14707
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14708
+ */
14709
+
14710
+ /**
14711
+ * DataTables initialisation complete event, fired when the table is fully
14712
+ * drawn, including Ajax data loaded, if Ajax data is required.
14713
+ * @name DataTable#init.dt
14714
+ * @event
14715
+ * @param {event} e jQuery event object
14716
+ * @param {object} oSettings DataTables settings object
14717
+ * @param {object} json The JSON object request from the server - only
14718
+ * present if client-side Ajax sourced data is used</li></ol>
14719
+ */
14720
+
14721
+ /**
14722
+ * State save event, fired when the table has changed state a new state save
14723
+ * is required. This event allows modification of the state saving object
14724
+ * prior to actually doing the save, including addition or other state
14725
+ * properties (for plug-ins) or modification of a DataTables core property.
14726
+ * @name DataTable#stateSaveParams.dt
14727
+ * @event
14728
+ * @param {event} e jQuery event object
14729
+ * @param {object} oSettings DataTables settings object
14730
+ * @param {object} json The state information to be saved
14731
+ */
14732
+
14733
+ /**
14734
+ * State load event, fired when the table is loading state from the stored
14735
+ * data, but prior to the settings object being modified by the saved state
14736
+ * - allowing modification of the saved state is required or loading of
14737
+ * state for a plug-in.
14738
+ * @name DataTable#stateLoadParams.dt
14739
+ * @event
14740
+ * @param {event} e jQuery event object
14741
+ * @param {object} oSettings DataTables settings object
14742
+ * @param {object} json The saved state information
14743
+ */
14744
+
14745
+ /**
14746
+ * State loaded event, fired when state has been loaded from stored data and
14747
+ * the settings object has been modified by the loaded data.
14748
+ * @name DataTable#stateLoaded.dt
14749
+ * @event
14750
+ * @param {event} e jQuery event object
14751
+ * @param {object} oSettings DataTables settings object
14752
+ * @param {object} json The saved state information
14753
+ */
14754
+
14755
+ /**
14756
+ * Processing event, fired when DataTables is doing some kind of processing
14757
+ * (be it, order, searcg or anything else). It can be used to indicate to
14758
+ * the end user that there is something happening, or that something has
14759
+ * finished.
14760
+ * @name DataTable#processing.dt
14761
+ * @event
14762
+ * @param {event} e jQuery event object
14763
+ * @param {object} oSettings DataTables settings object
14764
+ * @param {boolean} bShow Flag for if DataTables is doing processing or not
14765
+ */
14766
+
14767
+ /**
14768
+ * Ajax (XHR) event, fired whenever an Ajax request is completed from a
14769
+ * request to made to the server for new data. This event is called before
14770
+ * DataTables processed the returned data, so it can also be used to pre-
14771
+ * process the data returned from the server, if needed.
14772
+ *
14773
+ * Note that this trigger is called in `fnServerData`, if you override
14774
+ * `fnServerData` and which to use this event, you need to trigger it in you
14775
+ * success function.
14776
+ * @name DataTable#xhr.dt
14777
+ * @event
14778
+ * @param {event} e jQuery event object
14779
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14780
+ * @param {object} json JSON returned from the server
14781
+ *
14782
+ * @example
14783
+ * // Use a custom property returned from the server in another DOM element
14784
+ * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14785
+ * $('#status').html( json.status );
14786
+ * } );
14787
+ *
14788
+ * @example
14789
+ * // Pre-process the data returned from the server
14790
+ * $('#table').dataTable().on('xhr.dt', function (e, settings, json) {
14791
+ * for ( var i=0, ien=json.aaData.length ; i<ien ; i++ ) {
14792
+ * json.aaData[i].sum = json.aaData[i].one + json.aaData[i].two;
14793
+ * }
14794
+ * // Note no return - manipulate the data directly in the JSON object.
14795
+ * } );
14796
+ */
14797
+
14798
+ /**
14799
+ * Destroy event, fired when the DataTable is destroyed by calling fnDestroy
14800
+ * or passing the bDestroy:true parameter in the initialisation object. This
14801
+ * can be used to remove bound events, added DOM nodes, etc.
14802
+ * @name DataTable#destroy.dt
14803
+ * @event
14804
+ * @param {event} e jQuery event object
14805
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14806
+ */
14807
+
14808
+ /**
14809
+ * Page length change event, fired when number of records to show on each
14810
+ * page (the length) is changed.
14811
+ * @name DataTable#length.dt
14812
+ * @event
14813
+ * @param {event} e jQuery event object
14814
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14815
+ * @param {integer} len New length
14816
+ */
14817
+
14818
+ /**
14819
+ * Column sizing has changed.
14820
+ * @name DataTable#column-sizing.dt
14821
+ * @event
14822
+ * @param {event} e jQuery event object
14823
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14824
+ */
14825
+
14826
+ /**
14827
+ * Column visibility has changed.
14828
+ * @name DataTable#column-visibility.dt
14829
+ * @event
14830
+ * @param {event} e jQuery event object
14831
+ * @param {object} o DataTables settings object {@link DataTable.models.oSettings}
14832
+ * @param {int} column Column index
14833
+ * @param {bool} vis `false` if column now hidden, or `true` if visible
14834
+ */
14835
+
14836
+ return $.fn.dataTable;
14837
+ }));
14838
+
14839
+ }(window, document));
14840
+
assets/dependencies/datatables/js/jquery.dataTables.min.js ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! DataTables 1.10.4
2
+ * ©2008-2014 SpryMedia Ltd - datatables.net/license
3
+ */
4
+ (function(Da,P,l){var O=function(g){function V(a){var b,c,e={};g.each(a,function(d){if((b=d.match(/^([^A-Z]+?)([A-Z])/))&&-1!=="a aa ai ao as b fn i m o s ".indexOf(b[1]+" "))c=d.replace(b[0],b[2].toLowerCase()),e[c]=d,"o"===b[1]&&V(a[d])});a._hungarianMap=e}function G(a,b,c){a._hungarianMap||V(a);var e;g.each(b,function(d){e=a._hungarianMap[d];if(e!==l&&(c||b[e]===l))"o"===e.charAt(0)?(b[e]||(b[e]={}),g.extend(!0,b[e],b[d]),G(a[e],b[e],c)):b[e]=b[d]})}function O(a){var b=p.defaults.oLanguage,c=a.sZeroRecords;
5
+ !a.sEmptyTable&&(c&&"No data available in table"===b.sEmptyTable)&&D(a,a,"sZeroRecords","sEmptyTable");!a.sLoadingRecords&&(c&&"Loading..."===b.sLoadingRecords)&&D(a,a,"sZeroRecords","sLoadingRecords");a.sInfoThousands&&(a.sThousands=a.sInfoThousands);(a=a.sDecimal)&&cb(a)}function db(a){z(a,"ordering","bSort");z(a,"orderMulti","bSortMulti");z(a,"orderClasses","bSortClasses");z(a,"orderCellsTop","bSortCellsTop");z(a,"order","aaSorting");z(a,"orderFixed","aaSortingFixed");z(a,"paging","bPaginate");
6
+ z(a,"pagingType","sPaginationType");z(a,"pageLength","iDisplayLength");z(a,"searching","bFilter");if(a=a.aoSearchCols)for(var b=0,c=a.length;b<c;b++)a[b]&&G(p.models.oSearch,a[b])}function eb(a){z(a,"orderable","bSortable");z(a,"orderData","aDataSort");z(a,"orderSequence","asSorting");z(a,"orderDataType","sortDataType")}function fb(a){var a=a.oBrowser,b=g("<div/>").css({position:"absolute",top:0,left:0,height:1,width:1,overflow:"hidden"}).append(g("<div/>").css({position:"absolute",top:1,left:1,width:100,
7
+ overflow:"scroll"}).append(g('<div class="test"/>').css({width:"100%",height:10}))).appendTo("body"),c=b.find(".test");a.bScrollOversize=100===c[0].offsetWidth;a.bScrollbarLeft=1!==c.offset().left;b.remove()}function gb(a,b,c,e,d,f){var h,i=!1;c!==l&&(h=c,i=!0);for(;e!==d;)a.hasOwnProperty(e)&&(h=i?b(h,a[e],e,a):a[e],i=!0,e+=f);return h}function Ea(a,b){var c=p.defaults.column,e=a.aoColumns.length,c=g.extend({},p.models.oColumn,c,{nTh:b?b:P.createElement("th"),sTitle:c.sTitle?c.sTitle:b?b.innerHTML:
8
+ "",aDataSort:c.aDataSort?c.aDataSort:[e],mData:c.mData?c.mData:e,idx:e});a.aoColumns.push(c);c=a.aoPreSearchCols;c[e]=g.extend({},p.models.oSearch,c[e]);ja(a,e,null)}function ja(a,b,c){var b=a.aoColumns[b],e=a.oClasses,d=g(b.nTh);if(!b.sWidthOrig){b.sWidthOrig=d.attr("width")||null;var f=(d.attr("style")||"").match(/width:\s*(\d+[pxem%]+)/);f&&(b.sWidthOrig=f[1])}c!==l&&null!==c&&(eb(c),G(p.defaults.column,c),c.mDataProp!==l&&!c.mData&&(c.mData=c.mDataProp),c.sType&&(b._sManualType=c.sType),c.className&&
9
+ !c.sClass&&(c.sClass=c.className),g.extend(b,c),D(b,c,"sWidth","sWidthOrig"),"number"===typeof c.iDataSort&&(b.aDataSort=[c.iDataSort]),D(b,c,"aDataSort"));var h=b.mData,i=W(h),j=b.mRender?W(b.mRender):null,c=function(a){return"string"===typeof a&&-1!==a.indexOf("@")};b._bAttrSrc=g.isPlainObject(h)&&(c(h.sort)||c(h.type)||c(h.filter));b.fnGetData=function(a,b,c){var e=i(a,b,l,c);return j&&b?j(e,b,a,c):e};b.fnSetData=function(a,b,c){return Q(h)(a,b,c)};"number"!==typeof h&&(a._rowReadObject=!0);a.oFeatures.bSort||
10
+ (b.bSortable=!1,d.addClass(e.sSortableNone));a=-1!==g.inArray("asc",b.asSorting);c=-1!==g.inArray("desc",b.asSorting);!b.bSortable||!a&&!c?(b.sSortingClass=e.sSortableNone,b.sSortingClassJUI=""):a&&!c?(b.sSortingClass=e.sSortableAsc,b.sSortingClassJUI=e.sSortJUIAscAllowed):!a&&c?(b.sSortingClass=e.sSortableDesc,b.sSortingClassJUI=e.sSortJUIDescAllowed):(b.sSortingClass=e.sSortable,b.sSortingClassJUI=e.sSortJUI)}function X(a){if(!1!==a.oFeatures.bAutoWidth){var b=a.aoColumns;Fa(a);for(var c=0,e=b.length;c<
11
+ e;c++)b[c].nTh.style.width=b[c].sWidth}b=a.oScroll;(""!==b.sY||""!==b.sX)&&Y(a);u(a,null,"column-sizing",[a])}function ka(a,b){var c=Z(a,"bVisible");return"number"===typeof c[b]?c[b]:null}function $(a,b){var c=Z(a,"bVisible"),c=g.inArray(b,c);return-1!==c?c:null}function aa(a){return Z(a,"bVisible").length}function Z(a,b){var c=[];g.map(a.aoColumns,function(a,d){a[b]&&c.push(d)});return c}function Ga(a){var b=a.aoColumns,c=a.aoData,e=p.ext.type.detect,d,f,h,i,j,g,m,o,k;d=0;for(f=b.length;d<f;d++)if(m=
12
+ b[d],k=[],!m.sType&&m._sManualType)m.sType=m._sManualType;else if(!m.sType){h=0;for(i=e.length;h<i;h++){j=0;for(g=c.length;j<g;j++){k[j]===l&&(k[j]=v(a,j,d,"type"));o=e[h](k[j],a);if(!o&&h!==e.length-1)break;if("html"===o)break}if(o){m.sType=o;break}}m.sType||(m.sType="string")}}function hb(a,b,c,e){var d,f,h,i,j,n,m=a.aoColumns;if(b)for(d=b.length-1;0<=d;d--){n=b[d];var o=n.targets!==l?n.targets:n.aTargets;g.isArray(o)||(o=[o]);f=0;for(h=o.length;f<h;f++)if("number"===typeof o[f]&&0<=o[f]){for(;m.length<=
13
+ o[f];)Ea(a);e(o[f],n)}else if("number"===typeof o[f]&&0>o[f])e(m.length+o[f],n);else if("string"===typeof o[f]){i=0;for(j=m.length;i<j;i++)("_all"==o[f]||g(m[i].nTh).hasClass(o[f]))&&e(i,n)}}if(c){d=0;for(a=c.length;d<a;d++)e(d,c[d])}}function I(a,b,c,e){var d=a.aoData.length,f=g.extend(!0,{},p.models.oRow,{src:c?"dom":"data"});f._aData=b;a.aoData.push(f);for(var b=a.aoColumns,f=0,h=b.length;f<h;f++)c&&Ha(a,d,f,v(a,d,f)),b[f].sType=null;a.aiDisplayMaster.push(d);(c||!a.oFeatures.bDeferRender)&&Ia(a,
14
+ d,c,e);return d}function la(a,b){var c;b instanceof g||(b=g(b));return b.map(function(b,d){c=ma(a,d);return I(a,c.data,d,c.cells)})}function v(a,b,c,e){var d=a.iDraw,f=a.aoColumns[c],h=a.aoData[b]._aData,i=f.sDefaultContent,c=f.fnGetData(h,e,{settings:a,row:b,col:c});if(c===l)return a.iDrawError!=d&&null===i&&(R(a,0,"Requested unknown parameter "+("function"==typeof f.mData?"{function}":"'"+f.mData+"'")+" for row "+b,4),a.iDrawError=d),i;if((c===h||null===c)&&null!==i)c=i;else if("function"===typeof c)return c.call(h);
15
+ return null===c&&"display"==e?"":c}function Ha(a,b,c,e){a.aoColumns[c].fnSetData(a.aoData[b]._aData,e,{settings:a,row:b,col:c})}function Ja(a){return g.map(a.match(/(\\.|[^\.])+/g),function(a){return a.replace(/\\./g,".")})}function W(a){if(g.isPlainObject(a)){var b={};g.each(a,function(a,c){c&&(b[a]=W(c))});return function(a,c,f,h){var i=b[c]||b._;return i!==l?i(a,c,f,h):a}}if(null===a)return function(a){return a};if("function"===typeof a)return function(b,c,f,h){return a(b,c,f,h)};if("string"===
16
+ typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var c=function(a,b,f){var h,i;if(""!==f){i=Ja(f);for(var j=0,g=i.length;j<g;j++){f=i[j].match(ba);h=i[j].match(S);if(f){i[j]=i[j].replace(ba,"");""!==i[j]&&(a=a[i[j]]);h=[];i.splice(0,j+1);i=i.join(".");j=0;for(g=a.length;j<g;j++)h.push(c(a[j],b,i));a=f[0].substring(1,f[0].length-1);a=""===a?h:h.join(a);break}else if(h){i[j]=i[j].replace(S,"");a=a[i[j]]();continue}if(null===a||a[i[j]]===l)return l;a=a[i[j]]}}return a};return function(b,
17
+ d){return c(b,d,a)}}return function(b){return b[a]}}function Q(a){if(g.isPlainObject(a))return Q(a._);if(null===a)return function(){};if("function"===typeof a)return function(b,e,d){a(b,"set",e,d)};if("string"===typeof a&&(-1!==a.indexOf(".")||-1!==a.indexOf("[")||-1!==a.indexOf("("))){var b=function(a,e,d){var d=Ja(d),f;f=d[d.length-1];for(var h,i,j=0,g=d.length-1;j<g;j++){h=d[j].match(ba);i=d[j].match(S);if(h){d[j]=d[j].replace(ba,"");a[d[j]]=[];f=d.slice();f.splice(0,j+1);h=f.join(".");i=0;for(g=
18
+ e.length;i<g;i++)f={},b(f,e[i],h),a[d[j]].push(f);return}i&&(d[j]=d[j].replace(S,""),a=a[d[j]](e));if(null===a[d[j]]||a[d[j]]===l)a[d[j]]={};a=a[d[j]]}if(f.match(S))a[f.replace(S,"")](e);else a[f.replace(ba,"")]=e};return function(c,e){return b(c,e,a)}}return function(b,e){b[a]=e}}function Ka(a){return C(a.aoData,"_aData")}function na(a){a.aoData.length=0;a.aiDisplayMaster.length=0;a.aiDisplay.length=0}function oa(a,b,c){for(var e=-1,d=0,f=a.length;d<f;d++)a[d]==b?e=d:a[d]>b&&a[d]--; -1!=e&&c===l&&
19
+ a.splice(e,1)}function ca(a,b,c,e){var d=a.aoData[b],f,h=function(c,f){for(;c.childNodes.length;)c.removeChild(c.firstChild);c.innerHTML=v(a,b,f,"display")};if("dom"===c||(!c||"auto"===c)&&"dom"===d.src)d._aData=ma(a,d,e,e===l?l:d._aData).data;else{var i=d.anCells;if(i)if(e!==l)h(i[e],e);else{c=0;for(f=i.length;c<f;c++)h(i[c],c)}}d._aSortData=null;d._aFilterData=null;h=a.aoColumns;if(e!==l)h[e].sType=null;else{c=0;for(f=h.length;c<f;c++)h[c].sType=null;La(d)}}function ma(a,b,c,e){var d=[],f=b.firstChild,
20
+ h,i=0,j,n=a.aoColumns,m=a._rowReadObject,e=e||m?{}:[],o=function(a,b){if("string"===typeof a){var c=a.indexOf("@");-1!==c&&(c=a.substring(c+1),Q(a)(e,b.getAttribute(c)))}},a=function(a){if(c===l||c===i)h=n[i],j=g.trim(a.innerHTML),h&&h._bAttrSrc?(Q(h.mData._)(e,j),o(h.mData.sort,a),o(h.mData.type,a),o(h.mData.filter,a)):m?(h._setter||(h._setter=Q(h.mData)),h._setter(e,j)):e[i]=j;i++};if(f)for(;f;){b=f.nodeName.toUpperCase();if("TD"==b||"TH"==b)a(f),d.push(f);f=f.nextSibling}else{d=b.anCells;f=0;for(b=
21
+ d.length;f<b;f++)a(d[f])}return{data:e,cells:d}}function Ia(a,b,c,e){var d=a.aoData[b],f=d._aData,h=[],i,j,g,m,o;if(null===d.nTr){i=c||P.createElement("tr");d.nTr=i;d.anCells=h;i._DT_RowIndex=b;La(d);m=0;for(o=a.aoColumns.length;m<o;m++){g=a.aoColumns[m];j=c?e[m]:P.createElement(g.sCellType);h.push(j);if(!c||g.mRender||g.mData!==m)j.innerHTML=v(a,b,m,"display");g.sClass&&(j.className+=" "+g.sClass);g.bVisible&&!c?i.appendChild(j):!g.bVisible&&c&&j.parentNode.removeChild(j);g.fnCreatedCell&&g.fnCreatedCell.call(a.oInstance,
22
+ j,v(a,b,m),f,b,m)}u(a,"aoRowCreatedCallback",null,[i,f,b])}d.nTr.setAttribute("role","row")}function La(a){var b=a.nTr,c=a._aData;if(b){c.DT_RowId&&(b.id=c.DT_RowId);if(c.DT_RowClass){var e=c.DT_RowClass.split(" ");a.__rowc=a.__rowc?Ma(a.__rowc.concat(e)):e;g(b).removeClass(a.__rowc.join(" ")).addClass(c.DT_RowClass)}c.DT_RowData&&g(b).data(c.DT_RowData)}}function ib(a){var b,c,e,d,f,h=a.nTHead,i=a.nTFoot,j=0===g("th, td",h).length,n=a.oClasses,m=a.aoColumns;j&&(d=g("<tr/>").appendTo(h));b=0;for(c=
23
+ m.length;b<c;b++)f=m[b],e=g(f.nTh).addClass(f.sClass),j&&e.appendTo(d),a.oFeatures.bSort&&(e.addClass(f.sSortingClass),!1!==f.bSortable&&(e.attr("tabindex",a.iTabIndex).attr("aria-controls",a.sTableId),Na(a,f.nTh,b))),f.sTitle!=e.html()&&e.html(f.sTitle),Oa(a,"header")(a,e,f,n);j&&da(a.aoHeader,h);g(h).find(">tr").attr("role","row");g(h).find(">tr>th, >tr>td").addClass(n.sHeaderTH);g(i).find(">tr>th, >tr>td").addClass(n.sFooterTH);if(null!==i){a=a.aoFooter[0];b=0;for(c=a.length;b<c;b++)f=m[b],f.nTf=
24
+ a[b].cell,f.sClass&&g(f.nTf).addClass(f.sClass)}}function ea(a,b,c){var e,d,f,h=[],i=[],j=a.aoColumns.length,n;if(b){c===l&&(c=!1);e=0;for(d=b.length;e<d;e++){h[e]=b[e].slice();h[e].nTr=b[e].nTr;for(f=j-1;0<=f;f--)!a.aoColumns[f].bVisible&&!c&&h[e].splice(f,1);i.push([])}e=0;for(d=h.length;e<d;e++){if(a=h[e].nTr)for(;f=a.firstChild;)a.removeChild(f);f=0;for(b=h[e].length;f<b;f++)if(n=j=1,i[e][f]===l){a.appendChild(h[e][f].cell);for(i[e][f]=1;h[e+j]!==l&&h[e][f].cell==h[e+j][f].cell;)i[e+j][f]=1,j++;
25
+ for(;h[e][f+n]!==l&&h[e][f].cell==h[e][f+n].cell;){for(c=0;c<j;c++)i[e+c][f+n]=1;n++}g(h[e][f].cell).attr("rowspan",j).attr("colspan",n)}}}}function L(a){var b=u(a,"aoPreDrawCallback","preDraw",[a]);if(-1!==g.inArray(!1,b))B(a,!1);else{var b=[],c=0,e=a.asStripeClasses,d=e.length,f=a.oLanguage,h=a.iInitDisplayStart,i="ssp"==A(a),j=a.aiDisplay;a.bDrawing=!0;h!==l&&-1!==h&&(a._iDisplayStart=i?h:h>=a.fnRecordsDisplay()?0:h,a.iInitDisplayStart=-1);var h=a._iDisplayStart,n=a.fnDisplayEnd();if(a.bDeferLoading)a.bDeferLoading=
26
+ !1,a.iDraw++,B(a,!1);else if(i){if(!a.bDestroying&&!jb(a))return}else a.iDraw++;if(0!==j.length){f=i?a.aoData.length:n;for(i=i?0:h;i<f;i++){var m=j[i],o=a.aoData[m];null===o.nTr&&Ia(a,m);m=o.nTr;if(0!==d){var k=e[c%d];o._sRowStripe!=k&&(g(m).removeClass(o._sRowStripe).addClass(k),o._sRowStripe=k)}u(a,"aoRowCallback",null,[m,o._aData,c,i]);b.push(m);c++}}else c=f.sZeroRecords,1==a.iDraw&&"ajax"==A(a)?c=f.sLoadingRecords:f.sEmptyTable&&0===a.fnRecordsTotal()&&(c=f.sEmptyTable),b[0]=g("<tr/>",{"class":d?
27
+ e[0]:""}).append(g("<td />",{valign:"top",colSpan:aa(a),"class":a.oClasses.sRowEmpty}).html(c))[0];u(a,"aoHeaderCallback","header",[g(a.nTHead).children("tr")[0],Ka(a),h,n,j]);u(a,"aoFooterCallback","footer",[g(a.nTFoot).children("tr")[0],Ka(a),h,n,j]);e=g(a.nTBody);e.children().detach();e.append(g(b));u(a,"aoDrawCallback","draw",[a]);a.bSorted=!1;a.bFiltered=!1;a.bDrawing=!1}}function M(a,b){var c=a.oFeatures,e=c.bFilter;c.bSort&&kb(a);e?fa(a,a.oPreviousSearch):a.aiDisplay=a.aiDisplayMaster.slice();
28
+ !0!==b&&(a._iDisplayStart=0);a._drawHold=b;L(a);a._drawHold=!1}function lb(a){var b=a.oClasses,c=g(a.nTable),c=g("<div/>").insertBefore(c),e=a.oFeatures,d=g("<div/>",{id:a.sTableId+"_wrapper","class":b.sWrapper+(a.nTFoot?"":" "+b.sNoFooter)});a.nHolding=c[0];a.nTableWrapper=d[0];a.nTableReinsertBefore=a.nTable.nextSibling;for(var f=a.sDom.split(""),h,i,j,n,m,o,k=0;k<f.length;k++){h=null;i=f[k];if("<"==i){j=g("<div/>")[0];n=f[k+1];if("'"==n||'"'==n){m="";for(o=2;f[k+o]!=n;)m+=f[k+o],o++;"H"==m?m=b.sJUIHeader:
29
+ "F"==m&&(m=b.sJUIFooter);-1!=m.indexOf(".")?(n=m.split("."),j.id=n[0].substr(1,n[0].length-1),j.className=n[1]):"#"==m.charAt(0)?j.id=m.substr(1,m.length-1):j.className=m;k+=o}d.append(j);d=g(j)}else if(">"==i)d=d.parent();else if("l"==i&&e.bPaginate&&e.bLengthChange)h=mb(a);else if("f"==i&&e.bFilter)h=nb(a);else if("r"==i&&e.bProcessing)h=ob(a);else if("t"==i)h=pb(a);else if("i"==i&&e.bInfo)h=qb(a);else if("p"==i&&e.bPaginate)h=rb(a);else if(0!==p.ext.feature.length){j=p.ext.feature;o=0;for(n=j.length;o<
30
+ n;o++)if(i==j[o].cFeature){h=j[o].fnInit(a);break}}h&&(j=a.aanFeatures,j[i]||(j[i]=[]),j[i].push(h),d.append(h))}c.replaceWith(d)}function da(a,b){var c=g(b).children("tr"),e,d,f,h,i,j,n,m,o,k;a.splice(0,a.length);f=0;for(j=c.length;f<j;f++)a.push([]);f=0;for(j=c.length;f<j;f++){e=c[f];for(d=e.firstChild;d;){if("TD"==d.nodeName.toUpperCase()||"TH"==d.nodeName.toUpperCase()){m=1*d.getAttribute("colspan");o=1*d.getAttribute("rowspan");m=!m||0===m||1===m?1:m;o=!o||0===o||1===o?1:o;h=0;for(i=a[f];i[h];)h++;
31
+ n=h;k=1===m?!0:!1;for(i=0;i<m;i++)for(h=0;h<o;h++)a[f+h][n+i]={cell:d,unique:k},a[f+h].nTr=e}d=d.nextSibling}}}function pa(a,b,c){var e=[];c||(c=a.aoHeader,b&&(c=[],da(c,b)));for(var b=0,d=c.length;b<d;b++)for(var f=0,h=c[b].length;f<h;f++)if(c[b][f].unique&&(!e[f]||!a.bSortCellsTop))e[f]=c[b][f].cell;return e}function qa(a,b,c){u(a,"aoServerParams","serverParams",[b]);if(b&&g.isArray(b)){var e={},d=/(.*?)\[\]$/;g.each(b,function(a,b){var c=b.name.match(d);c?(c=c[0],e[c]||(e[c]=[]),e[c].push(b.value)):
32
+ e[b.name]=b.value});b=e}var f,h=a.ajax,i=a.oInstance;if(g.isPlainObject(h)&&h.data){f=h.data;var j=g.isFunction(f)?f(b):f,b=g.isFunction(f)&&j?j:g.extend(!0,b,j);delete h.data}j={data:b,success:function(b){var f=b.error||b.sError;f&&a.oApi._fnLog(a,0,f);a.json=b;u(a,null,"xhr",[a,b]);c(b)},dataType:"json",cache:!1,type:a.sServerMethod,error:function(b,c){var f=a.oApi._fnLog;"parsererror"==c?f(a,0,"Invalid JSON response",1):4===b.readyState&&f(a,0,"Ajax error",7);B(a,!1)}};a.oAjaxData=b;u(a,null,"preXhr",
33
+ [a,b]);a.fnServerData?a.fnServerData.call(i,a.sAjaxSource,g.map(b,function(a,b){return{name:b,value:a}}),c,a):a.sAjaxSource||"string"===typeof h?a.jqXHR=g.ajax(g.extend(j,{url:h||a.sAjaxSource})):g.isFunction(h)?a.jqXHR=h.call(i,b,c,a):(a.jqXHR=g.ajax(g.extend(j,h)),h.data=f)}function jb(a){return a.bAjaxDataGet?(a.iDraw++,B(a,!0),qa(a,sb(a),function(b){tb(a,b)}),!1):!0}function sb(a){var b=a.aoColumns,c=b.length,e=a.oFeatures,d=a.oPreviousSearch,f=a.aoPreSearchCols,h,i=[],j,n,m,o=T(a);h=a._iDisplayStart;
34
+ j=!1!==e.bPaginate?a._iDisplayLength:-1;var k=function(a,b){i.push({name:a,value:b})};k("sEcho",a.iDraw);k("iColumns",c);k("sColumns",C(b,"sName").join(","));k("iDisplayStart",h);k("iDisplayLength",j);var l={draw:a.iDraw,columns:[],order:[],start:h,length:j,search:{value:d.sSearch,regex:d.bRegex}};for(h=0;h<c;h++)n=b[h],m=f[h],j="function"==typeof n.mData?"function":n.mData,l.columns.push({data:j,name:n.sName,searchable:n.bSearchable,orderable:n.bSortable,search:{value:m.sSearch,regex:m.bRegex}}),
35
+ k("mDataProp_"+h,j),e.bFilter&&(k("sSearch_"+h,m.sSearch),k("bRegex_"+h,m.bRegex),k("bSearchable_"+h,n.bSearchable)),e.bSort&&k("bSortable_"+h,n.bSortable);e.bFilter&&(k("sSearch",d.sSearch),k("bRegex",d.bRegex));e.bSort&&(g.each(o,function(a,b){l.order.push({column:b.col,dir:b.dir});k("iSortCol_"+a,b.col);k("sSortDir_"+a,b.dir)}),k("iSortingCols",o.length));b=p.ext.legacy.ajax;return null===b?a.sAjaxSource?i:l:b?i:l}function tb(a,b){var c=b.sEcho!==l?b.sEcho:b.draw,e=b.iTotalRecords!==l?b.iTotalRecords:
36
+ b.recordsTotal,d=b.iTotalDisplayRecords!==l?b.iTotalDisplayRecords:b.recordsFiltered;if(c){if(1*c<a.iDraw)return;a.iDraw=1*c}na(a);a._iRecordsTotal=parseInt(e,10);a._iRecordsDisplay=parseInt(d,10);c=ra(a,b);e=0;for(d=c.length;e<d;e++)I(a,c[e]);a.aiDisplay=a.aiDisplayMaster.slice();a.bAjaxDataGet=!1;L(a);a._bInitComplete||sa(a,b);a.bAjaxDataGet=!0;B(a,!1)}function ra(a,b){var c=g.isPlainObject(a.ajax)&&a.ajax.dataSrc!==l?a.ajax.dataSrc:a.sAjaxDataProp;return"data"===c?b.aaData||b[c]:""!==c?W(c)(b):
37
+ b}function nb(a){var b=a.oClasses,c=a.sTableId,e=a.oLanguage,d=a.oPreviousSearch,f=a.aanFeatures,h='<input type="search" class="'+b.sFilterInput+'"/>',i=e.sSearch,i=i.match(/_INPUT_/)?i.replace("_INPUT_",h):i+h,b=g("<div/>",{id:!f.f?c+"_filter":null,"class":b.sFilter}).append(g("<label/>").append(i)),f=function(){var b=!this.value?"":this.value;b!=d.sSearch&&(fa(a,{sSearch:b,bRegex:d.bRegex,bSmart:d.bSmart,bCaseInsensitive:d.bCaseInsensitive}),a._iDisplayStart=0,L(a))},h=null!==a.searchDelay?a.searchDelay:
38
+ "ssp"===A(a)?400:0,j=g("input",b).val(d.sSearch).attr("placeholder",e.sSearchPlaceholder).bind("keyup.DT search.DT input.DT paste.DT cut.DT",h?ta(f,h):f).bind("keypress.DT",function(a){if(13==a.keyCode)return!1}).attr("aria-controls",c);g(a.nTable).on("search.dt.DT",function(b,c){if(a===c)try{j[0]!==P.activeElement&&j.val(d.sSearch)}catch(f){}});return b[0]}function fa(a,b,c){var e=a.oPreviousSearch,d=a.aoPreSearchCols,f=function(a){e.sSearch=a.sSearch;e.bRegex=a.bRegex;e.bSmart=a.bSmart;e.bCaseInsensitive=
39
+ a.bCaseInsensitive};Ga(a);if("ssp"!=A(a)){ub(a,b.sSearch,c,b.bEscapeRegex!==l?!b.bEscapeRegex:b.bRegex,b.bSmart,b.bCaseInsensitive);f(b);for(b=0;b<d.length;b++)vb(a,d[b].sSearch,b,d[b].bEscapeRegex!==l?!d[b].bEscapeRegex:d[b].bRegex,d[b].bSmart,d[b].bCaseInsensitive);wb(a)}else f(b);a.bFiltered=!0;u(a,null,"search",[a])}function wb(a){for(var b=p.ext.search,c=a.aiDisplay,e,d,f=0,h=b.length;f<h;f++){for(var i=[],j=0,g=c.length;j<g;j++)d=c[j],e=a.aoData[d],b[f](a,e._aFilterData,d,e._aData,j)&&i.push(d);
40
+ c.length=0;c.push.apply(c,i)}}function vb(a,b,c,e,d,f){if(""!==b)for(var h=a.aiDisplay,e=Pa(b,e,d,f),d=h.length-1;0<=d;d--)b=a.aoData[h[d]]._aFilterData[c],e.test(b)||h.splice(d,1)}function ub(a,b,c,e,d,f){var e=Pa(b,e,d,f),d=a.oPreviousSearch.sSearch,f=a.aiDisplayMaster,h;0!==p.ext.search.length&&(c=!0);h=xb(a);if(0>=b.length)a.aiDisplay=f.slice();else{if(h||c||d.length>b.length||0!==b.indexOf(d)||a.bSorted)a.aiDisplay=f.slice();b=a.aiDisplay;for(c=b.length-1;0<=c;c--)e.test(a.aoData[b[c]]._sFilterRow)||
41
+ b.splice(c,1)}}function Pa(a,b,c,e){a=b?a:ua(a);c&&(a="^(?=.*?"+g.map(a.match(/"[^"]+"|[^ ]+/g)||"",function(a){if('"'===a.charAt(0))var b=a.match(/^"(.*)"$/),a=b?b[1]:a;return a.replace('"',"")}).join(")(?=.*?")+").*$");return RegExp(a,e?"i":"")}function ua(a){return a.replace(Xb,"\\$1")}function xb(a){var b=a.aoColumns,c,e,d,f,h,i,g,n,m=p.ext.type.search;c=!1;e=0;for(f=a.aoData.length;e<f;e++)if(n=a.aoData[e],!n._aFilterData){i=[];d=0;for(h=b.length;d<h;d++)c=b[d],c.bSearchable?(g=v(a,e,d,"filter"),
42
+ m[c.sType]&&(g=m[c.sType](g)),null===g&&(g=""),"string"!==typeof g&&g.toString&&(g=g.toString())):g="",g.indexOf&&-1!==g.indexOf("&")&&(va.innerHTML=g,g=Yb?va.textContent:va.innerText),g.replace&&(g=g.replace(/[\r\n]/g,"")),i.push(g);n._aFilterData=i;n._sFilterRow=i.join(" ");c=!0}return c}function yb(a){return{search:a.sSearch,smart:a.bSmart,regex:a.bRegex,caseInsensitive:a.bCaseInsensitive}}function zb(a){return{sSearch:a.search,bSmart:a.smart,bRegex:a.regex,bCaseInsensitive:a.caseInsensitive}}
43
+ function qb(a){var b=a.sTableId,c=a.aanFeatures.i,e=g("<div/>",{"class":a.oClasses.sInfo,id:!c?b+"_info":null});c||(a.aoDrawCallback.push({fn:Ab,sName:"information"}),e.attr("role","status").attr("aria-live","polite"),g(a.nTable).attr("aria-describedby",b+"_info"));return e[0]}function Ab(a){var b=a.aanFeatures.i;if(0!==b.length){var c=a.oLanguage,e=a._iDisplayStart+1,d=a.fnDisplayEnd(),f=a.fnRecordsTotal(),h=a.fnRecordsDisplay(),i=h?c.sInfo:c.sInfoEmpty;h!==f&&(i+=" "+c.sInfoFiltered);i+=c.sInfoPostFix;
44
+ i=Bb(a,i);c=c.fnInfoCallback;null!==c&&(i=c.call(a.oInstance,a,e,d,f,h,i));g(b).html(i)}}function Bb(a,b){var c=a.fnFormatNumber,e=a._iDisplayStart+1,d=a._iDisplayLength,f=a.fnRecordsDisplay(),h=-1===d;return b.replace(/_START_/g,c.call(a,e)).replace(/_END_/g,c.call(a,a.fnDisplayEnd())).replace(/_MAX_/g,c.call(a,a.fnRecordsTotal())).replace(/_TOTAL_/g,c.call(a,f)).replace(/_PAGE_/g,c.call(a,h?1:Math.ceil(e/d))).replace(/_PAGES_/g,c.call(a,h?1:Math.ceil(f/d)))}function ga(a){var b,c,e=a.iInitDisplayStart,
45
+ d=a.aoColumns,f;c=a.oFeatures;if(a.bInitialised){lb(a);ib(a);ea(a,a.aoHeader);ea(a,a.aoFooter);B(a,!0);c.bAutoWidth&&Fa(a);b=0;for(c=d.length;b<c;b++)f=d[b],f.sWidth&&(f.nTh.style.width=s(f.sWidth));M(a);d=A(a);"ssp"!=d&&("ajax"==d?qa(a,[],function(c){var f=ra(a,c);for(b=0;b<f.length;b++)I(a,f[b]);a.iInitDisplayStart=e;M(a);B(a,!1);sa(a,c)},a):(B(a,!1),sa(a)))}else setTimeout(function(){ga(a)},200)}function sa(a,b){a._bInitComplete=!0;b&&X(a);u(a,"aoInitComplete","init",[a,b])}function Qa(a,b){var c=
46
+ parseInt(b,10);a._iDisplayLength=c;Ra(a);u(a,null,"length",[a,c])}function mb(a){for(var b=a.oClasses,c=a.sTableId,e=a.aLengthMenu,d=g.isArray(e[0]),f=d?e[0]:e,e=d?e[1]:e,d=g("<select/>",{name:c+"_length","aria-controls":c,"class":b.sLengthSelect}),h=0,i=f.length;h<i;h++)d[0][h]=new Option(e[h],f[h]);var j=g("<div><label/></div>").addClass(b.sLength);a.aanFeatures.l||(j[0].id=c+"_length");j.children().append(a.oLanguage.sLengthMenu.replace("_MENU_",d[0].outerHTML));g("select",j).val(a._iDisplayLength).bind("change.DT",
47
+ function(){Qa(a,g(this).val());L(a)});g(a.nTable).bind("length.dt.DT",function(b,c,f){a===c&&g("select",j).val(f)});return j[0]}function rb(a){var b=a.sPaginationType,c=p.ext.pager[b],e="function"===typeof c,d=function(a){L(a)},b=g("<div/>").addClass(a.oClasses.sPaging+b)[0],f=a.aanFeatures;e||c.fnInit(a,b,d);f.p||(b.id=a.sTableId+"_paginate",a.aoDrawCallback.push({fn:function(a){if(e){var b=a._iDisplayStart,g=a._iDisplayLength,n=a.fnRecordsDisplay(),m=-1===g,b=m?0:Math.ceil(b/g),g=m?1:Math.ceil(n/
48
+ g),n=c(b,g),o,m=0;for(o=f.p.length;m<o;m++)Oa(a,"pageButton")(a,f.p[m],m,n,b,g)}else c.fnUpdate(a,d)},sName:"pagination"}));return b}function Sa(a,b,c){var e=a._iDisplayStart,d=a._iDisplayLength,f=a.fnRecordsDisplay();0===f||-1===d?e=0:"number"===typeof b?(e=b*d,e>f&&(e=0)):"first"==b?e=0:"previous"==b?(e=0<=d?e-d:0,0>e&&(e=0)):"next"==b?e+d<f&&(e+=d):"last"==b?e=Math.floor((f-1)/d)*d:R(a,0,"Unknown paging action: "+b,5);b=a._iDisplayStart!==e;a._iDisplayStart=e;b&&(u(a,null,"page",[a]),c&&L(a));
49
+ return b}function ob(a){return g("<div/>",{id:!a.aanFeatures.r?a.sTableId+"_processing":null,"class":a.oClasses.sProcessing}).html(a.oLanguage.sProcessing).insertBefore(a.nTable)[0]}function B(a,b){a.oFeatures.bProcessing&&g(a.aanFeatures.r).css("display",b?"block":"none");u(a,null,"processing",[a,b])}function pb(a){var b=g(a.nTable);b.attr("role","grid");var c=a.oScroll;if(""===c.sX&&""===c.sY)return a.nTable;var e=c.sX,d=c.sY,f=a.oClasses,h=b.children("caption"),i=h.length?h[0]._captionSide:null,
50
+ j=g(b[0].cloneNode(!1)),n=g(b[0].cloneNode(!1)),m=b.children("tfoot");c.sX&&"100%"===b.attr("width")&&b.removeAttr("width");m.length||(m=null);c=g("<div/>",{"class":f.sScrollWrapper}).append(g("<div/>",{"class":f.sScrollHead}).css({overflow:"hidden",position:"relative",border:0,width:e?!e?null:s(e):"100%"}).append(g("<div/>",{"class":f.sScrollHeadInner}).css({"box-sizing":"content-box",width:c.sXInner||"100%"}).append(j.removeAttr("id").css("margin-left",0).append("top"===i?h:null).append(b.children("thead"))))).append(g("<div/>",
51
+ {"class":f.sScrollBody}).css({overflow:"auto",height:!d?null:s(d),width:!e?null:s(e)}).append(b));m&&c.append(g("<div/>",{"class":f.sScrollFoot}).css({overflow:"hidden",border:0,width:e?!e?null:s(e):"100%"}).append(g("<div/>",{"class":f.sScrollFootInner}).append(n.removeAttr("id").css("margin-left",0).append("bottom"===i?h:null).append(b.children("tfoot")))));var b=c.children(),o=b[0],f=b[1],k=m?b[2]:null;e&&g(f).scroll(function(){var a=this.scrollLeft;o.scrollLeft=a;m&&(k.scrollLeft=a)});a.nScrollHead=
52
+ o;a.nScrollBody=f;a.nScrollFoot=k;a.aoDrawCallback.push({fn:Y,sName:"scrolling"});return c[0]}function Y(a){var b=a.oScroll,c=b.sX,e=b.sXInner,d=b.sY,f=b.iBarWidth,h=g(a.nScrollHead),i=h[0].style,j=h.children("div"),n=j[0].style,m=j.children("table"),j=a.nScrollBody,o=g(j),k=j.style,l=g(a.nScrollFoot).children("div"),p=l.children("table"),r=g(a.nTHead),q=g(a.nTable),t=q[0],N=t.style,J=a.nTFoot?g(a.nTFoot):null,u=a.oBrowser,w=u.bScrollOversize,y,v,x,K,z,A=[],B=[],C=[],D,E=function(a){a=a.style;a.paddingTop=
53
+ "0";a.paddingBottom="0";a.borderTopWidth="0";a.borderBottomWidth="0";a.height=0};q.children("thead, tfoot").remove();z=r.clone().prependTo(q);y=r.find("tr");x=z.find("tr");z.find("th, td").removeAttr("tabindex");J&&(K=J.clone().prependTo(q),v=J.find("tr"),K=K.find("tr"));c||(k.width="100%",h[0].style.width="100%");g.each(pa(a,z),function(b,c){D=ka(a,b);c.style.width=a.aoColumns[D].sWidth});J&&F(function(a){a.style.width=""},K);b.bCollapse&&""!==d&&(k.height=o[0].offsetHeight+r[0].offsetHeight+"px");
54
+ h=q.outerWidth();if(""===c){if(N.width="100%",w&&(q.find("tbody").height()>j.offsetHeight||"scroll"==o.css("overflow-y")))N.width=s(q.outerWidth()-f)}else""!==e?N.width=s(e):h==o.width()&&o.height()<q.height()?(N.width=s(h-f),q.outerWidth()>h-f&&(N.width=s(h))):N.width=s(h);h=q.outerWidth();F(E,x);F(function(a){C.push(a.innerHTML);A.push(s(g(a).css("width")))},x);F(function(a,b){a.style.width=A[b]},y);g(x).height(0);J&&(F(E,K),F(function(a){B.push(s(g(a).css("width")))},K),F(function(a,b){a.style.width=
55
+ B[b]},v),g(K).height(0));F(function(a,b){a.innerHTML='<div class="dataTables_sizing" style="height:0;overflow:hidden;">'+C[b]+"</div>";a.style.width=A[b]},x);J&&F(function(a,b){a.innerHTML="";a.style.width=B[b]},K);if(q.outerWidth()<h){v=j.scrollHeight>j.offsetHeight||"scroll"==o.css("overflow-y")?h+f:h;if(w&&(j.scrollHeight>j.offsetHeight||"scroll"==o.css("overflow-y")))N.width=s(v-f);(""===c||""!==e)&&R(a,1,"Possible column misalignment",6)}else v="100%";k.width=s(v);i.width=s(v);J&&(a.nScrollFoot.style.width=
56
+ s(v));!d&&w&&(k.height=s(t.offsetHeight+f));d&&b.bCollapse&&(k.height=s(d),b=c&&t.offsetWidth>j.offsetWidth?f:0,t.offsetHeight<j.offsetHeight&&(k.height=s(t.offsetHeight+b)));b=q.outerWidth();m[0].style.width=s(b);n.width=s(b);m=q.height()>j.clientHeight||"scroll"==o.css("overflow-y");u="padding"+(u.bScrollbarLeft?"Left":"Right");n[u]=m?f+"px":"0px";J&&(p[0].style.width=s(b),l[0].style.width=s(b),l[0].style[u]=m?f+"px":"0px");o.scroll();if((a.bSorted||a.bFiltered)&&!a._drawHold)j.scrollTop=0}function F(a,
57
+ b,c){for(var e=0,d=0,f=b.length,h,g;d<f;){h=b[d].firstChild;for(g=c?c[d].firstChild:null;h;)1===h.nodeType&&(c?a(h,g,e):a(h,e),e++),h=h.nextSibling,g=c?g.nextSibling:null;d++}}function Fa(a){var b=a.nTable,c=a.aoColumns,e=a.oScroll,d=e.sY,f=e.sX,h=e.sXInner,i=c.length,e=Z(a,"bVisible"),j=g("th",a.nTHead),n=b.getAttribute("width"),m=b.parentNode,o=!1,k,l;for(k=0;k<e.length;k++)l=c[e[k]],null!==l.sWidth&&(l.sWidth=Cb(l.sWidthOrig,m),o=!0);if(!o&&!f&&!d&&i==aa(a)&&i==j.length)for(k=0;k<i;k++)c[k].sWidth=
58
+ s(j.eq(k).width());else{i=g(b).clone().empty().css("visibility","hidden").removeAttr("id").append(g(a.nTHead).clone(!1)).append(g(a.nTFoot).clone(!1)).append(g("<tbody><tr/></tbody>"));i.find("tfoot th, tfoot td").css("width","");var p=i.find("tbody tr"),j=pa(a,i.find("thead")[0]);for(k=0;k<e.length;k++)l=c[e[k]],j[k].style.width=null!==l.sWidthOrig&&""!==l.sWidthOrig?s(l.sWidthOrig):"";if(a.aoData.length)for(k=0;k<e.length;k++)o=e[k],l=c[o],g(Db(a,o)).clone(!1).append(l.sContentPadding).appendTo(p);
59
+ i.appendTo(m);f&&h?i.width(h):f?(i.css("width","auto"),i.width()<m.offsetWidth&&i.width(m.offsetWidth)):d?i.width(m.offsetWidth):n&&i.width(n);Eb(a,i[0]);if(f){for(k=h=0;k<e.length;k++)l=c[e[k]],d=g(j[k]).outerWidth(),h+=null===l.sWidthOrig?d:parseInt(l.sWidth,10)+d-g(j[k]).width();i.width(s(h));b.style.width=s(h)}for(k=0;k<e.length;k++)if(l=c[e[k]],d=g(j[k]).width())l.sWidth=s(d);b.style.width=s(i.css("width"));i.remove()}n&&(b.style.width=s(n));if((n||f)&&!a._reszEvt)g(Da).bind("resize.DT-"+a.sInstance,
60
+ ta(function(){X(a)})),a._reszEvt=!0}function ta(a,b){var c=b!==l?b:200,e,d;return function(){var b=this,h=+new Date,g=arguments;e&&h<e+c?(clearTimeout(d),d=setTimeout(function(){e=l;a.apply(b,g)},c)):e?(e=h,a.apply(b,g)):e=h}}function Cb(a,b){if(!a)return 0;var c=g("<div/>").css("width",s(a)).appendTo(b||P.body),e=c[0].offsetWidth;c.remove();return e}function Eb(a,b){var c=a.oScroll;if(c.sX||c.sY)c=!c.sX?c.iBarWidth:0,b.style.width=s(g(b).outerWidth()-c)}function Db(a,b){var c=Fb(a,b);if(0>c)return null;
61
+ var e=a.aoData[c];return!e.nTr?g("<td/>").html(v(a,c,b,"display"))[0]:e.anCells[b]}function Fb(a,b){for(var c,e=-1,d=-1,f=0,h=a.aoData.length;f<h;f++)c=v(a,f,b,"display")+"",c=c.replace(Zb,""),c.length>e&&(e=c.length,d=f);return d}function s(a){return null===a?"0px":"number"==typeof a?0>a?"0px":a+"px":a.match(/\d$/)?a+"px":a}function Gb(){if(!p.__scrollbarWidth){var a=g("<p/>").css({width:"100%",height:200,padding:0})[0],b=g("<div/>").css({position:"absolute",top:0,left:0,width:200,height:150,padding:0,
62
+ overflow:"hidden",visibility:"hidden"}).append(a).appendTo("body"),c=a.offsetWidth;b.css("overflow","scroll");a=a.offsetWidth;c===a&&(a=b[0].clientWidth);b.remove();p.__scrollbarWidth=c-a}return p.__scrollbarWidth}function T(a){var b,c,e=[],d=a.aoColumns,f,h,i,j;b=a.aaSortingFixed;c=g.isPlainObject(b);var n=[];f=function(a){a.length&&!g.isArray(a[0])?n.push(a):n.push.apply(n,a)};g.isArray(b)&&f(b);c&&b.pre&&f(b.pre);f(a.aaSorting);c&&b.post&&f(b.post);for(a=0;a<n.length;a++){j=n[a][0];f=d[j].aDataSort;
63
+ b=0;for(c=f.length;b<c;b++)h=f[b],i=d[h].sType||"string",n[a]._idx===l&&(n[a]._idx=g.inArray(n[a][1],d[h].asSorting)),e.push({src:j,col:h,dir:n[a][1],index:n[a]._idx,type:i,formatter:p.ext.type.order[i+"-pre"]})}return e}function kb(a){var b,c,e=[],d=p.ext.type.order,f=a.aoData,h=0,g,j=a.aiDisplayMaster,n;Ga(a);n=T(a);b=0;for(c=n.length;b<c;b++)g=n[b],g.formatter&&h++,Hb(a,g.col);if("ssp"!=A(a)&&0!==n.length){b=0;for(c=j.length;b<c;b++)e[j[b]]=b;h===n.length?j.sort(function(a,b){var c,d,h,g,i=n.length,
64
+ j=f[a]._aSortData,l=f[b]._aSortData;for(h=0;h<i;h++)if(g=n[h],c=j[g.col],d=l[g.col],c=c<d?-1:c>d?1:0,0!==c)return"asc"===g.dir?c:-c;c=e[a];d=e[b];return c<d?-1:c>d?1:0}):j.sort(function(a,b){var c,h,g,i,j=n.length,l=f[a]._aSortData,p=f[b]._aSortData;for(g=0;g<j;g++)if(i=n[g],c=l[i.col],h=p[i.col],i=d[i.type+"-"+i.dir]||d["string-"+i.dir],c=i(c,h),0!==c)return c;c=e[a];h=e[b];return c<h?-1:c>h?1:0})}a.bSorted=!0}function Ib(a){for(var b,c,e=a.aoColumns,d=T(a),a=a.oLanguage.oAria,f=0,h=e.length;f<h;f++){c=
65
+ e[f];var g=c.asSorting;b=c.sTitle.replace(/<.*?>/g,"");var j=c.nTh;j.removeAttribute("aria-sort");c.bSortable&&(0<d.length&&d[0].col==f?(j.setAttribute("aria-sort","asc"==d[0].dir?"ascending":"descending"),c=g[d[0].index+1]||g[0]):c=g[0],b+="asc"===c?a.sSortAscending:a.sSortDescending);j.setAttribute("aria-label",b)}}function Ta(a,b,c,e){var d=a.aaSorting,f=a.aoColumns[b].asSorting,h=function(a,b){var c=a._idx;c===l&&(c=g.inArray(a[1],f));return c+1<f.length?c+1:b?null:0};"number"===typeof d[0]&&
66
+ (d=a.aaSorting=[d]);c&&a.oFeatures.bSortMulti?(c=g.inArray(b,C(d,"0")),-1!==c?(b=h(d[c],!0),null===b?d.splice(c,1):(d[c][1]=f[b],d[c]._idx=b)):(d.push([b,f[0],0]),d[d.length-1]._idx=0)):d.length&&d[0][0]==b?(b=h(d[0]),d.length=1,d[0][1]=f[b],d[0]._idx=b):(d.length=0,d.push([b,f[0]]),d[0]._idx=0);M(a);"function"==typeof e&&e(a)}function Na(a,b,c,e){var d=a.aoColumns[c];Ua(b,{},function(b){!1!==d.bSortable&&(a.oFeatures.bProcessing?(B(a,!0),setTimeout(function(){Ta(a,c,b.shiftKey,e);"ssp"!==A(a)&&B(a,
67
+ !1)},0)):Ta(a,c,b.shiftKey,e))})}function wa(a){var b=a.aLastSort,c=a.oClasses.sSortColumn,e=T(a),d=a.oFeatures,f,h;if(d.bSort&&d.bSortClasses){d=0;for(f=b.length;d<f;d++)h=b[d].src,g(C(a.aoData,"anCells",h)).removeClass(c+(2>d?d+1:3));d=0;for(f=e.length;d<f;d++)h=e[d].src,g(C(a.aoData,"anCells",h)).addClass(c+(2>d?d+1:3))}a.aLastSort=e}function Hb(a,b){var c=a.aoColumns[b],e=p.ext.order[c.sSortDataType],d;e&&(d=e.call(a.oInstance,a,b,$(a,b)));for(var f,h=p.ext.type.order[c.sType+"-pre"],g=0,j=a.aoData.length;g<
68
+ j;g++)if(c=a.aoData[g],c._aSortData||(c._aSortData=[]),!c._aSortData[b]||e)f=e?d[g]:v(a,g,b,"sort"),c._aSortData[b]=h?h(f):f}function xa(a){if(a.oFeatures.bStateSave&&!a.bDestroying){var b={time:+new Date,start:a._iDisplayStart,length:a._iDisplayLength,order:g.extend(!0,[],a.aaSorting),search:yb(a.oPreviousSearch),columns:g.map(a.aoColumns,function(b,e){return{visible:b.bVisible,search:yb(a.aoPreSearchCols[e])}})};u(a,"aoStateSaveParams","stateSaveParams",[a,b]);a.oSavedState=b;a.fnStateSaveCallback.call(a.oInstance,
69
+ a,b)}}function Jb(a){var b,c,e=a.aoColumns;if(a.oFeatures.bStateSave){var d=a.fnStateLoadCallback.call(a.oInstance,a);if(d&&d.time&&(b=u(a,"aoStateLoadParams","stateLoadParams",[a,d]),-1===g.inArray(!1,b)&&(b=a.iStateDuration,!(0<b&&d.time<+new Date-1E3*b)&&e.length===d.columns.length))){a.oLoadedState=g.extend(!0,{},d);a._iDisplayStart=d.start;a.iInitDisplayStart=d.start;a._iDisplayLength=d.length;a.aaSorting=[];g.each(d.order,function(b,c){a.aaSorting.push(c[0]>=e.length?[0,c[1]]:c)});g.extend(a.oPreviousSearch,
70
+ zb(d.search));b=0;for(c=d.columns.length;b<c;b++){var f=d.columns[b];e[b].bVisible=f.visible;g.extend(a.aoPreSearchCols[b],zb(f.search))}u(a,"aoStateLoaded","stateLoaded",[a,d])}}}function ya(a){var b=p.settings,a=g.inArray(a,C(b,"nTable"));return-1!==a?b[a]:null}function R(a,b,c,e){c="DataTables warning: "+(null!==a?"table id="+a.sTableId+" - ":"")+c;e&&(c+=". For more information about this error, please see http://datatables.net/tn/"+e);if(b)Da.console&&console.log&&console.log(c);else if(a=p.ext,
71
+ "alert"==(a.sErrMode||a.errMode))alert(c);else throw Error(c);}function D(a,b,c,e){g.isArray(c)?g.each(c,function(c,f){g.isArray(f)?D(a,b,f[0],f[1]):D(a,b,f)}):(e===l&&(e=c),b[c]!==l&&(a[e]=b[c]))}function Kb(a,b,c){var e,d;for(d in b)b.hasOwnProperty(d)&&(e=b[d],g.isPlainObject(e)?(g.isPlainObject(a[d])||(a[d]={}),g.extend(!0,a[d],e)):a[d]=c&&"data"!==d&&"aaData"!==d&&g.isArray(e)?e.slice():e);return a}function Ua(a,b,c){g(a).bind("click.DT",b,function(b){a.blur();c(b)}).bind("keypress.DT",b,function(a){13===
72
+ a.which&&(a.preventDefault(),c(a))}).bind("selectstart.DT",function(){return!1})}function x(a,b,c,e){c&&a[b].push({fn:c,sName:e})}function u(a,b,c,e){var d=[];b&&(d=g.map(a[b].slice().reverse(),function(b){return b.fn.apply(a.oInstance,e)}));null!==c&&g(a.nTable).trigger(c+".dt",e);return d}function Ra(a){var b=a._iDisplayStart,c=a.fnDisplayEnd(),e=a._iDisplayLength;b>=c&&(b=c-e);b-=b%e;if(-1===e||0>b)b=0;a._iDisplayStart=b}function Oa(a,b){var c=a.renderer,e=p.ext.renderer[b];return g.isPlainObject(c)&&
73
+ c[b]?e[c[b]]||e._:"string"===typeof c?e[c]||e._:e._}function A(a){return a.oFeatures.bServerSide?"ssp":a.ajax||a.sAjaxSource?"ajax":"dom"}function Va(a,b){var c=[],c=Lb.numbers_length,e=Math.floor(c/2);b<=c?c=U(0,b):a<=e?(c=U(0,c-2),c.push("ellipsis"),c.push(b-1)):(a>=b-1-e?c=U(b-(c-2),b):(c=U(a-1,a+2),c.push("ellipsis"),c.push(b-1)),c.splice(0,0,"ellipsis"),c.splice(0,0,0));c.DT_el="span";return c}function cb(a){g.each({num:function(b){return za(b,a)},"num-fmt":function(b){return za(b,a,Wa)},"html-num":function(b){return za(b,
74
+ a,Aa)},"html-num-fmt":function(b){return za(b,a,Aa,Wa)}},function(b,c){w.type.order[b+a+"-pre"]=c;b.match(/^html\-/)&&(w.type.search[b+a]=w.type.search.html)})}function Mb(a){return function(){var b=[ya(this[p.ext.iApiIndex])].concat(Array.prototype.slice.call(arguments));return p.ext.internal[a].apply(this,b)}}var p,w,q,r,t,Xa={},Nb=/[\r\n]/g,Aa=/<.*?>/g,$b=/^[\w\+\-]/,ac=/[\w\+\-]$/,Xb=RegExp("(\\/|\\.|\\*|\\+|\\?|\\||\\(|\\)|\\[|\\]|\\{|\\}|\\\\|\\$|\\^|\\-)","g"),Wa=/[',$\u00a3\u20ac\u00a5%\u2009\u202F]/g,
75
+ H=function(a){return!a||!0===a||"-"===a?!0:!1},Ob=function(a){var b=parseInt(a,10);return!isNaN(b)&&isFinite(a)?b:null},Pb=function(a,b){Xa[b]||(Xa[b]=RegExp(ua(b),"g"));return"string"===typeof a&&"."!==b?a.replace(/\./g,"").replace(Xa[b],"."):a},Ya=function(a,b,c){var e="string"===typeof a;b&&e&&(a=Pb(a,b));c&&e&&(a=a.replace(Wa,""));return H(a)||!isNaN(parseFloat(a))&&isFinite(a)},Qb=function(a,b,c){return H(a)?!0:!(H(a)||"string"===typeof a)?null:Ya(a.replace(Aa,""),b,c)?!0:null},C=function(a,
76
+ b,c){var e=[],d=0,f=a.length;if(c!==l)for(;d<f;d++)a[d]&&a[d][b]&&e.push(a[d][b][c]);else for(;d<f;d++)a[d]&&e.push(a[d][b]);return e},ha=function(a,b,c,e){var d=[],f=0,h=b.length;if(e!==l)for(;f<h;f++)a[b[f]][c]&&d.push(a[b[f]][c][e]);else for(;f<h;f++)d.push(a[b[f]][c]);return d},U=function(a,b){var c=[],e;b===l?(b=0,e=a):(e=b,b=a);for(var d=b;d<e;d++)c.push(d);return c},Rb=function(a){for(var b=[],c=0,e=a.length;c<e;c++)a[c]&&b.push(a[c]);return b},Ma=function(a){var b=[],c,e,d=a.length,f,h=0;
77
+ e=0;a:for(;e<d;e++){c=a[e];for(f=0;f<h;f++)if(b[f]===c)continue a;b.push(c);h++}return b},z=function(a,b,c){a[b]!==l&&(a[c]=a[b])},ba=/\[.*?\]$/,S=/\(\)$/,va=g("<div>")[0],Yb=va.textContent!==l,Zb=/<.*?>/g;p=function(a){this.$=function(a,b){return this.api(!0).$(a,b)};this._=function(a,b){return this.api(!0).rows(a,b).data()};this.api=function(a){return a?new q(ya(this[w.iApiIndex])):new q(this)};this.fnAddData=function(a,b){var c=this.api(!0),e=g.isArray(a)&&(g.isArray(a[0])||g.isPlainObject(a[0]))?
78
+ c.rows.add(a):c.row.add(a);(b===l||b)&&c.draw();return e.flatten().toArray()};this.fnAdjustColumnSizing=function(a){var b=this.api(!0).columns.adjust(),c=b.settings()[0],e=c.oScroll;a===l||a?b.draw(!1):(""!==e.sX||""!==e.sY)&&Y(c)};this.fnClearTable=function(a){var b=this.api(!0).clear();(a===l||a)&&b.draw()};this.fnClose=function(a){this.api(!0).row(a).child.hide()};this.fnDeleteRow=function(a,b,c){var e=this.api(!0),a=e.rows(a),d=a.settings()[0],g=d.aoData[a[0][0]];a.remove();b&&b.call(this,d,g);
79
+ (c===l||c)&&e.draw();return g};this.fnDestroy=function(a){this.api(!0).destroy(a)};this.fnDraw=function(a){this.api(!0).draw(!a)};this.fnFilter=function(a,b,c,e,d,g){d=this.api(!0);null===b||b===l?d.search(a,c,e,g):d.column(b).search(a,c,e,g);d.draw()};this.fnGetData=function(a,b){var c=this.api(!0);if(a!==l){var e=a.nodeName?a.nodeName.toLowerCase():"";return b!==l||"td"==e||"th"==e?c.cell(a,b).data():c.row(a).data()||null}return c.data().toArray()};this.fnGetNodes=function(a){var b=this.api(!0);
80
+ return a!==l?b.row(a).node():b.rows().nodes().flatten().toArray()};this.fnGetPosition=function(a){var b=this.api(!0),c=a.nodeName.toUpperCase();return"TR"==c?b.row(a).index():"TD"==c||"TH"==c?(a=b.cell(a).index(),[a.row,a.columnVisible,a.column]):null};this.fnIsOpen=function(a){return this.api(!0).row(a).child.isShown()};this.fnOpen=function(a,b,c){return this.api(!0).row(a).child(b,c).show().child()[0]};this.fnPageChange=function(a,b){var c=this.api(!0).page(a);(b===l||b)&&c.draw(!1)};this.fnSetColumnVis=
81
+ function(a,b,c){a=this.api(!0).column(a).visible(b);(c===l||c)&&a.columns.adjust().draw()};this.fnSettings=function(){return ya(this[w.iApiIndex])};this.fnSort=function(a){this.api(!0).order(a).draw()};this.fnSortListener=function(a,b,c){this.api(!0).order.listener(a,b,c)};this.fnUpdate=function(a,b,c,e,d){var g=this.api(!0);c===l||null===c?g.row(b).data(a):g.cell(b,c).data(a);(d===l||d)&&g.columns.adjust();(e===l||e)&&g.draw();return 0};this.fnVersionCheck=w.fnVersionCheck;var b=this,c=a===l,e=this.length;
82
+ c&&(a={});this.oApi=this.internal=w.internal;for(var d in p.ext.internal)d&&(this[d]=Mb(d));this.each(function(){var d={},d=1<e?Kb(d,a,!0):a,h=0,i,j=this.getAttribute("id"),n=!1,m=p.defaults;if("table"!=this.nodeName.toLowerCase())R(null,0,"Non-table node initialisation ("+this.nodeName+")",2);else{db(m);eb(m.column);G(m,m,!0);G(m.column,m.column,!0);G(m,d);var o=p.settings,h=0;for(i=o.length;h<i;h++){if(o[h].nTable==this){i=d.bRetrieve!==l?d.bRetrieve:m.bRetrieve;if(c||i)return o[h].oInstance;if(d.bDestroy!==
83
+ l?d.bDestroy:m.bDestroy){o[h].oInstance.fnDestroy();break}else{R(o[h],0,"Cannot reinitialise DataTable",3);return}}if(o[h].sTableId==this.id){o.splice(h,1);break}}if(null===j||""===j)this.id=j="DataTables_Table_"+p.ext._unique++;var k=g.extend(!0,{},p.models.oSettings,{nTable:this,oApi:b.internal,oInit:d,sDestroyWidth:g(this)[0].style.width,sInstance:j,sTableId:j});o.push(k);k.oInstance=1===b.length?b:g(this).dataTable();db(d);d.oLanguage&&O(d.oLanguage);d.aLengthMenu&&!d.iDisplayLength&&(d.iDisplayLength=
84
+ g.isArray(d.aLengthMenu[0])?d.aLengthMenu[0][0]:d.aLengthMenu[0]);d=Kb(g.extend(!0,{},m),d);D(k.oFeatures,d,"bPaginate bLengthChange bFilter bSort bSortMulti bInfo bProcessing bAutoWidth bSortClasses bServerSide bDeferRender".split(" "));D(k,d,["asStripeClasses","ajax","fnServerData","fnFormatNumber","sServerMethod","aaSorting","aaSortingFixed","aLengthMenu","sPaginationType","sAjaxSource","sAjaxDataProp","iStateDuration","sDom","bSortCellsTop","iTabIndex","fnStateLoadCallback","fnStateSaveCallback",
85
+ "renderer","searchDelay",["iCookieDuration","iStateDuration"],["oSearch","oPreviousSearch"],["aoSearchCols","aoPreSearchCols"],["iDisplayLength","_iDisplayLength"],["bJQueryUI","bJUI"]]);D(k.oScroll,d,[["sScrollX","sX"],["sScrollXInner","sXInner"],["sScrollY","sY"],["bScrollCollapse","bCollapse"]]);D(k.oLanguage,d,"fnInfoCallback");x(k,"aoDrawCallback",d.fnDrawCallback,"user");x(k,"aoServerParams",d.fnServerParams,"user");x(k,"aoStateSaveParams",d.fnStateSaveParams,"user");x(k,"aoStateLoadParams",
86
+ d.fnStateLoadParams,"user");x(k,"aoStateLoaded",d.fnStateLoaded,"user");x(k,"aoRowCallback",d.fnRowCallback,"user");x(k,"aoRowCreatedCallback",d.fnCreatedRow,"user");x(k,"aoHeaderCallback",d.fnHeaderCallback,"user");x(k,"aoFooterCallback",d.fnFooterCallback,"user");x(k,"aoInitComplete",d.fnInitComplete,"user");x(k,"aoPreDrawCallback",d.fnPreDrawCallback,"user");j=k.oClasses;d.bJQueryUI?(g.extend(j,p.ext.oJUIClasses,d.oClasses),d.sDom===m.sDom&&"lfrtip"===m.sDom&&(k.sDom='<"H"lfr>t<"F"ip>'),k.renderer)?
87
+ g.isPlainObject(k.renderer)&&!k.renderer.header&&(k.renderer.header="jqueryui"):k.renderer="jqueryui":g.extend(j,p.ext.classes,d.oClasses);g(this).addClass(j.sTable);if(""!==k.oScroll.sX||""!==k.oScroll.sY)k.oScroll.iBarWidth=Gb();!0===k.oScroll.sX&&(k.oScroll.sX="100%");k.iInitDisplayStart===l&&(k.iInitDisplayStart=d.iDisplayStart,k._iDisplayStart=d.iDisplayStart);null!==d.iDeferLoading&&(k.bDeferLoading=!0,h=g.isArray(d.iDeferLoading),k._iRecordsDisplay=h?d.iDeferLoading[0]:d.iDeferLoading,k._iRecordsTotal=
88
+ h?d.iDeferLoading[1]:d.iDeferLoading);var r=k.oLanguage;g.extend(!0,r,d.oLanguage);""!==r.sUrl&&(g.ajax({dataType:"json",url:r.sUrl,success:function(a){O(a);G(m.oLanguage,a);g.extend(true,r,a);ga(k)},error:function(){ga(k)}}),n=!0);null===d.asStripeClasses&&(k.asStripeClasses=[j.sStripeOdd,j.sStripeEven]);var h=k.asStripeClasses,q=g("tbody tr:eq(0)",this);-1!==g.inArray(!0,g.map(h,function(a){return q.hasClass(a)}))&&(g("tbody tr",this).removeClass(h.join(" ")),k.asDestroyStripes=h.slice());var o=
89
+ [],s,h=this.getElementsByTagName("thead");0!==h.length&&(da(k.aoHeader,h[0]),o=pa(k));if(null===d.aoColumns){s=[];h=0;for(i=o.length;h<i;h++)s.push(null)}else s=d.aoColumns;h=0;for(i=s.length;h<i;h++)Ea(k,o?o[h]:null);hb(k,d.aoColumnDefs,s,function(a,b){ja(k,a,b)});if(q.length){var t=function(a,b){return a.getAttribute("data-"+b)?b:null};g.each(ma(k,q[0]).cells,function(a,b){var c=k.aoColumns[a];if(c.mData===a){var e=t(b,"sort")||t(b,"order"),d=t(b,"filter")||t(b,"search");if(e!==null||d!==null){c.mData=
90
+ {_:a+".display",sort:e!==null?a+".@data-"+e:l,type:e!==null?a+".@data-"+e:l,filter:d!==null?a+".@data-"+d:l};ja(k,a)}}})}var v=k.oFeatures;d.bStateSave&&(v.bStateSave=!0,Jb(k,d),x(k,"aoDrawCallback",xa,"state_save"));if(d.aaSorting===l){o=k.aaSorting;h=0;for(i=o.length;h<i;h++)o[h][1]=k.aoColumns[h].asSorting[0]}wa(k);v.bSort&&x(k,"aoDrawCallback",function(){if(k.bSorted){var a=T(k),b={};g.each(a,function(a,c){b[c.src]=c.dir});u(k,null,"order",[k,a,b]);Ib(k)}});x(k,"aoDrawCallback",function(){(k.bSorted||
91
+ A(k)==="ssp"||v.bDeferRender)&&wa(k)},"sc");fb(k);h=g(this).children("caption").each(function(){this._captionSide=g(this).css("caption-side")});i=g(this).children("thead");0===i.length&&(i=g("<thead/>").appendTo(this));k.nTHead=i[0];i=g(this).children("tbody");0===i.length&&(i=g("<tbody/>").appendTo(this));k.nTBody=i[0];i=g(this).children("tfoot");if(0===i.length&&0<h.length&&(""!==k.oScroll.sX||""!==k.oScroll.sY))i=g("<tfoot/>").appendTo(this);0===i.length||0===i.children().length?g(this).addClass(j.sNoFooter):
92
+ 0<i.length&&(k.nTFoot=i[0],da(k.aoFooter,k.nTFoot));if(d.aaData)for(h=0;h<d.aaData.length;h++)I(k,d.aaData[h]);else(k.bDeferLoading||"dom"==A(k))&&la(k,g(k.nTBody).children("tr"));k.aiDisplay=k.aiDisplayMaster.slice();k.bInitialised=!0;!1===n&&ga(k)}});b=null;return this};var Sb=[],y=Array.prototype,bc=function(a){var b,c,e=p.settings,d=g.map(e,function(a){return a.nTable});if(a){if(a.nTable&&a.oApi)return[a];if(a.nodeName&&"table"===a.nodeName.toLowerCase())return b=g.inArray(a,d),-1!==b?[e[b]]:
93
+ null;if(a&&"function"===typeof a.settings)return a.settings().toArray();"string"===typeof a?c=g(a):a instanceof g&&(c=a)}else return[];if(c)return c.map(function(){b=g.inArray(this,d);return-1!==b?e[b]:null}).toArray()};q=function(a,b){if(!this instanceof q)throw"DT API must be constructed as a new object";var c=[],e=function(a){(a=bc(a))&&c.push.apply(c,a)};if(g.isArray(a))for(var d=0,f=a.length;d<f;d++)e(a[d]);else e(a);this.context=Ma(c);b&&this.push.apply(this,b.toArray?b.toArray():b);this.selector=
94
+ {rows:null,cols:null,opts:null};q.extend(this,this,Sb)};p.Api=q;q.prototype={concat:y.concat,context:[],each:function(a){for(var b=0,c=this.length;b<c;b++)a.call(this,this[b],b,this);return this},eq:function(a){var b=this.context;return b.length>a?new q(b[a],this[a]):null},filter:function(a){var b=[];if(y.filter)b=y.filter.call(this,a,this);else for(var c=0,e=this.length;c<e;c++)a.call(this,this[c],c,this)&&b.push(this[c]);return new q(this.context,b)},flatten:function(){var a=[];return new q(this.context,
95
+ a.concat.apply(a,this.toArray()))},join:y.join,indexOf:y.indexOf||function(a,b){for(var c=b||0,e=this.length;c<e;c++)if(this[c]===a)return c;return-1},iterator:function(a,b,c,e){var d=[],f,h,g,j,n,m=this.context,o,k,p=this.selector;"string"===typeof a&&(e=c,c=b,b=a,a=!1);h=0;for(g=m.length;h<g;h++){var r=new q(m[h]);if("table"===b)f=c.call(r,m[h],h),f!==l&&d.push(f);else if("columns"===b||"rows"===b)f=c.call(r,m[h],this[h],h),f!==l&&d.push(f);else if("column"===b||"column-rows"===b||"row"===b||"cell"===
96
+ b){k=this[h];"column-rows"===b&&(o=Ba(m[h],p.opts));j=0;for(n=k.length;j<n;j++)f=k[j],f="cell"===b?c.call(r,m[h],f.row,f.column,h,j):c.call(r,m[h],f,h,j,o),f!==l&&d.push(f)}}return d.length||e?(a=new q(m,a?d.concat.apply([],d):d),b=a.selector,b.rows=p.rows,b.cols=p.cols,b.opts=p.opts,a):this},lastIndexOf:y.lastIndexOf||function(a,b){return this.indexOf.apply(this.toArray.reverse(),arguments)},length:0,map:function(a){var b=[];if(y.map)b=y.map.call(this,a,this);else for(var c=0,e=this.length;c<e;c++)b.push(a.call(this,
97
+ this[c],c));return new q(this.context,b)},pluck:function(a){return this.map(function(b){return b[a]})},pop:y.pop,push:y.push,reduce:y.reduce||function(a,b){return gb(this,a,b,0,this.length,1)},reduceRight:y.reduceRight||function(a,b){return gb(this,a,b,this.length-1,-1,-1)},reverse:y.reverse,selector:null,shift:y.shift,sort:y.sort,splice:y.splice,toArray:function(){return y.slice.call(this)},to$:function(){return g(this)},toJQuery:function(){return g(this)},unique:function(){return new q(this.context,
98
+ Ma(this))},unshift:y.unshift};q.extend=function(a,b,c){if(b&&(b instanceof q||b.__dt_wrapper)){var e,d,f,h=function(a,b,c){return function(){var e=b.apply(a,arguments);q.extend(e,e,c.methodExt);return e}};e=0;for(d=c.length;e<d;e++)f=c[e],b[f.name]="function"===typeof f.val?h(a,f.val,f):g.isPlainObject(f.val)?{}:f.val,b[f.name].__dt_wrapper=!0,q.extend(a,b[f.name],f.propExt)}};q.register=r=function(a,b){if(g.isArray(a))for(var c=0,e=a.length;c<e;c++)q.register(a[c],b);else for(var d=a.split("."),
99
+ f=Sb,h,i,c=0,e=d.length;c<e;c++){h=(i=-1!==d[c].indexOf("()"))?d[c].replace("()",""):d[c];var j;a:{j=0;for(var n=f.length;j<n;j++)if(f[j].name===h){j=f[j];break a}j=null}j||(j={name:h,val:{},methodExt:[],propExt:[]},f.push(j));c===e-1?j.val=b:f=i?j.methodExt:j.propExt}};q.registerPlural=t=function(a,b,c){q.register(a,c);q.register(b,function(){var a=c.apply(this,arguments);return a===this?this:a instanceof q?a.length?g.isArray(a[0])?new q(a.context,a[0]):a[0]:l:a})};r("tables()",function(a){var b;
100
+ if(a){b=q;var c=this.context;if("number"===typeof a)a=[c[a]];else var e=g.map(c,function(a){return a.nTable}),a=g(e).filter(a).map(function(){var a=g.inArray(this,e);return c[a]}).toArray();b=new b(a)}else b=this;return b});r("table()",function(a){var a=this.tables(a),b=a.context;return b.length?new q(b[0]):a});t("tables().nodes()","table().node()",function(){return this.iterator("table",function(a){return a.nTable},1)});t("tables().body()","table().body()",function(){return this.iterator("table",
101
+ function(a){return a.nTBody},1)});t("tables().header()","table().header()",function(){return this.iterator("table",function(a){return a.nTHead},1)});t("tables().footer()","table().footer()",function(){return this.iterator("table",function(a){return a.nTFoot},1)});t("tables().containers()","table().container()",function(){return this.iterator("table",function(a){return a.nTableWrapper},1)});r("draw()",function(a){return this.iterator("table",function(b){M(b,!1===a)})});r("page()",function(a){return a===
102
+ l?this.page.info().page:this.iterator("table",function(b){Sa(b,a)})});r("page.info()",function(){if(0===this.context.length)return l;var a=this.context[0],b=a._iDisplayStart,c=a._iDisplayLength,e=a.fnRecordsDisplay(),d=-1===c;return{page:d?0:Math.floor(b/c),pages:d?1:Math.ceil(e/c),start:b,end:a.fnDisplayEnd(),length:c,recordsTotal:a.fnRecordsTotal(),recordsDisplay:e}});r("page.len()",function(a){return a===l?0!==this.context.length?this.context[0]._iDisplayLength:l:this.iterator("table",function(b){Qa(b,
103
+ a)})});var Tb=function(a,b,c){"ssp"==A(a)?M(a,b):(B(a,!0),qa(a,[],function(c){na(a);for(var c=ra(a,c),e=0,h=c.length;e<h;e++)I(a,c[e]);M(a,b);B(a,!1)}));if(c){var e=new q(a);e.one("draw",function(){c(e.ajax.json())})}};r("ajax.json()",function(){var a=this.context;if(0<a.length)return a[0].json});r("ajax.params()",function(){var a=this.context;if(0<a.length)return a[0].oAjaxData});r("ajax.reload()",function(a,b){return this.iterator("table",function(c){Tb(c,!1===b,a)})});r("ajax.url()",function(a){var b=
104
+ this.context;if(a===l){if(0===b.length)return l;b=b[0];return b.ajax?g.isPlainObject(b.ajax)?b.ajax.url:b.ajax:b.sAjaxSource}return this.iterator("table",function(b){g.isPlainObject(b.ajax)?b.ajax.url=a:b.ajax=a})});r("ajax.url().load()",function(a,b){return this.iterator("table",function(c){Tb(c,!1===b,a)})});var Za=function(a,b){var c=[],e,d,f,h,i,j;e=typeof a;if(!a||"string"===e||"function"===e||a.length===l)a=[a];f=0;for(h=a.length;f<h;f++){d=a[f]&&a[f].split?a[f].split(","):[a[f]];i=0;for(j=
105
+ d.length;i<j;i++)(e=b("string"===typeof d[i]?g.trim(d[i]):d[i]))&&e.length&&c.push.apply(c,e)}return c},$a=function(a){a||(a={});a.filter&&!a.search&&(a.search=a.filter);return{search:a.search||"none",order:a.order||"current",page:a.page||"all"}},ab=function(a){for(var b=0,c=a.length;b<c;b++)if(0<a[b].length)return a[0]=a[b],a.length=1,a.context=[a.context[b]],a;a.length=0;return a},Ba=function(a,b){var c,e,d,f=[],h=a.aiDisplay;c=a.aiDisplayMaster;var i=b.search;e=b.order;d=b.page;if("ssp"==A(a))return"removed"===
106
+ i?[]:U(0,c.length);if("current"==d){c=a._iDisplayStart;for(e=a.fnDisplayEnd();c<e;c++)f.push(h[c])}else if("current"==e||"applied"==e)f="none"==i?c.slice():"applied"==i?h.slice():g.map(c,function(a){return-1===g.inArray(a,h)?a:null});else if("index"==e||"original"==e){c=0;for(e=a.aoData.length;c<e;c++)"none"==i?f.push(c):(d=g.inArray(c,h),(-1===d&&"removed"==i||0<=d&&"applied"==i)&&f.push(c))}return f};r("rows()",function(a,b){a===l?a="":g.isPlainObject(a)&&(b=a,a="");var b=$a(b),c=this.iterator("table",
107
+ function(c){var d=b;return Za(a,function(a){var b=Ob(a);if(b!==null&&!d)return[b];var i=Ba(c,d);if(b!==null&&g.inArray(b,i)!==-1)return[b];if(!a)return i;if(typeof a==="function")return g.map(i,function(b){var d=c.aoData[b];return a(b,d._aData,d.nTr)?b:null});b=Rb(ha(c.aoData,i,"nTr"));return a.nodeName&&g.inArray(a,b)!==-1?[a._DT_RowIndex]:g(b).filter(a).map(function(){return this._DT_RowIndex}).toArray()})},1);c.selector.rows=a;c.selector.opts=b;return c});r("rows().nodes()",function(){return this.iterator("row",
108
+ function(a,b){return a.aoData[b].nTr||l},1)});r("rows().data()",function(){return this.iterator(!0,"rows",function(a,b){return ha(a.aoData,b,"_aData")},1)});t("rows().cache()","row().cache()",function(a){return this.iterator("row",function(b,c){var e=b.aoData[c];return"search"===a?e._aFilterData:e._aSortData},1)});t("rows().invalidate()","row().invalidate()",function(a){return this.iterator("row",function(b,c){ca(b,c,a)})});t("rows().indexes()","row().index()",function(){return this.iterator("row",
109
+ function(a,b){return b},1)});t("rows().remove()","row().remove()",function(){var a=this;return this.iterator("row",function(b,c,e){var d=b.aoData;d.splice(c,1);for(var f=0,h=d.length;f<h;f++)null!==d[f].nTr&&(d[f].nTr._DT_RowIndex=f);g.inArray(c,b.aiDisplay);oa(b.aiDisplayMaster,c);oa(b.aiDisplay,c);oa(a[e],c,!1);Ra(b)})});r("rows.add()",function(a){var b=this.iterator("table",function(b){var c,f,h,g=[];f=0;for(h=a.length;f<h;f++)c=a[f],c.nodeName&&"TR"===c.nodeName.toUpperCase()?g.push(la(b,c)[0]):
110
+ g.push(I(b,c));return g},1),c=this.rows(-1);c.pop();c.push.apply(c,b.toArray());return c});r("row()",function(a,b){return ab(this.rows(a,b))});r("row().data()",function(a){var b=this.context;if(a===l)return b.length&&this.length?b[0].aoData[this[0]]._aData:l;b[0].aoData[this[0]]._aData=a;ca(b[0],this[0],"data");return this});r("row().node()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]].nTr||null:null});r("row.add()",function(a){a instanceof g&&a.length&&(a=a[0]);
111
+ var b=this.iterator("table",function(b){return a.nodeName&&"TR"===a.nodeName.toUpperCase()?la(b,a)[0]:I(b,a)});return this.row(b[0])});var bb=function(a,b){var c=a.context;c.length&&(c=c[0].aoData[b!==l?b:a[0]],c._details&&(c._details.remove(),c._detailsShow=l,c._details=l))},Ub=function(a,b){var c=a.context;if(c.length&&a.length){var e=c[0].aoData[a[0]];if(e._details){(e._detailsShow=b)?e._details.insertAfter(e.nTr):e._details.detach();var d=c[0],f=new q(d),h=d.aoData;f.off("draw.dt.DT_details column-visibility.dt.DT_details destroy.dt.DT_details");
112
+ 0<C(h,"_details").length&&(f.on("draw.dt.DT_details",function(a,b){d===b&&f.rows({page:"current"}).eq(0).each(function(a){a=h[a];a._detailsShow&&a._details.insertAfter(a.nTr)})}),f.on("column-visibility.dt.DT_details",function(a,b){if(d===b)for(var c,e=aa(b),f=0,g=h.length;f<g;f++)c=h[f],c._details&&c._details.children("td[colspan]").attr("colspan",e)}),f.on("destroy.dt.DT_details",function(a,b){if(d===b)for(var c=0,e=h.length;c<e;c++)h[c]._details&&bb(f,c)}))}}};r("row().child()",function(a,b){var c=
113
+ this.context;if(a===l)return c.length&&this.length?c[0].aoData[this[0]]._details:l;if(!0===a)this.child.show();else if(!1===a)bb(this);else if(c.length&&this.length){var e=c[0],c=c[0].aoData[this[0]],d=[],f=function(a,b){if(a.nodeName&&"tr"===a.nodeName.toLowerCase())d.push(a);else{var c=g("<tr><td/></tr>").addClass(b);g("td",c).addClass(b).html(a)[0].colSpan=aa(e);d.push(c[0])}};if(g.isArray(a)||a instanceof g)for(var h=0,i=a.length;h<i;h++)f(a[h],b);else f(a,b);c._details&&c._details.remove();c._details=
114
+ g(d);c._detailsShow&&c._details.insertAfter(c.nTr)}return this});r(["row().child.show()","row().child().show()"],function(){Ub(this,!0);return this});r(["row().child.hide()","row().child().hide()"],function(){Ub(this,!1);return this});r(["row().child.remove()","row().child().remove()"],function(){bb(this);return this});r("row().child.isShown()",function(){var a=this.context;return a.length&&this.length?a[0].aoData[this[0]]._detailsShow||!1:!1});var cc=/^(.+):(name|visIdx|visible)$/,Vb=function(a,
115
+ b,c,e,d){for(var c=[],e=0,f=d.length;e<f;e++)c.push(v(a,d[e],b));return c};r("columns()",function(a,b){a===l?a="":g.isPlainObject(a)&&(b=a,a="");var b=$a(b),c=this.iterator("table",function(c){var d=a,f=b,h=c.aoColumns,i=C(h,"sName"),j=C(h,"nTh");return Za(d,function(a){var b=Ob(a);if(a==="")return U(h.length);if(b!==null)return[b>=0?b:h.length+b];if(typeof a==="function"){var d=Ba(c,f);return g.map(h,function(b,f){return a(f,Vb(c,f,0,0,d),j[f])?f:null})}var k=typeof a==="string"?a.match(cc):"";if(k)switch(k[2]){case "visIdx":case "visible":b=
116
+ parseInt(k[1],10);if(b<0){var l=g.map(h,function(a,b){return a.bVisible?b:null});return[l[l.length+b]]}return[ka(c,b)];case "name":return g.map(i,function(a,b){return a===k[1]?b:null})}else return g(j).filter(a).map(function(){return g.inArray(this,j)}).toArray()})},1);c.selector.cols=a;c.selector.opts=b;return c});t("columns().header()","column().header()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].nTh},1)});t("columns().footer()","column().footer()",function(){return this.iterator("column",
117
+ function(a,b){return a.aoColumns[b].nTf},1)});t("columns().data()","column().data()",function(){return this.iterator("column-rows",Vb,1)});t("columns().dataSrc()","column().dataSrc()",function(){return this.iterator("column",function(a,b){return a.aoColumns[b].mData},1)});t("columns().cache()","column().cache()",function(a){return this.iterator("column-rows",function(b,c,e,d,f){return ha(b.aoData,f,"search"===a?"_aFilterData":"_aSortData",c)},1)});t("columns().nodes()","column().nodes()",function(){return this.iterator("column-rows",
118
+ function(a,b,c,e,d){return ha(a.aoData,d,"anCells",b)},1)});t("columns().visible()","column().visible()",function(a,b){return this.iterator("column",function(c,e){if(a===l)return c.aoColumns[e].bVisible;var d=c.aoColumns,f=d[e],h=c.aoData,i,j,n;if(a!==l&&f.bVisible!==a){if(a){var m=g.inArray(!0,C(d,"bVisible"),e+1);i=0;for(j=h.length;i<j;i++)n=h[i].nTr,d=h[i].anCells,n&&n.insertBefore(d[e],d[m]||null)}else g(C(c.aoData,"anCells",e)).detach();f.bVisible=a;ea(c,c.aoHeader);ea(c,c.aoFooter);if(b===l||
119
+ b)X(c),(c.oScroll.sX||c.oScroll.sY)&&Y(c);u(c,null,"column-visibility",[c,e,a]);xa(c)}})});t("columns().indexes()","column().index()",function(a){return this.iterator("column",function(b,c){return"visible"===a?$(b,c):c},1)});r("columns.adjust()",function(){return this.iterator("table",function(a){X(a)},1)});r("column.index()",function(a,b){if(0!==this.context.length){var c=this.context[0];if("fromVisible"===a||"toData"===a)return ka(c,b);if("fromData"===a||"toVisible"===a)return $(c,b)}});r("column()",
120
+ function(a,b){return ab(this.columns(a,b))});r("cells()",function(a,b,c){g.isPlainObject(a)&&(typeof a.row!==l?(c=b,b=null):(c=a,a=null));g.isPlainObject(b)&&(c=b,b=null);if(null===b||b===l)return this.iterator("table",function(b){var e=a,d=$a(c),f=b.aoData,h=Ba(b,d),d=Rb(ha(f,h,"anCells")),i=g([].concat.apply([],d)),j,m=b.aoColumns.length,n,p,r,q,s,t;return Za(e,function(a){var c=typeof a==="function";if(a===null||a===l||c){n=[];p=0;for(r=h.length;p<r;p++){j=h[p];for(q=0;q<m;q++){s={row:j,column:q};
121
+ if(c){t=b.aoData[j];a(s,v(b,j,q),t.anCells[q])&&n.push(s)}else n.push(s)}}return n}return g.isPlainObject(a)?[a]:i.filter(a).map(function(a,b){j=b.parentNode._DT_RowIndex;return{row:j,column:g.inArray(b,f[j].anCells)}}).toArray()})});var e=this.columns(b,c),d=this.rows(a,c),f,h,i,j,n,m=this.iterator("table",function(a,b){f=[];h=0;for(i=d[b].length;h<i;h++){j=0;for(n=e[b].length;j<n;j++)f.push({row:d[b][h],column:e[b][j]})}return f},1);g.extend(m.selector,{cols:b,rows:a,opts:c});return m});t("cells().nodes()",
122
+ "cell().node()",function(){return this.iterator("cell",function(a,b,c){return(a=a.aoData[b].anCells)?a[c]:l},1)});r("cells().data()",function(){return this.iterator("cell",function(a,b,c){return v(a,b,c)},1)});t("cells().cache()","cell().cache()",function(a){a="search"===a?"_aFilterData":"_aSortData";return this.iterator("cell",function(b,c,e){return b.aoData[c][a][e]},1)});t("cells().render()","cell().render()",function(a){return this.iterator("cell",function(b,c,e){return v(b,c,e,a)},1)});t("cells().indexes()",
123
+ "cell().index()",function(){return this.iterator("cell",function(a,b,c){return{row:b,column:c,columnVisible:$(a,c)}},1)});t("cells().invalidate()","cell().invalidate()",function(a){return this.iterator("cell",function(b,c,e){ca(b,c,a,e)})});r("cell()",function(a,b,c){return ab(this.cells(a,b,c))});r("cell().data()",function(a){var b=this.context,c=this[0];if(a===l)return b.length&&c.length?v(b[0],c[0].row,c[0].column):l;Ha(b[0],c[0].row,c[0].column,a);ca(b[0],c[0].row,"data",c[0].column);return this});
124
+ r("order()",function(a,b){var c=this.context;if(a===l)return 0!==c.length?c[0].aaSorting:l;"number"===typeof a?a=[[a,b]]:g.isArray(a[0])||(a=Array.prototype.slice.call(arguments));return this.iterator("table",function(b){b.aaSorting=a.slice()})});r("order.listener()",function(a,b,c){return this.iterator("table",function(e){Na(e,a,b,c)})});r(["columns().order()","column().order()"],function(a){var b=this;return this.iterator("table",function(c,e){var d=[];g.each(b[e],function(b,c){d.push([c,a])});
125
+ c.aaSorting=d})});r("search()",function(a,b,c,e){var d=this.context;return a===l?0!==d.length?d[0].oPreviousSearch.sSearch:l:this.iterator("table",function(d){d.oFeatures.bFilter&&fa(d,g.extend({},d.oPreviousSearch,{sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===e?!0:e}),1)})});t("columns().search()","column().search()",function(a,b,c,e){return this.iterator("column",function(d,f){var h=d.aoPreSearchCols;if(a===l)return h[f].sSearch;d.oFeatures.bFilter&&(g.extend(h[f],
126
+ {sSearch:a+"",bRegex:null===b?!1:b,bSmart:null===c?!0:c,bCaseInsensitive:null===e?!0:e}),fa(d,d.oPreviousSearch,1))})});r("state()",function(){return this.context.length?this.context[0].oSavedState:null});r("state.clear()",function(){return this.iterator("table",function(a){a.fnStateSaveCallback.call(a.oInstance,a,{})})});r("state.loaded()",function(){return this.context.length?this.context[0].oLoadedState:null});r("state.save()",function(){return this.iterator("table",function(a){xa(a)})});p.versionCheck=
127
+ p.fnVersionCheck=function(a){for(var b=p.version.split("."),a=a.split("."),c,e,d=0,f=a.length;d<f;d++)if(c=parseInt(b[d],10)||0,e=parseInt(a[d],10)||0,c!==e)return c>e;return!0};p.isDataTable=p.fnIsDataTable=function(a){var b=g(a).get(0),c=!1;g.each(p.settings,function(a,d){if(d.nTable===b||d.nScrollHead===b||d.nScrollFoot===b)c=!0});return c};p.tables=p.fnTables=function(a){return g.map(p.settings,function(b){if(!a||a&&g(b.nTable).is(":visible"))return b.nTable})};p.util={throttle:ta,escapeRegex:ua};
128
+ p.camelToHungarian=G;r("$()",function(a,b){var c=this.rows(b).nodes(),c=g(c);return g([].concat(c.filter(a).toArray(),c.find(a).toArray()))});g.each(["on","one","off"],function(a,b){r(b+"()",function(){var a=Array.prototype.slice.call(arguments);a[0].match(/\.dt\b/)||(a[0]+=".dt");var e=g(this.tables().nodes());e[b].apply(e,a);return this})});r("clear()",function(){return this.iterator("table",function(a){na(a)})});r("settings()",function(){return new q(this.context,this.context)});r("data()",function(){return this.iterator("table",
129
+ function(a){return C(a.aoData,"_aData")}).flatten()});r("destroy()",function(a){a=a||!1;return this.iterator("table",function(b){var c=b.nTableWrapper.parentNode,e=b.oClasses,d=b.nTable,f=b.nTBody,h=b.nTHead,i=b.nTFoot,j=g(d),f=g(f),l=g(b.nTableWrapper),m=g.map(b.aoData,function(a){return a.nTr}),o;b.bDestroying=!0;u(b,"aoDestroyCallback","destroy",[b]);a||(new q(b)).columns().visible(!0);l.unbind(".DT").find(":not(tbody *)").unbind(".DT");g(Da).unbind(".DT-"+b.sInstance);d!=h.parentNode&&(j.children("thead").detach(),
130
+ j.append(h));i&&d!=i.parentNode&&(j.children("tfoot").detach(),j.append(i));j.detach();l.detach();b.aaSorting=[];b.aaSortingFixed=[];wa(b);g(m).removeClass(b.asStripeClasses.join(" "));g("th, td",h).removeClass(e.sSortable+" "+e.sSortableAsc+" "+e.sSortableDesc+" "+e.sSortableNone);b.bJUI&&(g("th span."+e.sSortIcon+", td span."+e.sSortIcon,h).detach(),g("th, td",h).each(function(){var a=g("div."+e.sSortJUIWrapper,this);g(this).append(a.contents());a.detach()}));!a&&c&&c.insertBefore(d,b.nTableReinsertBefore);
131
+ f.children().detach();f.append(m);j.css("width",b.sDestroyWidth).removeClass(e.sTable);(o=b.asDestroyStripes.length)&&f.children().each(function(a){g(this).addClass(b.asDestroyStripes[a%o])});c=g.inArray(b,p.settings);-1!==c&&p.settings.splice(c,1)})});p.version="1.10.4";p.settings=[];p.models={};p.models.oSearch={bCaseInsensitive:!0,sSearch:"",bRegex:!1,bSmart:!0};p.models.oRow={nTr:null,anCells:null,_aData:[],_aSortData:null,_aFilterData:null,_sFilterRow:null,_sRowStripe:"",src:null};p.models.oColumn=
132
+ {idx:null,aDataSort:null,asSorting:null,bSearchable:null,bSortable:null,bVisible:null,_sManualType:null,_bAttrSrc:!1,fnCreatedCell:null,fnGetData:null,fnSetData:null,mData:null,mRender:null,nTh:null,nTf:null,sClass:null,sContentPadding:null,sDefaultContent:null,sName:null,sSortDataType:"std",sSortingClass:null,sSortingClassJUI:null,sTitle:null,sType:null,sWidth:null,sWidthOrig:null};p.defaults={aaData:null,aaSorting:[[0,"asc"]],aaSortingFixed:[],ajax:null,aLengthMenu:[10,25,50,100],aoColumns:null,
133
+ aoColumnDefs:null,aoSearchCols:[],asStripeClasses:null,bAutoWidth:!0,bDeferRender:!1,bDestroy:!1,bFilter:!0,bInfo:!0,bJQueryUI:!1,bLengthChange:!0,bPaginate:!0,bProcessing:!1,bRetrieve:!1,bScrollCollapse:!1,bServerSide:!1,bSort:!0,bSortMulti:!0,bSortCellsTop:!1,bSortClasses:!0,bStateSave:!1,fnCreatedRow:null,fnDrawCallback:null,fnFooterCallback:null,fnFormatNumber:function(a){return a.toString().replace(/\B(?=(\d{3})+(?!\d))/g,this.oLanguage.sThousands)},fnHeaderCallback:null,fnInfoCallback:null,
134
+ fnInitComplete:null,fnPreDrawCallback:null,fnRowCallback:null,fnServerData:null,fnServerParams:null,fnStateLoadCallback:function(a){try{return JSON.parse((-1===a.iStateDuration?sessionStorage:localStorage).getItem("DataTables_"+a.sInstance+"_"+location.pathname))}catch(b){}},fnStateLoadParams:null,fnStateLoaded:null,fnStateSaveCallback:function(a,b){try{(-1===a.iStateDuration?sessionStorage:localStorage).setItem("DataTables_"+a.sInstance+"_"+location.pathname,JSON.stringify(b))}catch(c){}},fnStateSaveParams:null,
135
+ iStateDuration:7200,iDeferLoading:null,iDisplayLength:10,iDisplayStart:0,iTabIndex:0,oClasses:{},oLanguage:{oAria:{sSortAscending:": activate to sort column ascending",sSortDescending:": activate to sort column descending"},oPaginate:{sFirst:"First",sLast:"Last",sNext:"Next",sPrevious:"Previous"},sEmptyTable:"No data available in table",sInfo:"Showing _START_ to _END_ of _TOTAL_ entries",sInfoEmpty:"Showing 0 to 0 of 0 entries",sInfoFiltered:"(filtered from _MAX_ total entries)",sInfoPostFix:"",sDecimal:"",
136
+ sThousands:",",sLengthMenu:"Show _MENU_ entries",sLoadingRecords:"Loading...",sProcessing:"Processing...",sSearch:"Search:",sSearchPlaceholder:"",sUrl:"",sZeroRecords:"No matching records found"},oSearch:g.extend({},p.models.oSearch),sAjaxDataProp:"data",sAjaxSource:null,sDom:"lfrtip",searchDelay:null,sPaginationType:"simple_numbers",sScrollX:"",sScrollXInner:"",sScrollY:"",sServerMethod:"GET",renderer:null};V(p.defaults);p.defaults.column={aDataSort:null,iDataSort:-1,asSorting:["asc","desc"],bSearchable:!0,
137
+ bSortable:!0,bVisible:!0,fnCreatedCell:null,mData:null,mRender:null,sCellType:"td",sClass:"",sContentPadding:"",sDefaultContent:null,sName:"",sSortDataType:"std",sTitle:null,sType:null,sWidth:null};V(p.defaults.column);p.models.oSettings={oFeatures:{bAutoWidth:null,bDeferRender:null,bFilter:null,bInfo:null,bLengthChange:null,bPaginate:null,bProcessing:null,bServerSide:null,bSort:null,bSortMulti:null,bSortClasses:null,bStateSave:null},oScroll:{bCollapse:null,iBarWidth:0,sX:null,sXInner:null,sY:null},
138
+ oLanguage:{fnInfoCallback:null},oBrowser:{bScrollOversize:!1,bScrollbarLeft:!1},ajax:null,aanFeatures:[],aoData:[],aiDisplay:[],aiDisplayMaster:[],aoColumns:[],aoHeader:[],aoFooter:[],oPreviousSearch:{},aoPreSearchCols:[],aaSorting:null,aaSortingFixed:[],asStripeClasses:null,asDestroyStripes:[],sDestroyWidth:0,aoRowCallback:[],aoHeaderCallback:[],aoFooterCallback:[],aoDrawCallback:[],aoRowCreatedCallback:[],aoPreDrawCallback:[],aoInitComplete:[],aoStateSaveParams:[],aoStateLoadParams:[],aoStateLoaded:[],
139
+ sTableId:"",nTable:null,nTHead:null,nTFoot:null,nTBody:null,nTableWrapper:null,bDeferLoading:!1,bInitialised:!1,aoOpenRows:[],sDom:null,searchDelay:null,sPaginationType:"two_button",iStateDuration:0,aoStateSave:[],aoStateLoad:[],oSavedState:null,oLoadedState:null,sAjaxSource:null,sAjaxDataProp:null,bAjaxDataGet:!0,jqXHR:null,json:l,oAjaxData:l,fnServerData:null,aoServerParams:[],sServerMethod:null,fnFormatNumber:null,aLengthMenu:null,iDraw:0,bDrawing:!1,iDrawError:-1,_iDisplayLength:10,_iDisplayStart:0,
140
+ _iRecordsTotal:0,_iRecordsDisplay:0,bJUI:null,oClasses:{},bFiltered:!1,bSorted:!1,bSortCellsTop:null,oInit:null,aoDestroyCallback:[],fnRecordsTotal:function(){return"ssp"==A(this)?1*this._iRecordsTotal:this.aiDisplayMaster.length},fnRecordsDisplay:function(){return"ssp"==A(this)?1*this._iRecordsDisplay:this.aiDisplay.length},fnDisplayEnd:function(){var a=this._iDisplayLength,b=this._iDisplayStart,c=b+a,e=this.aiDisplay.length,d=this.oFeatures,f=d.bPaginate;return d.bServerSide?!1===f||-1===a?b+e:
141
+ Math.min(b+a,this._iRecordsDisplay):!f||c>e||-1===a?e:c},oInstance:null,sInstance:null,iTabIndex:0,nScrollHead:null,nScrollFoot:null,aLastSort:[],oPlugins:{}};p.ext=w={classes:{},errMode:"alert",feature:[],search:[],internal:{},legacy:{ajax:null},pager:{},renderer:{pageButton:{},header:{}},order:{},type:{detect:[],search:{},order:{}},_unique:0,fnVersionCheck:p.fnVersionCheck,iApiIndex:0,oJUIClasses:{},sVersion:p.version};g.extend(w,{afnFiltering:w.search,aTypes:w.type.detect,ofnSearch:w.type.search,
142
+ oSort:w.type.order,afnSortData:w.order,aoFeatures:w.feature,oApi:w.internal,oStdClasses:w.classes,oPagination:w.pager});g.extend(p.ext.classes,{sTable:"dataTable",sNoFooter:"no-footer",sPageButton:"paginate_button",sPageButtonActive:"current",sPageButtonDisabled:"disabled",sStripeOdd:"odd",sStripeEven:"even",sRowEmpty:"dataTables_empty",sWrapper:"dataTables_wrapper",sFilter:"dataTables_filter",sInfo:"dataTables_info",sPaging:"dataTables_paginate paging_",sLength:"dataTables_length",sProcessing:"dataTables_processing",
143
+ sSortAsc:"sorting_asc",sSortDesc:"sorting_desc",sSortable:"sorting",sSortableAsc:"sorting_asc_disabled",sSortableDesc:"sorting_desc_disabled",sSortableNone:"sorting_disabled",sSortColumn:"sorting_",sFilterInput:"",sLengthSelect:"",sScrollWrapper:"dataTables_scroll",sScrollHead:"dataTables_scrollHead",sScrollHeadInner:"dataTables_scrollHeadInner",sScrollBody:"dataTables_scrollBody",sScrollFoot:"dataTables_scrollFoot",sScrollFootInner:"dataTables_scrollFootInner",sHeaderTH:"",sFooterTH:"",sSortJUIAsc:"",
144
+ sSortJUIDesc:"",sSortJUI:"",sSortJUIAscAllowed:"",sSortJUIDescAllowed:"",sSortJUIWrapper:"",sSortIcon:"",sJUIHeader:"",sJUIFooter:""});var Ca="",Ca="",E=Ca+"ui-state-default",ia=Ca+"css_right ui-icon ui-icon-",Wb=Ca+"fg-toolbar ui-toolbar ui-widget-header ui-helper-clearfix";g.extend(p.ext.oJUIClasses,p.ext.classes,{sPageButton:"fg-button ui-button "+E,sPageButtonActive:"ui-state-disabled",sPageButtonDisabled:"ui-state-disabled",sPaging:"dataTables_paginate fg-buttonset ui-buttonset fg-buttonset-multi ui-buttonset-multi paging_",
145
+ sSortAsc:E+" sorting_asc",sSortDesc:E+" sorting_desc",sSortable:E+" sorting",sSortableAsc:E+" sorting_asc_disabled",sSortableDesc:E+" sorting_desc_disabled",sSortableNone:E+" sorting_disabled",sSortJUIAsc:ia+"triangle-1-n",sSortJUIDesc:ia+"triangle-1-s",sSortJUI:ia+"carat-2-n-s",sSortJUIAscAllowed:ia+"carat-1-n",sSortJUIDescAllowed:ia+"carat-1-s",sSortJUIWrapper:"DataTables_sort_wrapper",sSortIcon:"DataTables_sort_icon",sScrollHead:"dataTables_scrollHead "+E,sScrollFoot:"dataTables_scrollFoot "+E,
146
+ sHeaderTH:E,sFooterTH:E,sJUIHeader:Wb+" ui-corner-tl ui-corner-tr",sJUIFooter:Wb+" ui-corner-bl ui-corner-br"});var Lb=p.ext.pager;g.extend(Lb,{simple:function(){return["previous","next"]},full:function(){return["first","previous","next","last"]},simple_numbers:function(a,b){return["previous",Va(a,b),"next"]},full_numbers:function(a,b){return["first","previous",Va(a,b),"next","last"]},_numbers:Va,numbers_length:7});g.extend(!0,p.ext.renderer,{pageButton:{_:function(a,b,c,e,d,f){var h=a.oClasses,i=
147
+ a.oLanguage.oPaginate,j,l,m=0,o=function(b,e){var k,p,r,q,s=function(b){Sa(a,b.data.action,true)};k=0;for(p=e.length;k<p;k++){q=e[k];if(g.isArray(q)){r=g("<"+(q.DT_el||"div")+"/>").appendTo(b);o(r,q)}else{l=j="";switch(q){case "ellipsis":b.append("<span>&hellip;</span>");break;case "first":j=i.sFirst;l=q+(d>0?"":" "+h.sPageButtonDisabled);break;case "previous":j=i.sPrevious;l=q+(d>0?"":" "+h.sPageButtonDisabled);break;case "next":j=i.sNext;l=q+(d<f-1?"":" "+h.sPageButtonDisabled);break;case "last":j=
148
+ i.sLast;l=q+(d<f-1?"":" "+h.sPageButtonDisabled);break;default:j=q+1;l=d===q?h.sPageButtonActive:""}if(j){r=g("<a>",{"class":h.sPageButton+" "+l,"aria-controls":a.sTableId,"data-dt-idx":m,tabindex:a.iTabIndex,id:c===0&&typeof q==="string"?a.sTableId+"_"+q:null}).html(j).appendTo(b);Ua(r,{action:q},s);m++}}}};try{var k=g(P.activeElement).data("dt-idx");o(g(b).empty(),e);k!==null&&g(b).find("[data-dt-idx="+k+"]").focus()}catch(p){}}}});g.extend(p.ext.type.detect,[function(a,b){var c=b.oLanguage.sDecimal;
149
+ return Ya(a,c)?"num"+c:null},function(a){if(a&&!(a instanceof Date)&&(!$b.test(a)||!ac.test(a)))return null;var b=Date.parse(a);return null!==b&&!isNaN(b)||H(a)?"date":null},function(a,b){var c=b.oLanguage.sDecimal;return Ya(a,c,!0)?"num-fmt"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Qb(a,c)?"html-num"+c:null},function(a,b){var c=b.oLanguage.sDecimal;return Qb(a,c,!0)?"html-num-fmt"+c:null},function(a){return H(a)||"string"===typeof a&&-1!==a.indexOf("<")?"html":null}]);g.extend(p.ext.type.search,
150
+ {html:function(a){return H(a)?a:"string"===typeof a?a.replace(Nb," ").replace(Aa,""):""},string:function(a){return H(a)?a:"string"===typeof a?a.replace(Nb," "):a}});var za=function(a,b,c,e){if(0!==a&&(!a||"-"===a))return-Infinity;b&&(a=Pb(a,b));a.replace&&(c&&(a=a.replace(c,"")),e&&(a=a.replace(e,"")));return 1*a};g.extend(w.type.order,{"date-pre":function(a){return Date.parse(a)||0},"html-pre":function(a){return H(a)?"":a.replace?a.replace(/<.*?>/g,"").toLowerCase():a+""},"string-pre":function(a){return H(a)?
151
+ "":"string"===typeof a?a.toLowerCase():!a.toString?"":a.toString()},"string-asc":function(a,b){return a<b?-1:a>b?1:0},"string-desc":function(a,b){return a<b?1:a>b?-1:0}});cb("");g.extend(!0,p.ext.renderer,{header:{_:function(a,b,c,e){g(a.nTable).on("order.dt.DT",function(d,f,h,g){if(a===f){d=c.idx;b.removeClass(c.sSortingClass+" "+e.sSortAsc+" "+e.sSortDesc).addClass(g[d]=="asc"?e.sSortAsc:g[d]=="desc"?e.sSortDesc:c.sSortingClass)}})},jqueryui:function(a,b,c,e){g("<div/>").addClass(e.sSortJUIWrapper).append(b.contents()).append(g("<span/>").addClass(e.sSortIcon+
152
+ " "+c.sSortingClassJUI)).appendTo(b);g(a.nTable).on("order.dt.DT",function(d,f,g,i){if(a===f){d=c.idx;b.removeClass(e.sSortAsc+" "+e.sSortDesc).addClass(i[d]=="asc"?e.sSortAsc:i[d]=="desc"?e.sSortDesc:c.sSortingClass);b.find("span."+e.sSortIcon).removeClass(e.sSortJUIAsc+" "+e.sSortJUIDesc+" "+e.sSortJUI+" "+e.sSortJUIAscAllowed+" "+e.sSortJUIDescAllowed).addClass(i[d]=="asc"?e.sSortJUIAsc:i[d]=="desc"?e.sSortJUIDesc:c.sSortingClassJUI)}})}}});p.render={number:function(a,b,c,e){return{display:function(d){var f=
153
+ 0>d?"-":"",d=Math.abs(parseFloat(d)),g=parseInt(d,10),d=c?b+(d-g).toFixed(c).substring(2):"";return f+(e||"")+g.toString().replace(/\B(?=(\d{3})+(?!\d))/g,a)+d}}}};g.extend(p.ext.internal,{_fnExternApiFunc:Mb,_fnBuildAjax:qa,_fnAjaxUpdate:jb,_fnAjaxParameters:sb,_fnAjaxUpdateDraw:tb,_fnAjaxDataSrc:ra,_fnAddColumn:Ea,_fnColumnOptions:ja,_fnAdjustColumnSizing:X,_fnVisibleToColumnIndex:ka,_fnColumnIndexToVisible:$,_fnVisbleColumns:aa,_fnGetColumns:Z,_fnColumnTypes:Ga,_fnApplyColumnDefs:hb,_fnHungarianMap:V,
154
+ _fnCamelToHungarian:G,_fnLanguageCompat:O,_fnBrowserDetect:fb,_fnAddData:I,_fnAddTr:la,_fnNodeToDataIndex:function(a,b){return b._DT_RowIndex!==l?b._DT_RowIndex:null},_fnNodeToColumnIndex:function(a,b,c){return g.inArray(c,a.aoData[b].anCells)},_fnGetCellData:v,_fnSetCellData:Ha,_fnSplitObjNotation:Ja,_fnGetObjectDataFn:W,_fnSetObjectDataFn:Q,_fnGetDataMaster:Ka,_fnClearTable:na,_fnDeleteIndex:oa,_fnInvalidate:ca,_fnGetRowElements:ma,_fnCreateTr:Ia,_fnBuildHead:ib,_fnDrawHead:ea,_fnDraw:L,_fnReDraw:M,
155
+ _fnAddOptionsHtml:lb,_fnDetectHeader:da,_fnGetUniqueThs:pa,_fnFeatureHtmlFilter:nb,_fnFilterComplete:fa,_fnFilterCustom:wb,_fnFilterColumn:vb,_fnFilter:ub,_fnFilterCreateSearch:Pa,_fnEscapeRegex:ua,_fnFilterData:xb,_fnFeatureHtmlInfo:qb,_fnUpdateInfo:Ab,_fnInfoMacros:Bb,_fnInitialise:ga,_fnInitComplete:sa,_fnLengthChange:Qa,_fnFeatureHtmlLength:mb,_fnFeatureHtmlPaginate:rb,_fnPageChange:Sa,_fnFeatureHtmlProcessing:ob,_fnProcessingDisplay:B,_fnFeatureHtmlTable:pb,_fnScrollDraw:Y,_fnApplyToChildren:F,
156
+ _fnCalculateColumnWidths:Fa,_fnThrottle:ta,_fnConvertToWidth:Cb,_fnScrollingWidthAdjust:Eb,_fnGetWidestNode:Db,_fnGetMaxLenString:Fb,_fnStringToCss:s,_fnScrollBarWidth:Gb,_fnSortFlatten:T,_fnSort:kb,_fnSortAria:Ib,_fnSortListener:Ta,_fnSortAttachListener:Na,_fnSortingClasses:wa,_fnSortData:Hb,_fnSaveState:xa,_fnLoadState:Jb,_fnSettingsFromNode:ya,_fnLog:R,_fnMap:D,_fnBindAction:Ua,_fnCallbackReg:x,_fnCallbackFire:u,_fnLengthOverflow:Ra,_fnRenderer:Oa,_fnDataSource:A,_fnRowAttributes:La,_fnCalculateEnd:function(){}});
157
+ g.fn.dataTable=p;g.fn.dataTableSettings=p.settings;g.fn.dataTableExt=p.ext;g.fn.DataTable=function(a){return g(this).dataTable(a).api()};g.each(p,function(a,b){g.fn.DataTable[a]=b});return g.fn.dataTable};"function"===typeof define&&define.amd?define("datatables",["jquery"],O):"object"===typeof exports?O(require("jquery")):jQuery&&!jQuery.fn.dataTable&&O(jQuery)})(window,document);
assets/dependencies/index.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ //Nothing to see here
3
+
4
+ header( 'HTTP/1.0 403 Forbidden' );
assets/dependencies/qtip/index.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ //Nothing to see here
3
+
4
+ header( 'HTTP/1.0 403 Forbidden' );
{js → assets/dependencies/qtip}/jquery.qtip.min.js RENAMED
File without changes
assets/dependencies/rickshaw/d3.v3.min.js ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ !function(){function n(n,t){return t>n?-1:n>t?1:n>=t?0:0/0}function t(n){return null===n?0/0:+n}function e(n){return!isNaN(n)}function r(n){return{left:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)<0?r=i+1:u=i}return r},right:function(t,e,r,u){for(arguments.length<3&&(r=0),arguments.length<4&&(u=t.length);u>r;){var i=r+u>>>1;n(t[i],e)>0?u=i:r=i+1}return r}}}function u(n){return n.length}function i(n){for(var t=1;n*t%1;)t*=10;return t}function o(n,t){for(var e in t)Object.defineProperty(n.prototype,e,{value:t[e],enumerable:!1})}function a(){this._=Object.create(null)}function c(n){return(n+="")===la||n[0]===sa?sa+n:n}function l(n){return(n+="")[0]===sa?n.slice(1):n}function s(n){return c(n)in this._}function f(n){return(n=c(n))in this._&&delete this._[n]}function h(){var n=[];for(var t in this._)n.push(l(t));return n}function g(){var n=0;for(var t in this._)++n;return n}function p(){for(var n in this._)return!1;return!0}function v(){this._=Object.create(null)}function d(n,t,e){return function(){var r=e.apply(t,arguments);return r===t?n:r}}function m(n,t){if(t in n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(var e=0,r=fa.length;r>e;++e){var u=fa[e]+t;if(u in n)return u}}function y(){}function x(){}function M(n){function t(){for(var t,r=e,u=-1,i=r.length;++u<i;)(t=r[u].on)&&t.apply(this,arguments);return n}var e=[],r=new a;return t.on=function(t,u){var i,o=r.get(t);return arguments.length<2?o&&o.on:(o&&(o.on=null,e=e.slice(0,i=e.indexOf(o)).concat(e.slice(i+1)),r.remove(t)),u&&e.push(r.set(t,{on:u})),n)},t}function _(){Bo.event.preventDefault()}function b(){for(var n,t=Bo.event;n=t.sourceEvent;)t=n;return t}function w(n){for(var t=new x,e=0,r=arguments.length;++e<r;)t[arguments[e]]=M(t);return t.of=function(e,r){return function(u){try{var i=u.sourceEvent=Bo.event;u.target=n,Bo.event=u,t[u.type].apply(e,r)}finally{Bo.event=i}}},t}function S(n){return ga(n,ya),n}function k(n){return"function"==typeof n?n:function(){return pa(n,this)}}function E(n){return"function"==typeof n?n:function(){return va(n,this)}}function A(n,t){function e(){this.removeAttribute(n)}function r(){this.removeAttributeNS(n.space,n.local)}function u(){this.setAttribute(n,t)}function i(){this.setAttributeNS(n.space,n.local,t)}function o(){var e=t.apply(this,arguments);null==e?this.removeAttribute(n):this.setAttribute(n,e)}function a(){var e=t.apply(this,arguments);null==e?this.removeAttributeNS(n.space,n.local):this.setAttributeNS(n.space,n.local,e)}return n=Bo.ns.qualify(n),null==t?n.local?r:e:"function"==typeof t?n.local?a:o:n.local?i:u}function C(n){return n.trim().replace(/\s+/g," ")}function N(n){return new RegExp("(?:^|\\s+)"+Bo.requote(n)+"(?:\\s+|$)","g")}function z(n){return(n+"").trim().split(/^|\s+/)}function L(n,t){function e(){for(var e=-1;++e<u;)n[e](this,t)}function r(){for(var e=-1,r=t.apply(this,arguments);++e<u;)n[e](this,r)}n=z(n).map(T);var u=n.length;return"function"==typeof t?r:e}function T(n){var t=N(n);return function(e,r){if(u=e.classList)return r?u.add(n):u.remove(n);var u=e.getAttribute("class")||"";r?(t.lastIndex=0,t.test(u)||e.setAttribute("class",C(u+" "+n))):e.setAttribute("class",C(u.replace(t," ")))}}function q(n,t,e){function r(){this.style.removeProperty(n)}function u(){this.style.setProperty(n,t,e)}function i(){var r=t.apply(this,arguments);null==r?this.style.removeProperty(n):this.style.setProperty(n,r,e)}return null==t?r:"function"==typeof t?i:u}function R(n,t){function e(){delete this[n]}function r(){this[n]=t}function u(){var e=t.apply(this,arguments);null==e?delete this[n]:this[n]=e}return null==t?e:"function"==typeof t?u:r}function D(n){return"function"==typeof n?n:(n=Bo.ns.qualify(n)).local?function(){return this.ownerDocument.createElementNS(n.space,n.local)}:function(){return this.ownerDocument.createElementNS(this.namespaceURI,n)}}function P(n){return{__data__:n}}function U(n){return function(){return ma(this,n)}}function j(t){return arguments.length||(t=n),function(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}}function F(n,t){for(var e=0,r=n.length;r>e;e++)for(var u,i=n[e],o=0,a=i.length;a>o;o++)(u=i[o])&&t(u,o,e);return n}function H(n){return ga(n,Ma),n}function O(n){var t,e;return function(r,u,i){var o,a=n[i].update,c=a.length;for(i!=e&&(e=i,t=0),u>=t&&(t=u+1);!(o=a[t])&&++t<c;);return o}}function Y(){var n=this.__transition__;n&&++n.active}function I(n,t,e){function r(){var t=this[o];t&&(this.removeEventListener(n,t,t.$),delete this[o])}function u(){var u=c(t,Jo(arguments));r.call(this),this.addEventListener(n,this[o]=u,u.$=e),u._=t}function i(){var t,e=new RegExp("^__on([^.]+)"+Bo.requote(n)+"$");for(var r in this)if(t=r.match(e)){var u=this[r];this.removeEventListener(t[1],u,u.$),delete this[r]}}var o="__on"+n,a=n.indexOf("."),c=Z;a>0&&(n=n.slice(0,a));var l=ba.get(n);return l&&(n=l,c=V),a?t?u:r:t?y:i}function Z(n,t){return function(e){var r=Bo.event;Bo.event=e,t[0]=this.__data__;try{n.apply(this,t)}finally{Bo.event=r}}}function V(n,t){var e=Z(n,t);return function(n){var t=this,r=n.relatedTarget;r&&(r===t||8&r.compareDocumentPosition(t))||e.call(t,n)}}function X(){var n=".dragsuppress-"+ ++Sa,t="click"+n,e=Bo.select(Qo).on("touchmove"+n,_).on("dragstart"+n,_).on("selectstart"+n,_);if(wa){var r=Ko.style,u=r[wa];r[wa]="none"}return function(i){function o(){e.on(t,null)}e.on(n,null),wa&&(r[wa]=u),i&&(e.on(t,function(){_(),o()},!0),setTimeout(o,0))}}function $(n,t){t.changedTouches&&(t=t.changedTouches[0]);var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();if(0>ka&&(Qo.scrollX||Qo.scrollY)){e=Bo.select("body").append("svg").style({position:"absolute",top:0,left:0,margin:0,padding:0,border:"none"},"important");var u=e[0][0].getScreenCTM();ka=!(u.f||u.e),e.remove()}return ka?(r.x=t.pageX,r.y=t.pageY):(r.x=t.clientX,r.y=t.clientY),r=r.matrixTransform(n.getScreenCTM().inverse()),[r.x,r.y]}var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}function B(){return Bo.event.changedTouches[0].identifier}function W(){return Bo.event.target}function J(){return Qo}function G(n){return n>0?1:0>n?-1:0}function K(n,t,e){return(t[0]-n[0])*(e[1]-n[1])-(t[1]-n[1])*(e[0]-n[0])}function Q(n){return n>1?0:-1>n?Ea:Math.acos(n)}function nt(n){return n>1?Ca:-1>n?-Ca:Math.asin(n)}function tt(n){return((n=Math.exp(n))-1/n)/2}function et(n){return((n=Math.exp(n))+1/n)/2}function rt(n){return((n=Math.exp(2*n))-1)/(n+1)}function ut(n){return(n=Math.sin(n/2))*n}function it(){}function ot(n,t,e){return this instanceof ot?(this.h=+n,this.s=+t,void(this.l=+e)):arguments.length<2?n instanceof ot?new ot(n.h,n.s,n.l):Mt(""+n,_t,ot):new ot(n,t,e)}function at(n,t,e){function r(n){return n>360?n-=360:0>n&&(n+=360),60>n?i+(o-i)*n/60:180>n?o:240>n?i+(o-i)*(240-n)/60:i}function u(n){return Math.round(255*r(n))}var i,o;return n=isNaN(n)?0:(n%=360)<0?n+360:n,t=isNaN(t)?0:0>t?0:t>1?1:t,e=0>e?0:e>1?1:e,o=.5>=e?e*(1+t):e+t-e*t,i=2*e-o,new dt(u(n+120),u(n),u(n-120))}function ct(n,t,e){return this instanceof ct?(this.h=+n,this.c=+t,void(this.l=+e)):arguments.length<2?n instanceof ct?new ct(n.h,n.c,n.l):n instanceof st?ht(n.l,n.a,n.b):ht((n=bt((n=Bo.rgb(n)).r,n.g,n.b)).l,n.a,n.b):new ct(n,t,e)}function lt(n,t,e){return isNaN(n)&&(n=0),isNaN(t)&&(t=0),new st(e,Math.cos(n*=La)*t,Math.sin(n)*t)}function st(n,t,e){return this instanceof st?(this.l=+n,this.a=+t,void(this.b=+e)):arguments.length<2?n instanceof st?new st(n.l,n.a,n.b):n instanceof ct?lt(n.h,n.c,n.l):bt((n=dt(n)).r,n.g,n.b):new st(n,t,e)}function ft(n,t,e){var r=(n+16)/116,u=r+t/500,i=r-e/200;return u=gt(u)*Ya,r=gt(r)*Ia,i=gt(i)*Za,new dt(vt(3.2404542*u-1.5371385*r-.4985314*i),vt(-.969266*u+1.8760108*r+.041556*i),vt(.0556434*u-.2040259*r+1.0572252*i))}function ht(n,t,e){return n>0?new ct(Math.atan2(e,t)*Ta,Math.sqrt(t*t+e*e),n):new ct(0/0,0/0,n)}function gt(n){return n>.206893034?n*n*n:(n-4/29)/7.787037}function pt(n){return n>.008856?Math.pow(n,1/3):7.787037*n+4/29}function vt(n){return Math.round(255*(.00304>=n?12.92*n:1.055*Math.pow(n,1/2.4)-.055))}function dt(n,t,e){return this instanceof dt?(this.r=~~n,this.g=~~t,void(this.b=~~e)):arguments.length<2?n instanceof dt?new dt(n.r,n.g,n.b):Mt(""+n,dt,at):new dt(n,t,e)}function mt(n){return new dt(n>>16,255&n>>8,255&n)}function yt(n){return mt(n)+""}function xt(n){return 16>n?"0"+Math.max(0,n).toString(16):Math.min(255,n).toString(16)}function Mt(n,t,e){var r,u,i,o=0,a=0,c=0;if(r=/([a-z]+)\((.*)\)/i.exec(n))switch(u=r[2].split(","),r[1]){case"hsl":return e(parseFloat(u[0]),parseFloat(u[1])/100,parseFloat(u[2])/100);case"rgb":return t(St(u[0]),St(u[1]),St(u[2]))}return(i=$a.get(n))?t(i.r,i.g,i.b):(null==n||"#"!==n.charAt(0)||isNaN(i=parseInt(n.slice(1),16))||(4===n.length?(o=(3840&i)>>4,o=o>>4|o,a=240&i,a=a>>4|a,c=15&i,c=c<<4|c):7===n.length&&(o=(16711680&i)>>16,a=(65280&i)>>8,c=255&i)),t(o,a,c))}function _t(n,t,e){var r,u,i=Math.min(n/=255,t/=255,e/=255),o=Math.max(n,t,e),a=o-i,c=(o+i)/2;return a?(u=.5>c?a/(o+i):a/(2-o-i),r=n==o?(t-e)/a+(e>t?6:0):t==o?(e-n)/a+2:(n-t)/a+4,r*=60):(r=0/0,u=c>0&&1>c?0:r),new ot(r,u,c)}function bt(n,t,e){n=wt(n),t=wt(t),e=wt(e);var r=pt((.4124564*n+.3575761*t+.1804375*e)/Ya),u=pt((.2126729*n+.7151522*t+.072175*e)/Ia),i=pt((.0193339*n+.119192*t+.9503041*e)/Za);return st(116*u-16,500*(r-u),200*(u-i))}function wt(n){return(n/=255)<=.04045?n/12.92:Math.pow((n+.055)/1.055,2.4)}function St(n){var t=parseFloat(n);return"%"===n.charAt(n.length-1)?Math.round(2.55*t):t}function kt(n){return"function"==typeof n?n:function(){return n}}function Et(n){return n}function At(n){return function(t,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=null),Ct(t,e,n,r)}}function Ct(n,t,e,r){function u(){var n,t=c.status;if(!t&&zt(c)||t>=200&&300>t||304===t){try{n=e.call(i,c)}catch(r){return o.error.call(i,r),void 0}o.load.call(i,n)}else o.error.call(i,c)}var i={},o=Bo.dispatch("beforesend","progress","load","error"),a={},c=new XMLHttpRequest,l=null;return!Qo.XDomainRequest||"withCredentials"in c||!/^(http(s)?:)?\/\//.test(n)||(c=new XDomainRequest),"onload"in c?c.onload=c.onerror=u:c.onreadystatechange=function(){c.readyState>3&&u()},c.onprogress=function(n){var t=Bo.event;Bo.event=n;try{o.progress.call(i,c)}finally{Bo.event=t}},i.header=function(n,t){return n=(n+"").toLowerCase(),arguments.length<2?a[n]:(null==t?delete a[n]:a[n]=t+"",i)},i.mimeType=function(n){return arguments.length?(t=null==n?null:n+"",i):t},i.responseType=function(n){return arguments.length?(l=n,i):l},i.response=function(n){return e=n,i},["get","post"].forEach(function(n){i[n]=function(){return i.send.apply(i,[n].concat(Jo(arguments)))}}),i.send=function(e,r,u){if(2===arguments.length&&"function"==typeof r&&(u=r,r=null),c.open(e,n,!0),null==t||"accept"in a||(a.accept=t+",*/*"),c.setRequestHeader)for(var s in a)c.setRequestHeader(s,a[s]);return null!=t&&c.overrideMimeType&&c.overrideMimeType(t),null!=l&&(c.responseType=l),null!=u&&i.on("error",u).on("load",function(n){u(null,n)}),o.beforesend.call(i,c),c.send(null==r?null:r),i},i.abort=function(){return c.abort(),i},Bo.rebind(i,o,"on"),null==r?i:i.get(Nt(r))}function Nt(n){return 1===n.length?function(t,e){n(null==t?e:null)}:n}function zt(n){var t=n.responseType;return t&&"text"!==t?n.response:n.responseText}function Lt(){var n=Tt(),t=qt()-n;t>24?(isFinite(t)&&(clearTimeout(Ga),Ga=setTimeout(Lt,t)),Ja=0):(Ja=1,Qa(Lt))}function Tt(){var n=Date.now();for(Ka=Ba;Ka;)n>=Ka.t&&(Ka.f=Ka.c(n-Ka.t)),Ka=Ka.n;return n}function qt(){for(var n,t=Ba,e=1/0;t;)t.f?t=n?n.n=t.n:Ba=t.n:(t.t<e&&(e=t.t),t=(n=t).n);return Wa=n,e}function Rt(n,t){return t-(n?Math.ceil(Math.log(n)/Math.LN10):1)}function Dt(n,t){var e=Math.pow(10,3*ca(8-t));return{scale:t>8?function(n){return n/e}:function(n){return n*e},symbol:n}}function Pt(n){var t=n.decimal,e=n.thousands,r=n.grouping,u=n.currency,i=r&&e?function(n,t){for(var u=n.length,i=[],o=0,a=r[0],c=0;u>0&&a>0&&(c+a+1>t&&(a=Math.max(1,t-c)),i.push(n.substring(u-=a,u+a)),!((c+=a+1)>t));)a=r[o=(o+1)%r.length];return i.reverse().join(e)}:Et;return function(n){var e=tc.exec(n),r=e[1]||" ",o=e[2]||">",a=e[3]||"-",c=e[4]||"",l=e[5],s=+e[6],f=e[7],h=e[8],g=e[9],p=1,v="",d="",m=!1,y=!0;switch(h&&(h=+h.substring(1)),(l||"0"===r&&"="===o)&&(l=r="0",o="="),g){case"n":f=!0,g="g";break;case"%":p=100,d="%",g="f";break;case"p":p=100,d="%",g="r";break;case"b":case"o":case"x":case"X":"#"===c&&(v="0"+g.toLowerCase());case"c":y=!1;case"d":m=!0,h=0;break;case"s":p=-1,g="r"}"$"===c&&(v=u[0],d=u[1]),"r"!=g||h||(g="g"),null!=h&&("g"==g?h=Math.max(1,Math.min(21,h)):("e"==g||"f"==g)&&(h=Math.max(0,Math.min(20,h)))),g=ec.get(g)||Ut;var x=l&&f;return function(n){var e=d;if(m&&n%1)return"";var u=0>n||0===n&&0>1/n?(n=-n,"-"):"-"===a?"":a;if(0>p){var c=Bo.formatPrefix(n,h);n=c.scale(n),e=c.symbol+d}else n*=p;n=g(n,h);var M,_,b=n.lastIndexOf(".");if(0>b){var w=y?n.lastIndexOf("e"):-1;0>w?(M=n,_=""):(M=n.substring(0,w),_=n.substring(w))}else M=n.substring(0,b),_=t+n.substring(b+1);!l&&f&&(M=i(M,1/0));var S=v.length+M.length+_.length+(x?0:u.length),k=s>S?new Array(S=s-S+1).join(r):"";return x&&(M=i(k+M,k.length?s-_.length:1/0)),u+=v,n=M+_,("<"===o?u+n+k:">"===o?k+u+n:"^"===o?k.substring(0,S>>=1)+u+n+k.substring(S):u+(x?n:k+n))+e}}}function Ut(n){return n+""}function jt(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function Ft(n,t,e){function r(t){var e=n(t),r=i(e,1);return r-t>t-e?e:r}function u(e){return t(e=n(new uc(e-1)),1),e}function i(n,e){return t(n=new uc(+n),e),n}function o(n,r,i){var o=u(n),a=[];if(i>1)for(;r>o;)e(o)%i||a.push(new Date(+o)),t(o,1);else for(;r>o;)a.push(new Date(+o)),t(o,1);return a}function a(n,t,e){try{uc=jt;var r=new jt;return r._=n,o(r,t,e)}finally{uc=Date}}n.floor=n,n.round=r,n.ceil=u,n.offset=i,n.range=o;var c=n.utc=Ht(n);return c.floor=c,c.round=Ht(r),c.ceil=Ht(u),c.offset=Ht(i),c.range=a,n}function Ht(n){return function(t,e){try{uc=jt;var r=new jt;return r._=t,n(r,e)._}finally{uc=Date}}}function Ot(n){function t(n){function t(t){for(var e,u,i,o=[],a=-1,c=0;++a<r;)37===n.charCodeAt(a)&&(o.push(n.slice(c,a)),null!=(u=oc[e=n.charAt(++a)])&&(e=n.charAt(++a)),(i=C[e])&&(e=i(t,null==u?"e"===e?" ":"0":u)),o.push(e),c=a+1);return o.push(n.slice(c,a)),o.join("")}var r=n.length;return t.parse=function(t){var r={y:1900,m:0,d:1,H:0,M:0,S:0,L:0,Z:null},u=e(r,n,t,0);if(u!=t.length)return null;"p"in r&&(r.H=r.H%12+12*r.p);var i=null!=r.Z&&uc!==jt,o=new(i?jt:uc);return"j"in r?o.setFullYear(r.y,0,r.j):"w"in r&&("W"in r||"U"in r)?(o.setFullYear(r.y,0,1),o.setFullYear(r.y,0,"W"in r?(r.w+6)%7+7*r.W-(o.getDay()+5)%7:r.w+7*r.U-(o.getDay()+6)%7)):o.setFullYear(r.y,r.m,r.d),o.setHours(r.H+(0|r.Z/100),r.M+r.Z%100,r.S,r.L),i?o._:o},t.toString=function(){return n},t}function e(n,t,e,r){for(var u,i,o,a=0,c=t.length,l=e.length;c>a;){if(r>=l)return-1;if(u=t.charCodeAt(a++),37===u){if(o=t.charAt(a++),i=N[o in oc?t.charAt(a++):o],!i||(r=i(n,e,r))<0)return-1}else if(u!=e.charCodeAt(r++))return-1}return r}function r(n,t,e){b.lastIndex=0;var r=b.exec(t.slice(e));return r?(n.w=w.get(r[0].toLowerCase()),e+r[0].length):-1}function u(n,t,e){M.lastIndex=0;var r=M.exec(t.slice(e));return r?(n.w=_.get(r[0].toLowerCase()),e+r[0].length):-1}function i(n,t,e){E.lastIndex=0;var r=E.exec(t.slice(e));return r?(n.m=A.get(r[0].toLowerCase()),e+r[0].length):-1}function o(n,t,e){S.lastIndex=0;var r=S.exec(t.slice(e));return r?(n.m=k.get(r[0].toLowerCase()),e+r[0].length):-1}function a(n,t,r){return e(n,C.c.toString(),t,r)}function c(n,t,r){return e(n,C.x.toString(),t,r)}function l(n,t,r){return e(n,C.X.toString(),t,r)}function s(n,t,e){var r=x.get(t.slice(e,e+=2).toLowerCase());return null==r?-1:(n.p=r,e)}var f=n.dateTime,h=n.date,g=n.time,p=n.periods,v=n.days,d=n.shortDays,m=n.months,y=n.shortMonths;t.utc=function(n){function e(n){try{uc=jt;var t=new uc;return t._=n,r(t)}finally{uc=Date}}var r=t(n);return e.parse=function(n){try{uc=jt;var t=r.parse(n);return t&&t._}finally{uc=Date}},e.toString=r.toString,e},t.multi=t.utc.multi=ae;var x=Bo.map(),M=It(v),_=Zt(v),b=It(d),w=Zt(d),S=It(m),k=Zt(m),E=It(y),A=Zt(y);p.forEach(function(n,t){x.set(n.toLowerCase(),t)});var C={a:function(n){return d[n.getDay()]},A:function(n){return v[n.getDay()]},b:function(n){return y[n.getMonth()]},B:function(n){return m[n.getMonth()]},c:t(f),d:function(n,t){return Yt(n.getDate(),t,2)},e:function(n,t){return Yt(n.getDate(),t,2)},H:function(n,t){return Yt(n.getHours(),t,2)},I:function(n,t){return Yt(n.getHours()%12||12,t,2)},j:function(n,t){return Yt(1+rc.dayOfYear(n),t,3)},L:function(n,t){return Yt(n.getMilliseconds(),t,3)},m:function(n,t){return Yt(n.getMonth()+1,t,2)},M:function(n,t){return Yt(n.getMinutes(),t,2)},p:function(n){return p[+(n.getHours()>=12)]},S:function(n,t){return Yt(n.getSeconds(),t,2)},U:function(n,t){return Yt(rc.sundayOfYear(n),t,2)},w:function(n){return n.getDay()},W:function(n,t){return Yt(rc.mondayOfYear(n),t,2)},x:t(h),X:t(g),y:function(n,t){return Yt(n.getFullYear()%100,t,2)},Y:function(n,t){return Yt(n.getFullYear()%1e4,t,4)},Z:ie,"%":function(){return"%"}},N={a:r,A:u,b:i,B:o,c:a,d:Qt,e:Qt,H:te,I:te,j:ne,L:ue,m:Kt,M:ee,p:s,S:re,U:Xt,w:Vt,W:$t,x:c,X:l,y:Wt,Y:Bt,Z:Jt,"%":oe};return t}function Yt(n,t,e){var r=0>n?"-":"",u=(r?-n:n)+"",i=u.length;return r+(e>i?new Array(e-i+1).join(t)+u:u)}function It(n){return new RegExp("^(?:"+n.map(Bo.requote).join("|")+")","i")}function Zt(n){for(var t=new a,e=-1,r=n.length;++e<r;)t.set(n[e].toLowerCase(),e);return t}function Vt(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+1));return r?(n.w=+r[0],e+r[0].length):-1}function Xt(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e));return r?(n.U=+r[0],e+r[0].length):-1}function $t(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e));return r?(n.W=+r[0],e+r[0].length):-1}function Bt(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+4));return r?(n.y=+r[0],e+r[0].length):-1}function Wt(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+2));return r?(n.y=Gt(+r[0]),e+r[0].length):-1}function Jt(n,t,e){return/^[+-]\d{4}$/.test(t=t.slice(e,e+5))?(n.Z=-t,e+5):-1}function Gt(n){return n+(n>68?1900:2e3)}function Kt(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+2));return r?(n.m=r[0]-1,e+r[0].length):-1}function Qt(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+2));return r?(n.d=+r[0],e+r[0].length):-1}function ne(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+3));return r?(n.j=+r[0],e+r[0].length):-1}function te(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+2));return r?(n.H=+r[0],e+r[0].length):-1}function ee(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+2));return r?(n.M=+r[0],e+r[0].length):-1}function re(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+2));return r?(n.S=+r[0],e+r[0].length):-1}function ue(n,t,e){ac.lastIndex=0;var r=ac.exec(t.slice(e,e+3));return r?(n.L=+r[0],e+r[0].length):-1}function ie(n){var t=n.getTimezoneOffset(),e=t>0?"-":"+",r=0|ca(t)/60,u=ca(t)%60;return e+Yt(r,"0",2)+Yt(u,"0",2)}function oe(n,t,e){cc.lastIndex=0;var r=cc.exec(t.slice(e,e+1));return r?e+r[0].length:-1}function ae(n){for(var t=n.length,e=-1;++e<t;)n[e][0]=this(n[e][0]);return function(t){for(var e=0,r=n[e];!r[1](t);)r=n[++e];return r[0](t)}}function ce(){}function le(n,t,e){var r=e.s=n+t,u=r-n,i=r-u;e.t=n-i+(t-u)}function se(n,t){n&&hc.hasOwnProperty(n.type)&&hc[n.type](n,t)}function fe(n,t,e){var r,u=-1,i=n.length-e;for(t.lineStart();++u<i;)r=n[u],t.point(r[0],r[1],r[2]);t.lineEnd()}function he(n,t){var e=-1,r=n.length;for(t.polygonStart();++e<r;)fe(n[e],t,1);t.polygonEnd()}function ge(){function n(n,t){n*=La,t=t*La/2+Ea/4;var e=n-r,o=e>=0?1:-1,a=o*e,c=Math.cos(t),l=Math.sin(t),s=i*l,f=u*c+s*Math.cos(a),h=s*o*Math.sin(a);pc.add(Math.atan2(h,f)),r=n,u=c,i=l}var t,e,r,u,i;vc.point=function(o,a){vc.point=n,r=(t=o)*La,u=Math.cos(a=(e=a)*La/2+Ea/4),i=Math.sin(a)},vc.lineEnd=function(){n(t,e)}}function pe(n){var t=n[0],e=n[1],r=Math.cos(e);return[r*Math.cos(t),r*Math.sin(t),Math.sin(e)]}function ve(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]}function de(n,t){return[n[1]*t[2]-n[2]*t[1],n[2]*t[0]-n[0]*t[2],n[0]*t[1]-n[1]*t[0]]}function me(n,t){n[0]+=t[0],n[1]+=t[1],n[2]+=t[2]}function ye(n,t){return[n[0]*t,n[1]*t,n[2]*t]}function xe(n){var t=Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);n[0]/=t,n[1]/=t,n[2]/=t}function Me(n){return[Math.atan2(n[1],n[0]),nt(n[2])]}function _e(n,t){return ca(n[0]-t[0])<Na&&ca(n[1]-t[1])<Na}function be(n,t){n*=La;var e=Math.cos(t*=La);we(e*Math.cos(n),e*Math.sin(n),Math.sin(t))}function we(n,t,e){++dc,yc+=(n-yc)/dc,xc+=(t-xc)/dc,Mc+=(e-Mc)/dc}function Se(){function n(n,u){n*=La;var i=Math.cos(u*=La),o=i*Math.cos(n),a=i*Math.sin(n),c=Math.sin(u),l=Math.atan2(Math.sqrt((l=e*c-r*a)*l+(l=r*o-t*c)*l+(l=t*a-e*o)*l),t*o+e*a+r*c);mc+=l,_c+=l*(t+(t=o)),bc+=l*(e+(e=a)),wc+=l*(r+(r=c)),we(t,e,r)}var t,e,r;Ac.point=function(u,i){u*=La;var o=Math.cos(i*=La);t=o*Math.cos(u),e=o*Math.sin(u),r=Math.sin(i),Ac.point=n,we(t,e,r)}}function ke(){Ac.point=be}function Ee(){function n(n,t){n*=La;var e=Math.cos(t*=La),o=e*Math.cos(n),a=e*Math.sin(n),c=Math.sin(t),l=u*c-i*a,s=i*o-r*c,f=r*a-u*o,h=Math.sqrt(l*l+s*s+f*f),g=r*o+u*a+i*c,p=h&&-Q(g)/h,v=Math.atan2(h,g);Sc+=p*l,kc+=p*s,Ec+=p*f,mc+=v,_c+=v*(r+(r=o)),bc+=v*(u+(u=a)),wc+=v*(i+(i=c)),we(r,u,i)}var t,e,r,u,i;Ac.point=function(o,a){t=o,e=a,Ac.point=n,o*=La;var c=Math.cos(a*=La);r=c*Math.cos(o),u=c*Math.sin(o),i=Math.sin(a),we(r,u,i)},Ac.lineEnd=function(){n(t,e),Ac.lineEnd=ke,Ac.point=be}}function Ae(){return!0}function Ce(n,t,e,r,u){var i=[],o=[];if(n.forEach(function(n){if(!((t=n.length-1)<=0)){var t,e=n[0],r=n[t];if(_e(e,r)){u.lineStart();for(var a=0;t>a;++a)u.point((e=n[a])[0],e[1]);return u.lineEnd(),void 0}var c=new ze(e,n,null,!0),l=new ze(e,null,c,!1);c.o=l,i.push(c),o.push(l),c=new ze(r,n,null,!1),l=new ze(r,null,c,!0),c.o=l,i.push(c),o.push(l)}}),o.sort(t),Ne(i),Ne(o),i.length){for(var a=0,c=e,l=o.length;l>a;++a)o[a].e=c=!c;for(var s,f,h=i[0];;){for(var g=h,p=!0;g.v;)if((g=g.n)===h)return;s=g.z,u.lineStart();do{if(g.v=g.o.v=!0,g.e){if(p)for(var a=0,l=s.length;l>a;++a)u.point((f=s[a])[0],f[1]);else r(g.x,g.n.x,1,u);g=g.n}else{if(p){s=g.p.z;for(var a=s.length-1;a>=0;--a)u.point((f=s[a])[0],f[1])}else r(g.x,g.p.x,-1,u);g=g.p}g=g.o,s=g.z,p=!p}while(!g.v);u.lineEnd()}}}function Ne(n){if(t=n.length){for(var t,e,r=0,u=n[0];++r<t;)u.n=e=n[r],e.p=u,u=e;u.n=e=n[0],e.p=u}}function ze(n,t,e,r){this.x=n,this.z=t,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function Le(n,t,e,r){return function(u,i){function o(t,e){var r=u(t,e);n(t=r[0],e=r[1])&&i.point(t,e)}function a(n,t){var e=u(n,t);d.point(e[0],e[1])}function c(){y.point=a,d.lineStart()}function l(){y.point=o,d.lineEnd()}function s(n,t){v.push([n,t]);var e=u(n,t);M.point(e[0],e[1])}function f(){M.lineStart(),v=[]}function h(){s(v[0][0],v[0][1]),M.lineEnd();var n,t=M.clean(),e=x.buffer(),r=e.length;if(v.pop(),p.push(v),v=null,r)if(1&t){n=e[0];var u,r=n.length-1,o=-1;if(r>0){for(_||(i.polygonStart(),_=!0),i.lineStart();++o<r;)i.point((u=n[o])[0],u[1]);i.lineEnd()}}else r>1&&2&t&&e.push(e.pop().concat(e.shift())),g.push(e.filter(Te))}var g,p,v,d=t(i),m=u.invert(r[0],r[1]),y={point:o,lineStart:c,lineEnd:l,polygonStart:function(){y.point=s,y.lineStart=f,y.lineEnd=h,g=[],p=[]},polygonEnd:function(){y.point=o,y.lineStart=c,y.lineEnd=l,g=Bo.merge(g);var n=je(m,p);g.length?(_||(i.polygonStart(),_=!0),Ce(g,Re,n,e,i)):n&&(_||(i.polygonStart(),_=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),_&&(i.polygonEnd(),_=!1),g=p=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}},x=qe(),M=t(x),_=!1;return y}}function Te(n){return n.length>1}function qe(){var n,t=[];return{lineStart:function(){t.push(n=[])},point:function(t,e){n.push([t,e])},lineEnd:y,buffer:function(){var e=t;return t=[],n=null,e},rejoin:function(){t.length>1&&t.push(t.pop().concat(t.shift()))}}}function Re(n,t){return((n=n.x)[0]<0?n[1]-Ca-Na:Ca-n[1])-((t=t.x)[0]<0?t[1]-Ca-Na:Ca-t[1])}function De(n){var t,e=0/0,r=0/0,u=0/0;return{lineStart:function(){n.lineStart(),t=1},point:function(i,o){var a=i>0?Ea:-Ea,c=ca(i-e);ca(c-Ea)<Na?(n.point(e,r=(r+o)/2>0?Ca:-Ca),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),n.point(i,r),t=0):u!==a&&c>=Ea&&(ca(e-u)<Na&&(e-=u*Na),ca(i-a)<Na&&(i-=a*Na),r=Pe(e,r,i,o),n.point(u,r),n.lineEnd(),n.lineStart(),n.point(a,r),t=0),n.point(e=i,r=o),u=a},lineEnd:function(){n.lineEnd(),e=r=0/0},clean:function(){return 2-t}}}function Pe(n,t,e,r){var u,i,o=Math.sin(n-e);return ca(o)>Na?Math.atan((Math.sin(t)*(i=Math.cos(r))*Math.sin(e)-Math.sin(r)*(u=Math.cos(t))*Math.sin(n))/(u*i*o)):(t+r)/2}function Ue(n,t,e,r){var u;if(null==n)u=e*Ca,r.point(-Ea,u),r.point(0,u),r.point(Ea,u),r.point(Ea,0),r.point(Ea,-u),r.point(0,-u),r.point(-Ea,-u),r.point(-Ea,0),r.point(-Ea,u);else if(ca(n[0]-t[0])>Na){var i=n[0]<t[0]?Ea:-Ea;u=e*i/2,r.point(-i,u),r.point(0,u),r.point(i,u)}else r.point(t[0],t[1])}function je(n,t){var e=n[0],r=n[1],u=[Math.sin(e),-Math.cos(e),0],i=0,o=0;pc.reset();for(var a=0,c=t.length;c>a;++a){var l=t[a],s=l.length;if(s)for(var f=l[0],h=f[0],g=f[1]/2+Ea/4,p=Math.sin(g),v=Math.cos(g),d=1;;){d===s&&(d=0),n=l[d];var m=n[0],y=n[1]/2+Ea/4,x=Math.sin(y),M=Math.cos(y),_=m-h,b=_>=0?1:-1,w=b*_,S=w>Ea,k=p*x;if(pc.add(Math.atan2(k*b*Math.sin(w),v*M+k*Math.cos(w))),i+=S?_+b*Aa:_,S^h>=e^m>=e){var E=de(pe(f),pe(n));xe(E);var A=de(u,E);xe(A);var C=(S^_>=0?-1:1)*nt(A[2]);(r>C||r===C&&(E[0]||E[1]))&&(o+=S^_>=0?1:-1)}if(!d++)break;h=m,p=x,v=M,f=n}}return(-Na>i||Na>i&&0>pc)^1&o}function Fe(n){function t(n,t){return Math.cos(n)*Math.cos(t)>i}function e(n){var e,i,c,l,s;return{lineStart:function(){l=c=!1,s=1},point:function(f,h){var g,p=[f,h],v=t(f,h),d=o?v?0:u(f,h):v?u(f+(0>f?Ea:-Ea),h):0;if(!e&&(l=c=v)&&n.lineStart(),v!==c&&(g=r(e,p),(_e(e,g)||_e(p,g))&&(p[0]+=Na,p[1]+=Na,v=t(p[0],p[1]))),v!==c)s=0,v?(n.lineStart(),g=r(p,e),n.point(g[0],g[1])):(g=r(e,p),n.point(g[0],g[1]),n.lineEnd()),e=g;else if(a&&e&&o^v){var m;d&i||!(m=r(p,e,!0))||(s=0,o?(n.lineStart(),n.point(m[0][0],m[0][1]),n.point(m[1][0],m[1][1]),n.lineEnd()):(n.point(m[1][0],m[1][1]),n.lineEnd(),n.lineStart(),n.point(m[0][0],m[0][1])))}!v||e&&_e(e,p)||n.point(p[0],p[1]),e=p,c=v,i=d},lineEnd:function(){c&&n.lineEnd(),e=null},clean:function(){return s|(l&&c)<<1}}}function r(n,t,e){var r=pe(n),u=pe(t),o=[1,0,0],a=de(r,u),c=ve(a,a),l=a[0],s=c-l*l;if(!s)return!e&&n;var f=i*c/s,h=-i*l/s,g=de(o,a),p=ye(o,f),v=ye(a,h);me(p,v);var d=g,m=ve(p,d),y=ve(d,d),x=m*m-y*(ve(p,p)-1);if(!(0>x)){var M=Math.sqrt(x),_=ye(d,(-m-M)/y);if(me(_,p),_=Me(_),!e)return _;var b,w=n[0],S=t[0],k=n[1],E=t[1];w>S&&(b=w,w=S,S=b);var A=S-w,C=ca(A-Ea)<Na,N=C||Na>A;if(!C&&k>E&&(b=k,k=E,E=b),N?C?k+E>0^_[1]<(ca(_[0]-w)<Na?k:E):k<=_[1]&&_[1]<=E:A>Ea^(w<=_[0]&&_[0]<=S)){var z=ye(d,(-m+M)/y);return me(z,p),[_,Me(z)]}}}function u(t,e){var r=o?n:Ea-n,u=0;return-r>t?u|=1:t>r&&(u|=2),-r>e?u|=4:e>r&&(u|=8),u}var i=Math.cos(n),o=i>0,a=ca(i)>Na,c=gr(n,6*La);return Le(t,e,c,o?[0,-n]:[-Ea,n-Ea])}function He(n,t,e,r){return function(u){var i,o=u.a,a=u.b,c=o.x,l=o.y,s=a.x,f=a.y,h=0,g=1,p=s-c,v=f-l;if(i=n-c,p||!(i>0)){if(i/=p,0>p){if(h>i)return;g>i&&(g=i)}else if(p>0){if(i>g)return;i>h&&(h=i)}if(i=e-c,p||!(0>i)){if(i/=p,0>p){if(i>g)return;i>h&&(h=i)}else if(p>0){if(h>i)return;g>i&&(g=i)}if(i=t-l,v||!(i>0)){if(i/=v,0>v){if(h>i)return;g>i&&(g=i)}else if(v>0){if(i>g)return;i>h&&(h=i)}if(i=r-l,v||!(0>i)){if(i/=v,0>v){if(i>g)return;i>h&&(h=i)}else if(v>0){if(h>i)return;g>i&&(g=i)}return h>0&&(u.a={x:c+h*p,y:l+h*v}),1>g&&(u.b={x:c+g*p,y:l+g*v}),u}}}}}}function Oe(n,t,e,r){function u(r,u){return ca(r[0]-n)<Na?u>0?0:3:ca(r[0]-e)<Na?u>0?2:1:ca(r[1]-t)<Na?u>0?1:0:u>0?3:2}function i(n,t){return o(n.x,t.x)}function o(n,t){var e=u(n,1),r=u(t,1);return e!==r?e-r:0===e?t[1]-n[1]:1===e?n[0]-t[0]:2===e?n[1]-t[1]:t[0]-n[0]}return function(a){function c(n){for(var t=0,e=d.length,r=n[1],u=0;e>u;++u)for(var i,o=1,a=d[u],c=a.length,l=a[0];c>o;++o)i=a[o],l[1]<=r?i[1]>r&&K(l,i,n)>0&&++t:i[1]<=r&&K(l,i,n)<0&&--t,l=i;return 0!==t}function l(i,a,c,l){var s=0,f=0;if(null==i||(s=u(i,c))!==(f=u(a,c))||o(i,a)<0^c>0){do l.point(0===s||3===s?n:e,s>1?r:t);while((s=(s+c+4)%4)!==f)}else l.point(a[0],a[1])}function s(u,i){return u>=n&&e>=u&&i>=t&&r>=i}function f(n,t){s(n,t)&&a.point(n,t)}function h(){N.point=p,d&&d.push(m=[]),S=!0,w=!1,_=b=0/0}function g(){v&&(p(y,x),M&&w&&A.rejoin(),v.push(A.buffer())),N.point=f,w&&a.lineEnd()}function p(n,t){n=Math.max(-Nc,Math.min(Nc,n)),t=Math.max(-Nc,Math.min(Nc,t));var e=s(n,t);if(d&&m.push([n,t]),S)y=n,x=t,M=e,S=!1,e&&(a.lineStart(),a.point(n,t));else if(e&&w)a.point(n,t);else{var r={a:{x:_,y:b},b:{x:n,y:t}};C(r)?(w||(a.lineStart(),a.point(r.a.x,r.a.y)),a.point(r.b.x,r.b.y),e||a.lineEnd(),k=!1):e&&(a.lineStart(),a.point(n,t),k=!1)}_=n,b=t,w=e}var v,d,m,y,x,M,_,b,w,S,k,E=a,A=qe(),C=He(n,t,e,r),N={point:f,lineStart:h,lineEnd:g,polygonStart:function(){a=A,v=[],d=[],k=!0},polygonEnd:function(){a=E,v=Bo.merge(v);var t=c([n,r]),e=k&&t,u=v.length;(e||u)&&(a.polygonStart(),e&&(a.lineStart(),l(null,null,1,a),a.lineEnd()),u&&Ce(v,i,t,l,a),a.polygonEnd()),v=d=m=null}};return N}}function Ye(n,t){function e(e,r){return e=n(e,r),t(e[0],e[1])}return n.invert&&t.invert&&(e.invert=function(e,r){return e=t.invert(e,r),e&&n.invert(e[0],e[1])}),e}function Ie(n){var t=0,e=Ea/3,r=ir(n),u=r(t,e);return u.parallels=function(n){return arguments.length?r(t=n[0]*Ea/180,e=n[1]*Ea/180):[180*(t/Ea),180*(e/Ea)]},u}function Ze(n,t){function e(n,t){var e=Math.sqrt(i-2*u*Math.sin(t))/u;return[e*Math.sin(n*=u),o-e*Math.cos(n)]}var r=Math.sin(n),u=(r+Math.sin(t))/2,i=1+r*(2*u-r),o=Math.sqrt(i)/u;return e.invert=function(n,t){var e=o-t;return[Math.atan2(n,e)/u,nt((i-(n*n+e*e)*u*u)/(2*u))]},e}function Ve(){function n(n,t){Lc+=u*n-r*t,r=n,u=t}var t,e,r,u;Pc.point=function(i,o){Pc.point=n,t=r=i,e=u=o},Pc.lineEnd=function(){n(t,e)}}function Xe(n,t){Tc>n&&(Tc=n),n>Rc&&(Rc=n),qc>t&&(qc=t),t>Dc&&(Dc=t)}function $e(){function n(n,t){o.push("M",n,",",t,i)}function t(n,t){o.push("M",n,",",t),a.point=e}function e(n,t){o.push("L",n,",",t)}function r(){a.point=n}function u(){o.push("Z")}var i=Be(4.5),o=[],a={point:n,lineStart:function(){a.point=t},lineEnd:r,polygonStart:function(){a.lineEnd=u},polygonEnd:function(){a.lineEnd=r,a.point=n},pointRadius:function(n){return i=Be(n),a},result:function(){if(o.length){var n=o.join("");return o=[],n}}};return a}function Be(n){return"m0,"+n+"a"+n+","+n+" 0 1,1 0,"+-2*n+"a"+n+","+n+" 0 1,1 0,"+2*n+"z"}function We(n,t){yc+=n,xc+=t,++Mc}function Je(){function n(n,r){var u=n-t,i=r-e,o=Math.sqrt(u*u+i*i);_c+=o*(t+n)/2,bc+=o*(e+r)/2,wc+=o,We(t=n,e=r)}var t,e;jc.point=function(r,u){jc.point=n,We(t=r,e=u)}}function Ge(){jc.point=We}function Ke(){function n(n,t){var e=n-r,i=t-u,o=Math.sqrt(e*e+i*i);_c+=o*(r+n)/2,bc+=o*(u+t)/2,wc+=o,o=u*n-r*t,Sc+=o*(r+n),kc+=o*(u+t),Ec+=3*o,We(r=n,u=t)}var t,e,r,u;jc.point=function(i,o){jc.point=n,We(t=r=i,e=u=o)},jc.lineEnd=function(){n(t,e)}}function Qe(n){function t(t,e){n.moveTo(t,e),n.arc(t,e,o,0,Aa)}function e(t,e){n.moveTo(t,e),a.point=r}function r(t,e){n.lineTo(t,e)}function u(){a.point=t}function i(){n.closePath()}var o=4.5,a={point:t,lineStart:function(){a.point=e},lineEnd:u,polygonStart:function(){a.lineEnd=i},polygonEnd:function(){a.lineEnd=u,a.point=t},pointRadius:function(n){return o=n,a},result:y};return a}function nr(n){function t(n){return(a?r:e)(n)}function e(t){return rr(t,function(e,r){e=n(e,r),t.point(e[0],e[1])})}function r(t){function e(e,r){e=n(e,r),t.point(e[0],e[1])}function r(){x=0/0,S.point=i,t.lineStart()}function i(e,r){var i=pe([e,r]),o=n(e,r);u(x,M,y,_,b,w,x=o[0],M=o[1],y=e,_=i[0],b=i[1],w=i[2],a,t),t.point(x,M)}function o(){S.point=e,t.lineEnd()}function c(){r(),S.point=l,S.lineEnd=s}function l(n,t){i(f=n,h=t),g=x,p=M,v=_,d=b,m=w,S.point=i}function s(){u(x,M,y,_,b,w,g,p,f,v,d,m,a,t),S.lineEnd=o,o()}var f,h,g,p,v,d,m,y,x,M,_,b,w,S={point:e,lineStart:r,lineEnd:o,polygonStart:function(){t.polygonStart(),S.lineStart=c},polygonEnd:function(){t.polygonEnd(),S.lineStart=r}};return S}function u(t,e,r,a,c,l,s,f,h,g,p,v,d,m){var y=s-t,x=f-e,M=y*y+x*x;if(M>4*i&&d--){var _=a+g,b=c+p,w=l+v,S=Math.sqrt(_*_+b*b+w*w),k=Math.asin(w/=S),E=ca(ca(w)-1)<Na||ca(r-h)<Na?(r+h)/2:Math.atan2(b,_),A=n(E,k),C=A[0],N=A[1],z=C-t,L=N-e,T=x*z-y*L;
2
+ (T*T/M>i||ca((y*z+x*L)/M-.5)>.3||o>a*g+c*p+l*v)&&(u(t,e,r,a,c,l,C,N,E,_/=S,b/=S,w,d,m),m.point(C,N),u(C,N,E,_,b,w,s,f,h,g,p,v,d,m))}}var i=.5,o=Math.cos(30*La),a=16;return t.precision=function(n){return arguments.length?(a=(i=n*n)>0&&16,t):Math.sqrt(i)},t}function tr(n){var t=nr(function(t,e){return n([t*Ta,e*Ta])});return function(n){return or(t(n))}}function er(n){this.stream=n}function rr(n,t){return{point:t,sphere:function(){n.sphere()},lineStart:function(){n.lineStart()},lineEnd:function(){n.lineEnd()},polygonStart:function(){n.polygonStart()},polygonEnd:function(){n.polygonEnd()}}}function ur(n){return ir(function(){return n})()}function ir(n){function t(n){return n=a(n[0]*La,n[1]*La),[n[0]*h+c,l-n[1]*h]}function e(n){return n=a.invert((n[0]-c)/h,(l-n[1])/h),n&&[n[0]*Ta,n[1]*Ta]}function r(){a=Ye(o=lr(m,y,x),i);var n=i(v,d);return c=g-n[0]*h,l=p+n[1]*h,u()}function u(){return s&&(s.valid=!1,s=null),t}var i,o,a,c,l,s,f=nr(function(n,t){return n=i(n,t),[n[0]*h+c,l-n[1]*h]}),h=150,g=480,p=250,v=0,d=0,m=0,y=0,x=0,M=Cc,_=Et,b=null,w=null;return t.stream=function(n){return s&&(s.valid=!1),s=or(M(o,f(_(n)))),s.valid=!0,s},t.clipAngle=function(n){return arguments.length?(M=null==n?(b=n,Cc):Fe((b=+n)*La),u()):b},t.clipExtent=function(n){return arguments.length?(w=n,_=n?Oe(n[0][0],n[0][1],n[1][0],n[1][1]):Et,u()):w},t.scale=function(n){return arguments.length?(h=+n,r()):h},t.translate=function(n){return arguments.length?(g=+n[0],p=+n[1],r()):[g,p]},t.center=function(n){return arguments.length?(v=n[0]%360*La,d=n[1]%360*La,r()):[v*Ta,d*Ta]},t.rotate=function(n){return arguments.length?(m=n[0]%360*La,y=n[1]%360*La,x=n.length>2?n[2]%360*La:0,r()):[m*Ta,y*Ta,x*Ta]},Bo.rebind(t,f,"precision"),function(){return i=n.apply(this,arguments),t.invert=i.invert&&e,r()}}function or(n){return rr(n,function(t,e){n.point(t*La,e*La)})}function ar(n,t){return[n,t]}function cr(n,t){return[n>Ea?n-Aa:-Ea>n?n+Aa:n,t]}function lr(n,t,e){return n?t||e?Ye(fr(n),hr(t,e)):fr(n):t||e?hr(t,e):cr}function sr(n){return function(t,e){return t+=n,[t>Ea?t-Aa:-Ea>t?t+Aa:t,e]}}function fr(n){var t=sr(n);return t.invert=sr(-n),t}function hr(n,t){function e(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*r+a*u;return[Math.atan2(c*i-s*o,a*r-l*u),nt(s*i+c*o)]}var r=Math.cos(n),u=Math.sin(n),i=Math.cos(t),o=Math.sin(t);return e.invert=function(n,t){var e=Math.cos(t),a=Math.cos(n)*e,c=Math.sin(n)*e,l=Math.sin(t),s=l*i-c*o;return[Math.atan2(c*i+l*o,a*r+s*u),nt(s*r-a*u)]},e}function gr(n,t){var e=Math.cos(n),r=Math.sin(n);return function(u,i,o,a){var c=o*t;null!=u?(u=pr(e,u),i=pr(e,i),(o>0?i>u:u>i)&&(u+=o*Aa)):(u=n+o*Aa,i=n-.5*c);for(var l,s=u;o>0?s>i:i>s;s-=c)a.point((l=Me([e,-r*Math.cos(s),-r*Math.sin(s)]))[0],l[1])}}function pr(n,t){var e=pe(t);e[0]-=n,xe(e);var r=Q(-e[1]);return((-e[2]<0?-r:r)+2*Math.PI-Na)%(2*Math.PI)}function vr(n,t,e){var r=Bo.range(n,t-Na,e).concat(t);return function(n){return r.map(function(t){return[n,t]})}}function dr(n,t,e){var r=Bo.range(n,t-Na,e).concat(t);return function(n){return r.map(function(t){return[t,n]})}}function mr(n){return n.source}function yr(n){return n.target}function xr(n,t,e,r){var u=Math.cos(t),i=Math.sin(t),o=Math.cos(r),a=Math.sin(r),c=u*Math.cos(n),l=u*Math.sin(n),s=o*Math.cos(e),f=o*Math.sin(e),h=2*Math.asin(Math.sqrt(ut(r-t)+u*o*ut(e-n))),g=1/Math.sin(h),p=h?function(n){var t=Math.sin(n*=h)*g,e=Math.sin(h-n)*g,r=e*c+t*s,u=e*l+t*f,o=e*i+t*a;return[Math.atan2(u,r)*Ta,Math.atan2(o,Math.sqrt(r*r+u*u))*Ta]}:function(){return[n*Ta,t*Ta]};return p.distance=h,p}function Mr(){function n(n,u){var i=Math.sin(u*=La),o=Math.cos(u),a=ca((n*=La)-t),c=Math.cos(a);Fc+=Math.atan2(Math.sqrt((a=o*Math.sin(a))*a+(a=r*i-e*o*c)*a),e*i+r*o*c),t=n,e=i,r=o}var t,e,r;Hc.point=function(u,i){t=u*La,e=Math.sin(i*=La),r=Math.cos(i),Hc.point=n},Hc.lineEnd=function(){Hc.point=Hc.lineEnd=y}}function _r(n,t){function e(t,e){var r=Math.cos(t),u=Math.cos(e),i=n(r*u);return[i*u*Math.sin(t),i*Math.sin(e)]}return e.invert=function(n,e){var r=Math.sqrt(n*n+e*e),u=t(r),i=Math.sin(u),o=Math.cos(u);return[Math.atan2(n*i,r*o),Math.asin(r&&e*i/r)]},e}function br(n,t){function e(n,t){o>0?-Ca+Na>t&&(t=-Ca+Na):t>Ca-Na&&(t=Ca-Na);var e=o/Math.pow(u(t),i);return[e*Math.sin(i*n),o-e*Math.cos(i*n)]}var r=Math.cos(n),u=function(n){return Math.tan(Ea/4+n/2)},i=n===t?Math.sin(n):Math.log(r/Math.cos(t))/Math.log(u(t)/u(n)),o=r*Math.pow(u(n),i)/i;return i?(e.invert=function(n,t){var e=o-t,r=G(i)*Math.sqrt(n*n+e*e);return[Math.atan2(n,e)/i,2*Math.atan(Math.pow(o/r,1/i))-Ca]},e):Sr}function wr(n,t){function e(n,t){var e=i-t;return[e*Math.sin(u*n),i-e*Math.cos(u*n)]}var r=Math.cos(n),u=n===t?Math.sin(n):(r-Math.cos(t))/(t-n),i=r/u+n;return ca(u)<Na?ar:(e.invert=function(n,t){var e=i-t;return[Math.atan2(n,e)/u,i-G(u)*Math.sqrt(n*n+e*e)]},e)}function Sr(n,t){return[n,Math.log(Math.tan(Ea/4+t/2))]}function kr(n){var t,e=ur(n),r=e.scale,u=e.translate,i=e.clipExtent;return e.scale=function(){var n=r.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.translate=function(){var n=u.apply(e,arguments);return n===e?t?e.clipExtent(null):e:n},e.clipExtent=function(n){var o=i.apply(e,arguments);if(o===e){if(t=null==n){var a=Ea*r(),c=u();i([[c[0]-a,c[1]-a],[c[0]+a,c[1]+a]])}}else t&&(o=null);return o},e.clipExtent(null)}function Er(n,t){return[Math.log(Math.tan(Ea/4+t/2)),-n]}function Ar(n){return n[0]}function Cr(n){return n[1]}function Nr(n){for(var t=n.length,e=[0,1],r=2,u=2;t>u;u++){for(;r>1&&K(n[e[r-2]],n[e[r-1]],n[u])<=0;)--r;e[r++]=u}return e.slice(0,r)}function zr(n,t){return n[0]-t[0]||n[1]-t[1]}function Lr(n,t,e){return(e[0]-t[0])*(n[1]-t[1])<(e[1]-t[1])*(n[0]-t[0])}function Tr(n,t,e,r){var u=n[0],i=e[0],o=t[0]-u,a=r[0]-i,c=n[1],l=e[1],s=t[1]-c,f=r[1]-l,h=(a*(c-l)-f*(u-i))/(f*o-a*s);return[u+h*o,c+h*s]}function qr(n){var t=n[0],e=n[n.length-1];return!(t[0]-e[0]||t[1]-e[1])}function Rr(){tu(this),this.edge=this.site=this.circle=null}function Dr(n){var t=Kc.pop()||new Rr;return t.site=n,t}function Pr(n){Xr(n),Wc.remove(n),Kc.push(n),tu(n)}function Ur(n){var t=n.circle,e=t.x,r=t.cy,u={x:e,y:r},i=n.P,o=n.N,a=[n];Pr(n);for(var c=i;c.circle&&ca(e-c.circle.x)<Na&&ca(r-c.circle.cy)<Na;)i=c.P,a.unshift(c),Pr(c),c=i;a.unshift(c),Xr(c);for(var l=o;l.circle&&ca(e-l.circle.x)<Na&&ca(r-l.circle.cy)<Na;)o=l.N,a.push(l),Pr(l),l=o;a.push(l),Xr(l);var s,f=a.length;for(s=1;f>s;++s)l=a[s],c=a[s-1],Kr(l.edge,c.site,l.site,u);c=a[0],l=a[f-1],l.edge=Jr(c.site,l.site,null,u),Vr(c),Vr(l)}function jr(n){for(var t,e,r,u,i=n.x,o=n.y,a=Wc._;a;)if(r=Fr(a,o)-i,r>Na)a=a.L;else{if(u=i-Hr(a,o),!(u>Na)){r>-Na?(t=a.P,e=a):u>-Na?(t=a,e=a.N):t=e=a;break}if(!a.R){t=a;break}a=a.R}var c=Dr(n);if(Wc.insert(t,c),t||e){if(t===e)return Xr(t),e=Dr(t.site),Wc.insert(c,e),c.edge=e.edge=Jr(t.site,c.site),Vr(t),Vr(e),void 0;if(!e)return c.edge=Jr(t.site,c.site),void 0;Xr(t),Xr(e);var l=t.site,s=l.x,f=l.y,h=n.x-s,g=n.y-f,p=e.site,v=p.x-s,d=p.y-f,m=2*(h*d-g*v),y=h*h+g*g,x=v*v+d*d,M={x:(d*y-g*x)/m+s,y:(h*x-v*y)/m+f};Kr(e.edge,l,p,M),c.edge=Jr(l,n,null,M),e.edge=Jr(n,p,null,M),Vr(t),Vr(e)}}function Fr(n,t){var e=n.site,r=e.x,u=e.y,i=u-t;if(!i)return r;var o=n.P;if(!o)return-1/0;e=o.site;var a=e.x,c=e.y,l=c-t;if(!l)return a;var s=a-r,f=1/i-1/l,h=s/l;return f?(-h+Math.sqrt(h*h-2*f*(s*s/(-2*l)-c+l/2+u-i/2)))/f+r:(r+a)/2}function Hr(n,t){var e=n.N;if(e)return Fr(e,t);var r=n.site;return r.y===t?r.x:1/0}function Or(n){this.site=n,this.edges=[]}function Yr(n){for(var t,e,r,u,i,o,a,c,l,s,f=n[0][0],h=n[1][0],g=n[0][1],p=n[1][1],v=Bc,d=v.length;d--;)if(i=v[d],i&&i.prepare())for(a=i.edges,c=a.length,o=0;c>o;)s=a[o].end(),r=s.x,u=s.y,l=a[++o%c].start(),t=l.x,e=l.y,(ca(r-t)>Na||ca(u-e)>Na)&&(a.splice(o,0,new Qr(Gr(i.site,s,ca(r-f)<Na&&p-u>Na?{x:f,y:ca(t-f)<Na?e:p}:ca(u-p)<Na&&h-r>Na?{x:ca(e-p)<Na?t:h,y:p}:ca(r-h)<Na&&u-g>Na?{x:h,y:ca(t-h)<Na?e:g}:ca(u-g)<Na&&r-f>Na?{x:ca(e-g)<Na?t:f,y:g}:null),i.site,null)),++c)}function Ir(n,t){return t.angle-n.angle}function Zr(){tu(this),this.x=this.y=this.arc=this.site=this.cy=null}function Vr(n){var t=n.P,e=n.N;if(t&&e){var r=t.site,u=n.site,i=e.site;if(r!==i){var o=u.x,a=u.y,c=r.x-o,l=r.y-a,s=i.x-o,f=i.y-a,h=2*(c*f-l*s);if(!(h>=-za)){var g=c*c+l*l,p=s*s+f*f,v=(f*g-l*p)/h,d=(c*p-s*g)/h,f=d+a,m=Qc.pop()||new Zr;m.arc=n,m.site=u,m.x=v+o,m.y=f+Math.sqrt(v*v+d*d),m.cy=f,n.circle=m;for(var y=null,x=Gc._;x;)if(m.y<x.y||m.y===x.y&&m.x<=x.x){if(!x.L){y=x.P;break}x=x.L}else{if(!x.R){y=x;break}x=x.R}Gc.insert(y,m),y||(Jc=m)}}}}function Xr(n){var t=n.circle;t&&(t.P||(Jc=t.N),Gc.remove(t),Qc.push(t),tu(t),n.circle=null)}function $r(n){for(var t,e=$c,r=He(n[0][0],n[0][1],n[1][0],n[1][1]),u=e.length;u--;)t=e[u],(!Br(t,n)||!r(t)||ca(t.a.x-t.b.x)<Na&&ca(t.a.y-t.b.y)<Na)&&(t.a=t.b=null,e.splice(u,1))}function Br(n,t){var e=n.b;if(e)return!0;var r,u,i=n.a,o=t[0][0],a=t[1][0],c=t[0][1],l=t[1][1],s=n.l,f=n.r,h=s.x,g=s.y,p=f.x,v=f.y,d=(h+p)/2,m=(g+v)/2;if(v===g){if(o>d||d>=a)return;if(h>p){if(i){if(i.y>=l)return}else i={x:d,y:c};e={x:d,y:l}}else{if(i){if(i.y<c)return}else i={x:d,y:l};e={x:d,y:c}}}else if(r=(h-p)/(v-g),u=m-r*d,-1>r||r>1)if(h>p){if(i){if(i.y>=l)return}else i={x:(c-u)/r,y:c};e={x:(l-u)/r,y:l}}else{if(i){if(i.y<c)return}else i={x:(l-u)/r,y:l};e={x:(c-u)/r,y:c}}else if(v>g){if(i){if(i.x>=a)return}else i={x:o,y:r*o+u};e={x:a,y:r*a+u}}else{if(i){if(i.x<o)return}else i={x:a,y:r*a+u};e={x:o,y:r*o+u}}return n.a=i,n.b=e,!0}function Wr(n,t){this.l=n,this.r=t,this.a=this.b=null}function Jr(n,t,e,r){var u=new Wr(n,t);return $c.push(u),e&&Kr(u,n,t,e),r&&Kr(u,t,n,r),Bc[n.i].edges.push(new Qr(u,n,t)),Bc[t.i].edges.push(new Qr(u,t,n)),u}function Gr(n,t,e){var r=new Wr(n,null);return r.a=t,r.b=e,$c.push(r),r}function Kr(n,t,e,r){n.a||n.b?n.l===e?n.b=r:n.a=r:(n.a=r,n.l=t,n.r=e)}function Qr(n,t,e){var r=n.a,u=n.b;this.edge=n,this.site=t,this.angle=e?Math.atan2(e.y-t.y,e.x-t.x):n.l===t?Math.atan2(u.x-r.x,r.y-u.y):Math.atan2(r.x-u.x,u.y-r.y)}function nu(){this._=null}function tu(n){n.U=n.C=n.L=n.R=n.P=n.N=null}function eu(n,t){var e=t,r=t.R,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.R=r.L,e.R&&(e.R.U=e),r.L=e}function ru(n,t){var e=t,r=t.L,u=e.U;u?u.L===e?u.L=r:u.R=r:n._=r,r.U=u,e.U=r,e.L=r.R,e.L&&(e.L.U=e),r.R=e}function uu(n){for(;n.L;)n=n.L;return n}function iu(n,t){var e,r,u,i=n.sort(ou).pop();for($c=[],Bc=new Array(n.length),Wc=new nu,Gc=new nu;;)if(u=Jc,i&&(!u||i.y<u.y||i.y===u.y&&i.x<u.x))(i.x!==e||i.y!==r)&&(Bc[i.i]=new Or(i),jr(i),e=i.x,r=i.y),i=n.pop();else{if(!u)break;Ur(u.arc)}t&&($r(t),Yr(t));var o={cells:Bc,edges:$c};return Wc=Gc=$c=Bc=null,o}function ou(n,t){return t.y-n.y||t.x-n.x}function au(n,t,e){return(n.x-e.x)*(t.y-n.y)-(n.x-t.x)*(e.y-n.y)}function cu(n){return n.x}function lu(n){return n.y}function su(){return{leaf:!0,nodes:[],point:null,x:null,y:null}}function fu(n,t,e,r,u,i){if(!n(t,e,r,u,i)){var o=.5*(e+u),a=.5*(r+i),c=t.nodes;c[0]&&fu(n,c[0],e,r,o,a),c[1]&&fu(n,c[1],o,r,u,a),c[2]&&fu(n,c[2],e,a,o,i),c[3]&&fu(n,c[3],o,a,u,i)}}function hu(n,t){n=Bo.rgb(n),t=Bo.rgb(t);var e=n.r,r=n.g,u=n.b,i=t.r-e,o=t.g-r,a=t.b-u;return function(n){return"#"+xt(Math.round(e+i*n))+xt(Math.round(r+o*n))+xt(Math.round(u+a*n))}}function gu(n,t){var e,r={},u={};for(e in n)e in t?r[e]=du(n[e],t[e]):u[e]=n[e];for(e in t)e in n||(u[e]=t[e]);return function(n){for(e in r)u[e]=r[e](n);return u}}function pu(n,t){return n=+n,t=+t,function(e){return n*(1-e)+t*e}}function vu(n,t){var e,r,u,i=tl.lastIndex=el.lastIndex=0,o=-1,a=[],c=[];for(n+="",t+="";(e=tl.exec(n))&&(r=el.exec(t));)(u=r.index)>i&&(u=t.slice(i,u),a[o]?a[o]+=u:a[++o]=u),(e=e[0])===(r=r[0])?a[o]?a[o]+=r:a[++o]=r:(a[++o]=null,c.push({i:o,x:pu(e,r)})),i=el.lastIndex;return i<t.length&&(u=t.slice(i),a[o]?a[o]+=u:a[++o]=u),a.length<2?c[0]?(t=c[0].x,function(n){return t(n)+""}):function(){return t}:(t=c.length,function(n){for(var e,r=0;t>r;++r)a[(e=c[r]).i]=e.x(n);return a.join("")})}function du(n,t){for(var e,r=Bo.interpolators.length;--r>=0&&!(e=Bo.interpolators[r](n,t)););return e}function mu(n,t){var e,r=[],u=[],i=n.length,o=t.length,a=Math.min(n.length,t.length);for(e=0;a>e;++e)r.push(du(n[e],t[e]));for(;i>e;++e)u[e]=n[e];for(;o>e;++e)u[e]=t[e];return function(n){for(e=0;a>e;++e)u[e]=r[e](n);return u}}function yu(n){return function(t){return 0>=t?0:t>=1?1:n(t)}}function xu(n){return function(t){return 1-n(1-t)}}function Mu(n){return function(t){return.5*(.5>t?n(2*t):2-n(2-2*t))}}function _u(n){return n*n}function bu(n){return n*n*n}function wu(n){if(0>=n)return 0;if(n>=1)return 1;var t=n*n,e=t*n;return 4*(.5>n?e:3*(n-t)+e-.75)}function Su(n){return function(t){return Math.pow(t,n)}}function ku(n){return 1-Math.cos(n*Ca)}function Eu(n){return Math.pow(2,10*(n-1))}function Au(n){return 1-Math.sqrt(1-n*n)}function Cu(n,t){var e;return arguments.length<2&&(t=.45),arguments.length?e=t/Aa*Math.asin(1/n):(n=1,e=t/4),function(r){return 1+n*Math.pow(2,-10*r)*Math.sin((r-e)*Aa/t)}}function Nu(n){return n||(n=1.70158),function(t){return t*t*((n+1)*t-n)}}function zu(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375}function Lu(n,t){n=Bo.hcl(n),t=Bo.hcl(t);var e=n.h,r=n.c,u=n.l,i=t.h-e,o=t.c-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.c:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return lt(e+i*n,r+o*n,u+a*n)+""}}function Tu(n,t){n=Bo.hsl(n),t=Bo.hsl(t);var e=n.h,r=n.s,u=n.l,i=t.h-e,o=t.s-r,a=t.l-u;return isNaN(o)&&(o=0,r=isNaN(r)?t.s:r),isNaN(i)?(i=0,e=isNaN(e)?t.h:e):i>180?i-=360:-180>i&&(i+=360),function(n){return at(e+i*n,r+o*n,u+a*n)+""}}function qu(n,t){n=Bo.lab(n),t=Bo.lab(t);var e=n.l,r=n.a,u=n.b,i=t.l-e,o=t.a-r,a=t.b-u;return function(n){return ft(e+i*n,r+o*n,u+a*n)+""}}function Ru(n,t){return t-=n,function(e){return Math.round(n+t*e)}}function Du(n){var t=[n.a,n.b],e=[n.c,n.d],r=Uu(t),u=Pu(t,e),i=Uu(ju(e,t,-u))||0;t[0]*e[1]<e[0]*t[1]&&(t[0]*=-1,t[1]*=-1,r*=-1,u*=-1),this.rotate=(r?Math.atan2(t[1],t[0]):Math.atan2(-e[0],e[1]))*Ta,this.translate=[n.e,n.f],this.scale=[r,i],this.skew=i?Math.atan2(u,i)*Ta:0}function Pu(n,t){return n[0]*t[0]+n[1]*t[1]}function Uu(n){var t=Math.sqrt(Pu(n,n));return t&&(n[0]/=t,n[1]/=t),t}function ju(n,t,e){return n[0]+=e*t[0],n[1]+=e*t[1],n}function Fu(n,t){var e,r=[],u=[],i=Bo.transform(n),o=Bo.transform(t),a=i.translate,c=o.translate,l=i.rotate,s=o.rotate,f=i.skew,h=o.skew,g=i.scale,p=o.scale;return a[0]!=c[0]||a[1]!=c[1]?(r.push("translate(",null,",",null,")"),u.push({i:1,x:pu(a[0],c[0])},{i:3,x:pu(a[1],c[1])})):c[0]||c[1]?r.push("translate("+c+")"):r.push(""),l!=s?(l-s>180?s+=360:s-l>180&&(l+=360),u.push({i:r.push(r.pop()+"rotate(",null,")")-2,x:pu(l,s)})):s&&r.push(r.pop()+"rotate("+s+")"),f!=h?u.push({i:r.push(r.pop()+"skewX(",null,")")-2,x:pu(f,h)}):h&&r.push(r.pop()+"skewX("+h+")"),g[0]!=p[0]||g[1]!=p[1]?(e=r.push(r.pop()+"scale(",null,",",null,")"),u.push({i:e-4,x:pu(g[0],p[0])},{i:e-2,x:pu(g[1],p[1])})):(1!=p[0]||1!=p[1])&&r.push(r.pop()+"scale("+p+")"),e=u.length,function(n){for(var t,i=-1;++i<e;)r[(t=u[i]).i]=t.x(n);return r.join("")}}function Hu(n,t){return t=(t-=n=+n)||1/t,function(e){return(e-n)/t}}function Ou(n,t){return t=(t-=n=+n)||1/t,function(e){return Math.max(0,Math.min(1,(e-n)/t))}}function Yu(n){for(var t=n.source,e=n.target,r=Zu(t,e),u=[t];t!==r;)t=t.parent,u.push(t);for(var i=u.length;e!==r;)u.splice(i,0,e),e=e.parent;return u}function Iu(n){for(var t=[],e=n.parent;null!=e;)t.push(n),n=e,e=e.parent;return t.push(n),t}function Zu(n,t){if(n===t)return n;for(var e=Iu(n),r=Iu(t),u=e.pop(),i=r.pop(),o=null;u===i;)o=u,u=e.pop(),i=r.pop();return o}function Vu(n){n.fixed|=2}function Xu(n){n.fixed&=-7}function $u(n){n.fixed|=4,n.px=n.x,n.py=n.y}function Bu(n){n.fixed&=-5}function Wu(n,t,e){var r=0,u=0;if(n.charge=0,!n.leaf)for(var i,o=n.nodes,a=o.length,c=-1;++c<a;)i=o[c],null!=i&&(Wu(i,t,e),n.charge+=i.charge,r+=i.charge*i.cx,u+=i.charge*i.cy);if(n.point){n.leaf||(n.point.x+=Math.random()-.5,n.point.y+=Math.random()-.5);var l=t*e[n.point.index];n.charge+=n.pointCharge=l,r+=l*n.point.x,u+=l*n.point.y}n.cx=r/n.charge,n.cy=u/n.charge}function Ju(n,t){return Bo.rebind(n,t,"sort","children","value"),n.nodes=n,n.links=ei,n}function Gu(n,t){for(var e=[n];null!=(n=e.pop());)if(t(n),(u=n.children)&&(r=u.length))for(var r,u;--r>=0;)e.push(u[r])}function Ku(n,t){for(var e=[n],r=[];null!=(n=e.pop());)if(r.push(n),(i=n.children)&&(u=i.length))for(var u,i,o=-1;++o<u;)e.push(i[o]);for(;null!=(n=r.pop());)t(n)}function Qu(n){return n.children}function ni(n){return n.value}function ti(n,t){return t.value-n.value}function ei(n){return Bo.merge(n.map(function(n){return(n.children||[]).map(function(t){return{source:n,target:t}})}))}function ri(n){return n.x}function ui(n){return n.y}function ii(n,t,e){n.y0=t,n.y=e}function oi(n){return Bo.range(n.length)}function ai(n){for(var t=-1,e=n[0].length,r=[];++t<e;)r[t]=0;return r}function ci(n){for(var t,e=1,r=0,u=n[0][1],i=n.length;i>e;++e)(t=n[e][1])>u&&(r=e,u=t);return r}function li(n){return n.reduce(si,0)}function si(n,t){return n+t[1]}function fi(n,t){return hi(n,Math.ceil(Math.log(t.length)/Math.LN2+1))}function hi(n,t){for(var e=-1,r=+n[0],u=(n[1]-r)/t,i=[];++e<=t;)i[e]=u*e+r;return i}function gi(n){return[Bo.min(n),Bo.max(n)]}function pi(n,t){return n.value-t.value}function vi(n,t){var e=n._pack_next;n._pack_next=t,t._pack_prev=n,t._pack_next=e,e._pack_prev=t}function di(n,t){n._pack_next=t,t._pack_prev=n}function mi(n,t){var e=t.x-n.x,r=t.y-n.y,u=n.r+t.r;return.999*u*u>e*e+r*r}function yi(n){function t(n){s=Math.min(n.x-n.r,s),f=Math.max(n.x+n.r,f),h=Math.min(n.y-n.r,h),g=Math.max(n.y+n.r,g)}if((e=n.children)&&(l=e.length)){var e,r,u,i,o,a,c,l,s=1/0,f=-1/0,h=1/0,g=-1/0;if(e.forEach(xi),r=e[0],r.x=-r.r,r.y=0,t(r),l>1&&(u=e[1],u.x=u.r,u.y=0,t(u),l>2))for(i=e[2],bi(r,u,i),t(i),vi(r,i),r._pack_prev=i,vi(i,u),u=r._pack_next,o=3;l>o;o++){bi(r,u,i=e[o]);var p=0,v=1,d=1;for(a=u._pack_next;a!==u;a=a._pack_next,v++)if(mi(a,i)){p=1;break}if(1==p)for(c=r._pack_prev;c!==a._pack_prev&&!mi(c,i);c=c._pack_prev,d++);p?(d>v||v==d&&u.r<r.r?di(r,u=a):di(r=c,u),o--):(vi(r,i),u=i,t(i))}var m=(s+f)/2,y=(h+g)/2,x=0;for(o=0;l>o;o++)i=e[o],i.x-=m,i.y-=y,x=Math.max(x,i.r+Math.sqrt(i.x*i.x+i.y*i.y));n.r=x,e.forEach(Mi)}}function xi(n){n._pack_next=n._pack_prev=n}function Mi(n){delete n._pack_next,delete n._pack_prev}function _i(n,t,e,r){var u=n.children;if(n.x=t+=r*n.x,n.y=e+=r*n.y,n.r*=r,u)for(var i=-1,o=u.length;++i<o;)_i(u[i],t,e,r)}function bi(n,t,e){var r=n.r+e.r,u=t.x-n.x,i=t.y-n.y;if(r&&(u||i)){var o=t.r+e.r,a=u*u+i*i;o*=o,r*=r;var c=.5+(r-o)/(2*a),l=Math.sqrt(Math.max(0,2*o*(r+a)-(r-=a)*r-o*o))/(2*a);e.x=n.x+c*u+l*i,e.y=n.y+c*i-l*u}else e.x=n.x+r,e.y=n.y}function wi(n,t){return n.parent==t.parent?1:2}function Si(n){var t=n.children;return t.length?t[0]:n.t}function ki(n){var t,e=n.children;return(t=e.length)?e[t-1]:n.t}function Ei(n,t,e){var r=e/(t.i-n.i);t.c-=r,t.s+=e,n.c+=r,t.z+=e,t.m+=e}function Ai(n){for(var t,e=0,r=0,u=n.children,i=u.length;--i>=0;)t=u[i],t.z+=e,t.m+=e,e+=t.s+(r+=t.c)}function Ci(n,t,e){return n.a.parent===t.parent?n.a:e}function Ni(n){return 1+Bo.max(n,function(n){return n.y})}function zi(n){return n.reduce(function(n,t){return n+t.x},0)/n.length}function Li(n){var t=n.children;return t&&t.length?Li(t[0]):n}function Ti(n){var t,e=n.children;return e&&(t=e.length)?Ti(e[t-1]):n}function qi(n){return{x:n.x,y:n.y,dx:n.dx,dy:n.dy}}function Ri(n,t){var e=n.x+t[3],r=n.y+t[0],u=n.dx-t[1]-t[3],i=n.dy-t[0]-t[2];return 0>u&&(e+=u/2,u=0),0>i&&(r+=i/2,i=0),{x:e,y:r,dx:u,dy:i}}function Di(n){var t=n[0],e=n[n.length-1];return e>t?[t,e]:[e,t]}function Pi(n){return n.rangeExtent?n.rangeExtent():Di(n.range())}function Ui(n,t,e,r){var u=e(n[0],n[1]),i=r(t[0],t[1]);return function(n){return i(u(n))}}function ji(n,t){var e,r=0,u=n.length-1,i=n[r],o=n[u];return i>o&&(e=r,r=u,u=e,e=i,i=o,o=e),n[r]=t.floor(i),n[u]=t.ceil(o),n}function Fi(n){return n?{floor:function(t){return Math.floor(t/n)*n},ceil:function(t){return Math.ceil(t/n)*n}}:gl}function Hi(n,t,e,r){var u=[],i=[],o=0,a=Math.min(n.length,t.length)-1;for(n[a]<n[0]&&(n=n.slice().reverse(),t=t.slice().reverse());++o<=a;)u.push(e(n[o-1],n[o])),i.push(r(t[o-1],t[o]));return function(t){var e=Bo.bisect(n,t,1,a)-1;return i[e](u[e](t))}}function Oi(n,t,e,r){function u(){var u=Math.min(n.length,t.length)>2?Hi:Ui,c=r?Ou:Hu;return o=u(n,t,c,e),a=u(t,n,c,du),i}function i(n){return o(n)}var o,a;return i.invert=function(n){return a(n)},i.domain=function(t){return arguments.length?(n=t.map(Number),u()):n},i.range=function(n){return arguments.length?(t=n,u()):t},i.rangeRound=function(n){return i.range(n).interpolate(Ru)},i.clamp=function(n){return arguments.length?(r=n,u()):r},i.interpolate=function(n){return arguments.length?(e=n,u()):e},i.ticks=function(t){return Vi(n,t)},i.tickFormat=function(t,e){return Xi(n,t,e)},i.nice=function(t){return Ii(n,t),u()},i.copy=function(){return Oi(n,t,e,r)},u()}function Yi(n,t){return Bo.rebind(n,t,"range","rangeRound","interpolate","clamp")}function Ii(n,t){return ji(n,Fi(Zi(n,t)[2]))}function Zi(n,t){null==t&&(t=10);var e=Di(n),r=e[1]-e[0],u=Math.pow(10,Math.floor(Math.log(r/t)/Math.LN10)),i=t/r*u;return.15>=i?u*=10:.35>=i?u*=5:.75>=i&&(u*=2),e[0]=Math.ceil(e[0]/u)*u,e[1]=Math.floor(e[1]/u)*u+.5*u,e[2]=u,e}function Vi(n,t){return Bo.range.apply(Bo,Zi(n,t))}function Xi(n,t,e){var r=Zi(n,t);if(e){var u=tc.exec(e);if(u.shift(),"s"===u[8]){var i=Bo.formatPrefix(Math.max(ca(r[0]),ca(r[1])));return u[7]||(u[7]="."+$i(i.scale(r[2]))),u[8]="f",e=Bo.format(u.join("")),function(n){return e(i.scale(n))+i.symbol}}u[7]||(u[7]="."+Bi(u[8],r)),e=u.join("")}else e=",."+$i(r[2])+"f";return Bo.format(e)}function $i(n){return-Math.floor(Math.log(n)/Math.LN10+.01)}function Bi(n,t){var e=$i(t[2]);return n in pl?Math.abs(e-$i(Math.max(ca(t[0]),ca(t[1]))))+ +("e"!==n):e-2*("%"===n)}function Wi(n,t,e,r){function u(n){return(e?Math.log(0>n?0:n):-Math.log(n>0?0:-n))/Math.log(t)}function i(n){return e?Math.pow(t,n):-Math.pow(t,-n)}function o(t){return n(u(t))}return o.invert=function(t){return i(n.invert(t))},o.domain=function(t){return arguments.length?(e=t[0]>=0,n.domain((r=t.map(Number)).map(u)),o):r},o.base=function(e){return arguments.length?(t=+e,n.domain(r.map(u)),o):t},o.nice=function(){var t=ji(r.map(u),e?Math:dl);return n.domain(t),r=t.map(i),o},o.ticks=function(){var n=Di(r),o=[],a=n[0],c=n[1],l=Math.floor(u(a)),s=Math.ceil(u(c)),f=t%1?2:t;if(isFinite(s-l)){if(e){for(;s>l;l++)for(var h=1;f>h;h++)o.push(i(l)*h);o.push(i(l))}else for(o.push(i(l));l++<s;)for(var h=f-1;h>0;h--)o.push(i(l)*h);for(l=0;o[l]<a;l++);for(s=o.length;o[s-1]>c;s--);o=o.slice(l,s)}return o},o.tickFormat=function(n,t){if(!arguments.length)return vl;arguments.length<2?t=vl:"function"!=typeof t&&(t=Bo.format(t));var r,a=Math.max(.1,n/o.ticks().length),c=e?(r=1e-12,Math.ceil):(r=-1e-12,Math.floor);return function(n){return n/i(c(u(n)+r))<=a?t(n):""}},o.copy=function(){return Wi(n.copy(),t,e,r)},Yi(o,n)}function Ji(n,t,e){function r(t){return n(u(t))}var u=Gi(t),i=Gi(1/t);return r.invert=function(t){return i(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain((e=t.map(Number)).map(u)),r):e},r.ticks=function(n){return Vi(e,n)},r.tickFormat=function(n,t){return Xi(e,n,t)},r.nice=function(n){return r.domain(Ii(e,n))},r.exponent=function(o){return arguments.length?(u=Gi(t=o),i=Gi(1/t),n.domain(e.map(u)),r):t},r.copy=function(){return Ji(n.copy(),t,e)},Yi(r,n)}function Gi(n){return function(t){return 0>t?-Math.pow(-t,n):Math.pow(t,n)}}function Ki(n,t){function e(e){return i[((u.get(e)||("range"===t.t?u.set(e,n.push(e)):0/0))-1)%i.length]}function r(t,e){return Bo.range(n.length).map(function(n){return t+e*n})}var u,i,o;return e.domain=function(r){if(!arguments.length)return n;n=[],u=new a;for(var i,o=-1,c=r.length;++o<c;)u.has(i=r[o])||u.set(i,n.push(i));return e[t.t].apply(e,t.a)},e.range=function(n){return arguments.length?(i=n,o=0,t={t:"range",a:arguments},e):i},e.rangePoints=function(u,a){arguments.length<2&&(a=0);var c=u[0],l=u[1],s=(l-c)/(Math.max(1,n.length-1)+a);return i=r(n.length<2?(c+l)/2:c+s*a/2,s),o=0,t={t:"rangePoints",a:arguments},e},e.rangeBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=(f-s)/(n.length-a+2*c);return i=r(s+h*c,h),l&&i.reverse(),o=h*(1-a),t={t:"rangeBands",a:arguments},e},e.rangeRoundBands=function(u,a,c){arguments.length<2&&(a=0),arguments.length<3&&(c=a);var l=u[1]<u[0],s=u[l-0],f=u[1-l],h=Math.floor((f-s)/(n.length-a+2*c)),g=f-s-(n.length-a)*h;return i=r(s+Math.round(g/2),h),l&&i.reverse(),o=Math.round(h*(1-a)),t={t:"rangeRoundBands",a:arguments},e},e.rangeBand=function(){return o},e.rangeExtent=function(){return Di(t.a[0])},e.copy=function(){return Ki(n,t)},e.domain(n)}function Qi(r,u){function i(){var n=0,t=u.length;for(a=[];++n<t;)a[n-1]=Bo.quantile(r,n/t);return o}function o(n){return isNaN(n=+n)?void 0:u[Bo.bisect(a,n)]}var a;return o.domain=function(u){return arguments.length?(r=u.map(t).filter(e).sort(n),i()):r},o.range=function(n){return arguments.length?(u=n,i()):u},o.quantiles=function(){return a},o.invertExtent=function(n){return n=u.indexOf(n),0>n?[0/0,0/0]:[n>0?a[n-1]:r[0],n<a.length?a[n]:r[r.length-1]]},o.copy=function(){return Qi(r,u)},i()}function no(n,t,e){function r(t){return e[Math.max(0,Math.min(o,Math.floor(i*(t-n))))]}function u(){return i=e.length/(t-n),o=e.length-1,r}var i,o;return r.domain=function(e){return arguments.length?(n=+e[0],t=+e[e.length-1],u()):[n,t]},r.range=function(n){return arguments.length?(e=n,u()):e},r.invertExtent=function(t){return t=e.indexOf(t),t=0>t?0/0:t/i+n,[t,t+1/i]},r.copy=function(){return no(n,t,e)},u()}function to(n,t){function e(e){return e>=e?t[Bo.bisect(n,e)]:void 0}return e.domain=function(t){return arguments.length?(n=t,e):n},e.range=function(n){return arguments.length?(t=n,e):t},e.invertExtent=function(e){return e=t.indexOf(e),[n[e-1],n[e]]},e.copy=function(){return to(n,t)},e}function eo(n){function t(n){return+n}return t.invert=t,t.domain=t.range=function(e){return arguments.length?(n=e.map(t),t):n},t.ticks=function(t){return Vi(n,t)},t.tickFormat=function(t,e){return Xi(n,t,e)},t.copy=function(){return eo(n)},t}function ro(n){return n.innerRadius}function uo(n){return n.outerRadius}function io(n){return n.startAngle}function oo(n){return n.endAngle}function ao(n){function t(t){function o(){l.push("M",i(n(s),a))}for(var c,l=[],s=[],f=-1,h=t.length,g=kt(e),p=kt(r);++f<h;)u.call(this,c=t[f],f)?s.push([+g.call(this,c,f),+p.call(this,c,f)]):s.length&&(o(),s=[]);return s.length&&o(),l.length?l.join(""):null}var e=Ar,r=Cr,u=Ae,i=co,o=i.key,a=.7;return t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t.defined=function(n){return arguments.length?(u=n,t):u},t.interpolate=function(n){return arguments.length?(o="function"==typeof n?i=n:(i=wl.get(n)||co).key,t):o},t.tension=function(n){return arguments.length?(a=n,t):a},t}function co(n){return n.join("L")}function lo(n){return co(n)+"Z"}function so(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r[0]+(r=n[t])[0])/2,"V",r[1]);return e>1&&u.push("H",r[0]),u.join("")}function fo(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("V",(r=n[t])[1],"H",r[0]);return u.join("")}function ho(n){for(var t=0,e=n.length,r=n[0],u=[r[0],",",r[1]];++t<e;)u.push("H",(r=n[t])[0],"V",r[1]);return u.join("")}function go(n,t){return n.length<4?co(n):n[1]+mo(n.slice(1,n.length-1),yo(n,t))}function po(n,t){return n.length<3?co(n):n[0]+mo((n.push(n[0]),n),yo([n[n.length-2]].concat(n,[n[1]]),t))}function vo(n,t){return n.length<3?co(n):n[0]+mo(n,yo(n,t))}function mo(n,t){if(t.length<1||n.length!=t.length&&n.length!=t.length+2)return co(n);var e=n.length!=t.length,r="",u=n[0],i=n[1],o=t[0],a=o,c=1;if(e&&(r+="Q"+(i[0]-2*o[0]/3)+","+(i[1]-2*o[1]/3)+","+i[0]+","+i[1],u=n[1],c=2),t.length>1){a=t[1],i=n[c],c++,r+="C"+(u[0]+o[0])+","+(u[1]+o[1])+","+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1];for(var l=2;l<t.length;l++,c++)i=n[c],a=t[l],r+="S"+(i[0]-a[0])+","+(i[1]-a[1])+","+i[0]+","+i[1]}if(e){var s=n[c];r+="Q"+(i[0]+2*a[0]/3)+","+(i[1]+2*a[1]/3)+","+s[0]+","+s[1]}return r}function yo(n,t){for(var e,r=[],u=(1-t)/2,i=n[0],o=n[1],a=1,c=n.length;++a<c;)e=i,i=o,o=n[a],r.push([u*(o[0]-e[0]),u*(o[1]-e[1])]);return r}function xo(n){if(n.length<3)return co(n);var t=1,e=n.length,r=n[0],u=r[0],i=r[1],o=[u,u,u,(r=n[1])[0]],a=[i,i,i,r[1]],c=[u,",",i,"L",wo(El,o),",",wo(El,a)];for(n.push(n[e-1]);++t<=e;)r=n[t],o.shift(),o.push(r[0]),a.shift(),a.push(r[1]),So(c,o,a);return n.pop(),c.push("L",r),c.join("")}function Mo(n){if(n.length<4)return co(n);for(var t,e=[],r=-1,u=n.length,i=[0],o=[0];++r<3;)t=n[r],i.push(t[0]),o.push(t[1]);for(e.push(wo(El,i)+","+wo(El,o)),--r;++r<u;)t=n[r],i.shift(),i.push(t[0]),o.shift(),o.push(t[1]),So(e,i,o);return e.join("")}function _o(n){for(var t,e,r=-1,u=n.length,i=u+4,o=[],a=[];++r<4;)e=n[r%u],o.push(e[0]),a.push(e[1]);for(t=[wo(El,o),",",wo(El,a)],--r;++r<i;)e=n[r%u],o.shift(),o.push(e[0]),a.shift(),a.push(e[1]),So(t,o,a);return t.join("")}function bo(n,t){var e=n.length-1;if(e)for(var r,u,i=n[0][0],o=n[0][1],a=n[e][0]-i,c=n[e][1]-o,l=-1;++l<=e;)r=n[l],u=l/e,r[0]=t*r[0]+(1-t)*(i+u*a),r[1]=t*r[1]+(1-t)*(o+u*c);return xo(n)}function wo(n,t){return n[0]*t[0]+n[1]*t[1]+n[2]*t[2]+n[3]*t[3]}function So(n,t,e){n.push("C",wo(Sl,t),",",wo(Sl,e),",",wo(kl,t),",",wo(kl,e),",",wo(El,t),",",wo(El,e))}function ko(n,t){return(t[1]-n[1])/(t[0]-n[0])}function Eo(n){for(var t=0,e=n.length-1,r=[],u=n[0],i=n[1],o=r[0]=ko(u,i);++t<e;)r[t]=(o+(o=ko(u=i,i=n[t+1])))/2;return r[t]=o,r}function Ao(n){for(var t,e,r,u,i=[],o=Eo(n),a=-1,c=n.length-1;++a<c;)t=ko(n[a],n[a+1]),ca(t)<Na?o[a]=o[a+1]=0:(e=o[a]/t,r=o[a+1]/t,u=e*e+r*r,u>9&&(u=3*t/Math.sqrt(u),o[a]=u*e,o[a+1]=u*r));for(a=-1;++a<=c;)u=(n[Math.min(c,a+1)][0]-n[Math.max(0,a-1)][0])/(6*(1+o[a]*o[a])),i.push([u||0,o[a]*u||0]);return i}function Co(n){return n.length<3?co(n):n[0]+mo(n,Ao(n))}function No(n){for(var t,e,r,u=-1,i=n.length;++u<i;)t=n[u],e=t[0],r=t[1]+_l,t[0]=e*Math.cos(r),t[1]=e*Math.sin(r);return n}function zo(n){function t(t){function c(){v.push("M",a(n(m),f),s,l(n(d.reverse()),f),"Z")}for(var h,g,p,v=[],d=[],m=[],y=-1,x=t.length,M=kt(e),_=kt(u),b=e===r?function(){return g}:kt(r),w=u===i?function(){return p}:kt(i);++y<x;)o.call(this,h=t[y],y)?(d.push([g=+M.call(this,h,y),p=+_.call(this,h,y)]),m.push([+b.call(this,h,y),+w.call(this,h,y)])):d.length&&(c(),d=[],m=[]);return d.length&&c(),v.length?v.join(""):null}var e=Ar,r=Ar,u=0,i=Cr,o=Ae,a=co,c=a.key,l=a,s="L",f=.7;return t.x=function(n){return arguments.length?(e=r=n,t):r},t.x0=function(n){return arguments.length?(e=n,t):e},t.x1=function(n){return arguments.length?(r=n,t):r},t.y=function(n){return arguments.length?(u=i=n,t):i},t.y0=function(n){return arguments.length?(u=n,t):u},t.y1=function(n){return arguments.length?(i=n,t):i},t.defined=function(n){return arguments.length?(o=n,t):o},t.interpolate=function(n){return arguments.length?(c="function"==typeof n?a=n:(a=wl.get(n)||co).key,l=a.reverse||a,s=a.closed?"M":"L",t):c},t.tension=function(n){return arguments.length?(f=n,t):f},t}function Lo(n){return n.radius}function To(n){return[n.x,n.y]}function qo(n){return function(){var t=n.apply(this,arguments),e=t[0],r=t[1]+_l;return[e*Math.cos(r),e*Math.sin(r)]}}function Ro(){return 64}function Do(){return"circle"}function Po(n){var t=Math.sqrt(n/Ea);return"M0,"+t+"A"+t+","+t+" 0 1,1 0,"+-t+"A"+t+","+t+" 0 1,1 0,"+t+"Z"}function Uo(n,t){return ga(n,Tl),n.id=t,n}function jo(n,t,e,r){var u=n.id;return F(n,"function"==typeof e?function(n,i,o){n.__transition__[u].tween.set(t,r(e.call(n,n.__data__,i,o)))}:(e=r(e),function(n){n.__transition__[u].tween.set(t,e)}))}function Fo(n){return null==n&&(n=""),function(){this.textContent=n}}function Ho(n,t,e,r){var u=n.__transition__||(n.__transition__={active:0,count:0}),i=u[e];if(!i){var o=r.time;i=u[e]={tween:new a,time:o,ease:r.ease,delay:r.delay,duration:r.duration},++u.count,Bo.timer(function(r){function a(r){return u.active>e?l():(u.active=e,i.event&&i.event.start.call(n,s,t),i.tween.forEach(function(e,r){(r=r.call(n,s,t))&&v.push(r)
3
+ }),Bo.timer(function(){return p.c=c(r||1)?Ae:c,1},0,o),void 0)}function c(r){if(u.active!==e)return l();for(var o=r/g,a=f(o),c=v.length;c>0;)v[--c].call(n,a);return o>=1?(i.event&&i.event.end.call(n,s,t),l()):void 0}function l(){return--u.count?delete u[e]:delete n.__transition__,1}var s=n.__data__,f=i.ease,h=i.delay,g=i.duration,p=Ka,v=[];return p.t=h+o,r>=h?a(r-h):(p.c=a,void 0)},0,o)}}function Oo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate("+(isFinite(r)?r:e(n))+",0)"})}function Yo(n,t,e){n.attr("transform",function(n){var r=t(n);return"translate(0,"+(isFinite(r)?r:e(n))+")"})}function Io(n){return n.toISOString()}function Zo(n,t,e){function r(t){return n(t)}function u(n,e){var r=n[1]-n[0],u=r/e,i=Bo.bisect(Ol,u);return i==Ol.length?[t.year,Zi(n.map(function(n){return n/31536e6}),e)[2]]:i?t[u/Ol[i-1]<Ol[i]/u?i-1:i]:[Zl,Zi(n,e)[2]]}return r.invert=function(t){return Vo(n.invert(t))},r.domain=function(t){return arguments.length?(n.domain(t),r):n.domain().map(Vo)},r.nice=function(n,t){function e(e){return!isNaN(e)&&!n.range(e,Vo(+e+1),t).length}var i=r.domain(),o=Di(i),a=null==n?u(o,10):"number"==typeof n&&u(o,n);return a&&(n=a[0],t=a[1]),r.domain(ji(i,t>1?{floor:function(t){for(;e(t=n.floor(t));)t=Vo(t-1);return t},ceil:function(t){for(;e(t=n.ceil(t));)t=Vo(+t+1);return t}}:n))},r.ticks=function(n,t){var e=Di(r.domain()),i=null==n?u(e,10):"number"==typeof n?u(e,n):!n.range&&[{range:n},t];return i&&(n=i[0],t=i[1]),n.range(e[0],Vo(+e[1]+1),1>t?1:t)},r.tickFormat=function(){return e},r.copy=function(){return Zo(n.copy(),t,e)},Yi(r,n)}function Vo(n){return new Date(n)}function Xo(n){return JSON.parse(n.responseText)}function $o(n){var t=Go.createRange();return t.selectNode(Go.body),t.createContextualFragment(n.responseText)}var Bo={version:"3.4.13"};Date.now||(Date.now=function(){return+new Date});var Wo=[].slice,Jo=function(n){return Wo.call(n)},Go=document,Ko=Go.documentElement,Qo=window;try{Jo(Ko.childNodes)[0].nodeType}catch(na){Jo=function(n){for(var t=n.length,e=new Array(t);t--;)e[t]=n[t];return e}}try{Go.createElement("div").style.setProperty("opacity",0,"")}catch(ta){var ea=Qo.Element.prototype,ra=ea.setAttribute,ua=ea.setAttributeNS,ia=Qo.CSSStyleDeclaration.prototype,oa=ia.setProperty;ea.setAttribute=function(n,t){ra.call(this,n,t+"")},ea.setAttributeNS=function(n,t,e){ua.call(this,n,t,e+"")},ia.setProperty=function(n,t,e){oa.call(this,n,t+"",e)}}Bo.ascending=n,Bo.descending=function(n,t){return n>t?-1:t>n?1:t>=n?0:0/0},Bo.min=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&e>r&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&e>r&&(e=r)}return e},Bo.max=function(n,t){var e,r,u=-1,i=n.length;if(1===arguments.length){for(;++u<i&&!(null!=(e=n[u])&&e>=e);)e=void 0;for(;++u<i;)null!=(r=n[u])&&r>e&&(e=r)}else{for(;++u<i&&!(null!=(e=t.call(n,n[u],u))&&e>=e);)e=void 0;for(;++u<i;)null!=(r=t.call(n,n[u],u))&&r>e&&(e=r)}return e},Bo.extent=function(n,t){var e,r,u,i=-1,o=n.length;if(1===arguments.length){for(;++i<o&&!(null!=(e=u=n[i])&&e>=e);)e=u=void 0;for(;++i<o;)null!=(r=n[i])&&(e>r&&(e=r),r>u&&(u=r))}else{for(;++i<o&&!(null!=(e=u=t.call(n,n[i],i))&&e>=e);)e=void 0;for(;++i<o;)null!=(r=t.call(n,n[i],i))&&(e>r&&(e=r),r>u&&(u=r))}return[e,u]},Bo.sum=function(n,t){var r,u=0,i=n.length,o=-1;if(1===arguments.length)for(;++o<i;)e(r=+n[o])&&(u+=r);else for(;++o<i;)e(r=+t.call(n,n[o],o))&&(u+=r);return u},Bo.mean=function(n,r){var u,i=0,o=n.length,a=-1,c=o;if(1===arguments.length)for(;++a<o;)e(u=t(n[a]))?i+=u:--c;else for(;++a<o;)e(u=t(r.call(n,n[a],a)))?i+=u:--c;return c?i/c:void 0},Bo.quantile=function(n,t){var e=(n.length-1)*t+1,r=Math.floor(e),u=+n[r-1],i=e-r;return i?u+i*(n[r]-u):u},Bo.median=function(r,u){var i,o=[],a=r.length,c=-1;if(1===arguments.length)for(;++c<a;)e(i=t(r[c]))&&o.push(i);else for(;++c<a;)e(i=t(u.call(r,r[c],c)))&&o.push(i);return o.length?Bo.quantile(o.sort(n),.5):void 0};var aa=r(n);Bo.bisectLeft=aa.left,Bo.bisect=Bo.bisectRight=aa.right,Bo.bisector=function(t){return r(1===t.length?function(e,r){return n(t(e),r)}:t)},Bo.shuffle=function(n){for(var t,e,r=n.length;r;)e=0|Math.random()*r--,t=n[r],n[r]=n[e],n[e]=t;return n},Bo.permute=function(n,t){for(var e=t.length,r=new Array(e);e--;)r[e]=n[t[e]];return r},Bo.pairs=function(n){for(var t,e=0,r=n.length-1,u=n[0],i=new Array(0>r?0:r);r>e;)i[e]=[t=u,u=n[++e]];return i},Bo.zip=function(){if(!(r=arguments.length))return[];for(var n=-1,t=Bo.min(arguments,u),e=new Array(t);++n<t;)for(var r,i=-1,o=e[n]=new Array(r);++i<r;)o[i]=arguments[i][n];return e},Bo.transpose=function(n){return Bo.zip.apply(Bo,n)},Bo.keys=function(n){var t=[];for(var e in n)t.push(e);return t},Bo.values=function(n){var t=[];for(var e in n)t.push(n[e]);return t},Bo.entries=function(n){var t=[];for(var e in n)t.push({key:e,value:n[e]});return t},Bo.merge=function(n){for(var t,e,r,u=n.length,i=-1,o=0;++i<u;)o+=n[i].length;for(e=new Array(o);--u>=0;)for(r=n[u],t=r.length;--t>=0;)e[--o]=r[t];return e};var ca=Math.abs;Bo.range=function(n,t,e){if(arguments.length<3&&(e=1,arguments.length<2&&(t=n,n=0)),1/0===(t-n)/e)throw new Error("infinite range");var r,u=[],o=i(ca(e)),a=-1;if(n*=o,t*=o,e*=o,0>e)for(;(r=n+e*++a)>t;)u.push(r/o);else for(;(r=n+e*++a)<t;)u.push(r/o);return u},Bo.map=function(n){var t=new a;if(n instanceof a)n.forEach(function(n,e){t.set(n,e)});else for(var e in n)t.set(e,n[e]);return t};var la="__proto__",sa="\x00";o(a,{has:s,get:function(n){return this._[c(n)]},set:function(n,t){return this._[c(n)]=t},remove:f,keys:h,values:function(){var n=[];for(var t in this._)n.push(this._[t]);return n},entries:function(){var n=[];for(var t in this._)n.push({key:l(t),value:this._[t]});return n},size:g,empty:p,forEach:function(n){for(var t in this._)n.call(this,l(t),this._[t])}}),Bo.nest=function(){function n(t,o,c){if(c>=i.length)return r?r.call(u,o):e?o.sort(e):o;for(var l,s,f,h,g=-1,p=o.length,v=i[c++],d=new a;++g<p;)(h=d.get(l=v(s=o[g])))?h.push(s):d.set(l,[s]);return t?(s=t(),f=function(e,r){s.set(e,n(t,r,c))}):(s={},f=function(e,r){s[e]=n(t,r,c)}),d.forEach(f),s}function t(n,e){if(e>=i.length)return n;var r=[],u=o[e++];return n.forEach(function(n,u){r.push({key:n,values:t(u,e)})}),u?r.sort(function(n,t){return u(n.key,t.key)}):r}var e,r,u={},i=[],o=[];return u.map=function(t,e){return n(e,t,0)},u.entries=function(e){return t(n(Bo.map,e,0),0)},u.key=function(n){return i.push(n),u},u.sortKeys=function(n){return o[i.length-1]=n,u},u.sortValues=function(n){return e=n,u},u.rollup=function(n){return r=n,u},u},Bo.set=function(n){var t=new v;if(n)for(var e=0,r=n.length;r>e;++e)t.add(n[e]);return t},o(v,{has:s,add:function(n){return this._[c(n+="")]=!0,n},remove:f,values:h,size:g,empty:p,forEach:function(n){for(var t in this._)n.call(this,l(t))}}),Bo.behavior={},Bo.rebind=function(n,t){for(var e,r=1,u=arguments.length;++r<u;)n[e=arguments[r]]=d(n,t,t[e]);return n};var fa=["webkit","ms","moz","Moz","o","O"];Bo.dispatch=function(){for(var n=new x,t=-1,e=arguments.length;++t<e;)n[arguments[t]]=M(n);return n},x.prototype.on=function(n,t){var e=n.indexOf("."),r="";if(e>=0&&(r=n.slice(e+1),n=n.slice(0,e)),n)return arguments.length<2?this[n].on(r):this[n].on(r,t);if(2===arguments.length){if(null==t)for(n in this)this.hasOwnProperty(n)&&this[n].on(r,null);return this}},Bo.event=null,Bo.requote=function(n){return n.replace(ha,"\\$&")};var ha=/[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g,ga={}.__proto__?function(n,t){n.__proto__=t}:function(n,t){for(var e in t)n[e]=t[e]},pa=function(n,t){return t.querySelector(n)},va=function(n,t){return t.querySelectorAll(n)},da=Ko.matches||Ko[m(Ko,"matchesSelector")],ma=function(n,t){return da.call(n,t)};"function"==typeof Sizzle&&(pa=function(n,t){return Sizzle(n,t)[0]||null},va=Sizzle,ma=Sizzle.matchesSelector),Bo.selection=function(){return _a};var ya=Bo.selection.prototype=[];ya.select=function(n){var t,e,r,u,i=[];n=k(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]),t.parentNode=(r=this[o]).parentNode;for(var c=-1,l=r.length;++c<l;)(u=r[c])?(t.push(e=n.call(u,u.__data__,c,o)),e&&"__data__"in u&&(e.__data__=u.__data__)):t.push(null)}return S(i)},ya.selectAll=function(n){var t,e,r=[];n=E(n);for(var u=-1,i=this.length;++u<i;)for(var o=this[u],a=-1,c=o.length;++a<c;)(e=o[a])&&(r.push(t=Jo(n.call(e,e.__data__,a,u))),t.parentNode=e);return S(r)};var xa={svg:"http://www.w3.org/2000/svg",xhtml:"http://www.w3.org/1999/xhtml",xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};Bo.ns={prefix:xa,qualify:function(n){var t=n.indexOf(":"),e=n;return t>=0&&(e=n.slice(0,t),n=n.slice(t+1)),xa.hasOwnProperty(e)?{space:xa[e],local:n}:n}},ya.attr=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node();return n=Bo.ns.qualify(n),n.local?e.getAttributeNS(n.space,n.local):e.getAttribute(n)}for(t in n)this.each(A(t,n[t]));return this}return this.each(A(n,t))},ya.classed=function(n,t){if(arguments.length<2){if("string"==typeof n){var e=this.node(),r=(n=z(n)).length,u=-1;if(t=e.classList){for(;++u<r;)if(!t.contains(n[u]))return!1}else for(t=e.getAttribute("class");++u<r;)if(!N(n[u]).test(t))return!1;return!0}for(t in n)this.each(L(t,n[t]));return this}return this.each(L(n,t))},ya.style=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t="");for(e in n)this.each(q(e,n[e],t));return this}if(2>r)return Qo.getComputedStyle(this.node(),null).getPropertyValue(n);e=""}return this.each(q(n,t,e))},ya.property=function(n,t){if(arguments.length<2){if("string"==typeof n)return this.node()[n];for(t in n)this.each(R(t,n[t]));return this}return this.each(R(n,t))},ya.text=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.textContent=null==t?"":t}:null==n?function(){this.textContent=""}:function(){this.textContent=n}):this.node().textContent},ya.html=function(n){return arguments.length?this.each("function"==typeof n?function(){var t=n.apply(this,arguments);this.innerHTML=null==t?"":t}:null==n?function(){this.innerHTML=""}:function(){this.innerHTML=n}):this.node().innerHTML},ya.append=function(n){return n=D(n),this.select(function(){return this.appendChild(n.apply(this,arguments))})},ya.insert=function(n,t){return n=D(n),t=k(t),this.select(function(){return this.insertBefore(n.apply(this,arguments),t.apply(this,arguments)||null)})},ya.remove=function(){return this.each(function(){var n=this.parentNode;n&&n.removeChild(this)})},ya.data=function(n,t){function e(n,e){var r,u,i,o=n.length,f=e.length,h=Math.min(o,f),g=new Array(f),p=new Array(f),v=new Array(o);if(t){var d,m=new a,y=new Array(o);for(r=-1;++r<o;)m.has(d=t.call(u=n[r],u.__data__,r))?v[r]=u:m.set(d,u),y[r]=d;for(r=-1;++r<f;)(u=m.get(d=t.call(e,i=e[r],r)))?u!==!0&&(g[r]=u,u.__data__=i):p[r]=P(i),m.set(d,!0);for(r=-1;++r<o;)m.get(y[r])!==!0&&(v[r]=n[r])}else{for(r=-1;++r<h;)u=n[r],i=e[r],u?(u.__data__=i,g[r]=u):p[r]=P(i);for(;f>r;++r)p[r]=P(e[r]);for(;o>r;++r)v[r]=n[r]}p.update=g,p.parentNode=g.parentNode=v.parentNode=n.parentNode,c.push(p),l.push(g),s.push(v)}var r,u,i=-1,o=this.length;if(!arguments.length){for(n=new Array(o=(r=this[0]).length);++i<o;)(u=r[i])&&(n[i]=u.__data__);return n}var c=H([]),l=S([]),s=S([]);if("function"==typeof n)for(;++i<o;)e(r=this[i],n.call(r,r.parentNode.__data__,i));else for(;++i<o;)e(r=this[i],n);return l.enter=function(){return c},l.exit=function(){return s},l},ya.datum=function(n){return arguments.length?this.property("__data__",n):this.property("__data__")},ya.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=U(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]),t.parentNode=(e=this[i]).parentNode;for(var a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return S(u)},ya.order=function(){for(var n=-1,t=this.length;++n<t;)for(var e,r=this[n],u=r.length-1,i=r[u];--u>=0;)(e=r[u])&&(i&&i!==e.nextSibling&&i.parentNode.insertBefore(e,i),i=e);return this},ya.sort=function(n){n=j.apply(this,arguments);for(var t=-1,e=this.length;++t<e;)this[t].sort(n);return this.order()},ya.each=function(n){return F(this,function(t,e,r){n.call(t,t.__data__,e,r)})},ya.call=function(n){var t=Jo(arguments);return n.apply(t[0]=this,t),this},ya.empty=function(){return!this.node()},ya.node=function(){for(var n=0,t=this.length;t>n;n++)for(var e=this[n],r=0,u=e.length;u>r;r++){var i=e[r];if(i)return i}return null},ya.size=function(){var n=0;return F(this,function(){++n}),n};var Ma=[];Bo.selection.enter=H,Bo.selection.enter.prototype=Ma,Ma.append=ya.append,Ma.empty=ya.empty,Ma.node=ya.node,Ma.call=ya.call,Ma.size=ya.size,Ma.select=function(n){for(var t,e,r,u,i,o=[],a=-1,c=this.length;++a<c;){r=(u=this[a]).update,o.push(t=[]),t.parentNode=u.parentNode;for(var l=-1,s=u.length;++l<s;)(i=u[l])?(t.push(r[l]=e=n.call(u.parentNode,i.__data__,l,a)),e.__data__=i.__data__):t.push(null)}return S(o)},Ma.insert=function(n,t){return arguments.length<2&&(t=O(this)),ya.insert.call(this,n,t)},ya.transition=function(){for(var n,t,e=Cl||++ql,r=[],u=Nl||{time:Date.now(),ease:wu,delay:0,duration:250},i=-1,o=this.length;++i<o;){r.push(n=[]);for(var a=this[i],c=-1,l=a.length;++c<l;)(t=a[c])&&Ho(t,c,e,u),n.push(t)}return Uo(r,e)},ya.interrupt=function(){return this.each(Y)},Bo.select=function(n){var t=["string"==typeof n?pa(n,Go):n];return t.parentNode=Ko,S([t])},Bo.selectAll=function(n){var t=Jo("string"==typeof n?va(n,Go):n);return t.parentNode=Ko,S([t])};var _a=Bo.select(Ko);ya.on=function(n,t,e){var r=arguments.length;if(3>r){if("string"!=typeof n){2>r&&(t=!1);for(e in n)this.each(I(e,n[e],t));return this}if(2>r)return(r=this.node()["__on"+n])&&r._;e=!1}return this.each(I(n,t,e))};var ba=Bo.map({mouseenter:"mouseover",mouseleave:"mouseout"});ba.forEach(function(n){"on"+n in Go&&ba.remove(n)});var wa="onselectstart"in Go?null:m(Ko.style,"userSelect"),Sa=0;Bo.mouse=function(n){return $(n,b())};var ka=/WebKit/.test(Qo.navigator.userAgent)?-1:0;Bo.touch=function(n,t,e){if(arguments.length<3&&(e=t,t=b().changedTouches),t)for(var r,u=0,i=t.length;i>u;++u)if((r=t[u]).identifier===e)return $(n,r)},Bo.behavior.drag=function(){function n(){this.on("mousedown.drag",u).on("touchstart.drag",i)}function t(n,t,u,i,o){return function(){function a(){var n,e,r=t(h,v);r&&(n=r[0]-x[0],e=r[1]-x[1],p|=n|e,x=r,g({type:"drag",x:r[0]+l[0],y:r[1]+l[1],dx:n,dy:e}))}function c(){t(h,v)&&(m.on(i+d,null).on(o+d,null),y(p&&Bo.event.target===f),g({type:"dragend"}))}var l,s=this,f=Bo.event.target,h=s.parentNode,g=e.of(s,arguments),p=0,v=n(),d=".drag"+(null==v?"":"-"+v),m=Bo.select(u()).on(i+d,a).on(o+d,c),y=X(),x=t(h,v);r?(l=r.apply(s,arguments),l=[l.x-x[0],l.y-x[1]]):l=[0,0],g({type:"dragstart"})}}var e=w(n,"drag","dragstart","dragend"),r=null,u=t(y,Bo.mouse,J,"mousemove","mouseup"),i=t(B,Bo.touch,W,"touchmove","touchend");return n.origin=function(t){return arguments.length?(r=t,n):r},Bo.rebind(n,e,"on")},Bo.touches=function(n,t){return arguments.length<2&&(t=b().touches),t?Jo(t).map(function(t){var e=$(n,t);return e.identifier=t.identifier,e}):[]};var Ea=Math.PI,Aa=2*Ea,Ca=Ea/2,Na=1e-6,za=Na*Na,La=Ea/180,Ta=180/Ea,qa=Math.SQRT2,Ra=2,Da=4;Bo.interpolateZoom=function(n,t){function e(n){var t=n*y;if(m){var e=et(v),o=i/(Ra*h)*(e*rt(qa*t+v)-tt(v));return[r+o*l,u+o*s,i*e/et(qa*t+v)]}return[r+n*l,u+n*s,i*Math.exp(qa*t)]}var r=n[0],u=n[1],i=n[2],o=t[0],a=t[1],c=t[2],l=o-r,s=a-u,f=l*l+s*s,h=Math.sqrt(f),g=(c*c-i*i+Da*f)/(2*i*Ra*h),p=(c*c-i*i-Da*f)/(2*c*Ra*h),v=Math.log(Math.sqrt(g*g+1)-g),d=Math.log(Math.sqrt(p*p+1)-p),m=d-v,y=(m||Math.log(c/i))/qa;return e.duration=1e3*y,e},Bo.behavior.zoom=function(){function n(n){n.on(A,l).on(ja+".zoom",f).on("dblclick.zoom",h).on(z,s)}function t(n){return[(n[0]-S.x)/S.k,(n[1]-S.y)/S.k]}function e(n){return[n[0]*S.k+S.x,n[1]*S.k+S.y]}function r(n){S.k=Math.max(E[0],Math.min(E[1],n))}function u(n,t){t=e(t),S.x+=n[0]-t[0],S.y+=n[1]-t[1]}function i(){x&&x.domain(y.range().map(function(n){return(n-S.x)/S.k}).map(y.invert)),b&&b.domain(M.range().map(function(n){return(n-S.y)/S.k}).map(M.invert))}function o(n){n({type:"zoomstart"})}function a(n){i(),n({type:"zoom",scale:S.k,translate:[S.x,S.y]})}function c(n){n({type:"zoomend"})}function l(){function n(){s=1,u(Bo.mouse(r),h),a(l)}function e(){f.on(C,null).on(N,null),g(s&&Bo.event.target===i),c(l)}var r=this,i=Bo.event.target,l=L.of(r,arguments),s=0,f=Bo.select(Qo).on(C,n).on(N,e),h=t(Bo.mouse(r)),g=X();Y.call(r),o(l)}function s(){function n(){var n=Bo.touches(g);return h=S.k,n.forEach(function(n){n.identifier in v&&(v[n.identifier]=t(n))}),n}function e(){var t=Bo.event.target;Bo.select(t).on(x,i).on(M,f),b.push(t);for(var e=Bo.event.changedTouches,o=0,c=e.length;c>o;++o)v[e[o].identifier]=null;var l=n(),s=Date.now();if(1===l.length){if(500>s-m){var h=l[0],g=v[h.identifier];r(2*S.k),u(h,g),_(),a(p)}m=s}else if(l.length>1){var h=l[0],y=l[1],w=h[0]-y[0],k=h[1]-y[1];d=w*w+k*k}}function i(){for(var n,t,e,i,o=Bo.touches(g),c=0,l=o.length;l>c;++c,i=null)if(e=o[c],i=v[e.identifier]){if(t)break;n=e,t=i}if(i){var s=(s=e[0]-n[0])*s+(s=e[1]-n[1])*s,f=d&&Math.sqrt(s/d);n=[(n[0]+e[0])/2,(n[1]+e[1])/2],t=[(t[0]+i[0])/2,(t[1]+i[1])/2],r(f*h)}m=null,u(n,t),a(p)}function f(){if(Bo.event.touches.length){for(var t=Bo.event.changedTouches,e=0,r=t.length;r>e;++e)delete v[t[e].identifier];for(var u in v)return void n()}Bo.selectAll(b).on(y,null),w.on(A,l).on(z,s),k(),c(p)}var h,g=this,p=L.of(g,arguments),v={},d=0,y=".zoom-"+Bo.event.changedTouches[0].identifier,x="touchmove"+y,M="touchend"+y,b=[],w=Bo.select(g),k=X();Y.call(g),e(),o(p),w.on(A,null).on(z,e)}function f(){var n=L.of(this,arguments);d?clearTimeout(d):(g=t(p=v||Bo.mouse(this)),Y.call(this),o(n)),d=setTimeout(function(){d=null,c(n)},50),_(),r(Math.pow(2,.002*Pa())*S.k),u(p,g),a(n)}function h(){var n=L.of(this,arguments),e=Bo.mouse(this),i=t(e),l=Math.log(S.k)/Math.LN2;o(n),r(Math.pow(2,Bo.event.shiftKey?Math.ceil(l)-1:Math.floor(l)+1)),u(e,i),a(n),c(n)}var g,p,v,d,m,y,x,M,b,S={x:0,y:0,k:1},k=[960,500],E=Ua,A="mousedown.zoom",C="mousemove.zoom",N="mouseup.zoom",z="touchstart.zoom",L=w(n,"zoomstart","zoom","zoomend");return n.event=function(n){n.each(function(){var n=L.of(this,arguments),t=S;Cl?Bo.select(this).transition().each("start.zoom",function(){S=this.__chart__||{x:0,y:0,k:1},o(n)}).tween("zoom:zoom",function(){var e=k[0],r=k[1],u=e/2,i=r/2,o=Bo.interpolateZoom([(u-S.x)/S.k,(i-S.y)/S.k,e/S.k],[(u-t.x)/t.k,(i-t.y)/t.k,e/t.k]);return function(t){var r=o(t),c=e/r[2];this.__chart__=S={x:u-r[0]*c,y:i-r[1]*c,k:c},a(n)}}).each("end.zoom",function(){c(n)}):(this.__chart__=S,o(n),a(n),c(n))})},n.translate=function(t){return arguments.length?(S={x:+t[0],y:+t[1],k:S.k},i(),n):[S.x,S.y]},n.scale=function(t){return arguments.length?(S={x:S.x,y:S.y,k:+t},i(),n):S.k},n.scaleExtent=function(t){return arguments.length?(E=null==t?Ua:[+t[0],+t[1]],n):E},n.center=function(t){return arguments.length?(v=t&&[+t[0],+t[1]],n):v},n.size=function(t){return arguments.length?(k=t&&[+t[0],+t[1]],n):k},n.x=function(t){return arguments.length?(x=t,y=t.copy(),S={x:0,y:0,k:1},n):x},n.y=function(t){return arguments.length?(b=t,M=t.copy(),S={x:0,y:0,k:1},n):b},Bo.rebind(n,L,"on")};var Pa,Ua=[0,1/0],ja="onwheel"in Go?(Pa=function(){return-Bo.event.deltaY*(Bo.event.deltaMode?120:1)},"wheel"):"onmousewheel"in Go?(Pa=function(){return Bo.event.wheelDelta},"mousewheel"):(Pa=function(){return-Bo.event.detail},"MozMousePixelScroll");Bo.color=it,it.prototype.toString=function(){return this.rgb()+""},Bo.hsl=ot;var Fa=ot.prototype=new it;Fa.brighter=function(n){return n=Math.pow(.7,arguments.length?n:1),new ot(this.h,this.s,this.l/n)},Fa.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new ot(this.h,this.s,n*this.l)},Fa.rgb=function(){return at(this.h,this.s,this.l)},Bo.hcl=ct;var Ha=ct.prototype=new it;Ha.brighter=function(n){return new ct(this.h,this.c,Math.min(100,this.l+Oa*(arguments.length?n:1)))},Ha.darker=function(n){return new ct(this.h,this.c,Math.max(0,this.l-Oa*(arguments.length?n:1)))},Ha.rgb=function(){return lt(this.h,this.c,this.l).rgb()},Bo.lab=st;var Oa=18,Ya=.95047,Ia=1,Za=1.08883,Va=st.prototype=new it;Va.brighter=function(n){return new st(Math.min(100,this.l+Oa*(arguments.length?n:1)),this.a,this.b)},Va.darker=function(n){return new st(Math.max(0,this.l-Oa*(arguments.length?n:1)),this.a,this.b)},Va.rgb=function(){return ft(this.l,this.a,this.b)},Bo.rgb=dt;var Xa=dt.prototype=new it;Xa.brighter=function(n){n=Math.pow(.7,arguments.length?n:1);var t=this.r,e=this.g,r=this.b,u=30;return t||e||r?(t&&u>t&&(t=u),e&&u>e&&(e=u),r&&u>r&&(r=u),new dt(Math.min(255,t/n),Math.min(255,e/n),Math.min(255,r/n))):new dt(u,u,u)},Xa.darker=function(n){return n=Math.pow(.7,arguments.length?n:1),new dt(n*this.r,n*this.g,n*this.b)},Xa.hsl=function(){return _t(this.r,this.g,this.b)},Xa.toString=function(){return"#"+xt(this.r)+xt(this.g)+xt(this.b)};var $a=Bo.map({aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074});$a.forEach(function(n,t){$a.set(n,mt(t))}),Bo.functor=kt,Bo.xhr=At(Et),Bo.dsv=function(n,t){function e(n,e,i){arguments.length<3&&(i=e,e=null);var o=Ct(n,t,null==e?r:u(e),i);return o.row=function(n){return arguments.length?o.response(null==(e=n)?r:u(n)):e},o}function r(n){return e.parse(n.responseText)}function u(n){return function(t){return e.parse(t.responseText,n)}}function i(t){return t.map(o).join(n)}function o(n){return a.test(n)?'"'+n.replace(/\"/g,'""')+'"':n}var a=new RegExp('["'+n+"\n]"),c=n.charCodeAt(0);return e.parse=function(n,t){var r;return e.parseRows(n,function(n,e){if(r)return r(n,e-1);var u=new Function("d","return {"+n.map(function(n,t){return JSON.stringify(n)+": d["+t+"]"}).join(",")+"}");r=t?function(n,e){return t(u(n),e)}:u})},e.parseRows=function(n,t){function e(){if(s>=l)return o;if(u)return u=!1,i;var t=s;if(34===n.charCodeAt(t)){for(var e=t;e++<l;)if(34===n.charCodeAt(e)){if(34!==n.charCodeAt(e+1))break;++e}s=e+2;var r=n.charCodeAt(e+1);return 13===r?(u=!0,10===n.charCodeAt(e+2)&&++s):10===r&&(u=!0),n.slice(t+1,e).replace(/""/g,'"')}for(;l>s;){var r=n.charCodeAt(s++),a=1;if(10===r)u=!0;else if(13===r)u=!0,10===n.charCodeAt(s)&&(++s,++a);else if(r!==c)continue;return n.slice(t,s-a)}return n.slice(t)}for(var r,u,i={},o={},a=[],l=n.length,s=0,f=0;(r=e())!==o;){for(var h=[];r!==i&&r!==o;)h.push(r),r=e();t&&null==(h=t(h,f++))||a.push(h)}return a},e.format=function(t){if(Array.isArray(t[0]))return e.formatRows(t);var r=new v,u=[];return t.forEach(function(n){for(var t in n)r.has(t)||u.push(r.add(t))}),[u.map(o).join(n)].concat(t.map(function(t){return u.map(function(n){return o(t[n])}).join(n)})).join("\n")},e.formatRows=function(n){return n.map(i).join("\n")},e},Bo.csv=Bo.dsv(",","text/csv"),Bo.tsv=Bo.dsv(" ","text/tab-separated-values");var Ba,Wa,Ja,Ga,Ka,Qa=Qo[m(Qo,"requestAnimationFrame")]||function(n){setTimeout(n,17)};Bo.timer=function(n,t,e){var r=arguments.length;2>r&&(t=0),3>r&&(e=Date.now());var u=e+t,i={c:n,t:u,f:!1,n:null};Wa?Wa.n=i:Ba=i,Wa=i,Ja||(Ga=clearTimeout(Ga),Ja=1,Qa(Lt))},Bo.timer.flush=function(){Tt(),qt()},Bo.round=function(n,t){return t?Math.round(n*(t=Math.pow(10,t)))/t:Math.round(n)};var nc=["y","z","a","f","p","n","\xb5","m","","k","M","G","T","P","E","Z","Y"].map(Dt);Bo.formatPrefix=function(n,t){var e=0;return n&&(0>n&&(n*=-1),t&&(n=Bo.round(n,Rt(n,t))),e=1+Math.floor(1e-12+Math.log(n)/Math.LN10),e=Math.max(-24,Math.min(24,3*Math.floor((e-1)/3)))),nc[8+e/3]};var tc=/(?:([^{])?([<>=^]))?([+\- ])?([$#])?(0)?(\d+)?(,)?(\.-?\d+)?([a-z%])?/i,ec=Bo.map({b:function(n){return n.toString(2)},c:function(n){return String.fromCharCode(n)},o:function(n){return n.toString(8)},x:function(n){return n.toString(16)},X:function(n){return n.toString(16).toUpperCase()},g:function(n,t){return n.toPrecision(t)},e:function(n,t){return n.toExponential(t)},f:function(n,t){return n.toFixed(t)},r:function(n,t){return(n=Bo.round(n,Rt(n,t))).toFixed(Math.max(0,Math.min(20,Rt(n*(1+1e-15),t))))}}),rc=Bo.time={},uc=Date;jt.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){ic.setUTCDate.apply(this._,arguments)},setDay:function(){ic.setUTCDay.apply(this._,arguments)},setFullYear:function(){ic.setUTCFullYear.apply(this._,arguments)},setHours:function(){ic.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){ic.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){ic.setUTCMinutes.apply(this._,arguments)},setMonth:function(){ic.setUTCMonth.apply(this._,arguments)},setSeconds:function(){ic.setUTCSeconds.apply(this._,arguments)},setTime:function(){ic.setTime.apply(this._,arguments)}};var ic=Date.prototype;rc.year=Ft(function(n){return n=rc.day(n),n.setMonth(0,1),n},function(n,t){n.setFullYear(n.getFullYear()+t)},function(n){return n.getFullYear()}),rc.years=rc.year.range,rc.years.utc=rc.year.utc.range,rc.day=Ft(function(n){var t=new uc(2e3,0);return t.setFullYear(n.getFullYear(),n.getMonth(),n.getDate()),t},function(n,t){n.setDate(n.getDate()+t)},function(n){return n.getDate()-1}),rc.days=rc.day.range,rc.days.utc=rc.day.utc.range,rc.dayOfYear=function(n){var t=rc.year(n);return Math.floor((n-t-6e4*(n.getTimezoneOffset()-t.getTimezoneOffset()))/864e5)},["sunday","monday","tuesday","wednesday","thursday","friday","saturday"].forEach(function(n,t){t=7-t;var e=rc[n]=Ft(function(n){return(n=rc.day(n)).setDate(n.getDate()-(n.getDay()+t)%7),n},function(n,t){n.setDate(n.getDate()+7*Math.floor(t))},function(n){var e=rc.year(n).getDay();return Math.floor((rc.dayOfYear(n)+(e+t)%7)/7)-(e!==t)});rc[n+"s"]=e.range,rc[n+"s"].utc=e.utc.range,rc[n+"OfYear"]=function(n){var e=rc.year(n).getDay();return Math.floor((rc.dayOfYear(n)+(e+t)%7)/7)}}),rc.week=rc.sunday,rc.weeks=rc.sunday.range,rc.weeks.utc=rc.sunday.utc.range,rc.weekOfYear=rc.sundayOfYear;var oc={"-":"",_:" ",0:"0"},ac=/^\s*\d+/,cc=/^%/;Bo.locale=function(n){return{numberFormat:Pt(n),timeFormat:Ot(n)}};var lc=Bo.locale({decimal:".",thousands:",",grouping:[3],currency:["$",""],dateTime:"%a %b %e %X %Y",date:"%m/%d/%Y",time:"%H:%M:%S",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});Bo.format=lc.numberFormat,Bo.geo={},ce.prototype={s:0,t:0,add:function(n){le(n,this.t,sc),le(sc.s,this.s,this),this.s?this.t+=sc.t:this.s=sc.t},reset:function(){this.s=this.t=0},valueOf:function(){return this.s}};var sc=new ce;Bo.geo.stream=function(n,t){n&&fc.hasOwnProperty(n.type)?fc[n.type](n,t):se(n,t)};var fc={Feature:function(n,t){se(n.geometry,t)},FeatureCollection:function(n,t){for(var e=n.features,r=-1,u=e.length;++r<u;)se(e[r].geometry,t)}},hc={Sphere:function(n,t){t.sphere()},Point:function(n,t){n=n.coordinates,t.point(n[0],n[1],n[2])},MultiPoint:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)n=e[r],t.point(n[0],n[1],n[2])},LineString:function(n,t){fe(n.coordinates,t,0)},MultiLineString:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)fe(e[r],t,0)},Polygon:function(n,t){he(n.coordinates,t)},MultiPolygon:function(n,t){for(var e=n.coordinates,r=-1,u=e.length;++r<u;)he(e[r],t)},GeometryCollection:function(n,t){for(var e=n.geometries,r=-1,u=e.length;++r<u;)se(e[r],t)}};Bo.geo.area=function(n){return gc=0,Bo.geo.stream(n,vc),gc};var gc,pc=new ce,vc={sphere:function(){gc+=4*Ea},point:y,lineStart:y,lineEnd:y,polygonStart:function(){pc.reset(),vc.lineStart=ge},polygonEnd:function(){var n=2*pc;gc+=0>n?4*Ea+n:n,vc.lineStart=vc.lineEnd=vc.point=y}};Bo.geo.bounds=function(){function n(n,t){x.push(M=[s=n,h=n]),f>t&&(f=t),t>g&&(g=t)}function t(t,e){var r=pe([t*La,e*La]);if(m){var u=de(m,r),i=[u[1],-u[0],0],o=de(i,u);xe(o),o=Me(o);var c=t-p,l=c>0?1:-1,v=o[0]*Ta*l,d=ca(c)>180;if(d^(v>l*p&&l*t>v)){var y=o[1]*Ta;y>g&&(g=y)}else if(v=(v+360)%360-180,d^(v>l*p&&l*t>v)){var y=-o[1]*Ta;f>y&&(f=y)}else f>e&&(f=e),e>g&&(g=e);d?p>t?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t):h>=s?(s>t&&(s=t),t>h&&(h=t)):t>p?a(s,t)>a(s,h)&&(h=t):a(t,h)>a(s,h)&&(s=t)}else n(t,e);m=r,p=t}function e(){_.point=t}function r(){M[0]=s,M[1]=h,_.point=n,m=null}function u(n,e){if(m){var r=n-p;y+=ca(r)>180?r+(r>0?360:-360):r}else v=n,d=e;vc.point(n,e),t(n,e)}function i(){vc.lineStart()}function o(){u(v,d),vc.lineEnd(),ca(y)>Na&&(s=-(h=180)),M[0]=s,M[1]=h,m=null}function a(n,t){return(t-=n)<0?t+360:t}function c(n,t){return n[0]-t[0]}function l(n,t){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var s,f,h,g,p,v,d,m,y,x,M,_={point:n,lineStart:e,lineEnd:r,polygonStart:function(){_.point=u,_.lineStart=i,_.lineEnd=o,y=0,vc.polygonStart()},polygonEnd:function(){vc.polygonEnd(),_.point=n,_.lineStart=e,_.lineEnd=r,0>pc?(s=-(h=180),f=-(g=90)):y>Na?g=90:-Na>y&&(f=-90),M[0]=s,M[1]=h}};return function(n){g=h=-(s=f=1/0),x=[],Bo.geo.stream(n,_);
4
+ var t=x.length;if(t){x.sort(c);for(var e,r=1,u=x[0],i=[u];t>r;++r)e=x[r],l(e[0],u)||l(e[1],u)?(a(u[0],e[1])>a(u[0],u[1])&&(u[1]=e[1]),a(e[0],u[1])>a(u[0],u[1])&&(u[0]=e[0])):i.push(u=e);for(var o,e,p=-1/0,t=i.length-1,r=0,u=i[t];t>=r;u=e,++r)e=i[r],(o=a(u[1],e[0]))>p&&(p=o,s=e[0],h=u[1])}return x=M=null,1/0===s||1/0===f?[[0/0,0/0],[0/0,0/0]]:[[s,f],[h,g]]}}(),Bo.geo.centroid=function(n){dc=mc=yc=xc=Mc=_c=bc=wc=Sc=kc=Ec=0,Bo.geo.stream(n,Ac);var t=Sc,e=kc,r=Ec,u=t*t+e*e+r*r;return za>u&&(t=_c,e=bc,r=wc,Na>mc&&(t=yc,e=xc,r=Mc),u=t*t+e*e+r*r,za>u)?[0/0,0/0]:[Math.atan2(e,t)*Ta,nt(r/Math.sqrt(u))*Ta]};var dc,mc,yc,xc,Mc,_c,bc,wc,Sc,kc,Ec,Ac={sphere:y,point:be,lineStart:Se,lineEnd:ke,polygonStart:function(){Ac.lineStart=Ee},polygonEnd:function(){Ac.lineStart=Se}},Cc=Le(Ae,De,Ue,[-Ea,-Ea/2]),Nc=1e9;Bo.geo.clipExtent=function(){var n,t,e,r,u,i,o={stream:function(n){return u&&(u.valid=!1),u=i(n),u.valid=!0,u},extent:function(a){return arguments.length?(i=Oe(n=+a[0][0],t=+a[0][1],e=+a[1][0],r=+a[1][1]),u&&(u.valid=!1,u=null),o):[[n,t],[e,r]]}};return o.extent([[0,0],[960,500]])},(Bo.geo.conicEqualArea=function(){return Ie(Ze)}).raw=Ze,Bo.geo.albers=function(){return Bo.geo.conicEqualArea().rotate([96,0]).center([-.6,38.7]).parallels([29.5,45.5]).scale(1070)},Bo.geo.albersUsa=function(){function n(n){var i=n[0],o=n[1];return t=null,e(i,o),t||(r(i,o),t)||u(i,o),t}var t,e,r,u,i=Bo.geo.albers(),o=Bo.geo.conicEqualArea().rotate([154,0]).center([-2,58.5]).parallels([55,65]),a=Bo.geo.conicEqualArea().rotate([157,0]).center([-3,19.9]).parallels([8,18]),c={point:function(n,e){t=[n,e]}};return n.invert=function(n){var t=i.scale(),e=i.translate(),r=(n[0]-e[0])/t,u=(n[1]-e[1])/t;return(u>=.12&&.234>u&&r>=-.425&&-.214>r?o:u>=.166&&.234>u&&r>=-.214&&-.115>r?a:i).invert(n)},n.stream=function(n){var t=i.stream(n),e=o.stream(n),r=a.stream(n);return{point:function(n,u){t.point(n,u),e.point(n,u),r.point(n,u)},sphere:function(){t.sphere(),e.sphere(),r.sphere()},lineStart:function(){t.lineStart(),e.lineStart(),r.lineStart()},lineEnd:function(){t.lineEnd(),e.lineEnd(),r.lineEnd()},polygonStart:function(){t.polygonStart(),e.polygonStart(),r.polygonStart()},polygonEnd:function(){t.polygonEnd(),e.polygonEnd(),r.polygonEnd()}}},n.precision=function(t){return arguments.length?(i.precision(t),o.precision(t),a.precision(t),n):i.precision()},n.scale=function(t){return arguments.length?(i.scale(t),o.scale(.35*t),a.scale(t),n.translate(i.translate())):i.scale()},n.translate=function(t){if(!arguments.length)return i.translate();var l=i.scale(),s=+t[0],f=+t[1];return e=i.translate(t).clipExtent([[s-.455*l,f-.238*l],[s+.455*l,f+.238*l]]).stream(c).point,r=o.translate([s-.307*l,f+.201*l]).clipExtent([[s-.425*l+Na,f+.12*l+Na],[s-.214*l-Na,f+.234*l-Na]]).stream(c).point,u=a.translate([s-.205*l,f+.212*l]).clipExtent([[s-.214*l+Na,f+.166*l+Na],[s-.115*l-Na,f+.234*l-Na]]).stream(c).point,n},n.scale(1070)};var zc,Lc,Tc,qc,Rc,Dc,Pc={point:y,lineStart:y,lineEnd:y,polygonStart:function(){Lc=0,Pc.lineStart=Ve},polygonEnd:function(){Pc.lineStart=Pc.lineEnd=Pc.point=y,zc+=ca(Lc/2)}},Uc={point:Xe,lineStart:y,lineEnd:y,polygonStart:y,polygonEnd:y},jc={point:We,lineStart:Je,lineEnd:Ge,polygonStart:function(){jc.lineStart=Ke},polygonEnd:function(){jc.point=We,jc.lineStart=Je,jc.lineEnd=Ge}};Bo.geo.path=function(){function n(n){return n&&("function"==typeof a&&i.pointRadius(+a.apply(this,arguments)),o&&o.valid||(o=u(i)),Bo.geo.stream(n,o)),i.result()}function t(){return o=null,n}var e,r,u,i,o,a=4.5;return n.area=function(n){return zc=0,Bo.geo.stream(n,u(Pc)),zc},n.centroid=function(n){return yc=xc=Mc=_c=bc=wc=Sc=kc=Ec=0,Bo.geo.stream(n,u(jc)),Ec?[Sc/Ec,kc/Ec]:wc?[_c/wc,bc/wc]:Mc?[yc/Mc,xc/Mc]:[0/0,0/0]},n.bounds=function(n){return Rc=Dc=-(Tc=qc=1/0),Bo.geo.stream(n,u(Uc)),[[Tc,qc],[Rc,Dc]]},n.projection=function(n){return arguments.length?(u=(e=n)?n.stream||tr(n):Et,t()):e},n.context=function(n){return arguments.length?(i=null==(r=n)?new $e:new Qe(n),"function"!=typeof a&&i.pointRadius(a),t()):r},n.pointRadius=function(t){return arguments.length?(a="function"==typeof t?t:(i.pointRadius(+t),+t),n):a},n.projection(Bo.geo.albersUsa()).context(null)},Bo.geo.transform=function(n){return{stream:function(t){var e=new er(t);for(var r in n)e[r]=n[r];return e}}},er.prototype={point:function(n,t){this.stream.point(n,t)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}},Bo.geo.projection=ur,Bo.geo.projectionMutator=ir,(Bo.geo.equirectangular=function(){return ur(ar)}).raw=ar.invert=ar,Bo.geo.rotation=function(n){function t(t){return t=n(t[0]*La,t[1]*La),t[0]*=Ta,t[1]*=Ta,t}return n=lr(n[0]%360*La,n[1]*La,n.length>2?n[2]*La:0),t.invert=function(t){return t=n.invert(t[0]*La,t[1]*La),t[0]*=Ta,t[1]*=Ta,t},t},cr.invert=ar,Bo.geo.circle=function(){function n(){var n="function"==typeof r?r.apply(this,arguments):r,t=lr(-n[0]*La,-n[1]*La,0).invert,u=[];return e(null,null,1,{point:function(n,e){u.push(n=t(n,e)),n[0]*=Ta,n[1]*=Ta}}),{type:"Polygon",coordinates:[u]}}var t,e,r=[0,0],u=6;return n.origin=function(t){return arguments.length?(r=t,n):r},n.angle=function(r){return arguments.length?(e=gr((t=+r)*La,u*La),n):t},n.precision=function(r){return arguments.length?(e=gr(t*La,(u=+r)*La),n):u},n.angle(90)},Bo.geo.distance=function(n,t){var e,r=(t[0]-n[0])*La,u=n[1]*La,i=t[1]*La,o=Math.sin(r),a=Math.cos(r),c=Math.sin(u),l=Math.cos(u),s=Math.sin(i),f=Math.cos(i);return Math.atan2(Math.sqrt((e=f*o)*e+(e=l*s-c*f*a)*e),c*s+l*f*a)},Bo.geo.graticule=function(){function n(){return{type:"MultiLineString",coordinates:t()}}function t(){return Bo.range(Math.ceil(i/d)*d,u,d).map(h).concat(Bo.range(Math.ceil(l/m)*m,c,m).map(g)).concat(Bo.range(Math.ceil(r/p)*p,e,p).filter(function(n){return ca(n%d)>Na}).map(s)).concat(Bo.range(Math.ceil(a/v)*v,o,v).filter(function(n){return ca(n%m)>Na}).map(f))}var e,r,u,i,o,a,c,l,s,f,h,g,p=10,v=p,d=90,m=360,y=2.5;return n.lines=function(){return t().map(function(n){return{type:"LineString",coordinates:n}})},n.outline=function(){return{type:"Polygon",coordinates:[h(i).concat(g(c).slice(1),h(u).reverse().slice(1),g(l).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.majorExtent(t).minorExtent(t):n.minorExtent()},n.majorExtent=function(t){return arguments.length?(i=+t[0][0],u=+t[1][0],l=+t[0][1],c=+t[1][1],i>u&&(t=i,i=u,u=t),l>c&&(t=l,l=c,c=t),n.precision(y)):[[i,l],[u,c]]},n.minorExtent=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],a=+t[0][1],o=+t[1][1],r>e&&(t=r,r=e,e=t),a>o&&(t=a,a=o,o=t),n.precision(y)):[[r,a],[e,o]]},n.step=function(t){return arguments.length?n.majorStep(t).minorStep(t):n.minorStep()},n.majorStep=function(t){return arguments.length?(d=+t[0],m=+t[1],n):[d,m]},n.minorStep=function(t){return arguments.length?(p=+t[0],v=+t[1],n):[p,v]},n.precision=function(t){return arguments.length?(y=+t,s=vr(a,o,90),f=dr(r,e,y),h=vr(l,c,90),g=dr(i,u,y),n):y},n.majorExtent([[-180,-90+Na],[180,90-Na]]).minorExtent([[-180,-80-Na],[180,80+Na]])},Bo.geo.greatArc=function(){function n(){return{type:"LineString",coordinates:[t||r.apply(this,arguments),e||u.apply(this,arguments)]}}var t,e,r=mr,u=yr;return n.distance=function(){return Bo.geo.distance(t||r.apply(this,arguments),e||u.apply(this,arguments))},n.source=function(e){return arguments.length?(r=e,t="function"==typeof e?null:e,n):r},n.target=function(t){return arguments.length?(u=t,e="function"==typeof t?null:t,n):u},n.precision=function(){return arguments.length?n:0},n},Bo.geo.interpolate=function(n,t){return xr(n[0]*La,n[1]*La,t[0]*La,t[1]*La)},Bo.geo.length=function(n){return Fc=0,Bo.geo.stream(n,Hc),Fc};var Fc,Hc={sphere:y,point:y,lineStart:Mr,lineEnd:y,polygonStart:y,polygonEnd:y},Oc=_r(function(n){return Math.sqrt(2/(1+n))},function(n){return 2*Math.asin(n/2)});(Bo.geo.azimuthalEqualArea=function(){return ur(Oc)}).raw=Oc;var Yc=_r(function(n){var t=Math.acos(n);return t&&t/Math.sin(t)},Et);(Bo.geo.azimuthalEquidistant=function(){return ur(Yc)}).raw=Yc,(Bo.geo.conicConformal=function(){return Ie(br)}).raw=br,(Bo.geo.conicEquidistant=function(){return Ie(wr)}).raw=wr;var Ic=_r(function(n){return 1/n},Math.atan);(Bo.geo.gnomonic=function(){return ur(Ic)}).raw=Ic,Sr.invert=function(n,t){return[n,2*Math.atan(Math.exp(t))-Ca]},(Bo.geo.mercator=function(){return kr(Sr)}).raw=Sr;var Zc=_r(function(){return 1},Math.asin);(Bo.geo.orthographic=function(){return ur(Zc)}).raw=Zc;var Vc=_r(function(n){return 1/(1+n)},function(n){return 2*Math.atan(n)});(Bo.geo.stereographic=function(){return ur(Vc)}).raw=Vc,Er.invert=function(n,t){return[-t,2*Math.atan(Math.exp(n))-Ca]},(Bo.geo.transverseMercator=function(){var n=kr(Er),t=n.center,e=n.rotate;return n.center=function(n){return n?t([-n[1],n[0]]):(n=t(),[n[1],-n[0]])},n.rotate=function(n){return n?e([n[0],n[1],n.length>2?n[2]+90:90]):(n=e(),[n[0],n[1],n[2]-90])},e([0,0,90])}).raw=Er,Bo.geom={},Bo.geom.hull=function(n){function t(n){if(n.length<3)return[];var t,u=kt(e),i=kt(r),o=n.length,a=[],c=[];for(t=0;o>t;t++)a.push([+u.call(this,n[t],t),+i.call(this,n[t],t),t]);for(a.sort(zr),t=0;o>t;t++)c.push([a[t][0],-a[t][1]]);var l=Nr(a),s=Nr(c),f=s[0]===l[0],h=s[s.length-1]===l[l.length-1],g=[];for(t=l.length-1;t>=0;--t)g.push(n[a[l[t]][2]]);for(t=+f;t<s.length-h;++t)g.push(n[a[s[t]][2]]);return g}var e=Ar,r=Cr;return arguments.length?t(n):(t.x=function(n){return arguments.length?(e=n,t):e},t.y=function(n){return arguments.length?(r=n,t):r},t)},Bo.geom.polygon=function(n){return ga(n,Xc),n};var Xc=Bo.geom.polygon.prototype=[];Xc.area=function(){for(var n,t=-1,e=this.length,r=this[e-1],u=0;++t<e;)n=r,r=this[t],u+=n[1]*r[0]-n[0]*r[1];return.5*u},Xc.centroid=function(n){var t,e,r=-1,u=this.length,i=0,o=0,a=this[u-1];for(arguments.length||(n=-1/(6*this.area()));++r<u;)t=a,a=this[r],e=t[0]*a[1]-a[0]*t[1],i+=(t[0]+a[0])*e,o+=(t[1]+a[1])*e;return[i*n,o*n]},Xc.clip=function(n){for(var t,e,r,u,i,o,a=qr(n),c=-1,l=this.length-qr(this),s=this[l-1];++c<l;){for(t=n.slice(),n.length=0,u=this[c],i=t[(r=t.length-a)-1],e=-1;++e<r;)o=t[e],Lr(o,s,u)?(Lr(i,s,u)||n.push(Tr(i,o,s,u)),n.push(o)):Lr(i,s,u)&&n.push(Tr(i,o,s,u)),i=o;a&&n.push(n[0]),s=u}return n};var $c,Bc,Wc,Jc,Gc,Kc=[],Qc=[];Or.prototype.prepare=function(){for(var n,t=this.edges,e=t.length;e--;)n=t[e].edge,n.b&&n.a||t.splice(e,1);return t.sort(Ir),t.length},Qr.prototype={start:function(){return this.edge.l===this.site?this.edge.a:this.edge.b},end:function(){return this.edge.l===this.site?this.edge.b:this.edge.a}},nu.prototype={insert:function(n,t){var e,r,u;if(n){if(t.P=n,t.N=n.N,n.N&&(n.N.P=t),n.N=t,n.R){for(n=n.R;n.L;)n=n.L;n.L=t}else n.R=t;e=n}else this._?(n=uu(this._),t.P=null,t.N=n,n.P=n.L=t,e=n):(t.P=t.N=null,this._=t,e=null);for(t.L=t.R=null,t.U=e,t.C=!0,n=t;e&&e.C;)r=e.U,e===r.L?(u=r.R,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.R&&(eu(this,e),n=e,e=n.U),e.C=!1,r.C=!0,ru(this,r))):(u=r.L,u&&u.C?(e.C=u.C=!1,r.C=!0,n=r):(n===e.L&&(ru(this,e),n=e,e=n.U),e.C=!1,r.C=!0,eu(this,r))),e=n.U;this._.C=!1},remove:function(n){n.N&&(n.N.P=n.P),n.P&&(n.P.N=n.N),n.N=n.P=null;var t,e,r,u=n.U,i=n.L,o=n.R;if(e=i?o?uu(o):i:o,u?u.L===n?u.L=e:u.R=e:this._=e,i&&o?(r=e.C,e.C=n.C,e.L=i,i.U=e,e!==o?(u=e.U,e.U=n.U,n=e.R,u.L=n,e.R=o,o.U=e):(e.U=u,u=e,n=e.R)):(r=n.C,n=e),n&&(n.U=u),!r){if(n&&n.C)return n.C=!1,void 0;do{if(n===this._)break;if(n===u.L){if(t=u.R,t.C&&(t.C=!1,u.C=!0,eu(this,u),t=u.R),t.L&&t.L.C||t.R&&t.R.C){t.R&&t.R.C||(t.L.C=!1,t.C=!0,ru(this,t),t=u.R),t.C=u.C,u.C=t.R.C=!1,eu(this,u),n=this._;break}}else if(t=u.L,t.C&&(t.C=!1,u.C=!0,ru(this,u),t=u.L),t.L&&t.L.C||t.R&&t.R.C){t.L&&t.L.C||(t.R.C=!1,t.C=!0,eu(this,t),t=u.L),t.C=u.C,u.C=t.L.C=!1,ru(this,u),n=this._;break}t.C=!0,n=u,u=u.U}while(!n.C);n&&(n.C=!1)}}},Bo.geom.voronoi=function(n){function t(n){var t=new Array(n.length),r=a[0][0],u=a[0][1],i=a[1][0],o=a[1][1];return iu(e(n),a).cells.forEach(function(e,a){var c=e.edges,l=e.site,s=t[a]=c.length?c.map(function(n){var t=n.start();return[t.x,t.y]}):l.x>=r&&l.x<=i&&l.y>=u&&l.y<=o?[[r,o],[i,o],[i,u],[r,u]]:[];s.point=n[a]}),t}function e(n){return n.map(function(n,t){return{x:Math.round(i(n,t)/Na)*Na,y:Math.round(o(n,t)/Na)*Na,i:t}})}var r=Ar,u=Cr,i=r,o=u,a=nl;return n?t(n):(t.links=function(n){return iu(e(n)).edges.filter(function(n){return n.l&&n.r}).map(function(t){return{source:n[t.l.i],target:n[t.r.i]}})},t.triangles=function(n){var t=[];return iu(e(n)).cells.forEach(function(e,r){for(var u,i,o=e.site,a=e.edges.sort(Ir),c=-1,l=a.length,s=a[l-1].edge,f=s.l===o?s.r:s.l;++c<l;)u=s,i=f,s=a[c].edge,f=s.l===o?s.r:s.l,r<i.i&&r<f.i&&au(o,i,f)<0&&t.push([n[r],n[i.i],n[f.i]])}),t},t.x=function(n){return arguments.length?(i=kt(r=n),t):r},t.y=function(n){return arguments.length?(o=kt(u=n),t):u},t.clipExtent=function(n){return arguments.length?(a=null==n?nl:n,t):a===nl?null:a},t.size=function(n){return arguments.length?t.clipExtent(n&&[[0,0],n]):a===nl?null:a&&a[1]},t)};var nl=[[-1e6,-1e6],[1e6,1e6]];Bo.geom.delaunay=function(n){return Bo.geom.voronoi().triangles(n)},Bo.geom.quadtree=function(n,t,e,r,u){function i(n){function i(n,t,e,r,u,i,o,a){if(!isNaN(e)&&!isNaN(r))if(n.leaf){var c=n.x,s=n.y;if(null!=c)if(ca(c-e)+ca(s-r)<.01)l(n,t,e,r,u,i,o,a);else{var f=n.point;n.x=n.y=n.point=null,l(n,f,c,s,u,i,o,a),l(n,t,e,r,u,i,o,a)}else n.x=e,n.y=r,n.point=t}else l(n,t,e,r,u,i,o,a)}function l(n,t,e,r,u,o,a,c){var l=.5*(u+a),s=.5*(o+c),f=e>=l,h=r>=s,g=(h<<1)+f;n.leaf=!1,n=n.nodes[g]||(n.nodes[g]=su()),f?u=l:a=l,h?o=s:c=s,i(n,t,e,r,u,o,a,c)}var s,f,h,g,p,v,d,m,y,x=kt(a),M=kt(c);if(null!=t)v=t,d=e,m=r,y=u;else if(m=y=-(v=d=1/0),f=[],h=[],p=n.length,o)for(g=0;p>g;++g)s=n[g],s.x<v&&(v=s.x),s.y<d&&(d=s.y),s.x>m&&(m=s.x),s.y>y&&(y=s.y),f.push(s.x),h.push(s.y);else for(g=0;p>g;++g){var _=+x(s=n[g],g),b=+M(s,g);v>_&&(v=_),d>b&&(d=b),_>m&&(m=_),b>y&&(y=b),f.push(_),h.push(b)}var w=m-v,S=y-d;w>S?y=d+w:m=v+S;var k=su();if(k.add=function(n){i(k,n,+x(n,++g),+M(n,g),v,d,m,y)},k.visit=function(n){fu(n,k,v,d,m,y)},g=-1,null==t){for(;++g<p;)i(k,n[g],f[g],h[g],v,d,m,y);--g}else n.forEach(k.add);return f=h=n=s=null,k}var o,a=Ar,c=Cr;return(o=arguments.length)?(a=cu,c=lu,3===o&&(u=e,r=t,e=t=0),i(n)):(i.x=function(n){return arguments.length?(a=n,i):a},i.y=function(n){return arguments.length?(c=n,i):c},i.extent=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=+n[0][0],e=+n[0][1],r=+n[1][0],u=+n[1][1]),i):null==t?null:[[t,e],[r,u]]},i.size=function(n){return arguments.length?(null==n?t=e=r=u=null:(t=e=0,r=+n[0],u=+n[1]),i):null==t?null:[r-t,u-e]},i)},Bo.interpolateRgb=hu,Bo.interpolateObject=gu,Bo.interpolateNumber=pu,Bo.interpolateString=vu;var tl=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,el=new RegExp(tl.source,"g");Bo.interpolate=du,Bo.interpolators=[function(n,t){var e=typeof t;return("string"===e?$a.has(t)||/^(#|rgb\(|hsl\()/.test(t)?hu:vu:t instanceof it?hu:Array.isArray(t)?mu:"object"===e&&isNaN(t)?gu:pu)(n,t)}],Bo.interpolateArray=mu;var rl=function(){return Et},ul=Bo.map({linear:rl,poly:Su,quad:function(){return _u},cubic:function(){return bu},sin:function(){return ku},exp:function(){return Eu},circle:function(){return Au},elastic:Cu,back:Nu,bounce:function(){return zu}}),il=Bo.map({"in":Et,out:xu,"in-out":Mu,"out-in":function(n){return Mu(xu(n))}});Bo.ease=function(n){var t=n.indexOf("-"),e=t>=0?n.slice(0,t):n,r=t>=0?n.slice(t+1):"in";return e=ul.get(e)||rl,r=il.get(r)||Et,yu(r(e.apply(null,Wo.call(arguments,1))))},Bo.interpolateHcl=Lu,Bo.interpolateHsl=Tu,Bo.interpolateLab=qu,Bo.interpolateRound=Ru,Bo.transform=function(n){var t=Go.createElementNS(Bo.ns.prefix.svg,"g");return(Bo.transform=function(n){if(null!=n){t.setAttribute("transform",n);var e=t.transform.baseVal.consolidate()}return new Du(e?e.matrix:ol)})(n)},Du.prototype.toString=function(){return"translate("+this.translate+")rotate("+this.rotate+")skewX("+this.skew+")scale("+this.scale+")"};var ol={a:1,b:0,c:0,d:1,e:0,f:0};Bo.interpolateTransform=Fu,Bo.layout={},Bo.layout.bundle=function(){return function(n){for(var t=[],e=-1,r=n.length;++e<r;)t.push(Yu(n[e]));return t}},Bo.layout.chord=function(){function n(){var n,l,f,h,g,p={},v=[],d=Bo.range(i),m=[];for(e=[],r=[],n=0,h=-1;++h<i;){for(l=0,g=-1;++g<i;)l+=u[h][g];v.push(l),m.push(Bo.range(i)),n+=l}for(o&&d.sort(function(n,t){return o(v[n],v[t])}),a&&m.forEach(function(n,t){n.sort(function(n,e){return a(u[t][n],u[t][e])})}),n=(Aa-s*i)/n,l=0,h=-1;++h<i;){for(f=l,g=-1;++g<i;){var y=d[h],x=m[y][g],M=u[y][x],_=l,b=l+=M*n;p[y+"-"+x]={index:y,subindex:x,startAngle:_,endAngle:b,value:M}}r[y]={index:y,startAngle:f,endAngle:l,value:(l-f)/n},l+=s}for(h=-1;++h<i;)for(g=h-1;++g<i;){var w=p[h+"-"+g],S=p[g+"-"+h];(w.value||S.value)&&e.push(w.value<S.value?{source:S,target:w}:{source:w,target:S})}c&&t()}function t(){e.sort(function(n,t){return c((n.source.value+n.target.value)/2,(t.source.value+t.target.value)/2)})}var e,r,u,i,o,a,c,l={},s=0;return l.matrix=function(n){return arguments.length?(i=(u=n)&&u.length,e=r=null,l):u},l.padding=function(n){return arguments.length?(s=n,e=r=null,l):s},l.sortGroups=function(n){return arguments.length?(o=n,e=r=null,l):o},l.sortSubgroups=function(n){return arguments.length?(a=n,e=null,l):a},l.sortChords=function(n){return arguments.length?(c=n,e&&t(),l):c},l.chords=function(){return e||n(),e},l.groups=function(){return r||n(),r},l},Bo.layout.force=function(){function n(n){return function(t,e,r,u){if(t.point!==n){var i=t.cx-n.x,o=t.cy-n.y,a=u-e,c=i*i+o*o;if(c>a*a/d){if(p>c){var l=t.charge/c;n.px-=i*l,n.py-=o*l}return!0}if(t.point&&c&&p>c){var l=t.pointCharge/c;n.px-=i*l,n.py-=o*l}}return!t.charge}}function t(n){n.px=Bo.event.x,n.py=Bo.event.y,a.resume()}var e,r,u,i,o,a={},c=Bo.dispatch("start","tick","end"),l=[1,1],s=.9,f=al,h=cl,g=-30,p=ll,v=.1,d=.64,m=[],y=[];return a.tick=function(){if((r*=.99)<.005)return c.end({type:"end",alpha:r=0}),!0;var t,e,a,f,h,p,d,x,M,_=m.length,b=y.length;for(e=0;b>e;++e)a=y[e],f=a.source,h=a.target,x=h.x-f.x,M=h.y-f.y,(p=x*x+M*M)&&(p=r*i[e]*((p=Math.sqrt(p))-u[e])/p,x*=p,M*=p,h.x-=x*(d=f.weight/(h.weight+f.weight)),h.y-=M*d,f.x+=x*(d=1-d),f.y+=M*d);if((d=r*v)&&(x=l[0]/2,M=l[1]/2,e=-1,d))for(;++e<_;)a=m[e],a.x+=(x-a.x)*d,a.y+=(M-a.y)*d;if(g)for(Wu(t=Bo.geom.quadtree(m),r,o),e=-1;++e<_;)(a=m[e]).fixed||t.visit(n(a));for(e=-1;++e<_;)a=m[e],a.fixed?(a.x=a.px,a.y=a.py):(a.x-=(a.px-(a.px=a.x))*s,a.y-=(a.py-(a.py=a.y))*s);c.tick({type:"tick",alpha:r})},a.nodes=function(n){return arguments.length?(m=n,a):m},a.links=function(n){return arguments.length?(y=n,a):y},a.size=function(n){return arguments.length?(l=n,a):l},a.linkDistance=function(n){return arguments.length?(f="function"==typeof n?n:+n,a):f},a.distance=a.linkDistance,a.linkStrength=function(n){return arguments.length?(h="function"==typeof n?n:+n,a):h},a.friction=function(n){return arguments.length?(s=+n,a):s},a.charge=function(n){return arguments.length?(g="function"==typeof n?n:+n,a):g},a.chargeDistance=function(n){return arguments.length?(p=n*n,a):Math.sqrt(p)},a.gravity=function(n){return arguments.length?(v=+n,a):v},a.theta=function(n){return arguments.length?(d=n*n,a):Math.sqrt(d)},a.alpha=function(n){return arguments.length?(n=+n,r?r=n>0?n:0:n>0&&(c.start({type:"start",alpha:r=n}),Bo.timer(a.tick)),a):r},a.start=function(){function n(n,r){if(!e){for(e=new Array(c),a=0;c>a;++a)e[a]=[];for(a=0;l>a;++a){var u=y[a];e[u.source.index].push(u.target),e[u.target.index].push(u.source)}}for(var i,o=e[t],a=-1,l=o.length;++a<l;)if(!isNaN(i=o[a][n]))return i;return Math.random()*r}var t,e,r,c=m.length,s=y.length,p=l[0],v=l[1];for(t=0;c>t;++t)(r=m[t]).index=t,r.weight=0;for(t=0;s>t;++t)r=y[t],"number"==typeof r.source&&(r.source=m[r.source]),"number"==typeof r.target&&(r.target=m[r.target]),++r.source.weight,++r.target.weight;for(t=0;c>t;++t)r=m[t],isNaN(r.x)&&(r.x=n("x",p)),isNaN(r.y)&&(r.y=n("y",v)),isNaN(r.px)&&(r.px=r.x),isNaN(r.py)&&(r.py=r.y);if(u=[],"function"==typeof f)for(t=0;s>t;++t)u[t]=+f.call(this,y[t],t);else for(t=0;s>t;++t)u[t]=f;if(i=[],"function"==typeof h)for(t=0;s>t;++t)i[t]=+h.call(this,y[t],t);else for(t=0;s>t;++t)i[t]=h;if(o=[],"function"==typeof g)for(t=0;c>t;++t)o[t]=+g.call(this,m[t],t);else for(t=0;c>t;++t)o[t]=g;return a.resume()},a.resume=function(){return a.alpha(.1)},a.stop=function(){return a.alpha(0)},a.drag=function(){return e||(e=Bo.behavior.drag().origin(Et).on("dragstart.force",Vu).on("drag.force",t).on("dragend.force",Xu)),arguments.length?(this.on("mouseover.force",$u).on("mouseout.force",Bu).call(e),void 0):e},Bo.rebind(a,c,"on")};var al=20,cl=1,ll=1/0;Bo.layout.hierarchy=function(){function n(u){var i,o=[u],a=[];for(u.depth=0;null!=(i=o.pop());)if(a.push(i),(l=e.call(n,i,i.depth))&&(c=l.length)){for(var c,l,s;--c>=0;)o.push(s=l[c]),s.parent=i,s.depth=i.depth+1;r&&(i.value=0),i.children=l}else r&&(i.value=+r.call(n,i,i.depth)||0),delete i.children;return Ku(u,function(n){var e,u;t&&(e=n.children)&&e.sort(t),r&&(u=n.parent)&&(u.value+=n.value)}),a}var t=ti,e=Qu,r=ni;return n.sort=function(e){return arguments.length?(t=e,n):t},n.children=function(t){return arguments.length?(e=t,n):e},n.value=function(t){return arguments.length?(r=t,n):r},n.revalue=function(t){return r&&(Gu(t,function(n){n.children&&(n.value=0)}),Ku(t,function(t){var e;t.children||(t.value=+r.call(n,t,t.depth)||0),(e=t.parent)&&(e.value+=t.value)})),t},n},Bo.layout.partition=function(){function n(t,e,r,u){var i=t.children;if(t.x=e,t.y=t.depth*u,t.dx=r,t.dy=u,i&&(o=i.length)){var o,a,c,l=-1;for(r=t.value?r/t.value:0;++l<o;)n(a=i[l],e,c=a.value*r,u),e+=c}}function t(n){var e=n.children,r=0;if(e&&(u=e.length))for(var u,i=-1;++i<u;)r=Math.max(r,t(e[i]));return 1+r}function e(e,i){var o=r.call(this,e,i);return n(o[0],0,u[0],u[1]/t(o[0])),o}var r=Bo.layout.hierarchy(),u=[1,1];return e.size=function(n){return arguments.length?(u=n,e):u},Ju(e,r)},Bo.layout.pie=function(){function n(i){var o=i.map(function(e,r){return+t.call(n,e,r)}),a=+("function"==typeof r?r.apply(this,arguments):r),c=(("function"==typeof u?u.apply(this,arguments):u)-a)/Bo.sum(o),l=Bo.range(i.length);null!=e&&l.sort(e===sl?function(n,t){return o[t]-o[n]}:function(n,t){return e(i[n],i[t])});var s=[];return l.forEach(function(n){var t;s[n]={data:i[n],value:t=o[n],startAngle:a,endAngle:a+=t*c}}),s}var t=Number,e=sl,r=0,u=Aa;return n.value=function(e){return arguments.length?(t=e,n):t},n.sort=function(t){return arguments.length?(e=t,n):e},n.startAngle=function(t){return arguments.length?(r=t,n):r},n.endAngle=function(t){return arguments.length?(u=t,n):u},n};var sl={};Bo.layout.stack=function(){function n(a,c){if(!(h=a.length))return a;var l=a.map(function(e,r){return t.call(n,e,r)}),s=l.map(function(t){return t.map(function(t,e){return[i.call(n,t,e),o.call(n,t,e)]})}),f=e.call(n,s,c);l=Bo.permute(l,f),s=Bo.permute(s,f);var h,g,p,v,d=r.call(n,s,c),m=l[0].length;for(p=0;m>p;++p)for(u.call(n,l[0][p],v=d[p],s[0][p][1]),g=1;h>g;++g)u.call(n,l[g][p],v+=s[g-1][p][1],s[g][p][1]);return a}var t=Et,e=oi,r=ai,u=ii,i=ri,o=ui;return n.values=function(e){return arguments.length?(t=e,n):t},n.order=function(t){return arguments.length?(e="function"==typeof t?t:fl.get(t)||oi,n):e},n.offset=function(t){return arguments.length?(r="function"==typeof t?t:hl.get(t)||ai,n):r},n.x=function(t){return arguments.length?(i=t,n):i},n.y=function(t){return arguments.length?(o=t,n):o},n.out=function(t){return arguments.length?(u=t,n):u},n};var fl=Bo.map({"inside-out":function(n){var t,e,r=n.length,u=n.map(ci),i=n.map(li),o=Bo.range(r).sort(function(n,t){return u[n]-u[t]}),a=0,c=0,l=[],s=[];for(t=0;r>t;++t)e=o[t],c>a?(a+=i[e],l.push(e)):(c+=i[e],s.push(e));return s.reverse().concat(l)},reverse:function(n){return Bo.range(n.length).reverse()},"default":oi}),hl=Bo.map({silhouette:function(n){var t,e,r,u=n.length,i=n[0].length,o=[],a=0,c=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];r>a&&(a=r),o.push(r)}for(e=0;i>e;++e)c[e]=(a-o[e])/2;return c},wiggle:function(n){var t,e,r,u,i,o,a,c,l,s=n.length,f=n[0],h=f.length,g=[];for(g[0]=c=l=0,e=1;h>e;++e){for(t=0,u=0;s>t;++t)u+=n[t][e][1];for(t=0,i=0,a=f[e][0]-f[e-1][0];s>t;++t){for(r=0,o=(n[t][e][1]-n[t][e-1][1])/(2*a);t>r;++r)o+=(n[r][e][1]-n[r][e-1][1])/a;i+=o*n[t][e][1]}g[e]=c-=u?i/u*a:0,l>c&&(l=c)}for(e=0;h>e;++e)g[e]-=l;return g},expand:function(n){var t,e,r,u=n.length,i=n[0].length,o=1/u,a=[];for(e=0;i>e;++e){for(t=0,r=0;u>t;t++)r+=n[t][e][1];if(r)for(t=0;u>t;t++)n[t][e][1]/=r;else for(t=0;u>t;t++)n[t][e][1]=o}for(e=0;i>e;++e)a[e]=0;return a},zero:ai});Bo.layout.histogram=function(){function n(n,i){for(var o,a,c=[],l=n.map(e,this),s=r.call(this,l,i),f=u.call(this,s,l,i),i=-1,h=l.length,g=f.length-1,p=t?1:1/h;++i<g;)o=c[i]=[],o.dx=f[i+1]-(o.x=f[i]),o.y=0;if(g>0)for(i=-1;++i<h;)a=l[i],a>=s[0]&&a<=s[1]&&(o=c[Bo.bisect(f,a,1,g)-1],o.y+=p,o.push(n[i]));return c}var t=!0,e=Number,r=gi,u=fi;return n.value=function(t){return arguments.length?(e=t,n):e},n.range=function(t){return arguments.length?(r=kt(t),n):r},n.bins=function(t){return arguments.length?(u="number"==typeof t?function(n){return hi(n,t)}:kt(t),n):u},n.frequency=function(e){return arguments.length?(t=!!e,n):t},n},Bo.layout.pack=function(){function n(n,i){var o=e.call(this,n,i),a=o[0],c=u[0],l=u[1],s=null==t?Math.sqrt:"function"==typeof t?t:function(){return t};if(a.x=a.y=0,Ku(a,function(n){n.r=+s(n.value)}),Ku(a,yi),r){var f=r*(t?1:Math.max(2*a.r/c,2*a.r/l))/2;Ku(a,function(n){n.r+=f}),Ku(a,yi),Ku(a,function(n){n.r-=f})}return _i(a,c/2,l/2,t?1:1/Math.max(2*a.r/c,2*a.r/l)),o}var t,e=Bo.layout.hierarchy().sort(pi),r=0,u=[1,1];return n.size=function(t){return arguments.length?(u=t,n):u},n.radius=function(e){return arguments.length?(t=null==e||"function"==typeof e?e:+e,n):t},n.padding=function(t){return arguments.length?(r=+t,n):r},Ju(n,e)},Bo.layout.tree=function(){function n(n,u){var s=o.call(this,n,u),f=s[0],h=t(f);if(Ku(h,e),h.parent.m=-h.z,Gu(h,r),l)Gu(f,i);else{var g=f,p=f,v=f;Gu(f,function(n){n.x<g.x&&(g=n),n.x>p.x&&(p=n),n.depth>v.depth&&(v=n)});var d=a(g,p)/2-g.x,m=c[0]/(p.x+a(p,g)/2+d),y=c[1]/(v.depth||1);Gu(f,function(n){n.x=(n.x+d)*m,n.y=n.depth*y})}return s}function t(n){for(var t,e={A:null,children:[n]},r=[e];null!=(t=r.pop());)for(var u,i=t.children,o=0,a=i.length;a>o;++o)r.push((i[o]=u={_:i[o],parent:t,children:(u=i[o].children)&&u.slice()||[],A:null,a:null,z:0,m:0,c:0,s:0,t:null,i:o}).a=u);return e.children[0]}function e(n){var t=n.children,e=n.parent.children,r=n.i?e[n.i-1]:null;if(t.length){Ai(n);var i=(t[0].z+t[t.length-1].z)/2;r?(n.z=r.z+a(n._,r._),n.m=n.z-i):n.z=i}else r&&(n.z=r.z+a(n._,r._));n.parent.A=u(n,r,n.parent.A||e[0])}function r(n){n._.x=n.z+n.parent.m,n.m+=n.parent.m}function u(n,t,e){if(t){for(var r,u=n,i=n,o=t,c=u.parent.children[0],l=u.m,s=i.m,f=o.m,h=c.m;o=ki(o),u=Si(u),o&&u;)c=Si(c),i=ki(i),i.a=n,r=o.z+f-u.z-l+a(o._,u._),r>0&&(Ei(Ci(o,n,e),n,r),l+=r,s+=r),f+=o.m,l+=u.m,h+=c.m,s+=i.m;o&&!ki(i)&&(i.t=o,i.m+=f-s),u&&!Si(c)&&(c.t=u,c.m+=l-h,e=n)}return e}function i(n){n.x*=c[0],n.y=n.depth*c[1]}var o=Bo.layout.hierarchy().sort(null).value(null),a=wi,c=[1,1],l=null;return n.separation=function(t){return arguments.length?(a=t,n):a},n.size=function(t){return arguments.length?(l=null==(c=t)?i:null,n):l?null:c},n.nodeSize=function(t){return arguments.length?(l=null==(c=t)?null:i,n):l?c:null},Ju(n,o)},Bo.layout.cluster=function(){function n(n,i){var o,a=t.call(this,n,i),c=a[0],l=0;Ku(c,function(n){var t=n.children;t&&t.length?(n.x=zi(t),n.y=Ni(t)):(n.x=o?l+=e(n,o):0,n.y=0,o=n)});var s=Li(c),f=Ti(c),h=s.x-e(s,f)/2,g=f.x+e(f,s)/2;return Ku(c,u?function(n){n.x=(n.x-c.x)*r[0],n.y=(c.y-n.y)*r[1]}:function(n){n.x=(n.x-h)/(g-h)*r[0],n.y=(1-(c.y?n.y/c.y:1))*r[1]}),a}var t=Bo.layout.hierarchy().sort(null).value(null),e=wi,r=[1,1],u=!1;return n.separation=function(t){return arguments.length?(e=t,n):e},n.size=function(t){return arguments.length?(u=null==(r=t),n):u?null:r},n.nodeSize=function(t){return arguments.length?(u=null!=(r=t),n):u?r:null},Ju(n,t)},Bo.layout.treemap=function(){function n(n,t){for(var e,r,u=-1,i=n.length;++u<i;)r=(e=n[u]).value*(0>t?0:t),e.area=isNaN(r)||0>=r?0:r}function t(e){var i=e.children;if(i&&i.length){var o,a,c,l=f(e),s=[],h=i.slice(),p=1/0,v="slice"===g?l.dx:"dice"===g?l.dy:"slice-dice"===g?1&e.depth?l.dy:l.dx:Math.min(l.dx,l.dy);for(n(h,l.dx*l.dy/e.value),s.area=0;(c=h.length)>0;)s.push(o=h[c-1]),s.area+=o.area,"squarify"!==g||(a=r(s,v))<=p?(h.pop(),p=a):(s.area-=s.pop().area,u(s,v,l,!1),v=Math.min(l.dx,l.dy),s.length=s.area=0,p=1/0);s.length&&(u(s,v,l,!0),s.length=s.area=0),i.forEach(t)}}function e(t){var r=t.children;if(r&&r.length){var i,o=f(t),a=r.slice(),c=[];for(n(a,o.dx*o.dy/t.value),c.area=0;i=a.pop();)c.push(i),c.area+=i.area,null!=i.z&&(u(c,i.z?o.dx:o.dy,o,!a.length),c.length=c.area=0);r.forEach(e)}}function r(n,t){for(var e,r=n.area,u=0,i=1/0,o=-1,a=n.length;++o<a;)(e=n[o].area)&&(i>e&&(i=e),e>u&&(u=e));return r*=r,t*=t,r?Math.max(t*u*p/r,r/(t*i*p)):1/0}function u(n,t,e,r){var u,i=-1,o=n.length,a=e.x,l=e.y,s=t?c(n.area/t):0;if(t==e.dx){for((r||s>e.dy)&&(s=e.dy);++i<o;)u=n[i],u.x=a,u.y=l,u.dy=s,a+=u.dx=Math.min(e.x+e.dx-a,s?c(u.area/s):0);u.z=!0,u.dx+=e.x+e.dx-a,e.y+=s,e.dy-=s}else{for((r||s>e.dx)&&(s=e.dx);++i<o;)u=n[i],u.x=a,u.y=l,u.dx=s,l+=u.dy=Math.min(e.y+e.dy-l,s?c(u.area/s):0);u.z=!1,u.dy+=e.y+e.dy-l,e.x+=s,e.dx-=s}}function i(r){var u=o||a(r),i=u[0];return i.x=0,i.y=0,i.dx=l[0],i.dy=l[1],o&&a.revalue(i),n([i],i.dx*i.dy/i.value),(o?e:t)(i),h&&(o=u),u}var o,a=Bo.layout.hierarchy(),c=Math.round,l=[1,1],s=null,f=qi,h=!1,g="squarify",p=.5*(1+Math.sqrt(5));return i.size=function(n){return arguments.length?(l=n,i):l},i.padding=function(n){function t(t){var e=n.call(i,t,t.depth);return null==e?qi(t):Ri(t,"number"==typeof e?[e,e,e,e]:e)}function e(t){return Ri(t,n)}if(!arguments.length)return s;var r;return f=null==(s=n)?qi:"function"==(r=typeof n)?t:"number"===r?(n=[n,n,n,n],e):e,i},i.round=function(n){return arguments.length?(c=n?Math.round:Number,i):c!=Number},i.sticky=function(n){return arguments.length?(h=n,o=null,i):h},i.ratio=function(n){return arguments.length?(p=n,i):p},i.mode=function(n){return arguments.length?(g=n+"",i):g},Ju(i,a)},Bo.random={normal:function(n,t){var e=arguments.length;return 2>e&&(t=1),1>e&&(n=0),function(){var e,r,u;do e=2*Math.random()-1,r=2*Math.random()-1,u=e*e+r*r;while(!u||u>1);return n+t*e*Math.sqrt(-2*Math.log(u)/u)}},logNormal:function(){var n=Bo.random.normal.apply(Bo,arguments);return function(){return Math.exp(n())}},bates:function(n){var t=Bo.random.irwinHall(n);return function(){return t()/n}},irwinHall:function(n){return function(){for(var t=0,e=0;n>e;e++)t+=Math.random();return t}}},Bo.scale={};var gl={floor:Et,ceil:Et};Bo.scale.linear=function(){return Oi([0,1],[0,1],du,!1)};var pl={s:1,g:1,p:1,r:1,e:1};Bo.scale.log=function(){return Wi(Bo.scale.linear().domain([0,1]),10,!0,[1,10])};var vl=Bo.format(".0e"),dl={floor:function(n){return-Math.ceil(-n)},ceil:function(n){return-Math.floor(-n)}};Bo.scale.pow=function(){return Ji(Bo.scale.linear(),1,[0,1])},Bo.scale.sqrt=function(){return Bo.scale.pow().exponent(.5)},Bo.scale.ordinal=function(){return Ki([],{t:"range",a:[[]]})},Bo.scale.category10=function(){return Bo.scale.ordinal().range(ml)},Bo.scale.category20=function(){return Bo.scale.ordinal().range(yl)},Bo.scale.category20b=function(){return Bo.scale.ordinal().range(xl)},Bo.scale.category20c=function(){return Bo.scale.ordinal().range(Ml)};var ml=[2062260,16744206,2924588,14034728,9725885,9197131,14907330,8355711,12369186,1556175].map(yt),yl=[2062260,11454440,16744206,16759672,2924588,10018698,14034728,16750742,9725885,12955861,9197131,12885140,14907330,16234194,8355711,13092807,12369186,14408589,1556175,10410725].map(yt),xl=[3750777,5395619,7040719,10264286,6519097,9216594,11915115,13556636,9202993,12426809,15186514,15190932,8666169,11356490,14049643,15177372,8077683,10834324,13528509,14589654].map(yt),Ml=[3244733,7057110,10406625,13032431,15095053,16616764,16625259,16634018,3253076,7652470,10607003,13101504,7695281,10394312,12369372,14342891,6513507,9868950,12434877,14277081].map(yt);Bo.scale.quantile=function(){return Qi([],[])
5
+ },Bo.scale.quantize=function(){return no(0,1,[0,1])},Bo.scale.threshold=function(){return to([.5],[0,1])},Bo.scale.identity=function(){return eo([0,1])},Bo.svg={},Bo.svg.arc=function(){function n(){var n=t.apply(this,arguments),i=e.apply(this,arguments),o=r.apply(this,arguments)+_l,a=u.apply(this,arguments)+_l,c=(o>a&&(c=o,o=a,a=c),a-o),l=Ea>c?"0":"1",s=Math.cos(o),f=Math.sin(o),h=Math.cos(a),g=Math.sin(a);return c>=bl?n?"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"M0,"+n+"A"+n+","+n+" 0 1,0 0,"+-n+"A"+n+","+n+" 0 1,0 0,"+n+"Z":"M0,"+i+"A"+i+","+i+" 0 1,1 0,"+-i+"A"+i+","+i+" 0 1,1 0,"+i+"Z":n?"M"+i*s+","+i*f+"A"+i+","+i+" 0 "+l+",1 "+i*h+","+i*g+"L"+n*h+","+n*g+"A"+n+","+n+" 0 "+l+",0 "+n*s+","+n*f+"Z":"M"+i*s+","+i*f+"A"+i+","+i+" 0 "+l+",1 "+i*h+","+i*g+"L0,0"+"Z"}var t=ro,e=uo,r=io,u=oo;return n.innerRadius=function(e){return arguments.length?(t=kt(e),n):t},n.outerRadius=function(t){return arguments.length?(e=kt(t),n):e},n.startAngle=function(t){return arguments.length?(r=kt(t),n):r},n.endAngle=function(t){return arguments.length?(u=kt(t),n):u},n.centroid=function(){var n=(t.apply(this,arguments)+e.apply(this,arguments))/2,i=(r.apply(this,arguments)+u.apply(this,arguments))/2+_l;return[Math.cos(i)*n,Math.sin(i)*n]},n};var _l=-Ca,bl=Aa-Na;Bo.svg.line=function(){return ao(Et)};var wl=Bo.map({linear:co,"linear-closed":lo,step:so,"step-before":fo,"step-after":ho,basis:xo,"basis-open":Mo,"basis-closed":_o,bundle:bo,cardinal:vo,"cardinal-open":go,"cardinal-closed":po,monotone:Co});wl.forEach(function(n,t){t.key=n,t.closed=/-closed$/.test(n)});var Sl=[0,2/3,1/3,0],kl=[0,1/3,2/3,0],El=[0,1/6,2/3,1/6];Bo.svg.line.radial=function(){var n=ao(No);return n.radius=n.x,delete n.x,n.angle=n.y,delete n.y,n},fo.reverse=ho,ho.reverse=fo,Bo.svg.area=function(){return zo(Et)},Bo.svg.area.radial=function(){var n=zo(No);return n.radius=n.x,delete n.x,n.innerRadius=n.x0,delete n.x0,n.outerRadius=n.x1,delete n.x1,n.angle=n.y,delete n.y,n.startAngle=n.y0,delete n.y0,n.endAngle=n.y1,delete n.y1,n},Bo.svg.chord=function(){function n(n,a){var c=t(this,i,n,a),l=t(this,o,n,a);return"M"+c.p0+r(c.r,c.p1,c.a1-c.a0)+(e(c,l)?u(c.r,c.p1,c.r,c.p0):u(c.r,c.p1,l.r,l.p0)+r(l.r,l.p1,l.a1-l.a0)+u(l.r,l.p1,c.r,c.p0))+"Z"}function t(n,t,e,r){var u=t.call(n,e,r),i=a.call(n,u,r),o=c.call(n,u,r)+_l,s=l.call(n,u,r)+_l;return{r:i,a0:o,a1:s,p0:[i*Math.cos(o),i*Math.sin(o)],p1:[i*Math.cos(s),i*Math.sin(s)]}}function e(n,t){return n.a0==t.a0&&n.a1==t.a1}function r(n,t,e){return"A"+n+","+n+" 0 "+ +(e>Ea)+",1 "+t}function u(n,t,e,r){return"Q 0,0 "+r}var i=mr,o=yr,a=Lo,c=io,l=oo;return n.radius=function(t){return arguments.length?(a=kt(t),n):a},n.source=function(t){return arguments.length?(i=kt(t),n):i},n.target=function(t){return arguments.length?(o=kt(t),n):o},n.startAngle=function(t){return arguments.length?(c=kt(t),n):c},n.endAngle=function(t){return arguments.length?(l=kt(t),n):l},n},Bo.svg.diagonal=function(){function n(n,u){var i=t.call(this,n,u),o=e.call(this,n,u),a=(i.y+o.y)/2,c=[i,{x:i.x,y:a},{x:o.x,y:a},o];return c=c.map(r),"M"+c[0]+"C"+c[1]+" "+c[2]+" "+c[3]}var t=mr,e=yr,r=To;return n.source=function(e){return arguments.length?(t=kt(e),n):t},n.target=function(t){return arguments.length?(e=kt(t),n):e},n.projection=function(t){return arguments.length?(r=t,n):r},n},Bo.svg.diagonal.radial=function(){var n=Bo.svg.diagonal(),t=To,e=n.projection;return n.projection=function(n){return arguments.length?e(qo(t=n)):t},n},Bo.svg.symbol=function(){function n(n,r){return(Al.get(t.call(this,n,r))||Po)(e.call(this,n,r))}var t=Do,e=Ro;return n.type=function(e){return arguments.length?(t=kt(e),n):t},n.size=function(t){return arguments.length?(e=kt(t),n):e},n};var Al=Bo.map({circle:Po,cross:function(n){var t=Math.sqrt(n/5)/2;return"M"+-3*t+","+-t+"H"+-t+"V"+-3*t+"H"+t+"V"+-t+"H"+3*t+"V"+t+"H"+t+"V"+3*t+"H"+-t+"V"+t+"H"+-3*t+"Z"},diamond:function(n){var t=Math.sqrt(n/(2*Ll)),e=t*Ll;return"M0,"+-t+"L"+e+",0"+" 0,"+t+" "+-e+",0"+"Z"},square:function(n){var t=Math.sqrt(n)/2;return"M"+-t+","+-t+"L"+t+","+-t+" "+t+","+t+" "+-t+","+t+"Z"},"triangle-down":function(n){var t=Math.sqrt(n/zl),e=t*zl/2;return"M0,"+e+"L"+t+","+-e+" "+-t+","+-e+"Z"},"triangle-up":function(n){var t=Math.sqrt(n/zl),e=t*zl/2;return"M0,"+-e+"L"+t+","+e+" "+-t+","+e+"Z"}});Bo.svg.symbolTypes=Al.keys();var Cl,Nl,zl=Math.sqrt(3),Ll=Math.tan(30*La),Tl=[],ql=0;Tl.call=ya.call,Tl.empty=ya.empty,Tl.node=ya.node,Tl.size=ya.size,Bo.transition=function(n){return arguments.length?Cl?n.transition():n:_a.transition()},Bo.transition.prototype=Tl,Tl.select=function(n){var t,e,r,u=this.id,i=[];n=k(n);for(var o=-1,a=this.length;++o<a;){i.push(t=[]);for(var c=this[o],l=-1,s=c.length;++l<s;)(r=c[l])&&(e=n.call(r,r.__data__,l,o))?("__data__"in r&&(e.__data__=r.__data__),Ho(e,l,u,r.__transition__[u]),t.push(e)):t.push(null)}return Uo(i,u)},Tl.selectAll=function(n){var t,e,r,u,i,o=this.id,a=[];n=E(n);for(var c=-1,l=this.length;++c<l;)for(var s=this[c],f=-1,h=s.length;++f<h;)if(r=s[f]){i=r.__transition__[o],e=n.call(r,r.__data__,f,c),a.push(t=[]);for(var g=-1,p=e.length;++g<p;)(u=e[g])&&Ho(u,g,o,i),t.push(u)}return Uo(a,o)},Tl.filter=function(n){var t,e,r,u=[];"function"!=typeof n&&(n=U(n));for(var i=0,o=this.length;o>i;i++){u.push(t=[]);for(var e=this[i],a=0,c=e.length;c>a;a++)(r=e[a])&&n.call(r,r.__data__,a,i)&&t.push(r)}return Uo(u,this.id)},Tl.tween=function(n,t){var e=this.id;return arguments.length<2?this.node().__transition__[e].tween.get(n):F(this,null==t?function(t){t.__transition__[e].tween.remove(n)}:function(r){r.__transition__[e].tween.set(n,t)})},Tl.attr=function(n,t){function e(){this.removeAttribute(a)}function r(){this.removeAttributeNS(a.space,a.local)}function u(n){return null==n?e:(n+="",function(){var t,e=this.getAttribute(a);return e!==n&&(t=o(e,n),function(n){this.setAttribute(a,t(n))})})}function i(n){return null==n?r:(n+="",function(){var t,e=this.getAttributeNS(a.space,a.local);return e!==n&&(t=o(e,n),function(n){this.setAttributeNS(a.space,a.local,t(n))})})}if(arguments.length<2){for(t in n)this.attr(t,n[t]);return this}var o="transform"==n?Fu:du,a=Bo.ns.qualify(n);return jo(this,"attr."+n,t,a.local?i:u)},Tl.attrTween=function(n,t){function e(n,e){var r=t.call(this,n,e,this.getAttribute(u));return r&&function(n){this.setAttribute(u,r(n))}}function r(n,e){var r=t.call(this,n,e,this.getAttributeNS(u.space,u.local));return r&&function(n){this.setAttributeNS(u.space,u.local,r(n))}}var u=Bo.ns.qualify(n);return this.tween("attr."+n,u.local?r:e)},Tl.style=function(n,t,e){function r(){this.style.removeProperty(n)}function u(t){return null==t?r:(t+="",function(){var r,u=Qo.getComputedStyle(this,null).getPropertyValue(n);return u!==t&&(r=du(u,t),function(t){this.style.setProperty(n,r(t),e)})})}var i=arguments.length;if(3>i){if("string"!=typeof n){2>i&&(t="");for(e in n)this.style(e,n[e],t);return this}e=""}return jo(this,"style."+n,t,u)},Tl.styleTween=function(n,t,e){function r(r,u){var i=t.call(this,r,u,Qo.getComputedStyle(this,null).getPropertyValue(n));return i&&function(t){this.style.setProperty(n,i(t),e)}}return arguments.length<3&&(e=""),this.tween("style."+n,r)},Tl.text=function(n){return jo(this,"text",n,Fo)},Tl.remove=function(){return this.each("end.transition",function(){var n;this.__transition__.count<2&&(n=this.parentNode)&&n.removeChild(this)})},Tl.ease=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].ease:("function"!=typeof n&&(n=Bo.ease.apply(Bo,arguments)),F(this,function(e){e.__transition__[t].ease=n}))},Tl.delay=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].delay:F(this,"function"==typeof n?function(e,r,u){e.__transition__[t].delay=+n.call(e,e.__data__,r,u)}:(n=+n,function(e){e.__transition__[t].delay=n}))},Tl.duration=function(n){var t=this.id;return arguments.length<1?this.node().__transition__[t].duration:F(this,"function"==typeof n?function(e,r,u){e.__transition__[t].duration=Math.max(1,n.call(e,e.__data__,r,u))}:(n=Math.max(1,n),function(e){e.__transition__[t].duration=n}))},Tl.each=function(n,t){var e=this.id;if(arguments.length<2){var r=Nl,u=Cl;Cl=e,F(this,function(t,r,u){Nl=t.__transition__[e],n.call(t,t.__data__,r,u)}),Nl=r,Cl=u}else F(this,function(r){var u=r.__transition__[e];(u.event||(u.event=Bo.dispatch("start","end"))).on(n,t)});return this},Tl.transition=function(){for(var n,t,e,r,u=this.id,i=++ql,o=[],a=0,c=this.length;c>a;a++){o.push(n=[]);for(var t=this[a],l=0,s=t.length;s>l;l++)(e=t[l])&&(r=Object.create(e.__transition__[u]),r.delay+=r.duration,Ho(e,l,i,r)),n.push(e)}return Uo(o,i)},Bo.svg.axis=function(){function n(n){n.each(function(){var n,l=Bo.select(this),s=this.__chart__||e,f=this.__chart__=e.copy(),h=null==c?f.ticks?f.ticks.apply(f,a):f.domain():c,g=null==t?f.tickFormat?f.tickFormat.apply(f,a):Et:t,p=l.selectAll(".tick").data(h,f),v=p.enter().insert("g",".domain").attr("class","tick").style("opacity",Na),d=Bo.transition(p.exit()).style("opacity",Na).remove(),m=Bo.transition(p.order()).style("opacity",1),y=Math.max(u,0)+o,x=Pi(f),M=l.selectAll(".domain").data([0]),_=(M.enter().append("path").attr("class","domain"),Bo.transition(M));v.append("line"),v.append("text");var b,w,S,k,E=v.select("line"),A=m.select("line"),C=p.select("text").text(g),N=v.select("text"),z=m.select("text"),L="top"===r||"left"===r?-1:1;if("bottom"===r||"top"===r?(n=Oo,b="x",S="y",w="x2",k="y2",C.attr("dy",0>L?"0em":".71em").style("text-anchor","middle"),_.attr("d","M"+x[0]+","+L*i+"V0H"+x[1]+"V"+L*i)):(n=Yo,b="y",S="x",w="y2",k="x2",C.attr("dy",".32em").style("text-anchor",0>L?"end":"start"),_.attr("d","M"+L*i+","+x[0]+"H0V"+x[1]+"H"+L*i)),E.attr(k,L*u),N.attr(S,L*y),A.attr(w,0).attr(k,L*u),z.attr(b,0).attr(S,L*y),f.rangeBand){var T=f,q=T.rangeBand()/2;s=f=function(n){return T(n)+q}}else s.rangeBand?s=f:d.call(n,f,s);v.call(n,s,f),m.call(n,f,f)})}var t,e=Bo.scale.linear(),r=Rl,u=6,i=6,o=3,a=[10],c=null;return n.scale=function(t){return arguments.length?(e=t,n):e},n.orient=function(t){return arguments.length?(r=t in Dl?t+"":Rl,n):r},n.ticks=function(){return arguments.length?(a=arguments,n):a},n.tickValues=function(t){return arguments.length?(c=t,n):c},n.tickFormat=function(e){return arguments.length?(t=e,n):t},n.tickSize=function(t){var e=arguments.length;return e?(u=+t,i=+arguments[e-1],n):u},n.innerTickSize=function(t){return arguments.length?(u=+t,n):u},n.outerTickSize=function(t){return arguments.length?(i=+t,n):i},n.tickPadding=function(t){return arguments.length?(o=+t,n):o},n.tickSubdivide=function(){return arguments.length&&n},n};var Rl="bottom",Dl={top:1,right:1,bottom:1,left:1};Bo.svg.brush=function(){function n(i){i.each(function(){var i=Bo.select(this).style("pointer-events","all").style("-webkit-tap-highlight-color","rgba(0,0,0,0)").on("mousedown.brush",u).on("touchstart.brush",u),o=i.selectAll(".background").data([0]);o.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),i.selectAll(".extent").data([0]).enter().append("rect").attr("class","extent").style("cursor","move");var a=i.selectAll(".resize").data(p,Et);a.exit().remove(),a.enter().append("g").attr("class",function(n){return"resize "+n}).style("cursor",function(n){return Pl[n]}).append("rect").attr("x",function(n){return/[ew]$/.test(n)?-3:null}).attr("y",function(n){return/^[ns]/.test(n)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),a.style("display",n.empty()?"none":null);var s,f=Bo.transition(i),h=Bo.transition(o);c&&(s=Pi(c),h.attr("x",s[0]).attr("width",s[1]-s[0]),e(f)),l&&(s=Pi(l),h.attr("y",s[0]).attr("height",s[1]-s[0]),r(f)),t(f)})}function t(n){n.selectAll(".resize").attr("transform",function(n){return"translate("+s[+/e$/.test(n)]+","+f[+/^s/.test(n)]+")"})}function e(n){n.select(".extent").attr("x",s[0]),n.selectAll(".extent,.n>rect,.s>rect").attr("width",s[1]-s[0])}function r(n){n.select(".extent").attr("y",f[0]),n.selectAll(".extent,.e>rect,.w>rect").attr("height",f[1]-f[0])}function u(){function u(){32==Bo.event.keyCode&&(C||(y=null,z[0]-=s[1],z[1]-=f[1],C=2),_())}function p(){32==Bo.event.keyCode&&2==C&&(z[0]+=s[1],z[1]+=f[1],C=0,_())}function v(){var n=Bo.mouse(M),u=!1;x&&(n[0]+=x[0],n[1]+=x[1]),C||(Bo.event.altKey?(y||(y=[(s[0]+s[1])/2,(f[0]+f[1])/2]),z[0]=s[+(n[0]<y[0])],z[1]=f[+(n[1]<y[1])]):y=null),E&&d(n,c,0)&&(e(S),u=!0),A&&d(n,l,1)&&(r(S),u=!0),u&&(t(S),w({type:"brush",mode:C?"move":"resize"}))}function d(n,t,e){var r,u,a=Pi(t),c=a[0],l=a[1],p=z[e],v=e?f:s,d=v[1]-v[0];return C&&(c-=p,l-=d+p),r=(e?g:h)?Math.max(c,Math.min(l,n[e])):n[e],C?u=(r+=p)+d:(y&&(p=Math.max(c,Math.min(l,2*y[e]-r))),r>p?(u=r,r=p):u=p),v[0]!=r||v[1]!=u?(e?o=null:i=null,v[0]=r,v[1]=u,!0):void 0}function m(){v(),S.style("pointer-events","all").selectAll(".resize").style("display",n.empty()?"none":null),Bo.select("body").style("cursor",null),L.on("mousemove.brush",null).on("mouseup.brush",null).on("touchmove.brush",null).on("touchend.brush",null).on("keydown.brush",null).on("keyup.brush",null),N(),w({type:"brushend"})}var y,x,M=this,b=Bo.select(Bo.event.target),w=a.of(M,arguments),S=Bo.select(M),k=b.datum(),E=!/^(n|s)$/.test(k)&&c,A=!/^(e|w)$/.test(k)&&l,C=b.classed("extent"),N=X(),z=Bo.mouse(M),L=Bo.select(Qo).on("keydown.brush",u).on("keyup.brush",p);if(Bo.event.changedTouches?L.on("touchmove.brush",v).on("touchend.brush",m):L.on("mousemove.brush",v).on("mouseup.brush",m),S.interrupt().selectAll("*").interrupt(),C)z[0]=s[0]-z[0],z[1]=f[0]-z[1];else if(k){var T=+/w$/.test(k),q=+/^n/.test(k);x=[s[1-T]-z[0],f[1-q]-z[1]],z[0]=s[T],z[1]=f[q]}else Bo.event.altKey&&(y=z.slice());S.style("pointer-events","none").selectAll(".resize").style("display",null),Bo.select("body").style("cursor",b.style("cursor")),w({type:"brushstart"}),v()}var i,o,a=w(n,"brushstart","brush","brushend"),c=null,l=null,s=[0,0],f=[0,0],h=!0,g=!0,p=Ul[0];return n.event=function(n){n.each(function(){var n=a.of(this,arguments),t={x:s,y:f,i:i,j:o},e=this.__chart__||t;this.__chart__=t,Cl?Bo.select(this).transition().each("start.brush",function(){i=e.i,o=e.j,s=e.x,f=e.y,n({type:"brushstart"})}).tween("brush:brush",function(){var e=mu(s,t.x),r=mu(f,t.y);return i=o=null,function(u){s=t.x=e(u),f=t.y=r(u),n({type:"brush",mode:"resize"})}}).each("end.brush",function(){i=t.i,o=t.j,n({type:"brush",mode:"resize"}),n({type:"brushend"})}):(n({type:"brushstart"}),n({type:"brush",mode:"resize"}),n({type:"brushend"}))})},n.x=function(t){return arguments.length?(c=t,p=Ul[!c<<1|!l],n):c},n.y=function(t){return arguments.length?(l=t,p=Ul[!c<<1|!l],n):l},n.clamp=function(t){return arguments.length?(c&&l?(h=!!t[0],g=!!t[1]):c?h=!!t:l&&(g=!!t),n):c&&l?[h,g]:c?h:l?g:null},n.extent=function(t){var e,r,u,a,h;return arguments.length?(c&&(e=t[0],r=t[1],l&&(e=e[0],r=r[0]),i=[e,r],c.invert&&(e=c(e),r=c(r)),e>r&&(h=e,e=r,r=h),(e!=s[0]||r!=s[1])&&(s=[e,r])),l&&(u=t[0],a=t[1],c&&(u=u[1],a=a[1]),o=[u,a],l.invert&&(u=l(u),a=l(a)),u>a&&(h=u,u=a,a=h),(u!=f[0]||a!=f[1])&&(f=[u,a])),n):(c&&(i?(e=i[0],r=i[1]):(e=s[0],r=s[1],c.invert&&(e=c.invert(e),r=c.invert(r)),e>r&&(h=e,e=r,r=h))),l&&(o?(u=o[0],a=o[1]):(u=f[0],a=f[1],l.invert&&(u=l.invert(u),a=l.invert(a)),u>a&&(h=u,u=a,a=h))),c&&l?[[e,u],[r,a]]:c?[e,r]:l&&[u,a])},n.clear=function(){return n.empty()||(s=[0,0],f=[0,0],i=o=null),n},n.empty=function(){return!!c&&s[0]==s[1]||!!l&&f[0]==f[1]},Bo.rebind(n,a,"on")};var Pl={n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Ul=[["n","e","s","w","nw","ne","se","sw"],["e","w"],["n","s"],[]],jl=rc.format=lc.timeFormat,Fl=jl.utc,Hl=Fl("%Y-%m-%dT%H:%M:%S.%LZ");jl.iso=Date.prototype.toISOString&&+new Date("2000-01-01T00:00:00.000Z")?Io:Hl,Io.parse=function(n){var t=new Date(n);return isNaN(t)?null:t},Io.toString=Hl.toString,rc.second=Ft(function(n){return new uc(1e3*Math.floor(n/1e3))},function(n,t){n.setTime(n.getTime()+1e3*Math.floor(t))},function(n){return n.getSeconds()}),rc.seconds=rc.second.range,rc.seconds.utc=rc.second.utc.range,rc.minute=Ft(function(n){return new uc(6e4*Math.floor(n/6e4))},function(n,t){n.setTime(n.getTime()+6e4*Math.floor(t))},function(n){return n.getMinutes()}),rc.minutes=rc.minute.range,rc.minutes.utc=rc.minute.utc.range,rc.hour=Ft(function(n){var t=n.getTimezoneOffset()/60;return new uc(36e5*(Math.floor(n/36e5-t)+t))},function(n,t){n.setTime(n.getTime()+36e5*Math.floor(t))},function(n){return n.getHours()}),rc.hours=rc.hour.range,rc.hours.utc=rc.hour.utc.range,rc.month=Ft(function(n){return n=rc.day(n),n.setDate(1),n},function(n,t){n.setMonth(n.getMonth()+t)},function(n){return n.getMonth()}),rc.months=rc.month.range,rc.months.utc=rc.month.utc.range;var Ol=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],Yl=[[rc.second,1],[rc.second,5],[rc.second,15],[rc.second,30],[rc.minute,1],[rc.minute,5],[rc.minute,15],[rc.minute,30],[rc.hour,1],[rc.hour,3],[rc.hour,6],[rc.hour,12],[rc.day,1],[rc.day,2],[rc.week,1],[rc.month,1],[rc.month,3],[rc.year,1]],Il=jl.multi([[".%L",function(n){return n.getMilliseconds()}],[":%S",function(n){return n.getSeconds()}],["%I:%M",function(n){return n.getMinutes()}],["%I %p",function(n){return n.getHours()}],["%a %d",function(n){return n.getDay()&&1!=n.getDate()}],["%b %d",function(n){return 1!=n.getDate()}],["%B",function(n){return n.getMonth()}],["%Y",Ae]]),Zl={range:function(n,t,e){return Bo.range(Math.ceil(n/e)*e,+t,e).map(Vo)},floor:Et,ceil:Et};Yl.year=rc.year,rc.scale=function(){return Zo(Bo.scale.linear(),Yl,Il)};var Vl=Yl.map(function(n){return[n[0].utc,n[1]]}),Xl=Fl.multi([[".%L",function(n){return n.getUTCMilliseconds()}],[":%S",function(n){return n.getUTCSeconds()}],["%I:%M",function(n){return n.getUTCMinutes()}],["%I %p",function(n){return n.getUTCHours()}],["%a %d",function(n){return n.getUTCDay()&&1!=n.getUTCDate()}],["%b %d",function(n){return 1!=n.getUTCDate()}],["%B",function(n){return n.getUTCMonth()}],["%Y",Ae]]);Vl.year=rc.year.utc,rc.scale.utc=function(){return Zo(Bo.scale.linear(),Vl,Xl)},Bo.text=At(function(n){return n.responseText}),Bo.json=function(n,t){return Ct(n,"application/json",Xo,t)},Bo.html=function(n,t){return Ct(n,"text/html",$o,t)},Bo.xml=At(function(n){return n.responseXML}),"function"==typeof define&&define.amd?define(Bo):"object"==typeof module&&module.exports&&(module.exports=Bo),this.d3=Bo}();
assets/dependencies/rickshaw/index.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ //Nothing to see here
3
+
4
+ header( 'HTTP/1.0 403 Forbidden' );
assets/dependencies/rickshaw/rickshaw.min.css ADDED
@@ -0,0 +1 @@
 
1
+ .rickshaw_graph .detail{pointer-events:none;position:absolute;top:0;z-index:2;background:rgba(0,0,0,.1);bottom:0;width:1px;transition:opacity .25s linear;-moz-transition:opacity .25s linear;-o-transition:opacity .25s linear;-webkit-transition:opacity .25s linear}.rickshaw_graph .detail.inactive{opacity:0}.rickshaw_graph .detail .item.active{opacity:1}.rickshaw_graph .detail .x_label{font-family:Arial,sans-serif;border-radius:3px;padding:6px;opacity:.5;border:1px solid #e0e0e0;font-size:12px;position:absolute;background:#fff;white-space:nowrap}.rickshaw_graph .detail .x_label.left{left:0}.rickshaw_graph .detail .x_label.right{right:0}.rickshaw_graph .detail .item{position:absolute;z-index:2;border-radius:3px;padding:.25em;font-size:12px;font-family:Arial,sans-serif;opacity:0;background:rgba(0,0,0,.4);color:#fff;border:1px solid rgba(0,0,0,.4);margin-left:1em;margin-right:1em;margin-top:-1em;white-space:nowrap}.rickshaw_graph .detail .item.left{left:0}.rickshaw_graph .detail .item.right{right:0}.rickshaw_graph .detail .item.active{opacity:1;background:rgba(0,0,0,.8)}.rickshaw_graph .detail .item:after{position:absolute;display:block;width:0;height:0;content:"";border:5px solid transparent}.rickshaw_graph .detail .item.left:after{top:1em;left:-5px;margin-top:-5px;border-right-color:rgba(0,0,0,.8);border-left-width:0}.rickshaw_graph .detail .item.right:after{top:1em;right:-5px;margin-top:-5px;border-left-color:rgba(0,0,0,.8);border-right-width:0}.rickshaw_graph .detail .dot{width:4px;height:4px;margin-left:-3px;margin-top:-3.5px;border-radius:5px;position:absolute;box-shadow:0 0 2px rgba(0,0,0,.6);box-sizing:content-box;-moz-box-sizing:content-box;background:#fff;border-width:2px;border-style:solid;display:none;background-clip:padding-box}.rickshaw_graph .detail .dot.active{display:block}.rickshaw_graph{position:relative}.rickshaw_graph svg{display:block;overflow:hidden}.rickshaw_graph .x_tick{position:absolute;top:0;bottom:0;width:0;border-left:1px dotted rgba(0,0,0,.2);pointer-events:none}.rickshaw_graph .x_tick .title{position:absolute;font-size:12px;font-family:Arial,sans-serif;opacity:.5;white-space:nowrap;margin-left:3px;bottom:1px}.rickshaw_annotation_timeline{height:1px;border-top:1px solid #e0e0e0;margin-top:10px;position:relative}.rickshaw_annotation_timeline .annotation{position:absolute;height:6px;width:6px;margin-left:-2px;top:-3px;border-radius:5px;background-color:rgba(0,0,0,.25)}.rickshaw_graph .annotation_line{position:absolute;top:0;bottom:-6px;width:0;border-left:2px solid rgba(0,0,0,.3);display:none}.rickshaw_graph .annotation_line.active{display:block}.rickshaw_graph .annotation_range{background:rgba(0,0,0,.1);display:none;position:absolute;top:0;bottom:-6px}.rickshaw_graph .annotation_range.active{display:block}.rickshaw_graph .annotation_range.active.offscreen{display:none}.rickshaw_annotation_timeline .annotation .content{background:#fff;color:#000;opacity:.9;padding:5px;box-shadow:0 0 2px rgba(0,0,0,.8);border-radius:3px;position:relative;z-index:20;font-size:12px;padding:6px 8px 8px;top:18px;left:-11px;width:160px;display:none;cursor:pointer}.rickshaw_annotation_timeline .annotation .content:before{content:"\25b2";position:absolute;top:-11px;color:#fff;text-shadow:0 -1px 1px rgba(0,0,0,.8)}.rickshaw_annotation_timeline .annotation.active,.rickshaw_annotation_timeline .annotation:hover{background-color:rgba(0,0,0,.8);cursor:none}.rickshaw_annotation_timeline .annotation .content:hover{z-index:50}.rickshaw_annotation_timeline .annotation.active .content{display:block}.rickshaw_annotation_timeline .annotation:hover .content{display:block;z-index:50}.rickshaw_graph .y_axis,.rickshaw_graph .x_axis_d3{fill:none}.rickshaw_graph .y_ticks .tick line,.rickshaw_graph .x_ticks_d3 .tick{stroke:rgba(0,0,0,.16);stroke-width:2px;shape-rendering:crisp-edges;pointer-events:none}.rickshaw_graph .y_grid .tick,.rickshaw_graph .x_grid_d3 .tick{z-index:-1;stroke:rgba(0,0,0,.2);stroke-width:1px;stroke-dasharray:1 1}.rickshaw_graph .y_grid .tick[data-y-value="0"]{stroke-dasharray:1 0}.rickshaw_graph .y_grid path,.rickshaw_graph .x_grid_d3 path{fill:none;stroke:none}.rickshaw_graph .y_ticks path,.rickshaw_graph .x_ticks_d3 path{fill:none;stroke:gray}.rickshaw_graph .y_ticks text,.rickshaw_graph .x_ticks_d3 text{opacity:.5;font-size:12px;pointer-events:none}.rickshaw_graph .x_tick.glow .title,.rickshaw_graph .y_ticks.glow text{fill:#000;color:#000;text-shadow:-1px 1px 0 rgba(255,255,255,.1),1px -1px 0 rgba(255,255,255,.1),1px 1px 0 rgba(255,255,255,.1),0 1px 0 rgba(255,255,255,.1),0 -1px 0 rgba(255,255,255,.1),1px 0 0 rgba(255,255,255,.1),-1px 0 0 rgba(255,255,255,.1),-1px -1px 0 rgba(255,255,255,.1)}.rickshaw_graph .x_tick.inverse .title,.rickshaw_graph .y_ticks.inverse text{fill:#fff;color:#fff;text-shadow:-1px 1px 0 rgba(0,0,0,.8),1px -1px 0 rgba(0,0,0,.8),1px 1px 0 rgba(0,0,0,.8),0 1px 0 rgba(0,0,0,.8),0 -1px 0 rgba(0,0,0,.8),1px 0 0 rgba(0,0,0,.8),-1px 0 0 rgba(0,0,0,.8),-1px -1px 0 rgba(0,0,0,.8)}.rickshaw_legend{font-family:Arial;font-size:12px;color:#fff;background:#404040;display:inline-block;padding:12px 5px;border-radius:2px;position:relative}.rickshaw_legend:hover{z-index:10}.rickshaw_legend .swatch{width:10px;height:10px;border:1px solid rgba(0,0,0,.2)}.rickshaw_legend .line{clear:both;line-height:140%;padding-right:15px}.rickshaw_legend .line .swatch{display:inline-block;margin-right:3px;border-radius:2px}.rickshaw_legend .label{margin:0;white-space:nowrap;display:inline;font-size:inherit;background-color:transparent;color:inherit;font-weight:400;line-height:normal;padding:0;text-shadow:none}.rickshaw_legend .action:hover{opacity:.6}.rickshaw_legend .action{margin-right:.2em;font-size:10px;opacity:.2;cursor:pointer;font-size:14px}.rickshaw_legend .line.disabled{opacity:.4}.rickshaw_legend ul{list-style-type:none;margin:0;padding:0;margin:2px;cursor:pointer}.rickshaw_legend li{padding:0 0 0 2px;min-width:80px;white-space:nowrap}.rickshaw_legend li:hover{background:rgba(255,255,255,.08);border-radius:3px}.rickshaw_legend li:active{background:rgba(255,255,255,.2);border-radius:3px}
assets/dependencies/rickshaw/rickshaw.min.js ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ (function(root,factory){if(typeof define==="function"&&define.amd){define(["d3"],function(d3){return root.Rickshaw=factory(d3)})}else if(typeof exports==="object"){module.exports=factory(require("d3"))}else{root.Rickshaw=factory(d3)}})(this,function(d3){var Rickshaw={namespace:function(namespace,obj){var parts=namespace.split(".");var parent=Rickshaw;for(var i=1,length=parts.length;i<length;i++){var currentPart=parts[i];parent[currentPart]=parent[currentPart]||{};parent=parent[currentPart]}return parent},keys:function(obj){var keys=[];for(var key in obj)keys.push(key);return keys},extend:function(destination,source){for(var property in source){destination[property]=source[property]}return destination},clone:function(obj){return JSON.parse(JSON.stringify(obj))}};(function(globalContext){var _toString=Object.prototype.toString,NULL_TYPE="Null",UNDEFINED_TYPE="Undefined",BOOLEAN_TYPE="Boolean",NUMBER_TYPE="Number",STRING_TYPE="String",OBJECT_TYPE="Object",FUNCTION_CLASS="[object Function]";function isFunction(object){return _toString.call(object)===FUNCTION_CLASS}function extend(destination,source){for(var property in source)if(source.hasOwnProperty(property))destination[property]=source[property];return destination}function keys(object){if(Type(object)!==OBJECT_TYPE){throw new TypeError}var results=[];for(var property in object){if(object.hasOwnProperty(property)){results.push(property)}}return results}function Type(o){switch(o){case null:return NULL_TYPE;case void 0:return UNDEFINED_TYPE}var type=typeof o;switch(type){case"boolean":return BOOLEAN_TYPE;case"number":return NUMBER_TYPE;case"string":return STRING_TYPE}return OBJECT_TYPE}function isUndefined(object){return typeof object==="undefined"}var slice=Array.prototype.slice;function argumentNames(fn){var names=fn.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1].replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g,"").replace(/\s+/g,"").split(",");return names.length==1&&!names[0]?[]:names}function wrap(fn,wrapper){var __method=fn;return function(){var a=update([bind(__method,this)],arguments);return wrapper.apply(this,a)}}function update(array,args){var arrayLength=array.length,length=args.length;while(length--)array[arrayLength+length]=args[length];return array}function merge(array,args){array=slice.call(array,0);return update(array,args)}function bind(fn,context){if(arguments.length<2&&isUndefined(arguments[0]))return this;var __method=fn,args=slice.call(arguments,2);return function(){var a=merge(args,arguments);return __method.apply(context,a)}}var emptyFunction=function(){};var Class=function(){var IS_DONTENUM_BUGGY=function(){for(var p in{toString:1}){if(p==="toString")return false}return true}();function subclass(){}function create(){var parent=null,properties=[].slice.apply(arguments);if(isFunction(properties[0]))parent=properties.shift();function klass(){this.initialize.apply(this,arguments)}extend(klass,Class.Methods);klass.superclass=parent;klass.subclasses=[];if(parent){subclass.prototype=parent.prototype;klass.prototype=new subclass;try{parent.subclasses.push(klass)}catch(e){}}for(var i=0,length=properties.length;i<length;i++)klass.addMethods(properties[i]);if(!klass.prototype.initialize)klass.prototype.initialize=emptyFunction;klass.prototype.constructor=klass;return klass}function addMethods(source){var ancestor=this.superclass&&this.superclass.prototype,properties=keys(source);if(IS_DONTENUM_BUGGY){if(source.toString!=Object.prototype.toString)properties.push("toString");if(source.valueOf!=Object.prototype.valueOf)properties.push("valueOf")}for(var i=0,length=properties.length;i<length;i++){var property=properties[i],value=source[property];if(ancestor&&isFunction(value)&&argumentNames(value)[0]=="$super"){var method=value;value=wrap(function(m){return function(){return ancestor[m].apply(this,arguments)}}(property),method);value.valueOf=bind(method.valueOf,method);value.toString=bind(method.toString,method)}this.prototype[property]=value}return this}return{create:create,Methods:{addMethods:addMethods}}}();if(globalContext.exports){globalContext.exports.Class=Class}else{globalContext.Class=Class}})(Rickshaw);Rickshaw.namespace("Rickshaw.Compat.ClassList");Rickshaw.Compat.ClassList=function(){if(typeof document!=="undefined"&&!("classList"in document.createElement("a"))){(function(view){"use strict";var classListProp="classList",protoProp="prototype",elemCtrProto=(view.HTMLElement||view.Element)[protoProp],objCtr=Object,strTrim=String[protoProp].trim||function(){return this.replace(/^\s+|\s+$/g,"")},arrIndexOf=Array[protoProp].indexOf||function(item){var i=0,len=this.length;for(;i<len;i++){if(i in this&&this[i]===item){return i}}return-1},DOMEx=function(type,message){this.name=type;this.code=DOMException[type];this.message=message},checkTokenAndGetIndex=function(classList,token){if(token===""){throw new DOMEx("SYNTAX_ERR","An invalid or illegal string was specified")}if(/\s/.test(token)){throw new DOMEx("INVALID_CHARACTER_ERR","String contains an invalid character")}return arrIndexOf.call(classList,token)},ClassList=function(elem){var trimmedClasses=strTrim.call(elem.className),classes=trimmedClasses?trimmedClasses.split(/\s+/):[],i=0,len=classes.length;for(;i<len;i++){this.push(classes[i])}this._updateClassName=function(){elem.className=this.toString()}},classListProto=ClassList[protoProp]=[],classListGetter=function(){return new ClassList(this)};DOMEx[protoProp]=Error[protoProp];classListProto.item=function(i){return this[i]||null};classListProto.contains=function(token){token+="";return checkTokenAndGetIndex(this,token)!==-1};classListProto.add=function(token){token+="";if(checkTokenAndGetIndex(this,token)===-1){this.push(token);this._updateClassName()}};classListProto.remove=function(token){token+="";var index=checkTokenAndGetIndex(this,token);if(index!==-1){this.splice(index,1);this._updateClassName()}};classListProto.toggle=function(token){token+="";if(checkTokenAndGetIndex(this,token)===-1){this.add(token)}else{this.remove(token)}};classListProto.toString=function(){return this.join(" ")};if(objCtr.defineProperty){var classListPropDesc={get:classListGetter,enumerable:true,configurable:true};try{objCtr.defineProperty(elemCtrProto,classListProp,classListPropDesc)}catch(ex){if(ex.number===-2146823252){classListPropDesc.enumerable=false;objCtr.defineProperty(elemCtrProto,classListProp,classListPropDesc)}}}else if(objCtr[protoProp].__defineGetter__){elemCtrProto.__defineGetter__(classListProp,classListGetter)}})(window)}};if(typeof RICKSHAW_NO_COMPAT!=="undefined"&&!RICKSHAW_NO_COMPAT||typeof RICKSHAW_NO_COMPAT==="undefined"){new Rickshaw.Compat.ClassList}Rickshaw.namespace("Rickshaw.Graph");Rickshaw.Graph=function(args){var self=this;this.initialize=function(args){if(!args.element)throw"Rickshaw.Graph needs a reference to an element";if(args.element.nodeType!==1)throw"Rickshaw.Graph element was defined but not an HTML element";this.element=args.element;this.series=args.series;this.window={};this.updateCallbacks=[];this.configureCallbacks=[];this.defaults={interpolation:"cardinal",offset:"zero",min:undefined,max:undefined,preserve:false,xScale:undefined,yScale:undefined,stack:true};this._loadRenderers();this.configure(args);this.validateSeries(args.series);this.series.active=function(){return self.series.filter(function(s){return!s.disabled})};this.setSize({width:args.width,height:args.height});this.element.classList.add("rickshaw_graph");this.vis=d3.select(this.element).append("svg:svg").attr("width",this.width).attr("height",this.height);this.discoverRange()};this._loadRenderers=function(){for(var name in Rickshaw.Graph.Renderer){if(!name||!Rickshaw.Graph.Renderer.hasOwnProperty(name))continue;var r=Rickshaw.Graph.Renderer[name];if(!r||!r.prototype||!r.prototype.render)continue;self.registerRenderer(new r({graph:self}))}};this.validateSeries=function(series){if(!Array.isArray(series)&&!(series instanceof Rickshaw.Series)){var seriesSignature=Object.prototype.toString.apply(series);throw"series is not an array: "+seriesSignature}var pointsCount;series.forEach(function(s){if(!(s instanceof Object)){throw"series element is not an object: "+s}if(!s.data){throw"series has no data: "+JSON.stringify(s)}if(!Array.isArray(s.data)){throw"series data is not an array: "+JSON.stringify(s.data)}if(s.data.length>0){var x=s.data[0].x;var y=s.data[0].y;if(typeof x!="number"||typeof y!="number"&&y!==null){throw"x and y properties of points should be numbers instead of "+typeof x+" and "+typeof y}}if(s.data.length>=3){if(s.data[2].x<s.data[1].x||s.data[1].x<s.data[0].x||s.data[s.data.length-1].x<s.data[0].x){throw"series data needs to be sorted on x values for series name: "+s.name}}},this)};this.dataDomain=function(){var data=this.series.map(function(s){return s.data});var min=d3.min(data.map(function(d){return d[0].x}));var max=d3.max(data.map(function(d){return d[d.length-1].x}));return[min,max]};this.discoverRange=function(){var domain=this.renderer.domain();this.x=(this.xScale||d3.scale.linear()).copy().domain(domain.x).range([0,this.width]);this.y=(this.yScale||d3.scale.linear()).copy().domain(domain.y).range([this.height,0]);this.x.magnitude=d3.scale.linear().domain([domain.x[0]-domain.x[0],domain.x[1]-domain.x[0]]).range([0,this.width]);this.y.magnitude=d3.scale.linear().domain([domain.y[0]-domain.y[0],domain.y[1]-domain.y[0]]).range([0,this.height])};this.render=function(){var stackedData=this.stackData();this.discoverRange();this.renderer.render();this.updateCallbacks.forEach(function(callback){callback()})};this.update=this.render;this.stackData=function(){var data=this.series.active().map(function(d){return d.data}).map(function(d){return d.filter(function(d){return this._slice(d)},this)},this);var preserve=this.preserve;if(!preserve){this.series.forEach(function(series){if(series.scale){preserve=true}})}data=preserve?Rickshaw.clone(data):data;this.series.active().forEach(function(series,index){if(series.scale){var seriesData=data[index];if(seriesData){seriesData.forEach(function(d){d.y=series.scale(d.y)})}}});this.stackData.hooks.data.forEach(function(entry){data=entry.f.apply(self,[data])});var stackedData;if(!this.renderer.unstack){this._validateStackable();var layout=d3.layout.stack();layout.offset(self.offset);stackedData=layout(data)}stackedData=stackedData||data;if(this.renderer.unstack){stackedData.forEach(function(seriesData){seriesData.forEach(function(d){d.y0=d.y0===undefined?0:d.y0})})}this.stackData.hooks.after.forEach(function(entry){stackedData=entry.f.apply(self,[data])});var i=0;this.series.forEach(function(series){if(series.disabled)return;series.stack=stackedData[i++]});this.stackedData=stackedData;return stackedData};this._validateStackable=function(){var series=this.series;var pointsCount;series.forEach(function(s){pointsCount=pointsCount||s.data.length;if(pointsCount&&s.data.length!=pointsCount){throw"stacked series cannot have differing numbers of points: "+pointsCount+" vs "+s.data.length+"; see Rickshaw.Series.fill()"}},this)};this.stackData.hooks={data:[],after:[]};this._slice=function(d){if(this.window.xMin||this.window.xMax){var isInRange=true;if(this.window.xMin&&d.x<this.window.xMin)isInRange=false;if(this.window.xMax&&d.x>this.window.xMax)isInRange=false;return isInRange}return true};this.onUpdate=function(callback){this.updateCallbacks.push(callback)};this.onConfigure=function(callback){this.configureCallbacks.push(callback)};this.registerRenderer=function(renderer){this._renderers=this._renderers||{};this._renderers[renderer.name]=renderer};this.configure=function(args){this.config=this.config||{};if(args.width||args.height){this.setSize(args)}Rickshaw.keys(this.defaults).forEach(function(k){this.config[k]=k in args?args[k]:k in this?this[k]:this.defaults[k]},this);Rickshaw.keys(this.config).forEach(function(k){this[k]=this.config[k]},this);if("stack"in args)args.unstack=!args.stack;var renderer=args.renderer||this.renderer&&this.renderer.name||"stack";this.setRenderer(renderer,args);this.configureCallbacks.forEach(function(callback){callback(args)})};this.setRenderer=function(r,args){if(typeof r=="function"){this.renderer=new r({graph:self});this.registerRenderer(this.renderer)}else{if(!this._renderers[r]){throw"couldn't find renderer "+r}this.renderer=this._renderers[r]}if(typeof args=="object"){this.renderer.configure(args)}};this.setSize=function(args){args=args||{};if(typeof window!==undefined){var style=window.getComputedStyle(this.element,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);var elementHeight=parseInt(style.getPropertyValue("height"),10)}this.width=args.width||elementWidth||400;this.height=args.height||elementHeight||250;this.vis&&this.vis.attr("width",this.width).attr("height",this.height)};this.initialize(args)};Rickshaw.namespace("Rickshaw.Fixtures.Color");Rickshaw.Fixtures.Color=function(){this.schemes={};this.schemes.spectrum14=["#ecb796","#dc8f70","#b2a470","#92875a","#716c49","#d2ed82","#bbe468","#a1d05d","#e7cbe6","#d8aad6","#a888c2","#9dc2d3","#649eb9","#387aa3"].reverse();this.schemes.spectrum2000=["#57306f","#514c76","#646583","#738394","#6b9c7d","#84b665","#a7ca50","#bfe746","#e2f528","#fff726","#ecdd00","#d4b11d","#de8800","#de4800","#c91515","#9a0000","#7b0429","#580839","#31082b"];this.schemes.spectrum2001=["#2f243f","#3c2c55","#4a3768","#565270","#6b6b7c","#72957f","#86ad6e","#a1bc5e","#b8d954","#d3e04e","#ccad2a","#cc8412","#c1521d","#ad3821","#8a1010","#681717","#531e1e","#3d1818","#320a1b"];this.schemes.classic9=["#423d4f","#4a6860","#848f39","#a2b73c","#ddcb53","#c5a32f","#7d5836","#963b20","#7c2626","#491d37","#2f254a"].reverse();this.schemes.httpStatus={503:"#ea5029",502:"#d23f14",500:"#bf3613",410:"#efacea",409:"#e291dc",403:"#f457e8",408:"#e121d2",401:"#b92dae",405:"#f47ceb",404:"#a82a9f",400:"#b263c6",301:"#6fa024",302:"#87c32b",307:"#a0d84c",304:"#28b55c",200:"#1a4f74",206:"#27839f",201:"#52adc9",202:"#7c979f",203:"#a5b8bd",204:"#c1cdd1"};this.schemes.colorwheel=["#b5b6a9","#858772","#785f43","#96557e","#4682b4","#65b9ac","#73c03a","#cb513a"].reverse();this.schemes.cool=["#5e9d2f","#73c03a","#4682b4","#7bc3b8","#a9884e","#c1b266","#a47493","#c09fb5"];this.schemes.munin=["#00cc00","#0066b3","#ff8000","#ffcc00","#330099","#990099","#ccff00","#ff0000","#808080","#008f00","#00487d","#b35a00","#b38f00","#6b006b","#8fb300","#b30000","#bebebe","#80ff80","#80c9ff","#ffc080","#ffe680","#aa80ff","#ee00cc","#ff8080","#666600","#ffbfff","#00ffcc","#cc6699","#999900"]};Rickshaw.namespace("Rickshaw.Fixtures.RandomData");Rickshaw.Fixtures.RandomData=function(timeInterval){var addData;timeInterval=timeInterval||1;var lastRandomValue=200;var timeBase=Math.floor((new Date).getTime()/1e3);this.addData=function(data){var randomValue=Math.random()*100+15+lastRandomValue;var index=data[0].length;var counter=1;data.forEach(function(series){var randomVariance=Math.random()*20;var v=randomValue/25+counter++ +(Math.cos(index*counter*11/960)+2)*15+(Math.cos(index/7)+2)*7+(Math.cos(index/17)+2)*1;series.push({x:index*timeInterval+timeBase,y:v+randomVariance})});lastRandomValue=randomValue*.85};this.removeData=function(data){data.forEach(function(series){series.shift()});timeBase+=timeInterval}};Rickshaw.namespace("Rickshaw.Fixtures.Time");Rickshaw.Fixtures.Time=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getUTCFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getUTCFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getUTCMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getUTCDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getUTCMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getUTCSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getUTCMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getUTCMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toUTCString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year;if(unit.name=="month"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),date.getUTCMonth())/1e3;if(floor==time)return time;year=date.getUTCFullYear();var month=date.getUTCMonth();if(month==11){month=0;year=year+1}else{month+=1}return Date.UTC(year,month)/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=Date.UTC(date.getUTCFullYear(),0)/1e3;if(floor==time)return time;year=date.getUTCFullYear()+1;return Date.UTC(year,0)/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Time.Local");Rickshaw.Fixtures.Time.Local=function(){var self=this;this.months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];this.units=[{name:"decade",seconds:86400*365.25*10,formatter:function(d){return parseInt(d.getFullYear()/10,10)*10}},{name:"year",seconds:86400*365.25,formatter:function(d){return d.getFullYear()}},{name:"month",seconds:86400*30.5,formatter:function(d){return self.months[d.getMonth()]}},{name:"week",seconds:86400*7,formatter:function(d){return self.formatDate(d)}},{name:"day",seconds:86400,formatter:function(d){return d.getDate()}},{name:"6 hour",seconds:3600*6,formatter:function(d){return self.formatTime(d)}},{name:"hour",seconds:3600,formatter:function(d){return self.formatTime(d)}},{name:"15 minute",seconds:60*15,formatter:function(d){return self.formatTime(d)}},{name:"minute",seconds:60,formatter:function(d){return d.getMinutes()}},{name:"15 second",seconds:15,formatter:function(d){return d.getSeconds()+"s"}},{name:"second",seconds:1,formatter:function(d){return d.getSeconds()+"s"}},{name:"decisecond",seconds:1/10,formatter:function(d){return d.getMilliseconds()+"ms"}},{name:"centisecond",seconds:1/100,formatter:function(d){return d.getMilliseconds()+"ms"}}];this.unit=function(unitName){return this.units.filter(function(unit){return unitName==unit.name}).shift()};this.formatDate=function(d){return d3.time.format("%b %e")(d)};this.formatTime=function(d){return d.toString().match(/(\d+:\d+):/)[1]};this.ceil=function(time,unit){var date,floor,year;if(unit.name=="day"){var nearFuture=new Date((time+unit.seconds-1)*1e3);var rounded=new Date(0);rounded.setMilliseconds(0);rounded.setSeconds(0);rounded.setMinutes(0);rounded.setHours(0);rounded.setDate(nearFuture.getDate());rounded.setMonth(nearFuture.getMonth());rounded.setFullYear(nearFuture.getFullYear());return rounded.getTime()/1e3}if(unit.name=="month"){date=new Date(time*1e3);floor=new Date(date.getFullYear(),date.getMonth()).getTime()/1e3;if(floor==time)return time;year=date.getFullYear();var month=date.getMonth();if(month==11){month=0;year=year+1}else{month+=1}return new Date(year,month).getTime()/1e3}if(unit.name=="year"){date=new Date(time*1e3);floor=new Date(date.getUTCFullYear(),0).getTime()/1e3;if(floor==time)return time;year=date.getFullYear()+1;return new Date(year,0).getTime()/1e3}return Math.ceil(time/unit.seconds)*unit.seconds}};Rickshaw.namespace("Rickshaw.Fixtures.Number");Rickshaw.Fixtures.Number.formatKMBT=function(y){var abs_y=Math.abs(y);if(abs_y>=1e12){return y/1e12+"T"}else if(abs_y>=1e9){return y/1e9+"B"}else if(abs_y>=1e6){return y/1e6+"M"}else if(abs_y>=1e3){return y/1e3+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.Fixtures.Number.formatBase1024KMGTP=function(y){var abs_y=Math.abs(y);if(abs_y>=0x4000000000000){return y/0x4000000000000+"P"}else if(abs_y>=1099511627776){return y/1099511627776+"T"}else if(abs_y>=1073741824){return y/1073741824+"G"}else if(abs_y>=1048576){return y/1048576+"M"}else if(abs_y>=1024){return y/1024+"K"}else if(abs_y<1&&y>0){return y.toFixed(2)}else if(abs_y===0){return""}else{return y}};Rickshaw.namespace("Rickshaw.Color.Palette");Rickshaw.Color.Palette=function(args){var color=new Rickshaw.Fixtures.Color;args=args||{};this.schemes={};this.scheme=color.schemes[args.scheme]||args.scheme||color.schemes.colorwheel;this.runningIndex=0;this.generatorIndex=0;if(args.interpolatedStopCount){var schemeCount=this.scheme.length-1;var i,j,scheme=[];for(i=0;i<schemeCount;i++){scheme.push(this.scheme[i]);var generator=d3.interpolateHsl(this.scheme[i],this.scheme[i+1]);for(j=1;j<args.interpolatedStopCount;j++){scheme.push(generator(1/args.interpolatedStopCount*j))}}scheme.push(this.scheme[this.scheme.length-1]);this.scheme=scheme}this.rotateCount=this.scheme.length;this.color=function(key){return this.scheme[key]||this.scheme[this.runningIndex++]||this.interpolateColor()||"#808080"};this.interpolateColor=function(){if(!Array.isArray(this.scheme))return;var color;if(this.generatorIndex==this.rotateCount*2-1){color=d3.interpolateHsl(this.scheme[this.generatorIndex],this.scheme[0])(.5);this.generatorIndex=0;this.rotateCount*=2}else{color=d3.interpolateHsl(this.scheme[this.generatorIndex],this.scheme[this.generatorIndex+1])(.5);this.generatorIndex++}this.scheme.push(color);return color}};Rickshaw.namespace("Rickshaw.Graph.Ajax");Rickshaw.Graph.Ajax=Rickshaw.Class.create({initialize:function(args){this.dataURL=args.dataURL;this.onData=args.onData||function(d){return d};this.onComplete=args.onComplete||function(){};this.onError=args.onError||function(){};this.args=args;this.request()},request:function(){jQuery.ajax({url:this.dataURL,dataType:"json",success:this.success.bind(this),error:this.error.bind(this)})},error:function(){console.log("error loading dataURL: "+this.dataURL);this.onError(this)},success:function(data,status){data=this.onData(data);this.args.series=this._splice({data:data,series:this.args.series});this.graph=this.graph||new Rickshaw.Graph(this.args);this.graph.render();this.onComplete(this)},_splice:function(args){var data=args.data;var series=args.series;if(!args.series)return data;series.forEach(function(s){var seriesKey=s.key||s.name;if(!seriesKey)throw"series needs a key or a name";data.forEach(function(d){var dataKey=d.key||d.name;if(!dataKey)throw"data needs a key or a name";if(seriesKey==dataKey){var properties=["color","name","data"];properties.forEach(function(p){if(d[p])s[p]=d[p]})}})});return series}});Rickshaw.namespace("Rickshaw.Graph.Annotate");Rickshaw.Graph.Annotate=function(args){var graph=this.graph=args.graph;this.elements={timeline:args.element};var self=this;this.data={};this.elements.timeline.classList.add("rickshaw_annotation_timeline");this.add=function(time,content,end_time){self.data[time]=self.data[time]||{boxes:[]};self.data[time].boxes.push({content:content,end:end_time})};this.update=function(){Rickshaw.keys(self.data).forEach(function(time){var annotation=self.data[time];var left=self.graph.x(time);if(left<0||left>self.graph.x.range()[1]){if(annotation.element){annotation.line.classList.add("offscreen");annotation.element.style.display="none"}annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.add("offscreen")});return}if(!annotation.element){var element=annotation.element=document.createElement("div");element.classList.add("annotation");this.elements.timeline.appendChild(element);element.addEventListener("click",function(e){element.classList.toggle("active");annotation.line.classList.toggle("active");annotation.boxes.forEach(function(box){if(box.rangeElement)box.rangeElement.classList.toggle("active")})},false)}annotation.element.style.left=left+"px";annotation.element.style.display="block";annotation.boxes.forEach(function(box){var element=box.element;if(!element){element=box.element=document.createElement("div");element.classList.add("content");element.innerHTML=box.content;annotation.element.appendChild(element);annotation.line=document.createElement("div");annotation.line.classList.add("annotation_line");self.graph.element.appendChild(annotation.line);if(box.end){box.rangeElement=document.createElement("div");box.rangeElement.classList.add("annotation_range");self.graph.element.appendChild(box.rangeElement)}}if(box.end){var annotationRangeStart=left;var annotationRangeEnd=Math.min(self.graph.x(box.end),self.graph.x.range()[1]);if(annotationRangeStart>annotationRangeEnd){annotationRangeEnd=left;annotationRangeStart=Math.max(self.graph.x(box.end),self.graph.x.range()[0])}var annotationRangeWidth=annotationRangeEnd-annotationRangeStart;box.rangeElement.style.left=annotationRangeStart+"px";box.rangeElement.style.width=annotationRangeWidth+"px";box.rangeElement.classList.remove("offscreen")}annotation.line.classList.remove("offscreen");annotation.line.style.left=left+"px"})},this)};this.graph.onUpdate(function(){self.update()})};Rickshaw.namespace("Rickshaw.Graph.Axis.Time");Rickshaw.Graph.Axis.Time=function(args){var self=this;this.graph=args.graph;this.elements=[];this.ticksTreatment=args.ticksTreatment||"plain";this.fixedTimeUnit=args.timeUnit;var time=args.timeFixture||new Rickshaw.Fixtures.Time;this.appropriateTimeUnit=function(){var unit;var units=time.units;var domain=this.graph.x.domain();var rangeSeconds=domain[1]-domain[0];units.forEach(function(u){if(Math.floor(rangeSeconds/u.seconds)>=2){unit=unit||u}});return unit||time.units[time.units.length-1]};this.tickOffsets=function(){var domain=this.graph.x.domain();var unit=this.fixedTimeUnit||this.appropriateTimeUnit();var count=Math.ceil((domain[1]-domain[0])/unit.seconds);var runningTick=domain[0];var offsets=[];for(var i=0;i<count;i++){var tickValue=time.ceil(runningTick,unit);runningTick=tickValue+unit.seconds/2;offsets.push({value:tickValue,unit:unit})}return offsets};this.render=function(){this.elements.forEach(function(e){e.parentNode.removeChild(e)});this.elements=[];var offsets=this.tickOffsets();offsets.forEach(function(o){if(self.graph.x(o.value)>self.graph.x.range()[1])return;var element=document.createElement("div");element.style.left=self.graph.x(o.value)+"px";element.classList.add("x_tick");element.classList.add(self.ticksTreatment);var title=document.createElement("div");title.classList.add("title");title.innerHTML=o.unit.formatter(new Date(o.value*1e3));element.appendChild(title);self.graph.element.appendChild(element);self.elements.push(element)})};this.graph.onUpdate(function(){self.render()})};Rickshaw.namespace("Rickshaw.Graph.Axis.X");Rickshaw.Graph.Axis.X=function(args){var self=this;var berthRate=.1;this.initialize=function(args){this.graph=args.graph;this.orientation=args.orientation||"top";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";if(args.element){this.element=args.element;this._discoverSize(args.element,args);this.vis=d3.select(args.element).append("svg:svg").attr("height",this.height).attr("width",this.width).attr("class","rickshaw_graph x_axis_d3");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}this.graph.onUpdate(function(){self.render()})};this.setSize=function(args){args=args||{};if(!this.element)return;this._discoverSize(this.element.parentNode,args);this.vis.attr("height",this.height).attr("width",this.width*(1+berthRate));var berth=Math.floor(this.width*berthRate/2);this.element.style.left=-1*berth+"px"};this.render=function(){if(this._renderWidth!==undefined&&this.graph.width!==this._renderWidth)this.setSize({auto:true});var axis=d3.svg.axis().scale(this.graph.x).orient(this.orientation);axis.tickFormat(args.tickFormat||function(x){return x});if(this.tickValues)axis.tickValues(this.tickValues);this.ticks=this.staticTicks||Math.floor(this.graph.width/this.pixelsPerTick);var berth=Math.floor(this.width*berthRate/2)||0;var transform;if(this.orientation=="top"){var yOffset=this.height||this.graph.height;transform="translate("+berth+","+yOffset+")"}else{transform="translate("+berth+", 0)"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["x_ticks_d3",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));var gridSize=(this.orientation=="bottom"?1:-1)*this.graph.height;this.graph.vis.append("svg:g").attr("class","x_grid_d3").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-x-value",this.textContent)});this._renderHeight=this.graph.height};this._discoverSize=function(element,args){if(typeof window!=="undefined"){var style=window.getComputedStyle(element,null);var elementHeight=parseInt(style.getPropertyValue("height"),10);if(!args.auto){var elementWidth=parseInt(style.getPropertyValue("width"),10)}}this.width=(args.width||elementWidth||this.graph.width)*(1+berthRate);this.height=args.height||elementHeight||40};this.initialize(args)};Rickshaw.namespace("Rickshaw.Graph.Axis.Y");Rickshaw.Graph.Axis.Y=Rickshaw.Class.create({initialize:function(args){this.graph=args.graph;this.orientation=args.orientation||"right";this.pixelsPerTick=args.pixelsPerTick||75;if(args.ticks)this.staticTicks=args.ticks;if(args.tickValues)this.tickValues=args.tickValues;this.tickSize=args.tickSize||4;this.ticksTreatment=args.ticksTreatment||"plain";this.tickFormat=args.tickFormat||function(y){return y};this.berthRate=.1;if(args.element){this.element=args.element;this.vis=d3.select(args.element).append("svg:svg").attr("class","rickshaw_graph y_axis");this.element=this.vis[0][0];this.element.style.position="relative";this.setSize({width:args.width,height:args.height})}else{this.vis=this.graph.vis}var self=this;this.graph.onUpdate(function(){self.render()})},setSize:function(args){args=args||{};if(!this.element)return;if(typeof window!=="undefined"){var style=window.getComputedStyle(this.element.parentNode,null);var elementWidth=parseInt(style.getPropertyValue("width"),10);if(!args.auto){var elementHeight=parseInt(style.getPropertyValue("height"),10)}}this.width=args.width||elementWidth||this.graph.width*this.berthRate;this.height=args.height||elementHeight||this.graph.height;this.vis.attr("width",this.width).attr("height",this.height*(1+this.berthRate));var berth=this.height*this.berthRate;if(this.orientation=="left"){this.element.style.top=-1*berth+"px"}},render:function(){if(this._renderHeight!==undefined&&this.graph.height!==this._renderHeight)this.setSize({auto:true});this.ticks=this.staticTicks||Math.floor(this.graph.height/this.pixelsPerTick);var axis=this._drawAxis(this.graph.y);this._drawGrid(axis);this._renderHeight=this.graph.height},_drawAxis:function(scale){var axis=d3.svg.axis().scale(scale).orient(this.orientation);axis.tickFormat(this.tickFormat);if(this.tickValues)axis.tickValues(this.tickValues);if(this.orientation=="left"){var berth=this.height*this.berthRate;var transform="translate("+this.width+", "+berth+")"}if(this.element){this.vis.selectAll("*").remove()}this.vis.append("svg:g").attr("class",["y_ticks",this.ticksTreatment].join(" ")).attr("transform",transform).call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));return axis},_drawGrid:function(axis){var gridSize=(this.orientation=="right"?1:-1)*this.graph.width;this.graph.vis.append("svg:g").attr("class","y_grid").call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize)).selectAll("text").each(function(){this.parentNode.setAttribute("data-y-value",this.textContent)
2
+ })}});Rickshaw.namespace("Rickshaw.Graph.Axis.Y.Scaled");Rickshaw.Graph.Axis.Y.Scaled=Rickshaw.Class.create(Rickshaw.Graph.Axis.Y,{initialize:function($super,args){if(typeof args.scale==="undefined"){throw new Error("Scaled requires scale")}this.scale=args.scale;if(typeof args.grid==="undefined"){this.grid=true}else{this.grid=args.grid}$super(args)},_drawAxis:function($super,scale){var domain=this.scale.domain();var renderDomain=this.graph.renderer.domain().y;var extents=[Math.min.apply(Math,domain),Math.max.apply(Math,domain)];var extentMap=d3.scale.linear().domain([0,1]).range(extents);var adjExtents=[extentMap(renderDomain[0]),extentMap(renderDomain[1])];var adjustment=d3.scale.linear().domain(extents).range(adjExtents);var adjustedScale=this.scale.copy().domain(domain.map(adjustment)).range(scale.range());return $super(adjustedScale)},_drawGrid:function($super,axis){if(this.grid){$super(axis)}}});Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Highlight");Rickshaw.Graph.Behavior.Series.Highlight=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;var colorSafe={};var activeLine=null;var disabledColor=args.disabledColor||function(seriesColor){return d3.interpolateRgb(seriesColor,d3.rgb("#d8d8d8"))(.8).toString()};this.addHighlightEvents=function(l){l.element.addEventListener("mouseover",function(e){if(activeLine)return;else activeLine=l;self.legend.lines.forEach(function(line){if(l===line){if(self.graph.renderer.unstack&&(line.series.renderer?line.series.renderer.unstack:true)){var seriesIndex=self.graph.series.indexOf(line.series);line.originalIndex=seriesIndex;var series=self.graph.series.splice(seriesIndex,1)[0];self.graph.series.push(series)}return}colorSafe[line.series.name]=colorSafe[line.series.name]||line.series.color;line.series.color=disabledColor(line.series.color)});self.graph.update()},false);l.element.addEventListener("mouseout",function(e){if(!activeLine)return;else activeLine=null;self.legend.lines.forEach(function(line){if(l===line&&line.hasOwnProperty("originalIndex")){var series=self.graph.series.pop();self.graph.series.splice(line.originalIndex,0,series);delete line.originalIndex}if(colorSafe[line.series.name]){line.series.color=colorSafe[line.series.name]}});self.graph.update()},false)};if(this.legend){this.legend.lines.forEach(function(l){self.addHighlightEvents(l)})}};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Order");Rickshaw.Graph.Behavior.Series.Order=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;if(typeof window.jQuery=="undefined"){throw"couldn't find jQuery at window.jQuery"}if(typeof window.jQuery.ui=="undefined"){throw"couldn't find jQuery UI at window.jQuery.ui"}jQuery(function(){jQuery(self.legend.list).sortable({containment:"parent",tolerance:"pointer",update:function(event,ui){var series=[];jQuery(self.legend.list).find("li").each(function(index,item){if(!item.series)return;series.push(item.series)});for(var i=self.graph.series.length-1;i>=0;i--){self.graph.series[i]=series.shift()}self.graph.update()}});jQuery(self.legend.list).disableSelection()});this.graph.onUpdate(function(){var h=window.getComputedStyle(self.legend.element).height;self.legend.element.style.height=h})};Rickshaw.namespace("Rickshaw.Graph.Behavior.Series.Toggle");Rickshaw.Graph.Behavior.Series.Toggle=function(args){this.graph=args.graph;this.legend=args.legend;var self=this;this.addAnchor=function(line){var anchor=document.createElement("a");anchor.innerHTML="&#10004;";anchor.classList.add("action");line.element.insertBefore(anchor,line.element.firstChild);anchor.onclick=function(e){if(line.series.disabled){line.series.enable();line.element.classList.remove("disabled")}else{if(this.graph.series.filter(function(s){return!s.disabled}).length<=1)return;line.series.disable();line.element.classList.add("disabled")}}.bind(this);var label=line.element.getElementsByTagName("span")[0];label.onclick=function(e){var disableAllOtherLines=line.series.disabled;if(!disableAllOtherLines){for(var i=0;i<self.legend.lines.length;i++){var l=self.legend.lines[i];if(line.series===l.series){}else if(l.series.disabled){}else{disableAllOtherLines=true;break}}}if(disableAllOtherLines){line.series.enable();line.element.classList.remove("disabled");self.legend.lines.forEach(function(l){if(line.series===l.series){}else{l.series.disable();l.element.classList.add("disabled")}})}else{self.legend.lines.forEach(function(l){l.series.enable();l.element.classList.remove("disabled")})}}};if(this.legend){var $=jQuery;if(typeof $!="undefined"&&$(this.legend.list).sortable){$(this.legend.list).sortable({start:function(event,ui){ui.item.bind("no.onclick",function(event){event.preventDefault()})},stop:function(event,ui){setTimeout(function(){ui.item.unbind("no.onclick")},250)}})}this.legend.lines.forEach(function(l){self.addAnchor(l)})}this._addBehavior=function(){this.graph.series.forEach(function(s){s.disable=function(){if(self.graph.series.length<=1){throw"only one series left"}s.disabled=true;self.graph.update()};s.enable=function(){s.disabled=false;self.graph.update()}})};this._addBehavior();this.updateBehaviour=function(){this._addBehavior()}};Rickshaw.namespace("Rickshaw.Graph.HoverDetail");Rickshaw.Graph.HoverDetail=Rickshaw.Class.create({initialize:function(args){var graph=this.graph=args.graph;this.xFormatter=args.xFormatter||function(x){return new Date(x*1e3).toUTCString()};this.yFormatter=args.yFormatter||function(y){return y===null?y:y.toFixed(2)};var element=this.element=document.createElement("div");element.className="detail";this.visible=true;graph.element.appendChild(element);this.lastEvent=null;this._addListeners();this.onShow=args.onShow;this.onHide=args.onHide;this.onRender=args.onRender;this.formatter=args.formatter||this.formatter},formatter:function(series,x,y,formattedX,formattedY,d){return series.name+":&nbsp;"+formattedY},update:function(e){e=e||this.lastEvent;if(!e)return;this.lastEvent=e;if(!e.target.nodeName.match(/^(path|svg|rect|circle)$/))return;var graph=this.graph;var eventX=e.offsetX||e.layerX;var eventY=e.offsetY||e.layerY;var j=0;var points=[];var nearestPoint;this.graph.series.active().forEach(function(series){var data=this.graph.stackedData[j++];if(!data.length)return;var domainX=graph.x.invert(eventX);var domainIndexScale=d3.scale.linear().domain([data[0].x,data.slice(-1)[0].x]).range([0,data.length-1]);var approximateIndex=Math.round(domainIndexScale(domainX));if(approximateIndex==data.length-1)approximateIndex--;var dataIndex=Math.min(approximateIndex||0,data.length-1);for(var i=approximateIndex;i<data.length-1;){if(!data[i]||!data[i+1])break;if(data[i].x<=domainX&&data[i+1].x>domainX){dataIndex=Math.abs(domainX-data[i].x)<Math.abs(domainX-data[i+1].x)?i:i+1;break}if(data[i+1].x<=domainX){i++}else{i--}}if(dataIndex<0)dataIndex=0;var value=data[dataIndex];var distance=Math.sqrt(Math.pow(Math.abs(graph.x(value.x)-eventX),2)+Math.pow(Math.abs(graph.y(value.y+value.y0)-eventY),2));var xFormatter=series.xFormatter||this.xFormatter;var yFormatter=series.yFormatter||this.yFormatter;var point={formattedXValue:xFormatter(value.x),formattedYValue:yFormatter(series.scale?series.scale.invert(value.y):value.y),series:series,value:value,distance:distance,order:j,name:series.name};if(!nearestPoint||distance<nearestPoint.distance){nearestPoint=point}points.push(point)},this);if(!nearestPoint)return;nearestPoint.active=true;var domainX=nearestPoint.value.x;var formattedXValue=nearestPoint.formattedXValue;this.element.innerHTML="";this.element.style.left=graph.x(domainX)+"px";this.visible&&this.render({points:points,detail:points,mouseX:eventX,mouseY:eventY,formattedXValue:formattedXValue,domainX:domainX})},hide:function(){this.visible=false;this.element.classList.add("inactive");if(typeof this.onHide=="function"){this.onHide()}},show:function(){this.visible=true;this.element.classList.remove("inactive");if(typeof this.onShow=="function"){this.onShow()}},render:function(args){var graph=this.graph;var points=args.points;var point=points.filter(function(p){return p.active}).shift();if(point.value.y===null)return;var formattedXValue=point.formattedXValue;var formattedYValue=point.formattedYValue;this.element.innerHTML="";this.element.style.left=graph.x(point.value.x)+"px";var xLabel=document.createElement("div");xLabel.className="x_label";xLabel.innerHTML=formattedXValue;this.element.appendChild(xLabel);var item=document.createElement("div");item.className="item";var series=point.series;var actualY=series.scale?series.scale.invert(point.value.y):point.value.y;item.innerHTML=this.formatter(series,point.value.x,actualY,formattedXValue,formattedYValue,point);item.style.top=this.graph.y(point.value.y0+point.value.y)+"px";this.element.appendChild(item);var dot=document.createElement("div");dot.className="dot";dot.style.top=item.style.top;dot.style.borderColor=series.color;this.element.appendChild(dot);if(point.active){item.classList.add("active");dot.classList.add("active")}var alignables=[xLabel,item];alignables.forEach(function(el){el.classList.add("left")});this.show();var leftAlignError=this._calcLayoutError(alignables);if(leftAlignError>0){alignables.forEach(function(el){el.classList.remove("left");el.classList.add("right")});var rightAlignError=this._calcLayoutError(alignables);if(rightAlignError>leftAlignError){alignables.forEach(function(el){el.classList.remove("right");el.classList.add("left")})}}if(typeof this.onRender=="function"){this.onRender(args)}},_calcLayoutError:function(alignables){var parentRect=this.element.parentNode.getBoundingClientRect();var error=0;var alignRight=alignables.forEach(function(el){var rect=el.getBoundingClientRect();if(!rect.width){return}if(rect.right>parentRect.right){error+=rect.right-parentRect.right}if(rect.left<parentRect.left){error+=parentRect.left-rect.left}});return error},_addListeners:function(){this.graph.element.addEventListener("mousemove",function(e){this.visible=true;this.update(e)}.bind(this),false);this.graph.onUpdate(function(){this.update()}.bind(this));this.graph.element.addEventListener("mouseout",function(e){if(e.relatedTarget&&!(e.relatedTarget.compareDocumentPosition(this.graph.element)&Node.DOCUMENT_POSITION_CONTAINS)){this.hide()}}.bind(this),false)}});Rickshaw.namespace("Rickshaw.Graph.JSONP");Rickshaw.Graph.JSONP=Rickshaw.Class.create(Rickshaw.Graph.Ajax,{request:function(){jQuery.ajax({url:this.dataURL,dataType:"jsonp",success:this.success.bind(this),error:this.error.bind(this)})}});Rickshaw.namespace("Rickshaw.Graph.Legend");Rickshaw.Graph.Legend=Rickshaw.Class.create({className:"rickshaw_legend",initialize:function(args){this.element=args.element;this.graph=args.graph;this.naturalOrder=args.naturalOrder;this.element.classList.add(this.className);this.list=document.createElement("ul");this.element.appendChild(this.list);this.render();this.graph.onUpdate(function(){})},render:function(){var self=this;while(this.list.firstChild){this.list.removeChild(this.list.firstChild)}this.lines=[];var series=this.graph.series.map(function(s){return s});if(!this.naturalOrder){series=series.reverse()}series.forEach(function(s){self.addLine(s)})},addLine:function(series){var line=document.createElement("li");line.className="line";if(series.disabled){line.className+=" disabled"}if(series.className){d3.select(line).classed(series.className,true)}var swatch=document.createElement("div");swatch.className="swatch";swatch.style.backgroundColor=series.color;line.appendChild(swatch);var label=document.createElement("span");label.className="label";label.innerHTML=series.name;line.appendChild(label);this.list.appendChild(line);line.series=series;if(series.noLegend){line.style.display="none"}var _line={element:line,series:series};if(this.shelving){this.shelving.addAnchor(_line);this.shelving.updateBehaviour()}if(this.highlighter){this.highlighter.addHighlightEvents(_line)}this.lines.push(_line);return line}});Rickshaw.namespace("Rickshaw.Graph.RangeSlider");Rickshaw.Graph.RangeSlider=Rickshaw.Class.create({initialize:function(args){var element=this.element=args.element;var graph=this.graph=args.graph;this.slideCallbacks=[];this.build();graph.onUpdate(function(){this.update()}.bind(this))},build:function(){var element=this.element;var graph=this.graph;var $=jQuery;var domain=graph.dataDomain();var self=this;$(function(){$(element).slider({range:true,min:domain[0],max:domain[1],values:[domain[0],domain[1]],slide:function(event,ui){if(ui.values[1]<=ui.values[0])return;graph.window.xMin=ui.values[0];graph.window.xMax=ui.values[1];graph.update();var domain=graph.dataDomain();if(domain[0]==ui.values[0]){graph.window.xMin=undefined}if(domain[1]==ui.values[1]){graph.window.xMax=undefined}self.slideCallbacks.forEach(function(callback){callback(graph,graph.window.xMin,graph.window.xMax)})}})});$(element)[0].style.width=graph.width+"px"},update:function(){var element=this.element;var graph=this.graph;var $=jQuery;var values=$(element).slider("option","values");var domain=graph.dataDomain();$(element).slider("option","min",domain[0]);$(element).slider("option","max",domain[1]);if(graph.window.xMin==null){values[0]=domain[0]}if(graph.window.xMax==null){values[1]=domain[1]}$(element).slider("option","values",values)},onSlide:function(callback){this.slideCallbacks.push(callback)}});Rickshaw.namespace("Rickshaw.Graph.RangeSlider.Preview");Rickshaw.Graph.RangeSlider.Preview=Rickshaw.Class.create({initialize:function(args){if(!args.element)throw"Rickshaw.Graph.RangeSlider.Preview needs a reference to an element";if(!args.graph&&!args.graphs)throw"Rickshaw.Graph.RangeSlider.Preview needs a reference to an graph or an array of graphs";this.element=args.element;this.element.style.position="relative";this.graphs=args.graph?[args.graph]:args.graphs;this.defaults={height:75,width:400,gripperColor:undefined,frameTopThickness:3,frameHandleThickness:10,frameColor:"#d4d4d4",frameOpacity:1,minimumFrameWidth:0,heightRatio:.2};this.heightRatio=args.heightRatio||this.defaults.heightRatio;this.defaults.gripperColor=d3.rgb(this.defaults.frameColor).darker().toString();this.configureCallbacks=[];this.slideCallbacks=[];this.previews=[];if(!args.width)this.widthFromGraph=true;if(!args.height)this.heightFromGraph=true;if(this.widthFromGraph||this.heightFromGraph){this.graphs[0].onConfigure(function(){this.configure(args);this.render()}.bind(this))}args.width=args.width||this.graphs[0].width||this.defaults.width;args.height=args.height||this.graphs[0].height*this.heightRatio||this.defaults.height;this.configure(args);this.render()},onSlide:function(callback){this.slideCallbacks.push(callback)},onConfigure:function(callback){this.configureCallbacks.push(callback)},configure:function(args){this.config=this.config||{};this.configureCallbacks.forEach(function(callback){callback(args)});Rickshaw.keys(this.defaults).forEach(function(k){this.config[k]=k in args?args[k]:k in this.config?this.config[k]:this.defaults[k]},this);if("width"in args||"height"in args){if(this.widthFromGraph){this.config.width=this.graphs[0].width}if(this.heightFromGraph){this.config.height=this.graphs[0].height*this.heightRatio;this.previewHeight=this.config.height}this.previews.forEach(function(preview){var height=this.previewHeight/this.graphs.length-this.config.frameTopThickness*2;var width=this.config.width-this.config.frameHandleThickness*2;preview.setSize({width:width,height:height});if(this.svg){var svgHeight=height+this.config.frameHandleThickness*2;var svgWidth=width+this.config.frameHandleThickness*2;this.svg.style("width",svgWidth+"px");this.svg.style("height",svgHeight+"px")}},this)}},render:function(){var self=this;this.svg=d3.select(this.element).selectAll("svg.rickshaw_range_slider_preview").data([null]);this.previewHeight=this.config.height-this.config.frameTopThickness*2;this.previewWidth=this.config.width-this.config.frameHandleThickness*2;this.currentFrame=[0,this.previewWidth];var buildGraph=function(parent,index){var graphArgs=Rickshaw.extend({},parent.config);var height=self.previewHeight/self.graphs.length;var renderer=parent.renderer.name;Rickshaw.extend(graphArgs,{element:this.appendChild(document.createElement("div")),height:height,width:self.previewWidth,series:parent.series,renderer:renderer});var graph=new Rickshaw.Graph(graphArgs);self.previews.push(graph);parent.onUpdate(function(){graph.render();self.render()});parent.onConfigure(function(args){delete args.height;args.width=args.width-self.config.frameHandleThickness*2;graph.configure(args);graph.render()});graph.render()};var graphContainer=d3.select(this.element).selectAll("div.rickshaw_range_slider_preview_container").data(this.graphs);var translateCommand="translate("+this.config.frameHandleThickness+"px, "+this.config.frameTopThickness+"px)";graphContainer.enter().append("div").classed("rickshaw_range_slider_preview_container",true).style("-webkit-transform",translateCommand).style("-moz-transform",translateCommand).style("-ms-transform",translateCommand).style("transform",translateCommand).each(buildGraph);graphContainer.exit().remove();var masterGraph=this.graphs[0];var domainScale=d3.scale.linear().domain([0,this.previewWidth]).range(masterGraph.dataDomain());var currentWindow=[masterGraph.window.xMin,masterGraph.window.xMax];this.currentFrame[0]=currentWindow[0]===undefined?0:Math.round(domainScale.invert(currentWindow[0]));if(this.currentFrame[0]<0)this.currentFrame[0]=0;this.currentFrame[1]=currentWindow[1]===undefined?this.previewWidth:domainScale.invert(currentWindow[1]);if(this.currentFrame[1]-this.currentFrame[0]<self.config.minimumFrameWidth){this.currentFrame[1]=(this.currentFrame[0]||0)+self.config.minimumFrameWidth}this.svg.enter().append("svg").classed("rickshaw_range_slider_preview",true).style("height",this.config.height+"px").style("width",this.config.width+"px").style("position","absolute").style("top",0);this._renderDimming();this._renderFrame();this._renderGrippers();this._renderHandles();this._renderMiddle();this._registerMouseEvents()},_renderDimming:function(){var element=this.svg.selectAll("path.dimming").data([null]);element.enter().append("path").attr("fill","white").attr("fill-opacity","0.7").attr("fill-rule","evenodd").classed("dimming",true);var path="";path+=" M "+this.config.frameHandleThickness+" "+this.config.frameTopThickness;path+=" h "+this.previewWidth;path+=" v "+this.previewHeight;path+=" h "+-this.previewWidth;path+=" z ";path+=" M "+Math.max(this.currentFrame[0],this.config.frameHandleThickness)+" "+this.config.frameTopThickness;path+=" H "+Math.min(this.currentFrame[1]+this.config.frameHandleThickness*2,this.previewWidth+this.config.frameHandleThickness);path+=" v "+this.previewHeight;path+=" H "+Math.max(this.currentFrame[0],this.config.frameHandleThickness);path+=" z";element.attr("d",path)},_renderFrame:function(){var element=this.svg.selectAll("path.frame").data([null]);element.enter().append("path").attr("stroke","white").attr("stroke-width","1px").attr("stroke-linejoin","round").attr("fill",this.config.frameColor).attr("fill-opacity",this.config.frameOpacity).attr("fill-rule","evenodd").classed("frame",true);var path="";path+=" M "+this.currentFrame[0]+" 0";path+=" H "+(this.currentFrame[1]+this.config.frameHandleThickness*2);path+=" V "+this.config.height;path+=" H "+this.currentFrame[0];path+=" z";path+=" M "+(this.currentFrame[0]+this.config.frameHandleThickness)+" "+this.config.frameTopThickness;path+=" H "+(this.currentFrame[1]+this.config.frameHandleThickness);path+=" v "+this.previewHeight;path+=" H "+(this.currentFrame[0]+this.config.frameHandleThickness);path+=" z";element.attr("d",path)},_renderGrippers:function(){var gripper=this.svg.selectAll("path.gripper").data([null]);gripper.enter().append("path").attr("stroke",this.config.gripperColor).classed("gripper",true);var path="";[.4,.6].forEach(function(spacing){path+=" M "+Math.round(this.currentFrame[0]+this.config.frameHandleThickness*spacing)+" "+Math.round(this.config.height*.3);path+=" V "+Math.round(this.config.height*.7);path+=" M "+Math.round(this.currentFrame[1]+this.config.frameHandleThickness*(1+spacing))+" "+Math.round(this.config.height*.3);path+=" V "+Math.round(this.config.height*.7)}.bind(this));gripper.attr("d",path)},_renderHandles:function(){var leftHandle=this.svg.selectAll("rect.left_handle").data([null]);leftHandle.enter().append("rect").attr("width",this.config.frameHandleThickness).style("cursor","ew-resize").style("fill-opacity","0").classed("left_handle",true);leftHandle.attr("x",this.currentFrame[0]).attr("height",this.config.height);var rightHandle=this.svg.selectAll("rect.right_handle").data([null]);rightHandle.enter().append("rect").attr("width",this.config.frameHandleThickness).style("cursor","ew-resize").style("fill-opacity","0").classed("right_handle",true);rightHandle.attr("x",this.currentFrame[1]+this.config.frameHandleThickness).attr("height",this.config.height)},_renderMiddle:function(){var middleHandle=this.svg.selectAll("rect.middle_handle").data([null]);middleHandle.enter().append("rect").style("cursor","move").style("fill-opacity","0").classed("middle_handle",true);middleHandle.attr("width",Math.max(0,this.currentFrame[1]-this.currentFrame[0])).attr("x",this.currentFrame[0]+this.config.frameHandleThickness).attr("height",this.config.height)},_registerMouseEvents:function(){var element=d3.select(this.element);var drag={target:null,start:null,stop:null,left:false,right:false,rigid:false};var self=this;function onMousemove(datum,index){drag.stop=self._getClientXFromEvent(d3.event,drag);var distanceTraveled=drag.stop-drag.start;var frameAfterDrag=self.frameBeforeDrag.slice(0);var minimumFrameWidth=self.config.minimumFrameWidth;if(drag.rigid){minimumFrameWidth=self.frameBeforeDrag[1]-self.frameBeforeDrag[0]}if(drag.left){frameAfterDrag[0]=Math.max(frameAfterDrag[0]+distanceTraveled,0)}if(drag.right){frameAfterDrag[1]=Math.min(frameAfterDrag[1]+distanceTraveled,self.previewWidth)}var currentFrameWidth=frameAfterDrag[1]-frameAfterDrag[0];if(currentFrameWidth<=minimumFrameWidth){if(drag.left){frameAfterDrag[0]=frameAfterDrag[1]-minimumFrameWidth}if(drag.right){frameAfterDrag[1]=frameAfterDrag[0]+minimumFrameWidth}if(frameAfterDrag[0]<=0){frameAfterDrag[1]-=frameAfterDrag[0];frameAfterDrag[0]=0}if(frameAfterDrag[1]>=self.previewWidth){frameAfterDrag[0]-=frameAfterDrag[1]-self.previewWidth;frameAfterDrag[1]=self.previewWidth}}self.graphs.forEach(function(graph){var domainScale=d3.scale.linear().interpolate(d3.interpolateNumber).domain([0,self.previewWidth]).range(graph.dataDomain());var windowAfterDrag=[domainScale(frameAfterDrag[0]),domainScale(frameAfterDrag[1])];self.slideCallbacks.forEach(function(callback){callback(graph,windowAfterDrag[0],windowAfterDrag[1])});if(frameAfterDrag[0]===0){windowAfterDrag[0]=undefined}if(frameAfterDrag[1]===self.previewWidth){windowAfterDrag[1]=undefined}graph.window.xMin=windowAfterDrag[0];graph.window.xMax=windowAfterDrag[1];graph.update()})}function onMousedown(){drag.target=d3.event.target;drag.start=self._getClientXFromEvent(d3.event,drag);self.frameBeforeDrag=self.currentFrame.slice();d3.event.preventDefault?d3.event.preventDefault():d3.event.returnValue=false;d3.select(document).on("mousemove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("mouseup.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchmove.rickshaw_range_slider_preview",onMousemove);d3.select(document).on("touchend.rickshaw_range_slider_preview",onMouseup);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",onMouseup)}function onMousedownLeftHandle(datum,index){drag.left=true;onMousedown()}function onMousedownRightHandle(datum,index){drag.right=true;onMousedown()}function onMousedownMiddleHandle(datum,index){drag.left=true;drag.right=true;drag.rigid=true;onMousedown()}function onMouseup(datum,index){d3.select(document).on("mousemove.rickshaw_range_slider_preview",null);d3.select(document).on("mouseup.rickshaw_range_slider_preview",null);d3.select(document).on("touchmove.rickshaw_range_slider_preview",null);d3.select(document).on("touchend.rickshaw_range_slider_preview",null);d3.select(document).on("touchcancel.rickshaw_range_slider_preview",null);delete self.frameBeforeDrag;drag.left=false;drag.right=false;drag.rigid=false}element.select("rect.left_handle").on("mousedown",onMousedownLeftHandle);element.select("rect.right_handle").on("mousedown",onMousedownRightHandle);element.select("rect.middle_handle").on("mousedown",onMousedownMiddleHandle);element.select("rect.left_handle").on("touchstart",onMousedownLeftHandle);element.select("rect.right_handle").on("touchstart",onMousedownRightHandle);element.select("rect.middle_handle").on("touchstart",onMousedownMiddleHandle)},_getClientXFromEvent:function(event,drag){switch(event.type){case"touchstart":case"touchmove":var touchList=event.changedTouches;var touch=null;for(var touchIndex=0;touchIndex<touchList.length;touchIndex++){if(touchList[touchIndex].target===drag.target){touch=touchList[touchIndex];break}}return touch!==null?touch.clientX:undefined;default:return event.clientX}}});Rickshaw.namespace("Rickshaw.Graph.Renderer");Rickshaw.Graph.Renderer=Rickshaw.Class.create({initialize:function(args){this.graph=args.graph;this.tension=args.tension||this.tension;this.configure(args)},seriesPathFactory:function(){},seriesStrokeFactory:function(){},defaults:function(){return{tension:.8,strokeWidth:2,unstack:true,padding:{top:.01,right:0,bottom:.01,left:0},stroke:false,fill:false}},domain:function(data){var stackedData=data||this.graph.stackedData||this.graph.stackData();var xMin=+Infinity;var xMax=-Infinity;var yMin=+Infinity;var yMax=-Infinity;stackedData.forEach(function(series){series.forEach(function(d){if(d.y==null)return;var y=d.y+d.y0;if(y<yMin)yMin=y;if(y>yMax)yMax=y});if(!series.length)return;if(series[0].x<xMin)xMin=series[0].x;if(series[series.length-1].x>xMax)xMax=series[series.length-1].x});xMin-=(xMax-xMin)*this.padding.left;xMax+=(xMax-xMin)*this.padding.right;yMin=this.graph.min==="auto"?yMin:this.graph.min||0;yMax=this.graph.max===undefined?yMax:this.graph.max;if(this.graph.min==="auto"||yMin<0){yMin-=(yMax-yMin)*this.padding.bottom}if(this.graph.max===undefined){yMax+=(yMax-yMin)*this.padding.top}return{x:[xMin,xMax],y:[yMin,yMax]}},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var pathNodes=vis.selectAll("path.path").data(data).enter().append("svg:path").classed("path",true).attr("d",this.seriesPathFactory());if(this.stroke){var strokeNodes=vis.selectAll("path.stroke").data(data).enter().append("svg:path").classed("stroke",true).attr("d",this.seriesStrokeFactory())}var i=0;series.forEach(function(series){if(series.disabled)return;series.path=pathNodes[0][i];if(this.stroke)series.stroke=strokeNodes[0][i];this._styleSeries(series);i++},this)},_styleSeries:function(series){var fill=this.fill?series.color:"none";var stroke=this.stroke?series.color:"none";series.path.setAttribute("fill",fill);series.path.setAttribute("stroke",stroke);series.path.setAttribute("stroke-width",this.strokeWidth);if(series.className){d3.select(series.path).classed(series.className,true)}if(series.className&&this.stroke){d3.select(series.stroke).classed(series.className,true)}},configure:function(args){args=args||{};Rickshaw.keys(this.defaults()).forEach(function(key){if(!args.hasOwnProperty(key)){this[key]=this[key]||this.graph[key]||this.defaults()[key];return}if(typeof this.defaults()[key]=="object"){Rickshaw.keys(this.defaults()[key]).forEach(function(k){this[key][k]=args[key][k]!==undefined?args[key][k]:this[key][k]!==undefined?this[key][k]:this.defaults()[key][k]},this)}else{this[key]=args[key]!==undefined?args[key]:this[key]!==undefined?this[key]:this.graph[key]!==undefined?this.graph[key]:this.defaults()[key]}},this)},setStrokeWidth:function(strokeWidth){if(strokeWidth!==undefined){this.strokeWidth=strokeWidth}},setTension:function(tension){if(tension!==undefined){this.tension=tension}}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Line");Rickshaw.Graph.Renderer.Line=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"line",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Stack");Rickshaw.Graph.Renderer.Stack=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"stack",defaults:function($super){return Rickshaw.extend($super(),{fill:true,stroke:false,unstack:false})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.area().x(function(d){return graph.x(d.x)}).y0(function(d){return graph.y(d.y0)}).y1(function(d){return graph.y(d.y+d.y0)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Bar");Rickshaw.Graph.Renderer.Bar=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"bar",defaults:function($super){var defaults=Rickshaw.extend($super(),{gapSize:.05,unstack:false});delete defaults.tension;return defaults},initialize:function($super,args){args=args||{};this.gapSize=args.gapSize||this.gapSize;$super(args)},domain:function($super){var domain=$super();var frequentInterval=this._frequentInterval(this.graph.stackedData.slice(-1).shift());domain.x[1]+=Number(frequentInterval.magnitude);return domain},barWidth:function(series){var frequentInterval=this._frequentInterval(series.stack);var barWidth=this.graph.x.magnitude(frequentInterval.magnitude)*(1-this.gapSize);return barWidth},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var barWidth=this.barWidth(series.active()[0]);var barXOffset=0;var activeSeriesCount=series.filter(function(s){return!s.disabled}).length;var seriesBarWidth=this.unstack?barWidth/activeSeriesCount:barWidth;var transform=function(d){var matrix=[1,0,0,d.y<0?-1:1,0,d.y<0?graph.y.magnitude(Math.abs(d.y))*2:0];return"matrix("+matrix.join(",")+")"};series.forEach(function(series){if(series.disabled)return;var barWidth=this.barWidth(series);var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:rect").attr("x",function(d){return graph.x(d.x)+barXOffset}).attr("y",function(d){return graph.y(d.y0+Math.abs(d.y))*(d.y<0?-1:1)}).attr("width",seriesBarWidth).attr("height",function(d){return graph.y.magnitude(Math.abs(d.y))}).attr("transform",transform);Array.prototype.forEach.call(nodes[0],function(n){n.setAttribute("fill",series.color)});if(this.unstack)barXOffset+=seriesBarWidth},this)},_frequentInterval:function(data){var intervalCounts={};for(var i=0;i<data.length-1;i++){var interval=data[i+1].x-data[i].x;intervalCounts[interval]=intervalCounts[interval]||0;intervalCounts[interval]++}var frequentInterval={count:0,magnitude:1};Rickshaw.keys(intervalCounts).forEach(function(i){if(frequentInterval.count<intervalCounts[i]){frequentInterval={count:intervalCounts[i],magnitude:i}}});return frequentInterval}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Area");Rickshaw.Graph.Renderer.Area=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"area",defaults:function($super){return Rickshaw.extend($super(),{unstack:false,fill:false,stroke:false})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.area().x(function(d){return graph.x(d.x)}).y0(function(d){return graph.y(d.y0)}).y1(function(d){return graph.y(d.y+d.y0)}).interpolate(graph.interpolation).tension(this.tension);
3
+ factory.defined&&factory.defined(function(d){return d.y!==null});return factory},seriesStrokeFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y+d.y0)}).interpolate(graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;vis.selectAll("*").remove();var method=this.unstack?"append":"insert";var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var nodes=vis.selectAll("path").data(data).enter()[method]("svg:g","g");nodes.append("svg:path").attr("d",this.seriesPathFactory()).attr("class","area");if(this.stroke){nodes.append("svg:path").attr("d",this.seriesStrokeFactory()).attr("class","line")}var i=0;series.forEach(function(series){if(series.disabled)return;series.path=nodes[0][i++];this._styleSeries(series)},this)},_styleSeries:function(series){if(!series.path)return;d3.select(series.path).select(".area").attr("fill",series.color);if(this.stroke){d3.select(series.path).select(".line").attr("fill","none").attr("stroke",series.stroke||d3.interpolateRgb(series.color,"black")(.125)).attr("stroke-width",this.strokeWidth)}if(series.className){series.path.setAttribute("class",series.className)}}});Rickshaw.namespace("Rickshaw.Graph.Renderer.ScatterPlot");Rickshaw.Graph.Renderer.ScatterPlot=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"scatterplot",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:true,stroke:false,padding:{top:.01,right:.01,bottom:.01,left:.01},dotSize:4})},initialize:function($super,args){$super(args)},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;var dotSize=this.dotSize;vis.selectAll("*").remove();series.forEach(function(series){if(series.disabled)return;var nodes=vis.selectAll("path").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:circle").attr("cx",function(d){return graph.x(d.x)}).attr("cy",function(d){return graph.y(d.y)}).attr("r",function(d){return"r"in d?d.r:dotSize});if(series.className){nodes.classed(series.className,true)}Array.prototype.forEach.call(nodes[0],function(n){n.setAttribute("fill",series.color)})},this)}});Rickshaw.namespace("Rickshaw.Graph.Renderer.Multi");Rickshaw.Graph.Renderer.Multi=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"multi",initialize:function($super,args){$super(args)},defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true})},configure:function($super,args){args=args||{};this.config=args;$super(args)},domain:function($super){this.graph.stackData();var domains=[];var groups=this._groups();this._stack(groups);groups.forEach(function(group){var data=group.series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});if(!data.length)return;var domain=null;if(group.renderer&&group.renderer.domain){domain=group.renderer.domain(data)}else{domain=$super(data)}domains.push(domain)});var xMin=d3.min(domains.map(function(d){return d.x[0]}));var xMax=d3.max(domains.map(function(d){return d.x[1]}));var yMin=d3.min(domains.map(function(d){return d.y[0]}));var yMax=d3.max(domains.map(function(d){return d.y[1]}));return{x:[xMin,xMax],y:[yMin,yMax]}},_groups:function(){var graph=this.graph;var renderGroups={};graph.series.forEach(function(series){if(series.disabled)return;if(!renderGroups[series.renderer]){var ns="http://www.w3.org/2000/svg";var vis=document.createElementNS(ns,"g");graph.vis[0][0].appendChild(vis);var renderer=graph._renderers[series.renderer];var config={};var defaults=[this.defaults(),renderer.defaults(),this.config,this.graph];defaults.forEach(function(d){Rickshaw.extend(config,d)});renderer.configure(config);renderGroups[series.renderer]={renderer:renderer,series:[],vis:d3.select(vis)}}renderGroups[series.renderer].series.push(series)},this);var groups=[];Object.keys(renderGroups).forEach(function(key){var group=renderGroups[key];groups.push(group)});return groups},_stack:function(groups){groups.forEach(function(group){var series=group.series.filter(function(series){return!series.disabled});var data=series.map(function(series){return series.stack});if(!group.renderer.unstack){var layout=d3.layout.stack();var stackedData=Rickshaw.clone(layout(data));series.forEach(function(series,index){series._stack=Rickshaw.clone(stackedData[index])})}},this);return groups},render:function(){this.graph.series.forEach(function(series){if(!series.renderer){throw new Error("Each series needs a renderer for graph 'multi' renderer")}});this.graph.vis.selectAll("*").remove();var groups=this._groups();groups=this._stack(groups);groups.forEach(function(group){var series=group.series.filter(function(series){return!series.disabled});series.active=function(){return series};group.renderer.render({series:series,vis:group.vis});series.forEach(function(s){s.stack=s._stack||s.stack||s.data})})}});Rickshaw.namespace("Rickshaw.Graph.Renderer.LinePlot");Rickshaw.Graph.Renderer.LinePlot=Rickshaw.Class.create(Rickshaw.Graph.Renderer,{name:"lineplot",defaults:function($super){return Rickshaw.extend($super(),{unstack:true,fill:false,stroke:true,padding:{top:.01,right:.01,bottom:.01,left:.01},dotSize:3,strokeWidth:2})},seriesPathFactory:function(){var graph=this.graph;var factory=d3.svg.line().x(function(d){return graph.x(d.x)}).y(function(d){return graph.y(d.y)}).interpolate(this.graph.interpolation).tension(this.tension);factory.defined&&factory.defined(function(d){return d.y!==null});return factory},render:function(args){args=args||{};var graph=this.graph;var series=args.series||graph.series;var vis=args.vis||graph.vis;var dotSize=this.dotSize;vis.selectAll("*").remove();var data=series.filter(function(s){return!s.disabled}).map(function(s){return s.stack});var nodes=vis.selectAll("path").data(data).enter().append("svg:path").attr("d",this.seriesPathFactory());var i=0;series.forEach(function(series){if(series.disabled)return;series.path=nodes[0][i++];this._styleSeries(series)},this);series.forEach(function(series){if(series.disabled)return;var nodes=vis.selectAll("x").data(series.stack.filter(function(d){return d.y!==null})).enter().append("svg:circle").attr("cx",function(d){return graph.x(d.x)}).attr("cy",function(d){return graph.y(d.y)}).attr("r",function(d){return"r"in d?d.r:dotSize});Array.prototype.forEach.call(nodes[0],function(n){if(!n)return;n.setAttribute("data-color",series.color);n.setAttribute("fill","white");n.setAttribute("stroke",series.color);n.setAttribute("stroke-width",this.strokeWidth)}.bind(this))},this)}});Rickshaw.namespace("Rickshaw.Graph.Smoother");Rickshaw.Graph.Smoother=Rickshaw.Class.create({initialize:function(args){this.graph=args.graph;this.element=args.element;this.aggregationScale=1;this.build();this.graph.stackData.hooks.data.push({name:"smoother",orderPosition:50,f:this.transformer.bind(this)})},build:function(){var self=this;var $=jQuery;if(this.element){$(function(){$(self.element).slider({min:1,max:100,slide:function(event,ui){self.setScale(ui.value);self.graph.update()}})})}},setScale:function(scale){if(scale<1){throw"scale out of range: "+scale}this.aggregationScale=scale;this.graph.update()},transformer:function(data){if(this.aggregationScale==1)return data;var aggregatedData=[];data.forEach(function(seriesData){var aggregatedSeriesData=[];while(seriesData.length){var avgX=0,avgY=0;var slice=seriesData.splice(0,this.aggregationScale);slice.forEach(function(d){avgX+=d.x/slice.length;avgY+=d.y/slice.length});aggregatedSeriesData.push({x:avgX,y:avgY})}aggregatedData.push(aggregatedSeriesData)}.bind(this));return aggregatedData}});Rickshaw.namespace("Rickshaw.Graph.Socketio");Rickshaw.Graph.Socketio=Rickshaw.Class.create(Rickshaw.Graph.Ajax,{request:function(){var socket=io.connect(this.dataURL);var self=this;socket.on("rickshaw",function(data){self.success(data)})}});Rickshaw.namespace("Rickshaw.Series");Rickshaw.Series=Rickshaw.Class.create(Array,{initialize:function(data,palette,options){options=options||{};this.palette=new Rickshaw.Color.Palette(palette);this.timeBase=typeof options.timeBase==="undefined"?Math.floor((new Date).getTime()/1e3):options.timeBase;var timeInterval=typeof options.timeInterval=="undefined"?1e3:options.timeInterval;this.setTimeInterval(timeInterval);if(data&&typeof data=="object"&&Array.isArray(data)){data.forEach(function(item){this.addItem(item)},this)}},addItem:function(item){if(typeof item.name==="undefined"){throw"addItem() needs a name"}item.color=item.color||this.palette.color(item.name);item.data=item.data||[];if(item.data.length===0&&this.length&&this.getIndex()>0){this[0].data.forEach(function(plot){item.data.push({x:plot.x,y:0})})}else if(item.data.length===0){item.data.push({x:this.timeBase-(this.timeInterval||0),y:0})}this.push(item);if(this.legend){this.legend.addLine(this.itemByName(item.name))}},addData:function(data,x){var index=this.getIndex();Rickshaw.keys(data).forEach(function(name){if(!this.itemByName(name)){this.addItem({name:name})}},this);this.forEach(function(item){item.data.push({x:x||(index*this.timeInterval||1)+this.timeBase,y:data[item.name]||0})},this)},getIndex:function(){return this[0]&&this[0].data&&this[0].data.length?this[0].data.length:0},itemByName:function(name){for(var i=0;i<this.length;i++){if(this[i].name==name)return this[i]}},setTimeInterval:function(iv){this.timeInterval=iv/1e3},setTimeBase:function(t){this.timeBase=t},dump:function(){var data={timeBase:this.timeBase,timeInterval:this.timeInterval,items:[]};this.forEach(function(item){var newItem={color:item.color,name:item.name,data:[]};item.data.forEach(function(plot){newItem.data.push({x:plot.x,y:plot.y})});data.items.push(newItem)});return data},load:function(data){if(data.timeInterval){this.timeInterval=data.timeInterval}if(data.timeBase){this.timeBase=data.timeBase}if(data.items){data.items.forEach(function(item){this.push(item);if(this.legend){this.legend.addLine(this.itemByName(item.name))}},this)}}});Rickshaw.Series.zeroFill=function(series){Rickshaw.Series.fill(series,0)};Rickshaw.Series.fill=function(series,fill){var x;var i=0;var data=series.map(function(s){return s.data});while(i<Math.max.apply(null,data.map(function(d){return d.length}))){x=Math.min.apply(null,data.filter(function(d){return d[i]}).map(function(d){return d[i].x}));data.forEach(function(d){if(!d[i]||d[i].x!=x){d.splice(i,0,{x:x,y:fill})}});i++}};Rickshaw.namespace("Rickshaw.Series.FixedDuration");Rickshaw.Series.FixedDuration=Rickshaw.Class.create(Rickshaw.Series,{initialize:function(data,palette,options){options=options||{};if(typeof options.timeInterval==="undefined"){throw new Error("FixedDuration series requires timeInterval")}if(typeof options.maxDataPoints==="undefined"){throw new Error("FixedDuration series requires maxDataPoints")}this.palette=new Rickshaw.Color.Palette(palette);this.timeBase=typeof options.timeBase==="undefined"?Math.floor((new Date).getTime()/1e3):options.timeBase;this.setTimeInterval(options.timeInterval);if(this[0]&&this[0].data&&this[0].data.length){this.currentSize=this[0].data.length;this.currentIndex=this[0].data.length}else{this.currentSize=0;this.currentIndex=0}this.maxDataPoints=options.maxDataPoints;if(data&&typeof data=="object"&&Array.isArray(data)){data.forEach(function(item){this.addItem(item)},this);this.currentSize+=1;this.currentIndex+=1}this.timeBase-=(this.maxDataPoints-this.currentSize)*this.timeInterval;if(typeof this.maxDataPoints!=="undefined"&&this.currentSize<this.maxDataPoints){for(var i=this.maxDataPoints-this.currentSize-1;i>1;i--){this.currentSize+=1;this.currentIndex+=1;this.forEach(function(item){item.data.unshift({x:((i-1)*this.timeInterval||1)+this.timeBase,y:0,i:i})},this)}}},addData:function($super,data,x){$super(data,x);this.currentSize+=1;this.currentIndex+=1;if(this.maxDataPoints!==undefined){while(this.currentSize>this.maxDataPoints){this.dropData()}}},dropData:function(){this.forEach(function(item){item.data.splice(0,1)});this.currentSize-=1},getIndex:function(){return this.currentIndex}});return Rickshaw});
{img → assets/img}/banner-ga-ecommerce.png RENAMED
File without changes
{img → assets/img}/banner-premium-ga.png RENAMED
File without changes
{img → assets/img}/banner-website-review.png RENAMED
File without changes
{img → assets/img}/eBook_261x130.png RENAMED
File without changes
{img → assets/img}/eComm_130x100.png RENAMED
File without changes
{img → assets/img}/ga-premium-banner.png RENAMED
File without changes
assets/img/index.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ //Nothing to see here
3
+
4
+ header( 'HTTP/1.0 403 Forbidden' );
{img → assets/img}/question-mark.png RENAMED
File without changes
assets/index.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ //Nothing to see here
3
+
4
+ header( 'HTTP/1.0 403 Forbidden' );
assets/js/index.php ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php
2
+ //Nothing to see here
3
+
4
+ header( 'HTTP/1.0 403 Forbidden' );
{js → assets/js}/yoast_ga_admin.js RENAMED
File without changes
{js → assets/js}/yoast_ga_admin.min.js RENAMED
File without changes
assets/js/yoast_ga_admin_dashboard.js ADDED
@@ -0,0 +1,476 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Extending element functionality and bind them to element.
2
+ jQuery.fn.extend(
3
+ {
4
+ yoast_ga_table: function () {
5
+ 'use strict';
6
+
7
+ /**
8
+ * Is is possible to have more graph holders, so they will be taken and looped by each to do all
9
+ * magic for each element.
10
+ *
11
+ */
12
+ return this.each(
13
+ function () {
14
+
15
+ var element = jQuery(this);
16
+ var table_id = jQuery(element).attr('id'); // Getting ID-attribute from element
17
+
18
+ var table = {
19
+ /**
20
+ * Initialize the object. This will get the data and set the events
21
+ */
22
+ init: function () {
23
+ this.get_data();
24
+ },
25
+
26
+ /**
27
+ * Doing AJAX response to get the data for the graph
28
+ */
29
+ get_data: function () {
30
+
31
+ var data = {
32
+ action : 'yoast_dashboard_tabledata',
33
+ _ajax_nonce : yoast_ga_dashboard_nonce,
34
+ graph_id : table_id,
35
+ period : 'lastmonth',
36
+ dimension_id: jQuery(element).attr('data-dimension')
37
+ };
38
+
39
+ jQuery.getJSON(ajaxurl, data, this.parse_response);
40
+ },
41
+
42
+ /**
43
+ * Parsing the JSON that is returned from request. Method will set the data, axis mapping and
44
+ * after all setting, it will create the graph
45
+ *
46
+ * @param response
47
+ */
48
+ parse_response: function (response) {
49
+ element.find('table').dataTable(
50
+ {
51
+ columns : [
52
+ {data: 'name'},
53
+ {data: 'value'}
54
+ ],
55
+ data : response.data,
56
+ order : [1, 'dsc'],
57
+
58
+ // Translations
59
+ language: {
60
+ aria : {
61
+ sortAscending : dashboard_translate.sort_ascending,
62
+ sortDescending: dashboard_translate.sort_descending
63
+ },
64
+ emptyTable : dashboard_translate.empty_table,
65
+ info : dashboard_translate.info,
66
+ infoEmpty : dashboard_translate.info_empty,
67
+ infoFiltered : dashboard_translate.info_filtered,
68
+ lengthMenu : dashboard_translate.length_menu,
69
+ loadingRecords : dashboard_translate.loading_records,
70
+ paginate : {
71
+ first : dashboard_translate.pagination_first,
72
+ last : dashboard_translate.pagination_last,
73
+ next : dashboard_translate.pagination_next,
74
+ previous: dashboard_translate.pagination_previous
75
+ },
76
+ processing : dashboard_translate.processing,
77
+ search : '_INPUT_',
78
+ searchPlaceholder: dashboard_translate.search_placeholder,
79
+ zeroRecords : dashboard_translate.zero_records
80
+ }
81
+ }
82
+ );
83
+ }
84
+ };
85
+
86
+ table.init();
87
+ }
88
+ );
89
+
90
+ },
91
+
92
+ yoast_ga_graph: function () {
93
+ 'use strict';
94
+
95
+ /**
96
+ * Is is possible to have more graph holders, so they will be taken and looped by each to do all
97
+ * magic for each element.
98
+ *
99
+ */
100
+ return this.each(
101
+ function () {
102
+
103
+ var element = jQuery(this);
104
+ var graph_id = jQuery(element).attr('id'); // Getting ID-attribute from element
105
+ var target = document.getElementById(graph_id); // Element obtaining doing the W3c way
106
+
107
+ // Object for doing the magic
108
+ var graph = {
109
+ data : [], // Placeholder for all getted data
110
+ axis : { // The values for X and Y axis
111
+ x: [],
112
+ y: []
113
+ },
114
+ hover : [],
115
+ width : 780, // The width of the graph
116
+ height : 300,
117
+ graph : '', // Graph element
118
+ graph_axis : { // The axis for X and Y
119
+ x: '',
120
+ y: ''
121
+ },
122
+ graph_hover: [], // Hover element
123
+
124
+ /**
125
+ * Initialize the object. This will get the data and set the events
126
+ */
127
+ init: function () {
128
+ this.get_data();
129
+ this.add_events();
130
+ },
131
+
132
+ /**
133
+ * Adding the update event on object
134
+ *
135
+ */
136
+ add_events: function () {
137
+ var _this = this;
138
+ jQuery(element).on('graph_update', function (event, response) {
139
+ _this.update(response, _this);
140
+ });
141
+ },
142
+
143
+ /**
144
+ * Doing AJAX response to get the data for the graph
145
+ */
146
+ get_data: function () {
147
+
148
+ var data = {
149
+ action : 'yoast_dashboard_graphdata',
150
+ _ajax_nonce: yoast_ga_dashboard_nonce,
151
+ graph_id : graph_id,
152
+ period : 'lastmonth'
153
+ };
154
+
155
+ jQuery.getJSON(ajaxurl, data, this.parse_response);
156
+ },
157
+
158
+ /**
159
+ * Parsing the JSON that is returned from request. Method will set the data, axis mapping and
160
+ * after all setting, it will create the graph
161
+ *
162
+ * @param response
163
+ */
164
+ parse_response: function (response) {
165
+ graph.set_data(response.data);
166
+
167
+ if (response.mapping.x !== undefined) {
168
+ graph.set_x_axis_mapping(response.mapping.x);
169
+ }
170
+
171
+ if (response.mapping.y !== undefined) {
172
+ graph.set_y_axis_mapping(response.mapping.y);
173
+ }
174
+
175
+ if (response.mapping.hover !== undefined) {
176
+ graph.set_hover_mapping(response.mapping.hover);
177
+ }
178
+
179
+ graph.create();
180
+ },
181
+
182
+ /**
183
+ * Setting the data with all values
184
+ *
185
+ * @param data
186
+ */
187
+ set_data: function (data) {
188
+ this.data = data;
189
+ },
190
+
191
+ /**
192
+ * Adding data to graph.data object
193
+ *
194
+ * @param data_to_add
195
+ */
196
+ add_data: function (data_to_add) {
197
+ graph.data.push(data_to_add);
198
+ },
199
+
200
+ /**
201
+ * Setting the x-axis with all mapping values
202
+ *
203
+ * @param mapping
204
+ */
205
+ set_x_axis_mapping: function (mapping) {
206
+ graph.axis.x = mapping;
207
+ },
208
+
209
+ /**
210
+ * Add value to the x axis
211
+ *
212
+ * @param mapping_to_add
213
+ */
214
+ add_x_axis_mapping: function (mapping_to_add) {
215
+ this.axis.x.push(mapping_to_add);
216
+ },
217
+
218
+ /**
219
+ * Setting the x-axis with all mapping values
220
+ *
221
+ * @param mapping
222
+ */
223
+ set_y_axis_mapping: function (mapping) {
224
+ graph.axis.y = mapping;
225
+ },
226
+
227
+ /**
228
+ * Setting the x-axis with all mapping values
229
+ *
230
+ * @param mapping
231
+ */
232
+ set_hover_mapping: function (mapping) {
233
+ graph.hover = mapping;
234
+ },
235
+
236
+ /**
237
+ * Add value to the x axis
238
+ *
239
+ * @param mapping_to_add
240
+ */
241
+ add_y_axis_mapping: function (mapping_to_add) {
242
+ this.axis.y.push(mapping_to_add);
243
+ },
244
+
245
+ /**
246
+ * Creating all magic: the graph, axises and hovers and render graph after everything is created
247
+ */
248
+ create: function () {
249
+ this.truncate_element();
250
+ this.create_graph();
251
+ this.create_axis();
252
+ this.create_hover();
253
+ this.render();
254
+ },
255
+
256
+ /**
257
+ * Empty element to be sure nothing is displayed multiple times
258
+ */
259
+ truncate_element: function () {
260
+ element.find('> div').html('');
261
+ },
262
+
263
+ /**
264
+ * Creating the graph
265
+ */
266
+ create_graph: function () {
267
+ this.graph = new Rickshaw.Graph(
268
+ {
269
+ element : target.querySelector('.yoast-graph-holder'),
270
+ width : this.width,
271
+ height : this.height,
272
+ series : [{
273
+ name : element.attr('data-label'),
274
+ color: '#0074a2',
275
+ data : this.data
276
+ }],
277
+ renderer: 'area',
278
+ padding : {
279
+ top : 0.10,
280
+ bottom: 0.02
281
+ }
282
+ }
283
+ );
284
+ },
285
+
286
+ /**
287
+ * Holder for creating the axises, this method will call this.create_x_axis and this.create_y_axis
288
+ */
289
+ create_axis: function () {
290
+ this.create_x_axis();
291
+ this.create_y_axis();
292
+ },
293
+
294
+ /**
295
+ * Creating the x_axis
296
+ */
297
+ create_x_axis: function () {
298
+ if (target.querySelector('.yoast-graph-xaxis') !== null) {
299
+ this.graph_axis.x = new Rickshaw.Graph.Axis.X(
300
+ {
301
+ element : target.querySelector('.yoast-graph-xaxis'),
302
+ graph : this.graph,
303
+ tickFormat : this.format_axis_x,
304
+ grid : true,
305
+ orientation : 'bottom',
306
+ pixelsPerTick: this.width / 4
307
+ }
308
+ );
309
+ }
310
+ },
311
+
312
+ /**
313
+ * Creating the y_axis
314
+ *
315
+ */
316
+ create_y_axis: function () {
317
+ if (target.querySelector('.yoast-graph-xaxis') !== null) {
318
+ this.graph_axis.y = new Rickshaw.Graph.Axis.Y(
319
+ {
320
+ element : target.querySelector('.yoast-graph-yaxis'),
321
+ graph : this.graph,
322
+ orientation: 'left',
323
+ height : '300',
324
+ // If n is 0 return emptystring, to prevent zero displayed on graph
325
+ tickFormat : function (n) {
326
+ return (n === 0) ? '' : n;
327
+ }
328
+ }
329
+ );
330
+ }
331
+
332
+ },
333
+
334
+ /**
335
+ * Creating hover details on graph
336
+ *
337
+ */
338
+ create_hover: function () {
339
+ this.graph_hover = new Rickshaw.Graph.HoverDetail(
340
+ {
341
+ graph : this.graph,
342
+ formatter: function (series, x, y) {
343
+ var value = graph.hover[x];
344
+
345
+ if (element.attr('data-percent') === '1') {
346
+ value += '%';
347
+ }
348
+ var swatch = '<span class="detail_swatch" style="background-color: ' + series.color + '"></span>';
349
+ var content = swatch + value + '<br />';
350
+ return content;
351
+ }
352
+ }
353
+ );
354
+
355
+ },
356
+
357
+ /**
358
+ * Render the graph object
359
+ */
360
+ render: function () {
361
+ this.graph.render();
362
+ },
363
+
364
+ /**
365
+ * Returns the formatting for the x-axis
366
+ *
367
+ * @param number
368
+ * @returns number
369
+ */
370
+ format_axis_x: function (number) {
371
+ return graph.axis.x[number];
372
+ },
373
+
374
+ /**
375
+ * Will be used to update the graph with new data
376
+ * @param response
377
+ * @param _this
378
+ */
379
+ update: function (response, _this) {
380
+ _this.add_data(response.data);
381
+ _this.add_x_axis_mapping(response.mapping);
382
+
383
+ _this.graph.update();
384
+ _this.render();
385
+ }
386
+ };
387
+
388
+ graph.init();
389
+ }
390
+ );
391
+
392
+ },
393
+
394
+ /**
395
+ * Adding function to object to pass some response data to event graph_update
396
+ *
397
+ * This can be used for updating the graph
398
+ *
399
+ * @param response
400
+ */
401
+ yoast_ga_graph_update: function (response) {
402
+ 'use strict';
403
+ jQuery(this).trigger('graph_update', [response]);
404
+ },
405
+
406
+ /**
407
+ * Adding function to object to pass some response data to event graph_update
408
+ *
409
+ * This can be used for updating the graph
410
+ *
411
+ * @param response
412
+ */
413
+ yoast_ga_table_update: function (response) {
414
+ 'use strict';
415
+ jQuery(this).trigger('table_update', [response]);
416
+ }
417
+ }
418
+ );
419
+
420
+ function dimension_switch(switch_select) {
421
+ 'use strict';
422
+
423
+ switch_select = jQuery(switch_select);
424
+
425
+ var list_tables = switch_select.closest('.wpseotab').find('.yoast-data-table');
426
+ var select_options = '';
427
+
428
+ jQuery.each(list_tables, function (num, table) {
429
+ select_options += '<option value="' + jQuery(table).attr('id') + '">' + jQuery(table).attr('data-label') + '</option>';
430
+ });
431
+
432
+ switch_select.append(select_options);
433
+
434
+ // First we have to hide all tables except the first one.
435
+ list_tables.not(':eq(0)').hide();
436
+
437
+ setTimeout(
438
+ function () {
439
+ switch_select.chosen().change(function () {
440
+ // Hide all elements
441
+ list_tables.hide();
442
+
443
+ // Show the selected on
444
+ jQuery('#' + jQuery(this).val()).show();
445
+ });
446
+ },
447
+ 1500
448
+ );
449
+
450
+ }
451
+
452
+ jQuery(
453
+ function () {
454
+ 'use strict';
455
+
456
+ jQuery('.yoast-graph').yoast_ga_graph();
457
+ jQuery('.yoast-data-table').yoast_ga_table();
458
+
459
+
460
+ /*
461
+ setTimeout(
462
+ function() {
463
+ jQuery('#graph-visitors').yoast_ga_graph_update(
464
+ {
465
+ data : {x: 30, y: 10},
466
+ mapping: ['andy']
467
+ }
468
+ );
469
+ },
470
+ 500
471
+ );
472
+ */
473
+
474
+
475
+ }
476
+ );
assets/js/yoast_ga_admin_dashboard.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function dimension_switch(a){"use strict";a=jQuery(a);var b=a.closest(".wpseotab").find(".yoast-data-table"),c="";jQuery.each(b,function(a,b){c+='<option value="'+jQuery(b).attr("id")+'">'+jQuery(b).attr("data-label")+"</option>"}),a.append(c),b.not(":eq(0)").hide(),setTimeout(function(){a.chosen().change(function(){b.hide(),jQuery("#"+jQuery(this).val()).show()})},1500)}jQuery.fn.extend({yoast_ga_table:function(){"use strict";return this.each(function(){var a=jQuery(this),b=jQuery(a).attr("id"),c={init:function(){this.get_data()},get_data:function(){var c={action:"yoast_dashboard_tabledata",_ajax_nonce:yoast_ga_dashboard_nonce,graph_id:b,period:"lastmonth",dimension_id:jQuery(a).attr("data-dimension")};jQuery.getJSON(ajaxurl,c,this.parse_response)},parse_response:function(b){a.find("table").dataTable({columns:[{data:"name"},{data:"value"}],data:b.data,order:[1,"dsc"],language:{aria:{sortAscending:dashboard_translate.sort_ascending,sortDescending:dashboard_translate.sort_descending},emptyTable:dashboard_translate.empty_table,info:dashboard_translate.info,infoEmpty:dashboard_translate.info_empty,infoFiltered:dashboard_translate.info_filtered,lengthMenu:dashboard_translate.length_menu,loadingRecords:dashboard_translate.loading_records,paginate:{first:dashboard_translate.pagination_first,last:dashboard_translate.pagination_last,next:dashboard_translate.pagination_next,previous:dashboard_translate.pagination_previous},processing:dashboard_translate.processing,search:"_INPUT_",searchPlaceholder:dashboard_translate.search_placeholder,zeroRecords:dashboard_translate.zero_records}})}};c.init()})},yoast_ga_graph:function(){"use strict";return this.each(function(){var a=jQuery(this),b=jQuery(a).attr("id"),c=document.getElementById(b),d={data:[],axis:{x:[],y:[]},hover:[],width:780,height:300,graph:"",graph_axis:{x:"",y:""},graph_hover:[],init:function(){this.get_data(),this.add_events()},add_events:function(){var b=this;jQuery(a).on("graph_update",function(a,c){b.update(c,b)})},get_data:function(){var a={action:"yoast_dashboard_graphdata",_ajax_nonce:yoast_ga_dashboard_nonce,graph_id:b,period:"lastmonth"};jQuery.getJSON(ajaxurl,a,this.parse_response)},parse_response:function(a){d.set_data(a.data),void 0!==a.mapping.x&&d.set_x_axis_mapping(a.mapping.x),void 0!==a.mapping.y&&d.set_y_axis_mapping(a.mapping.y),void 0!==a.mapping.hover&&d.set_hover_mapping(a.mapping.hover),d.create()},set_data:function(a){this.data=a},add_data:function(a){d.data.push(a)},set_x_axis_mapping:function(a){d.axis.x=a},add_x_axis_mapping:function(a){this.axis.x.push(a)},set_y_axis_mapping:function(a){d.axis.y=a},set_hover_mapping:function(a){d.hover=a},add_y_axis_mapping:function(a){this.axis.y.push(a)},create:function(){this.truncate_element(),this.create_graph(),this.create_axis(),this.create_hover(),this.render()},truncate_element:function(){a.find("> div").html("")},create_graph:function(){this.graph=new Rickshaw.Graph({element:c.querySelector(".yoast-graph-holder"),width:this.width,height:this.height,series:[{name:a.attr("data-label"),color:"#0074a2",data:this.data}],renderer:"area",padding:{top:.1,bottom:.02}})},create_axis:function(){this.create_x_axis(),this.create_y_axis()},create_x_axis:function(){null!==c.querySelector(".yoast-graph-xaxis")&&(this.graph_axis.x=new Rickshaw.Graph.Axis.X({element:c.querySelector(".yoast-graph-xaxis"),graph:this.graph,tickFormat:this.format_axis_x,grid:!0,orientation:"bottom",pixelsPerTick:this.width/4}))},create_y_axis:function(){null!==c.querySelector(".yoast-graph-xaxis")&&(this.graph_axis.y=new Rickshaw.Graph.Axis.Y({element:c.querySelector(".yoast-graph-yaxis"),graph:this.graph,orientation:"left",height:"300",tickFormat:function(a){return 0===a?"":a}}))},create_hover:function(){this.graph_hover=new Rickshaw.Graph.HoverDetail({graph:this.graph,formatter:function(b,c){var e=d.hover[c];"1"===a.attr("data-percent")&&(e+="%");var f='<span class="detail_swatch" style="background-color: '+b.color+'"></span>',g=f+e+"<br />";return g}})},render:function(){this.graph.render()},format_axis_x:function(a){return d.axis.x[a]},update:function(a,b){b.add_data(a.data),b.add_x_axis_mapping(a.mapping),b.graph.update(),b.render()}};d.init()})},yoast_ga_graph_update:function(a){"use strict";jQuery(this).trigger("graph_update",[a])},yoast_ga_table_update:function(a){"use strict";jQuery(this).trigger("table_update",[a])}}),jQuery(function(){"use strict";jQuery(".yoast-graph").yoast_ga_graph(),jQuery(".yoast-data-table").yoast_ga_table()});
css/chosen.min.css DELETED
@@ -1 +0,0 @@
1
- .chzn-container{display:inline-block;zoom:1;position:relative;font-size:13px}.chzn-container .chzn-drop{position:absolute;z-index:1010;top:29px;left:0;border:1px solid #aaa;border-top:0;background:#fff;box-shadow:0 4px 5px rgba(0,0,0,.15)}.chzn-container-single .chzn-single{display:block;overflow:hidden;position:relative;height:23px;padding:0 0 0 8px;border:1px solid #aaa;border-radius:5px;color:#444;background-color:#fff;background-image:linear-gradient(#fff 20%,#f6f6f6 50%,#eee 52%,#f4f4f4 100%);background-clip:padding-box;box-shadow:0 0 3px #fff inset,0 1px 1px rgba(0,0,0,.1);line-height:24px;white-space:nowrap;text-decoration:none;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0)}.chzn-container-single .chzn-default{color:#999}.chzn-container-single .chzn-single span{display:block;overflow:hidden;margin-right:26px;white-space:nowrap;text-overflow:ellipsis;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis}.chzn-container-single .chzn-single abbr{display:block;position:absolute;top:6px;right:26px;width:12px;height:12px;background:url(../img/chosen-sprite.png) -42px 1px no-repeat;font-size:1px}.chzn-container-single .chzn-single abbr:hover,.chzn-container-single.chzn-disabled .chzn-single abbr:hover{background-position:-42px -10px}.chzn-container-single .chzn-single div{display:block;position:absolute;top:0;right:0;width:18px;height:100%}.chzn-container-single .chzn-single div b{display:block;width:100%;height:100%;background:url(../img/chosen-sprite.png) 0 2px no-repeat}.chzn-container-single .chzn-search{position:relative;z-index:1010;margin:0;padding:3px 4px;white-space:nowrap}.chzn-container-single .chzn-search input{margin:1px 0;padding:4px 20px 4px 5px;border:1px solid #aaa;outline:0;background:url(../img/chosen-sprite.png) 100% -20px no-repeat #fff;background:url(../img/chosen-sprite.png) 100% -20px no-repeat,linear-gradient(#eee 1%,#fff 15%);font-family:sans-serif;font-size:1em}.chzn-container-single .chzn-drop{border-radius:0 0 4px 4px;background-clip:padding-box}.chzn-container-single-nosearch .chzn-search input{position:absolute;left:-9000px}.chzn-container-multi .chzn-choices{overflow:hidden;position:relative;height:auto!important;height:1%;margin:0;padding:0;border:1px solid #aaa;background-color:#fff;background-image:linear-gradient(#eee 1%,#fff 15%);cursor:text}.chzn-container-multi .chzn-choices li{float:left;list-style:none}.chzn-container-multi .chzn-choices .search-field{margin:0;padding:0;white-space:nowrap}.chzn-container-multi .chzn-choices .search-field input{height:15px;margin:1px 0;padding:5px;border:0!important;outline:0;color:#666;background:0 0!important;box-shadow:none;font-family:sans-serif;font-size:100%}.chzn-container-multi .chzn-choices .search-field .default{color:#999}.chzn-container-multi .chzn-choices .search-choice{position:relative;margin:3px 0 3px 5px;padding:3px 20px 3px 5px;border:1px solid #aaa;border-radius:3px;color:#333;background-color:#e4e4e4;background-image:linear-gradient(#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);background-clip:padding-box;box-shadow:0 0 2px #fff inset,0 1px 0 rgba(0,0,0,.05);line-height:13px;cursor:default;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0)}.chzn-container-multi .chzn-choices .search-choice.search-choice-disabled{padding-right:5px;border:1px solid #ccc;color:#666;background-color:#e4e4e4;background-image:linear-gradient(top,#f4f4f4 20%,#f0f0f0 50%,#e8e8e8 52%,#eee 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0)}.chzn-container-multi .chzn-choices .search-choice-focus{background:#d4d4d4}.chzn-container-multi .chzn-choices .search-choice .search-choice-close{display:block;position:absolute;top:4px;right:3px;width:12px;height:12px;background:url(../img/chosen-sprite.png) -42px 1px no-repeat;font-size:1px}.chzn-container-multi .chzn-choices .search-choice .search-choice-close:hover,.chzn-container-multi .chzn-choices .search-choice-focus .search-choice-close{background-position:-42px -10px}.chzn-container .chzn-results{overflow-x:hidden;overflow-y:auto;position:relative;max-height:240px;margin:0 4px 4px 0;padding:0 0 0 4px;-webkit-overflow-scrolling:touch}.chzn-container-multi .chzn-results{margin:-1px 0 0;padding:0}.chzn-container .chzn-results li{display:none;margin:0;padding:5px 6px;line-height:15px;list-style:none}.chzn-container .chzn-results .active-result{display:list-item;cursor:pointer}.chzn-container .chzn-results .highlighted{color:#fff;background-color:#3875d7;background-image:linear-gradient(#3875d7 20%,#2a62bc 90%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#3875d7', endColorstr='#2a62bc', GradientType=0)}.chzn-container .chzn-results li em{background:#feffde;font-style:normal}.chzn-container .chzn-results .highlighted em{background:0 0}.chzn-container .chzn-results .no-results{display:list-item;background:#f4f4f4}.chzn-container .chzn-results .group-result{color:#999;font-weight:700;cursor:default}.chzn-container .chzn-results .group-option{padding-left:15px}.chzn-container-multi .chzn-drop .result-selected{display:none}.chzn-container .chzn-results-scroll{position:absolute;z-index:1;width:321px;margin:0 4px;background:#fff;text-align:center}.chzn-container .chzn-results-scroll span{display:inline-block;width:9px;height:17px;text-indent:-5000px}.chzn-container .chzn-results-scroll-down{bottom:0}.chzn-container .chzn-results-scroll-down span{background:url(../img/chosen-sprite.png) -4px -3px no-repeat}.chzn-container .chzn-results-scroll-up span{background:url(../img/chosen-sprite.png) -22px -3px no-repeat}.chzn-container-active .chzn-single{border:1px solid #5897fb;box-shadow:0 0 5px rgba(0,0,0,.3)}.chzn-container-active .chzn-single-with-drop{border:1px solid #aaa;border-bottom-right-radius:0;border-bottom-left-radius:0;background-color:#eee;background-image:linear-gradient(#eee 20%,#fff 80%);box-shadow:0 1px 0 #fff inset;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0)}.chzn-container-active .chzn-single-with-drop div{border-left:none;background:0 0}.chzn-container-active .chzn-single-with-drop div b{background-position:-18px 2px}.chzn-container-active .chzn-choices{border:1px solid #5897fb;box-shadow:0 0 5px rgba(0,0,0,.3)}.chzn-container-active .chzn-choices .search-field input{color:#111!important}.chzn-disabled{opacity:.5!important;cursor:default}.chzn-disabled .chzn-choices .search-choice .search-choice-close,.chzn-disabled .chzn-single{cursor:default}.chzn-rtl{text-align:right}.chzn-rtl .chzn-single{overflow:visible;padding:0 8px 0 0}.chzn-rtl .chzn-single span{margin-right:0;margin-left:26px;direction:rtl}.chzn-rtl .chzn-single div{right:auto;left:3px}.chzn-rtl .chzn-single abbr{right:auto;left:26px}.chzn-rtl .chzn-choices .search-field input{direction:rtl}.chzn-rtl .chzn-choices li{float:right}.chzn-rtl .chzn-choices .search-choice{margin:3px 5px 3px 0;padding:3px 5px 3px 19px}.chzn-rtl .chzn-choices .search-choice .search-choice-close{right:auto;left:4px}.chzn-rtl.chzn-container-single .chzn-results{margin:0 0 4px 4px;padding:0 4px 0 0}.chzn-rtl .chzn-results .group-option{padding-right:15px;padding-left:0}.chzn-rtl.chzn-container-active .chzn-single-with-drop div{border-right:none}.chzn-rtl .chzn-search input{padding:4px 5px 4px 20px;background:url(../img/chosen-sprite.png) -30px -20px no-repeat #fff;background:url(../img/chosen-sprite.png) -30px -20px no-repeat,linear-gradient(#eee 1%,#fff 15%);direction:rtl}.chzn-container-single.chzn-rtl .chzn-single div b{background-position:6px 2px}.chzn-container-single.chzn-rtl .chzn-single-with-drop div b{background-position:-12px 2px}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-resolution:144dpi){.chzn-container .chzn-results-scroll-down span,.chzn-container .chzn-results-scroll-up span,.chzn-container-multi .chzn-choices .search-choice .search-choice-close,.chzn-container-single .chzn-search input,.chzn-container-single .chzn-single abbr,.chzn-container-single .chzn-single div b,.chzn-rtl .chzn-search input{background-image:url(../img/chosen-sprite@2x.png)!important;background-repeat:no-repeat!important;background-size:52px 37px!important}}
 
css/yoast_ga_styles.min.css DELETED
@@ -1 +0,0 @@
1
- h2#yoast_ga_title{padding:9px 15px 4px 0;font-size:23px;font-weight:400;line-height:29px}.nav-tab-wrapper{margin-bottom:0}.gatab{display:none}.gatab.active{display:block;padding:.5em .9em;border:1px solid #ddd;border-radius:0 3px 3px;background-color:#fff}.tabwrapper .gatab{padding:0;border:none;background:0 0}.tabwrapper .gatab h2{padding:9px 15px 4px 0;font-size:23px;font-weight:400}.ga-form-submit{margin-top:20px}.ga-form-label-left{float:left;width:250px;margin:0 0 0 5px;font-size:14px;font-weight:700;cursor:default}.ga-form-input{margin-top:10px}#yoast-ga-wrapper{display:table;width:auto;max-width:1150px}.yoast-ga-content{display:table-cell;min-width:850px;height:500px;margin:0;padding:0;vertical-align:top}.yoast-ga-banners{display:table-cell;width:261px;height:500px;margin:0;padding:20px;vertical-align:top}.ga-form-input{display:table;margin-bottom:20px}.ga-form-table{display:table-cell}.ga-form-description{display:block;float:right;max-width:325px;color:#999}p.ga-topdescription{max-width:600px}#ga-promote{max-width:600px;padding-left:10px;border:1px solid #ccc;background-color:#fff}#yoast-ga-form-settings input[type=text]{width:325px}#enter_ua{display:none;margin-top:10px;padding-top:10px}#yoast-ga-form-text-settings-ga_general-manual_ua_code_field{margin-top:-30px}select.ga-multiple{width:300px;height:150px!important}.wpseotab .extension{float:left;box-sizing:border-box;width:350px;height:230px;margin:10px 20px 10px 0;border:1px solid #ccc}.wpseotab .extension p{margin:0;padding:10px}.wpseotab .extension h3{box-sizing:border-box;height:110px;margin:0;padding:20px 10px 0 120px;border-bottom:1px solid #ccc;background:left 10px/130px 100px no-repeat #fff}.wpseotab .extension button.installed{border-color:#00a000;background-color:#00a000;cursor:default}.wpseotab .extension .button-primary.activate-link{border-color:#f06000;background-color:#f18500}.extension a{text-decoration:none}.ecommerce h3{background-image:url(../img/eComm_130x100.png)!important}.ga_premium h3{background-image:url(../img/ga-premium-banner.png)!important}#ga-debug-info h3{height:30px;margin-top:10px;padding-left:16px;font-size:14px}.yoast_help{margin:2px 5px 0}
 
frontend/class-frontend.php CHANGED
@@ -56,12 +56,9 @@ if ( ! class_exists( 'Yoast_GA_Frontend' ) ) {
56
  if ( isset( $this->options['ignore_users'] ) ) {
57
  if ( ! empty( $current_user->roles ) && in_array( $current_user->roles[0], $this->options['ignore_users'] ) ) {
58
  return false;
59
- } else {
60
- return true;
61
  }
62
- } else {
63
- return true;
64
  }
 
65
  }
66
 
67
  /**
@@ -87,12 +84,9 @@ if ( ! class_exists( 'Yoast_GA_Frontend' ) ) {
87
 
88
  if ( isset( $matches[0] ) ) {
89
  return array( 'domain' => $matches[0], 'host' => $host );
90
- } else {
91
- return false;
92
  }
93
- } else {
94
- return false;
95
  }
 
96
  }
97
 
98
  /**
56
  if ( isset( $this->options['ignore_users'] ) ) {
57
  if ( ! empty( $current_user->roles ) && in_array( $current_user->roles[0], $this->options['ignore_users'] ) ) {
58
  return false;
 
 
59
  }
 
 
60
  }
61
+ return true;
62
  }
63
 
64
  /**
84
 
85
  if ( isset( $matches[0] ) ) {
86
  return array( 'domain' => $matches[0], 'host' => $host );
 
 
87
  }
 
 
88
  }
89
+ return false;
90
  }
91
 
92
  /**
googleanalytics.php CHANGED
@@ -4,7 +4,7 @@ Plugin Name: Google Analytics by Yoast
4
  Plugin URI: https://yoast.com/wordpress/plugins/google-analytics/#utm_source=wordpress&utm_medium=plugin&utm_campaign=wpgaplugin&utm_content=v504
5
  Description: This plugin makes it simple to add Google Analytics to your WordPress blog, adding lots of features, eg. error page, search result and automatic clickout and download tracking.
6
  Author: Team Yoast
7
- Version: 5.1.4
8
  Requires at least: 3.8
9
  Author URI: https://yoast.com/
10
  License: GPL v3
@@ -30,7 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
30
 
31
  // This plugin was originally based on Rich Boakes' Analytics plugin: http://boakes.org/analytics, but has since been rewritten and refactored multiple times.
32
 
33
- define( 'GAWP_VERSION', '5.1.4' );
34
 
35
  define( 'GAWP_FILE', __FILE__ );
36
 
4
  Plugin URI: https://yoast.com/wordpress/plugins/google-analytics/#utm_source=wordpress&utm_medium=plugin&utm_campaign=wpgaplugin&utm_content=v504
5
  Description: This plugin makes it simple to add Google Analytics to your WordPress blog, adding lots of features, eg. error page, search result and automatic clickout and download tracking.
6
  Author: Team Yoast
7
+ Version: 5.2
8
  Requires at least: 3.8
9
  Author URI: https://yoast.com/
10
  License: GPL v3
30
 
31
  // This plugin was originally based on Rich Boakes' Analytics plugin: http://boakes.org/analytics, but has since been rewritten and refactored multiple times.
32
 
33
+ define( 'GAWP_VERSION', '5.2' );
34
 
35
  define( 'GAWP_FILE', __FILE__ );
36
 
includes/class-autoload.php CHANGED
@@ -13,34 +13,50 @@ if ( ! class_exists( 'Yoast_GA_Autoload' ) ) {
13
  if ( self::$classes === null ) {
14
 
15
  self::$classes = array(
16
- 'yoast_ga_options' => 'includes/class-options',
 
 
17
 
18
  // Frontend classes
19
- 'yoast_ga_frontend' => 'frontend/class-frontend',
20
- 'yoast_ga_universal' => 'frontend/class-universal',
21
- 'yoast_ga_js' => 'frontend/class-ga-js',
22
 
23
  // Admin classes
24
- 'yoast_ga_admin' => 'admin/class-admin',
25
- 'yoast_ga_admin_menu' => 'admin/class-admin-menu',
26
- 'yoast_google_analytics' => 'admin/class-google-analytics',
27
- 'yoast_ga_admin_ga_js' => 'admin/class-admin-ga-js',
28
- 'wp_gdata' => 'admin/wp-gdata/wp-gdata',
 
 
 
29
 
30
  // Dashboards
31
- 'yoast_ga_dashboards' => 'admin/class-admin-dashboards',
32
- 'yoast_ga_dashboards_aggregate' => 'admin/class-admin-dashboards-aggregate',
 
 
 
 
 
 
 
 
 
 
33
 
34
  // License manager
35
- 'yoast_license_manager' => 'admin/license-manager/class-license-manager',
36
- 'yoast_plugin_license_manager' => 'admin/license-manager/class-plugin-license-manager',
37
- 'yoast_product' => 'admin/license-manager/class-product',
38
 
39
  // API libraries
40
- 'yoast_api_libs' => 'admin/api-libs/class-api-libs',
41
 
42
  // i18n module
43
- 'yoast_i18n' => 'admin/i18n-module/i18n-module',
 
44
  );
45
  }
46
 
@@ -48,9 +64,7 @@ if ( ! class_exists( 'Yoast_GA_Autoload' ) ) {
48
  if ( isset( self::$classes[$class_name] ) ) {
49
  require_once $include_path . '/' . self::$classes[$class_name] . '.php';
50
  }
51
-
52
  }
53
-
54
  }
55
 
56
  // register class autoloader
13
  if ( self::$classes === null ) {
14
 
15
  self::$classes = array(
16
+ 'yoast_ga_options' => 'includes/class-options',
17
+ 'yoast_ga_utils' => 'includes/class-utils',
18
+
19
 
20
  // Frontend classes
21
+ 'yoast_ga_frontend' => 'frontend/class-frontend',
22
+ 'yoast_ga_universal' => 'frontend/class-universal',
23
+ 'yoast_ga_js' => 'frontend/class-ga-js',
24
 
25
  // Admin classes
26
+ 'yoast_ga_admin' => 'admin/class-admin',
27
+ 'yoast_ga_admin_menu' => 'admin/class-admin-menu',
28
+ 'yoast_google_analytics' => 'admin/class-google-analytics',
29
+ 'yoast_ga_admin_ga_js' => 'admin/class-admin-ga-js',
30
+ 'yoast_ga_admin_assets' => 'admin/class-admin-assets',
31
+ 'yoast_ga_admin_form' => 'admin/class-admin-form',
32
+
33
+ 'wp_gdata' => 'admin/wp-gdata/wp-gdata',
34
 
35
  // Dashboards
36
+ 'yoast_ga_dashboards_api_options' => 'admin/dashboards/class-admin-dashboards-api-options',
37
+ 'yoast_ga_dashboards' => 'admin/dashboards/class-admin-dashboards',
38
+ 'yoast_ga_dashboards_collector' => 'admin/dashboards/class-admin-dashboards-collector',
39
+ 'yoast_ga_dashboards_data' => 'admin/dashboards/class-admin-dashboards-data',
40
+
41
+ 'yoast_ga_dashboards_display' => 'admin/dashboards/class-admin-dashboards-display',
42
+ 'yoast_ga_dashboards_driver' => 'admin/dashboards/drivers/class-admin-dashboards-driver',
43
+ 'yoast_ga_dashboards_driver_generate' => 'admin/dashboards/drivers/class-admin-dashboards-driver-generate',
44
+ 'yoast_ga_dashboards_table' => 'admin/dashboards/drivers/class-admin-dashboards-table',
45
+ 'yoast_ga_dashboards_table_generate' => 'admin/dashboards/drivers/class-admin-dashboards-table-generate',
46
+ 'yoast_ga_dashboards_graph' => 'admin/dashboards/drivers/class-admin-dashboards-graph',
47
+ 'yoast_ga_dashboards_graph_generate' => 'admin/dashboards/drivers/class-admin-dashboards-graph-generate',
48
 
49
  // License manager
50
+ 'yoast_license_manager' => 'admin/license-manager/class-license-manager',
51
+ 'yoast_plugin_license_manager' => 'admin/license-manager/class-plugin-license-manager',
52
+ 'yoast_product' => 'admin/license-manager/class-product',
53
 
54
  // API libraries
55
+ 'yoast_api_libs' => 'admin/api-libs/class-api-libs',
56
 
57
  // i18n module
58
+ 'yoast_i18n' => 'admin/i18n-module/i18n-module',
59
+
60
  );
61
  }
62
 
64
  if ( isset( self::$classes[$class_name] ) ) {
65
  require_once $include_path . '/' . self::$classes[$class_name] . '.php';
66
  }
 
67
  }
 
68
  }
69
 
70
  // register class autoloader
includes/class-options.php CHANGED
@@ -142,7 +142,11 @@ if ( ! class_exists( 'Yoast_GA_Options' ) ) {
142
  $tracking_code = null;
143
  $this->options = $this->get_options();
144
 
145
- if ( ! empty( $this->options['analytics_profile'] ) ) {
 
 
 
 
146
  $tracking_code = $this->options['analytics_profile'];
147
  }
148
 
@@ -191,7 +195,7 @@ if ( ! class_exists( 'Yoast_GA_Options' ) ) {
191
  }
192
 
193
  // 5.1.2+ Remove firebug_lite from options, if set
194
- if ( ! isset ( $this->options['version']) || version_compare( $this->options['version'], '5.1.2', '<') ) {
195
  if ( isset( $this->options['firebug_lite'] ) ) {
196
  unset( $this->options['firebug_lite'] );
197
  }
@@ -226,6 +230,7 @@ if ( ! class_exists( 'Yoast_GA_Options' ) ) {
226
  $options = array(
227
  $this->option_prefix => array(
228
  'analytics_profile' => null,
 
229
  'manual_ua_code' => 0,
230
  'manual_ua_code_field' => null,
231
  'track_internal_as_outbound' => null,
142
  $tracking_code = null;
143
  $this->options = $this->get_options();
144
 
145
+ if ( ! empty( $this->options['analytics_profile'] ) && ! empty( $this->options['analytics_profile_code'] ) ) {
146
+ $tracking_code = $this->options['analytics_profile_code'];
147
+ }
148
+ elseif ( ! empty( $this->options['analytics_profile'] ) && empty( $this->options['analytics_profile_code'] ) ) {
149
+ // Analytics profile is still holding the UA code
150
  $tracking_code = $this->options['analytics_profile'];
151
  }
152
 
195
  }
196
 
197
  // 5.1.2+ Remove firebug_lite from options, if set
198
+ if ( ! isset ( $this->options['version'] ) || version_compare( $this->options['version'], '5.1.2', '<' ) ) {
199
  if ( isset( $this->options['firebug_lite'] ) ) {
200
  unset( $this->options['firebug_lite'] );
201
  }
230
  $options = array(
231
  $this->option_prefix => array(
232
  'analytics_profile' => null,
233
+ 'analytics_profile_code' => null,
234
  'manual_ua_code' => 0,
235
  'manual_ua_code_field' => null,
236
  'track_internal_as_outbound' => null,
includes/class-utils.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! class_exists( 'Yoast_GA_Utils' ) ) {
4
+
5
+ class Yoast_GA_Utils {
6
+
7
+ /**
8
+ * Check if WordPress SEO or WordPress SEO Premium is active
9
+ *
10
+ * @return bool
11
+ */
12
+ public static function wp_seo_active() {
13
+ $wp_seo_active = false;
14
+
15
+ //Makes sure is_plugin_active is available when called from front end
16
+ include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
17
+ if (is_plugin_active( 'wordpress-seo/wp-seo.php' ) || is_plugin_active( 'wordpress-seo-premium/wp-seo-premium.php' ) ) {
18
+ $wp_seo_active = true;
19
+ }
20
+ return $wp_seo_active;
21
+ }
22
+ }
23
+ }
js/chosen-sprite@2x.png DELETED
Binary file
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://yoast.com/donate/
4
  Tags: analytics, google analytics, statistics, tracking, stats, google, yoast
5
  Requires at least: 3.8
6
  Tested up to: 4.0
7
- Stable tag: 5.1.4
8
 
9
  Track your WordPress site easily with the latest tracking codes and lots added data for search result pages and error pages.
10
 
@@ -49,6 +49,15 @@ This section describes how to install the plugin and get it working.
49
 
50
  == Changelog ==
51
 
 
 
 
 
 
 
 
 
 
52
  = 5.1.4 =
53
 
54
  Release Date: December 2nd, 2014
4
  Tags: analytics, google analytics, statistics, tracking, stats, google, yoast
5
  Requires at least: 3.8
6
  Tested up to: 4.0
7
+ Stable tag: 5.2
8
 
9
  Track your WordPress site easily with the latest tracking codes and lots added data for search result pages and error pages.
10
 
49
 
50
  == Changelog ==
51
 
52
+ = 5.2 =
53
+
54
+ Release Date: December 9th, 2014
55
+
56
+ * Features:
57
+ * Added a brand new GA dashboard:
58
+ * Added graphs showing the sessions and bounce rates.
59
+ * Added reporting tables showing top pages, traffic sources and countries.
60
+
61
  = 5.1.4 =
62
 
63
  Release Date: December 2nd, 2014