BackUpWordPress - Version 2.0.1

Version Description

Download this release

Release Info

Developer willmot
Plugin Icon 128x128 BackUpWordPress
Version 2.0.1
Comparing to
See all releases

Code changes from version 1.6.9 to 2.0.1

Files changed (66) hide show
  1. admin.actions.php +0 -297
  2. admin.backup-button.php +0 -9
  3. admin.backups-table.php +0 -40
  4. admin.page.php +0 -31
  5. admin.settings.php +0 -98
  6. admin.status.php +0 -55
  7. admin/actions.php +400 -0
  8. admin/backups.php +74 -0
  9. admin.constants.php → admin/constants.php +1 -16
  10. admin.menus.php → admin/menu.php +10 -10
  11. admin/page.php +19 -0
  12. admin/schedule-form-excludes.php +123 -0
  13. admin/schedule-form.php +60 -0
  14. admin/schedule.php +100 -0
  15. assets/fancyBox/CHANGELOG.md +55 -0
  16. assets/fancyBox/README.md +199 -0
  17. assets/fancyBox/demo/1_b.jpg +0 -0
  18. assets/fancyBox/demo/1_s.jpg +0 -0
  19. assets/fancyBox/demo/2_b.jpg +0 -0
  20. assets/fancyBox/demo/2_s.jpg +0 -0
  21. assets/fancyBox/demo/3_b.jpg +0 -0
  22. assets/fancyBox/demo/3_s.jpg +0 -0
  23. assets/fancyBox/demo/4_b.jpg +0 -0
  24. assets/fancyBox/demo/4_s.jpg +0 -0
  25. assets/fancyBox/demo/5_b.jpg +0 -0
  26. assets/fancyBox/demo/5_s.jpg +0 -0
  27. assets/fancyBox/demo/ajax.txt +15 -0
  28. assets/fancyBox/demo/iframe.html +22 -0
  29. assets/fancyBox/demo/index.html +302 -0
  30. assets/fancyBox/lib/jquery-1.7.2.min.js +4 -0
  31. assets/fancyBox/lib/jquery.mousewheel-3.0.6.pack.js +13 -0
  32. assets/fancyBox/source/blank.gif +0 -0
  33. assets/fancyBox/source/fancybox_loading.gif +0 -0
  34. assets/fancyBox/source/fancybox_sprite.png +0 -0
  35. assets/fancyBox/source/helpers/fancybox_buttons.png +0 -0
  36. assets/fancyBox/source/helpers/jquery.fancybox-buttons.css +85 -0
  37. assets/fancyBox/source/helpers/jquery.fancybox-buttons.js +115 -0
  38. assets/fancyBox/source/helpers/jquery.fancybox-media.js +86 -0
  39. assets/fancyBox/source/helpers/jquery.fancybox-thumbs.css +54 -0
  40. assets/fancyBox/source/helpers/jquery.fancybox-thumbs.js +157 -0
  41. assets/fancyBox/source/jquery.fancybox.css +226 -0
  42. assets/fancyBox/source/jquery.fancybox.js +1449 -0
  43. assets/fancyBox/source/jquery.fancybox.pack.js +35 -0
  44. assets/hmbkp.css +66 -8
  45. assets/hmbkp.js +306 -39
  46. assets/wpspin_light.gif +0 -0
  47. backupwordpress.mo +0 -0
  48. backupwordpress.po +338 -291
  49. classes/email.php +164 -0
  50. classes/schedule.php +779 -0
  51. classes/schedules.php +56 -0
  52. classes/services.php +233 -0
  53. classes/wp-cli.php +95 -0
  54. functions/backup.actions.php +0 -61
  55. functions/backup.functions.php +0 -294
  56. functions/core.functions.php +0 -558
  57. functions/core.php +362 -0
  58. functions/interface.functions.php +0 -202
  59. functions/interface.php +284 -0
  60. functions/wp-cli.php +0 -105
  61. hm-backup/hm-backup.php +701 -372
  62. languages/hmbkp-de_DE.mo +0 -0
  63. languages/hmbkp-de_DE.po +578 -363
  64. plugin.php +53 -51
  65. readme.txt +29 -13
  66. screenshot-1.png +0 -0
admin.actions.php DELETED
@@ -1,297 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Verify & save all the user settings
5
- *
6
- * Returns WP_Error object if there are errors when updating settings.
7
- * Return (bool) true if no errors.
8
- *
9
- * Uses $_POST data
10
- *
11
- * @todo Should redirect on success
12
- * @return mixed
13
- */
14
- function hmbkp_option_save() {
15
-
16
- if ( empty( $_POST['hmbkp_settings_submit'] ) )
17
- return;
18
-
19
- check_admin_referer( 'hmbkp_settings', 'hmbkp_settings_nonce' );
20
-
21
- global $hmbkp_errors;
22
- $hmbkp_errors = new WP_Error;
23
-
24
- // Disable Automatic backups
25
- if ( isset( $_POST['hmbkp_automatic'] ) && ! (bool) $_POST['hmbkp_automatic'] ) {
26
- update_option( 'hmbkp_disable_automatic_backup', 'true' );
27
- wp_clear_scheduled_hook( 'hmbkp_schedule_backup_hook' );
28
-
29
- } else {
30
- delete_option( 'hmbkp_disable_automatic_backup');
31
-
32
- }
33
-
34
- // Update schedule frequency settings. Or reset to default of daily.
35
- if ( isset( $_POST['hmbkp_frequency'] ) && $_POST['hmbkp_frequency'] != 'daily' )
36
- update_option( 'hmbkp_schedule_frequency', esc_attr( $_POST['hmbkp_frequency'] ) );
37
-
38
- else
39
- delete_option( 'hmbkp_schedule_frequency' );
40
-
41
- // Clear schedule if settings have changed.
42
- if ( wp_get_schedule( 'hmbkp_schedule_backup_hook' ) != get_option( 'hmbkp_schedule_frequency' ) )
43
- wp_clear_scheduled_hook( 'hmbkp_schedule_backup_hook' );
44
-
45
- if ( isset( $_POST['hmbkp_what_to_backup'] ) && $_POST['hmbkp_what_to_backup'] == 'files_only' ) {
46
-
47
- update_option( 'hmbkp_files_only', 'true' );
48
- delete_option( 'hmbkp_database_only' );
49
-
50
- } elseif ( isset( $_POST['hmbkp_what_to_backup'] ) && $_POST['hmbkp_what_to_backup'] == 'database_only' ) {
51
-
52
- update_option( 'hmbkp_database_only', 'true' );
53
- delete_option( 'hmbkp_files_only' );
54
-
55
- } else {
56
-
57
- delete_option( 'hmbkp_database_only' );
58
- delete_option( 'hmbkp_files_only' );
59
-
60
- }
61
-
62
- if ( isset( $_POST['hmbkp_backup_number'] ) && $max_backups = intval( $_POST['hmbkp_backup_number'] ) ) {
63
- update_option( 'hmbkp_max_backups', intval( esc_attr( $_POST['hmbkp_backup_number'] ) ) );
64
-
65
- } else {
66
- delete_option( 'hmbkp_max_backups' );
67
-
68
- // Only error if it is actually empty.
69
- if ( isset( $_POST['hmbkp_backup_number'] ) )
70
- $hmbkp_errors->add( 'invalid_no_backups', __( 'You have entered an invalid number of backups.', 'hmbkp' ) );
71
-
72
- }
73
-
74
-
75
- if ( isset( $_POST['hmbkp_email_address'] ) ) {
76
-
77
- foreach( array_filter( array_map( 'trim', explode( ',', $_POST['hmbkp_email_address'] ) ) ) as $email_address )
78
- if ( ! is_email( $email_address ) && $email_error = true )
79
- $hmbkp_errors->add( 'invalid_email', sprintf( __( '%s is an invalid email address.', 'hmbkp' ), $email_address ) );
80
-
81
- if ( empty( $email_error ) )
82
- update_option( 'hmbkp_email_address', $_POST['hmbkp_email_address'] );
83
-
84
- if ( isset( $_POST['hmbkp_email_address'] ) && empty( $_POST['hmbkp_email_address'] ) )
85
- delete_option( 'hmbkp_email_address' );
86
-
87
- }
88
-
89
- if ( isset( $_POST['hmbkp_excludes'] ) && ! empty( $_POST['hmbkp_excludes'] ) ) {
90
- update_option( 'hmbkp_excludes', $_POST['hmbkp_excludes'] );
91
-
92
- } else {
93
- delete_option( 'hmbkp_excludes' );
94
-
95
- }
96
-
97
- delete_transient( 'hmbkp_estimated_filesize' );
98
-
99
- if ( $hmbkp_errors->get_error_code() )
100
- return $hmbkp_errors;
101
-
102
- return true;
103
-
104
- }
105
- add_action( 'load-tools_page_' . HMBKP_PLUGIN_SLUG, 'hmbkp_option_save' );
106
-
107
- /**
108
- * Delete the backup and then redirect
109
- * back to the backups page
110
- */
111
- function hmbkp_request_delete_backup() {
112
-
113
- if ( ! isset( $_GET['hmbkp_delete'] ) || empty( $_GET['hmbkp_delete'] ) )
114
- return;
115
-
116
- hmbkp_delete_backup( $_GET['hmbkp_delete'] );
117
-
118
- wp_redirect( remove_query_arg( 'hmbkp_delete' ), 303 );
119
-
120
- exit;
121
-
122
- }
123
- add_action( 'load-tools_page_' . HMBKP_PLUGIN_SLUG, 'hmbkp_request_delete_backup' );
124
-
125
- /**
126
- * Perform a manual backup and then
127
- * redirect back to the backups page
128
- */
129
- function hmbkp_request_do_backup() {
130
-
131
- if ( ! isset( $_GET['action'] ) || $_GET['action'] !== 'hmbkp_backup_now' )
132
- return;
133
-
134
- hmbkp_do_backup();
135
-
136
- wp_redirect( remove_query_arg( 'action' ), 303 );
137
-
138
- exit;
139
-
140
- }
141
- add_action( 'load-tools_page_' . HMBKP_PLUGIN_SLUG, 'hmbkp_request_do_backup' );
142
-
143
- /**
144
- * Perform a manual backup via ajax
145
- */
146
- function hmbkp_ajax_request_do_backup() {
147
-
148
- ignore_user_abort( true );
149
-
150
- hmbkp_do_backup();
151
-
152
- exit;
153
-
154
- }
155
- add_action( 'wp_ajax_hmbkp_backup', 'hmbkp_ajax_request_do_backup' );
156
-
157
- /**
158
- * Send the download file to the browser and
159
- * then redirect back to the backups page
160
- */
161
- function hmbkp_request_download_backup() {
162
-
163
- if ( empty( $_GET['hmbkp_download'] ) )
164
- return;
165
-
166
- // Force the .htaccess to be rebuilt
167
- if ( file_exists( hmbkp_path() . '/.htaccess' ) )
168
- unlink( hmbkp_path() . '/.htaccess' );
169
-
170
- // Force a refresh of the HMBKP_SECURE_KEY in .htaccess
171
- hmbkp_path();
172
-
173
- wp_redirect( add_query_arg( 'key', md5( HMBKP_SECURE_KEY ), str_replace( realpath( hmbkp_conform_dir( get_home_path() ) ), home_url(), base64_decode( $_GET['hmbkp_download'] ) ) ), 303 );
174
-
175
- exit;
176
-
177
- }
178
- add_action( 'load-tools_page_' . HMBKP_PLUGIN_SLUG, 'hmbkp_request_download_backup' );
179
-
180
- function hmbkp_request_cancel_backup() {
181
-
182
- if ( ! isset( $_GET['action'] ) || $_GET['action'] !== 'hmbkp_cancel' )
183
- return;
184
-
185
- hmbkp_cleanup();
186
-
187
- wp_redirect( remove_query_arg( 'action' ), 303 );
188
-
189
- exit;
190
-
191
- }
192
- add_action( 'load-tools_page_' . HMBKP_PLUGIN_SLUG, 'hmbkp_request_cancel_backup' );
193
-
194
- function hmbkp_dismiss_error() {
195
-
196
- if ( empty( $_GET['action'] ) || $_GET['action'] !== 'hmbkp_dismiss_error' )
197
- return;
198
-
199
- hmbkp_cleanup();
200
-
201
- wp_redirect( remove_query_arg( 'action' ), 303 );
202
-
203
- exit;
204
-
205
- }
206
- add_action( 'admin_init', 'hmbkp_dismiss_error' );
207
-
208
- /**
209
- * Display the running status via ajax
210
- *
211
- * @return void
212
- */
213
- function hmbkp_ajax_is_backup_in_progress() {
214
-
215
- if ( ! hmbkp_in_progress() )
216
- echo 0;
217
-
218
- else
219
- include( HMBKP_PLUGIN_PATH . '/admin.backup-button.php' );
220
-
221
- exit;
222
-
223
- }
224
- add_action( 'wp_ajax_hmbkp_is_in_progress', 'hmbkp_ajax_is_backup_in_progress' );
225
-
226
- /**
227
- * Display the calculated size via ajax
228
- *
229
- * @return void
230
- */
231
- function hmbkp_ajax_calculate_backup_size() {
232
-
233
- echo hmbkp_calculate();
234
-
235
- exit;
236
-
237
- }
238
- add_action( 'wp_ajax_hmbkp_calculate', 'hmbkp_ajax_calculate_backup_size' );
239
-
240
- /**
241
- * Test the cron response and if it's not 200 show a warning message
242
- *
243
- * @return void
244
- */
245
- function hmbkp_ajax_cron_test() {
246
-
247
- $response = wp_remote_get( site_url( 'wp-cron.php' ) );
248
-
249
- if ( ! is_wp_error( $response ) && $response['response']['code'] != '200' )
250
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( '%1$s is returning a %2$s response which could mean cron jobs aren\'t getting fired properly. BackUpWordPress relies on wp-cron to run scheduled back ups. See the %3$s for more details.', 'hmbkp' ), '<code>wp-cron.php</code>', '<code>' . $response['response']['code'] . '</code>', '<a href="http://wordpress.org/extend/plugins/backupwordpress/faq/">FAQ</a>' ) . '</p></div>';
251
-
252
- else
253
- echo 1;
254
-
255
- exit;
256
-
257
- }
258
- add_action( 'wp_ajax_hmbkp_cron_test', 'hmbkp_ajax_cron_test' );
259
-
260
- /**
261
- * Handles changes in the defined Constants
262
- * that users can define to control advanced
263
- * settings
264
- *
265
- * @return null
266
- */
267
- function hmbkp_constant_changes() {
268
-
269
- // Check whether we need to disable the cron
270
- if ( hmbkp_get_disable_automatic_backup() && wp_next_scheduled( 'hmbkp_schedule_backup_hook' ) )
271
- wp_clear_scheduled_hook( 'hmbkp_schedule_backup_hook' );
272
-
273
- // Or whether we need to re-enable it
274
- if ( ! hmbkp_get_disable_automatic_backup() && ! wp_next_scheduled( 'hmbkp_schedule_backup_hook' ) )
275
- hmbkp_setup_schedule();
276
-
277
- // Allow the time of the daily backup to be changed
278
- if ( wp_get_schedule( 'hmbkp_schedule_backup_hook' ) != get_option( 'hmbkp_schedule_frequency' ) )
279
- hmbkp_setup_schedule();
280
-
281
- // Reset if custom time is removed
282
- if ( ( ( defined( 'HMBKP_DAILY_SCHEDULE_TIME' ) && ! HMBKP_DAILY_SCHEDULE_TIME ) || ! defined( 'HMBKP_DAILY_SCHEDULE_TIME' ) ) && get_option( 'hmbkp_schedule_frequency' ) == 'daily' && date( 'H:i', wp_next_scheduled( 'hmbkp_schedule_backup_hook' ) ) != '23:00' && ! hmbkp_get_disable_automatic_backup() )
283
- hmbkp_setup_schedule();
284
-
285
- // If a custom backup path has been set or changed
286
- if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH && hmbkp_conform_dir( HMBKP_PATH ) != ( $from = hmbkp_conform_dir( get_option( 'hmbkp_path' ) ) ) )
287
- hmbkp_path_move( $from, HMBKP_PATH );
288
-
289
- // If a custom backup path has been removed
290
- if ( ( ( defined( 'HMBKP_PATH' ) && ! HMBKP_PATH ) || ! defined( 'HMBKP_PATH' ) && hmbkp_conform_dir( hmbkp_path_default() ) != ( $from = hmbkp_conform_dir( get_option( 'hmbkp_path' ) ) ) ) )
291
- hmbkp_path_move( $from, hmbkp_path_default() );
292
-
293
- // If the custom path has changed and the new directory isn't writable
294
- if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH && hmbkp_conform_dir( HMBKP_PATH ) != ( $from = hmbkp_conform_dir( get_option( 'hmbkp_path' ) ) ) && $from != hmbkp_path_default() && !is_writable( HMBKP_PATH ) && is_dir( $from ) )
295
- hmbkp_path_move( $from, hmbkp_path_default() );
296
-
297
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin.backup-button.php DELETED
@@ -1,9 +0,0 @@
1
- <?php if ( hmbkp_in_progress() ) : ?>
2
-
3
- <a id="hmbkp_backup" class="add-new-h2 hmbkp_running" href="tools.php?page=<?php echo HMBKP_PLUGIN_SLUG; ?>&amp;action=hmbkp_cancel"><?php echo hmbkp_get_status(); ?> [<?php _e( 'cancel', 'hmbkp' ); ?>]</a>
4
-
5
- <?php elseif ( hmbkp_possible() ) : ?>
6
-
7
- <a id="hmbkp_backup" class="add-new-h2" href="tools.php?page=<?php echo HMBKP_PLUGIN_SLUG; ?>&amp;action=hmbkp_backup_now"><?php _e( 'Back Up Now', 'hmbkp' ); ?></a>
8
-
9
- <?php endif; ?>
 
 
 
 
 
 
 
 
 
admin.backups-table.php DELETED
@@ -1,40 +0,0 @@
1
- <?php
2
-
3
- // If max backups has changed
4
- if ( ! hmbkp_in_progress() )
5
- hmbkp_delete_old_backups();
6
-
7
- if ( ( $backup_archives = hmbkp_get_backups() ) && count( $backup_archives ) ) : ?>
8
-
9
- <table class="widefat" id="hmbkp_manage_backups_table">
10
- <thead>
11
- <tr>
12
- <th scope="col"><?php printf( _n( '1 backup completed', '%d backups completed', count( $backup_archives ), 'hmbkp' ), count( $backup_archives ) ); ?></th>
13
- <th scope="col"><?php _e( 'Size', 'hmbkp' ); ?></th>
14
- <th scope="col"><?php _e( 'Actions', 'hmbkp' ); ?></th>
15
- </tr>
16
- </thead>
17
-
18
- <tfoot>
19
- <tr>
20
- <th><?php printf( _n( 'Only the most recent backup will be saved', 'The %d most recent backups will be saved', hmbkp_max_backups(), 'hmbkp' ), hmbkp_max_backups() ); ?></th>
21
- <th><?php printf( __( 'Total %s', 'hmbkp' ), hmbkp_total_filesize() ); ?></th>
22
- <th></th>
23
- </tr>
24
- </tfoot>
25
-
26
- <tbody id="the-list">
27
-
28
- <?php foreach ( (array) $backup_archives as $file ) :
29
-
30
- if ( ! file_exists( $file ) )
31
- continue;
32
-
33
- hmbkp_get_backup_row( $file );
34
-
35
- endforeach; ?>
36
-
37
- </tbody>
38
- </table>
39
-
40
- <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin.page.php DELETED
@@ -1,31 +0,0 @@
1
- <div class="wrap<?php if ( hmbkp_in_progress() ) { ?> hmbkp_running<?php } ?>">
2
-
3
- <?php screen_icon( 'backupwordpress' ); ?>
4
-
5
- <h2>
6
-
7
- <?php _e( 'Manage Backups', 'hmbkp' ); ?>
8
-
9
- <?php include_once( HMBKP_PLUGIN_PATH . '/admin.backup-button.php' ); ?>
10
-
11
- <a class="add-new-h2 hmbkp-settings-toggle" href="#hmbkp-settings"><?php _e( 'Settings', 'hmbkp' ); ?></a>
12
-
13
- </h2>
14
-
15
- <?php if ( hmbkp_possible() ) : ?>
16
-
17
- <?php include_once( HMBKP_PLUGIN_PATH . '/admin.status.php' ); ?>
18
-
19
- <?php include_once( HMBKP_PLUGIN_PATH . '/admin.backups-table.php' ); ?>
20
-
21
- <?php else : ?>
22
-
23
- <p><strong><?php _e( 'You need to fix the issues detailed above before BackUpWordPress can start.', 'hmbkp' ); ?></strong></p>
24
-
25
- <?php endif; ?>
26
-
27
- <?php include_once( HMBKP_PLUGIN_PATH . '/admin.settings.php' ); ?>
28
-
29
- <p class="howto"><?php printf( __( 'If you need help getting things working you are more than welcome to email us at %s and we\'ll do what we can to help.', 'hmbkp' ), '<a href="mailto:support@humanmade.co.uk">support@humanmade.co.uk</a>' ); ?></p>
30
-
31
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin.settings.php DELETED
@@ -1,98 +0,0 @@
1
- <div id="hmbkp-settings" <?php if ( ! hmbkp_get_backups() || ! empty( $_POST['hmbkp_settings_submit'] ) ) echo ' class="show_form"' ?>>
2
-
3
- <h3><?php _e( 'Settings', 'hmbkp' ); ?></h3>
4
-
5
- <p><?php printf( __( 'You can define %1$s in your %2$s to control some settings. A full list of %3$s can be found in the %4$s. Defined settings will not be editable below.', 'hmbkp' ), '<code>' . __( 'Constants', 'hmbkp' ) . '</code>', '<code>wp-config.php</code>', '<code>' . __( 'Constants', 'hmbkp' ) . '</code>', '<a href="#contextual-help-wrap" class="hmbkp-show-help-tab">' . __( 'help panel', 'hmbkp' ) . '</a>' ); ?></p>
6
-
7
- <form method="post">
8
-
9
- <?php wp_nonce_field( 'hmbkp_settings', 'hmbkp_settings_nonce' ); ?>
10
-
11
- <table class="form-table">
12
- <tbody>
13
-
14
- <tr align="top">
15
-
16
- <th scope="row"><?php _e( 'Automatic Backups', 'hmbkp' ); ?></th>
17
-
18
- <td>
19
-
20
- <label for="hmbkp_automatic_on">
21
- <input name="hmbkp_automatic" type="radio" id="hmbkp_automatic_on" value="1" <?php checked( ! hmbkp_get_disable_automatic_backup() ); ?> <?php disabled( defined( 'HMBKP_DISABLE_AUTOMATIC_BACKUP' ) ); ?>>
22
- <?php _e( 'Backup my site automatically.', 'hmbkp' ); ?>
23
- </label><br/>
24
-
25
- <label for="hmbkp_automatic_off">
26
- <input name="hmbkp_automatic" type="radio" id="hmbkp_automatic_off" value="0" <?php checked( hmbkp_get_disable_automatic_backup() ); ?> <?php disabled( defined( 'HMBKP_DISABLE_AUTOMATIC_BACKUP' ) ); ?>>
27
- <?php _e( 'No automatic backups.', 'hmbkp' ); ?>
28
- </label>
29
-
30
- </td>
31
-
32
- </tr>
33
-
34
- <tr align="top">
35
-
36
- <th scope="row"><label for="hmbkp_frequency"><?php _e( 'Frequency of backups', 'hmbkp' ); ?></label></th>
37
-
38
- <td>
39
-
40
- <?php _e( 'Automatic backups will occur', 'hmbkp' ); ?>
41
-
42
- <select name="hmbkp_frequency" id="hmbkp_frequency">
43
- <option value="daily" <?php selected( ! get_option( 'hmbkp_schedule_frequency' ) ); ?>><?php _e( 'Daily', 'hmbkp' ); ?></option>
44
- <option value="hmbkp_weekly" <?php selected( get_option( 'hmbkp_schedule_frequency' ), 'hmbkp_weekly' ); ?>><?php _e( 'Weekly', 'hmbkp' ); ?></option>
45
- <option value="hmbkp_fortnightly" <?php selected( get_option( 'hmbkp_schedule_frequency' ), 'hmbkp_fortnightly' ); ?>><?php _e( 'Fortnightly', 'hmbkp' ); ?></option>
46
- <option value="hmbkp_monthly" <?php selected( get_option( 'hmbkp_schedule_frequency' ), 'hmbkp_monthly' ); ?>><?php _e( 'Monthly', 'hmbkp' ); ?></option>
47
- </select>
48
-
49
- </td>
50
-
51
- </tr>
52
-
53
- <tr align="top">
54
-
55
- <th scope="row"><label for="hmbkp_what_to_backup"><?php _e( 'What to Backup', 'hmbkp' ); ?></label></th>
56
-
57
- <td>
58
-
59
- <?php _e( 'Backup my', 'hmbkp' ); ?>
60
-
61
- <select name="hmbkp_what_to_backup" id="hmbkp_what_to_backup" <?php disabled( defined( 'HMBKP_FILES_ONLY' ) || defined( 'HMBKP_DATABASE_ONLY' ) ); ?>>
62
- <option value="default" <?php selected( ! get_option( 'hmbkp_files_only' ) && !get_option( 'hmbkp_database_only' ) ); ?>><?php _e( 'database &amp; files', 'hmbkp' ); ?></option>
63
- <option value="database_only" <?php selected( hmbkp_get_database_only() ); ?>><?php _e( 'database only', 'hmbkp' ); ?></option>
64
- <option value="files_only" <?php selected( hmbkp_get_files_only() ); ?>><?php _e( 'files only', 'hmbkp' ); ?></option>
65
- </select>
66
-
67
- </td>
68
-
69
- </tr>
70
-
71
- <tr align="top">
72
- <th scope="row"><label for="hmbkp_backup_number"><?php _e( 'Number of backups', 'hmbkp' ); ?></label></th>
73
- <td><label for="hmbkp_backup_number"><?php printf( __( 'The last %s backups will be stored on the server.', 'hmbkp' ), '<input type="text" class="small-text ' . ( defined( 'HMBKP_MAX_BACKUPS' ) ? 'disabled' : '' ) . '" value="' . hmbkp_max_backups() . '" id="hmbkp_backup_number" name="hmbkp_backup_number"' . disabled( defined( 'HMBKP_MAX_BACKUPS' ), true, false ) . '>' ); ?></label></td>
74
- </tr>
75
-
76
- <tr valign="top">
77
- <th scope="row"><label for="hmbkp_email_address"><?php _e( 'Email backups', 'hmbkp' ); ?></label></th>
78
- <td><input name="hmbkp_email_address" type="text" id="hmbkp_email_address" value="<?php echo ! empty( $_POST['hmbkp_email_address'] ) ? $_POST['hmbkp_email_address'] : hmbkp_get_email_address( 'list' ); ?>" class="regular-text <?php if ( defined( 'HMBKP_EMAIL' ) ) echo 'disabled'; ?>" <?php disabled( defined( 'HMBKP_EMAIL' ) ); ?>> <span class="description"><?php _e( 'A copy of the backup file will be emailed to this address. Disabled if left blank.', 'hmbkp' ); ?></span></td>
79
- </tr>
80
-
81
- <tr align="top">
82
- <th scope="row"><label for="hmbkp_excludes"><?php _e( 'Excludes', 'hmbkp' ); ?></th>
83
- <td>
84
- <textarea class="code large-text<?php if ( defined( 'HMBKP_EXCLUDE' ) || hmbkp_get_database_only() ) echo ' disabled' ?>" name="hmbkp_excludes" id="hmbkp_excludes" <?php disabled( defined( 'HMBKP_EXCLUDE' ) || hmbkp_get_database_only() ); ?>><?php echo hmbkp_get_excludes(); ?></textarea>
85
- <span class="description"><?php _e( 'A comma separated list of file and directory paths that you do <strong>not</strong> want to backup.', 'hmbkp' ); ?></span><br/>
86
- <?php _e( 'e.g.', 'hmbkp' ); ?> <code>file.php, /directory/, /directory/file.jpg</code>
87
- </td>
88
- </tr>
89
-
90
- </tbody>
91
-
92
- </table>
93
-
94
- <p class="submit"><input type="submit" name="hmbkp_settings_submit" id="submit" class="button-primary" value="<?php _e( 'Save Changes', 'hmbkp' ); ?>"></p>
95
-
96
- </form>
97
-
98
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin.status.php DELETED
@@ -1,55 +0,0 @@
1
- <?php // If the form has been submitted, things may have changed.
2
- if ( ( ! empty( $_POST['hmbkp_settings_submit'] ) ) && ( ! wp_next_scheduled( 'hmbkp_schedule_backup_hook') || hmbkp_get_disable_automatic_backup() ) )
3
- hmbkp_constant_changes(); ?>
4
-
5
- <p>&#10003;
6
-
7
- <?php if ( hmbkp_get_disable_automatic_backup() && !wp_next_scheduled( 'hmbkp_schedule_backup_hook' ) ) : ?>
8
-
9
- <?php printf( __( 'Automatic backups are %s.', 'hmbkp' ), '<strong>' . __( 'disabled', 'hmbkp' ) . '</strong>' ); ?>
10
-
11
- <?php else :
12
-
13
- if ( ! hmbkp_get_database_only() && ! hmbkp_get_files_only() ) :
14
- $what_to_backup = '<code>' . __( 'database', 'hmbkp' ) . '</code> ' . __( '&amp;', 'hmbkp' ) . ' <code>' . __( 'files', 'hmbkp' ) . '</code>';
15
- $count = 2;
16
-
17
- elseif ( hmbkp_get_database_only() ) :
18
- $what_to_backup = '<code>' . __( 'database', 'hmbkp' ) . '</code>';
19
- $count = 1;
20
-
21
- else :
22
- $what_to_backup = '<code>' . __( 'files', 'hmbkp' ) . '</code>';
23
- $count = 2;
24
-
25
- endif;
26
-
27
- $offset = current_time( 'timestamp' ) - time();
28
- $schedules = wp_get_schedules();
29
- $schedule = $schedules[wp_get_schedule( 'hmbkp_schedule_backup_hook' )]['display'];
30
- printf(
31
- _n(
32
- 'Your %1$s will be automatically backed up %2$s. The next backup will occur at %3$s on %4$s and be saved to %5$s.', // singular
33
- 'Your %1$s will be automatically backed up %2$s. The next backup will occur at %3$s on %4$s and be saved to %5$s.', // plural
34
- $count, 'hmbkp'
35
- ),
36
- $what_to_backup,
37
- '<code>' . $schedule . '</code>',
38
- '<code>' . date_i18n( get_option( 'time_format' ), wp_next_scheduled( 'hmbkp_schedule_backup_hook' ) + $offset ) . '</code>',
39
- '<code title="' . sprintf( __( 'It\'s currently %s', 'hmbkp' ), date_i18n( get_option( 'time_format' ) ) ) . '">' . date_i18n( get_option( 'date_format' ), wp_next_scheduled( 'hmbkp_schedule_backup_hook' ) + $offset ) . '</code>',
40
- '<code>' . hmbkp_path() . '</code>'
41
- ); ?>
42
-
43
- <?php endif; ?>
44
-
45
- </p>
46
-
47
- <p>&#10003; <span class="hmbkp_estimated-size"><?php printf( __( 'Your site is %s. Backups will be compressed and should be smaller than this.', 'hmbkp' ), get_transient( 'hmbkp_estimated_filesize' ) ? '<code>' . hmbkp_calculate() . '</code>' : '<code class="calculate">' . __( 'Calculating Size...', 'hmbkp' ) . '</code>' ); ?></span></p>
48
-
49
- <?php if ( hmbkp_get_email_address() ) : ?>
50
- <p>&#10003; <?php printf( __( 'A copy of each backup will be emailed to %s.', 'hmbkp' ), '<code>' . implode( '</code>, <code>', array_filter( hmbkp_get_email_address(), 'is_email' ) ) . '</code>' ); ?></p>
51
- <?php endif; ?>
52
-
53
- <?php if ( ( $valid_excludes = hmbkp_valid_custom_excludes() ) && ! hmbkp_get_database_only() ) : ?>
54
- <p>&#10003; <?php printf( __( 'The following paths will be excluded from your backups %s.', 'hmbkp' ), '<code>' . implode( '</code>, <code>', $valid_excludes ) . '</code>' ); ?></p>
55
- <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/actions.php ADDED
@@ -0,0 +1,400 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Delete the backup and then redirect
5
+ * back to the backups page
6
+ */
7
+ function hmbkp_request_delete_backup() {
8
+
9
+ if ( empty( $_GET['hmbkp_delete_backup'] ) || ! check_admin_referer( 'hmbkp-delete_backup' ) )
10
+ return;
11
+
12
+ $schedule = new HMBKP_Scheduled_Backup( urldecode( $_GET['hmbkp_schedule_id'] ) );
13
+ $schedule->delete_backup( base64_decode( urldecode( $_GET['hmbkp_delete_backup'] ) ) );
14
+
15
+ wp_redirect( remove_query_arg( array( 'hmbkp_delete_backup', '_wpnonce' ) ), 303 );
16
+
17
+ exit;
18
+
19
+ }
20
+ add_action( 'load-tools_page_' . HMBKP_PLUGIN_SLUG, 'hmbkp_request_delete_backup' );
21
+
22
+ /**
23
+ * Delete a schedule and all it's backups and then redirect
24
+ * back to the backups page
25
+ */
26
+ function hmbkp_request_delete_schedule() {
27
+
28
+ if ( empty( $_GET['action'] ) || $_GET['action'] !== 'hmbkp_delete_schedule' || ! check_admin_referer( 'hmbkp-delete_schedule' ) )
29
+ return;
30
+
31
+ $schedule = new HMBKP_Scheduled_Backup( urldecode( $_GET['hmbkp_schedule_id'] ) );
32
+ $schedule->cancel( true );
33
+
34
+ wp_redirect( remove_query_arg( array( 'hmbkp_schedule_id', 'action', '_wpnonce' ) ), 303 );
35
+
36
+ exit;
37
+
38
+ }
39
+ add_action( 'load-tools_page_' . HMBKP_PLUGIN_SLUG, 'hmbkp_request_delete_schedule' );
40
+
41
+ /**
42
+ * Perform a manual backup via ajax
43
+ */
44
+ function hmbkp_ajax_request_do_backup() {
45
+
46
+ if ( empty( $_GET['hmbkp_schedule_id'] ) )
47
+ return;
48
+
49
+ ignore_user_abort( true );
50
+
51
+ hmbkp_cleanup();
52
+
53
+ $schedule = new HMBKP_Scheduled_Backup( urldecode( $_GET['hmbkp_schedule_id'] ) );
54
+
55
+ $schedule->run();
56
+
57
+ hmbkp_schedule_actions( $schedule );
58
+
59
+ exit;
60
+
61
+ }
62
+ add_action( 'wp_ajax_hmbkp_run_schedule', 'hmbkp_ajax_request_do_backup' );
63
+
64
+ /**
65
+ * Send the download file to the browser and
66
+ * then redirect back to the backups page
67
+ */
68
+ function hmbkp_request_download_backup() {
69
+
70
+ if ( empty( $_GET['hmbkp_download_backup'] ) || ! check_admin_referer( 'hmbkp-download_backup' ) )
71
+ return;
72
+
73
+ wp_redirect( str_replace( realpath( HM_Backup::conform_dir( HM_Backup::get_home_path() ) ), home_url(), base64_decode( $_GET['hmbkp_download_backup'] ) ), 303 );
74
+
75
+ exit;
76
+
77
+ }
78
+ add_action( 'load-tools_page_' . HMBKP_PLUGIN_SLUG, 'hmbkp_request_download_backup' );
79
+
80
+ /**
81
+ * cancels a running backup then redirect
82
+ * back to the backups page
83
+ */
84
+ function hmbkp_request_cancel_backup() {
85
+
86
+ if ( ! isset( $_GET['action'] ) || $_GET['action'] !== 'hmbkp_cancel' )
87
+ return;
88
+
89
+ $schedule = new HMBKP_Scheduled_Backup( urldecode( $_GET['hmbkp_schedule_id'] ) );
90
+
91
+ // Delete the running backup
92
+ if ( file_exists( trailingslashit( hmbkp_path() ) . $schedule->get_running_backup_filename() ) )
93
+ unlink( trailingslashit( hmbkp_path() ) . $schedule->get_running_backup_filename() );
94
+
95
+ hmbkp_cleanup();
96
+
97
+ wp_redirect( remove_query_arg( array( 'action' ) ), 303 );
98
+
99
+ exit;
100
+
101
+ }
102
+ add_action( 'load-tools_page_' . HMBKP_PLUGIN_SLUG, 'hmbkp_request_cancel_backup' );
103
+
104
+ /**
105
+ * Dismiss an error and then redirect
106
+ * back to the backups page
107
+ */
108
+ function hmbkp_dismiss_error() {
109
+
110
+ if ( empty( $_GET['action'] ) || $_GET['action'] !== 'hmbkp_dismiss_error' )
111
+ return;
112
+
113
+ hmbkp_cleanup();
114
+
115
+ wp_redirect( remove_query_arg( 'action' ), 303 );
116
+
117
+ exit;
118
+
119
+ }
120
+ add_action( 'admin_init', 'hmbkp_dismiss_error' );
121
+
122
+ /**
123
+ * Display the running status via ajax
124
+ */
125
+ function hmbkp_ajax_is_backup_in_progress() {
126
+
127
+ if ( empty( $_GET['hmbkp_schedule_id'] ) )
128
+ return;
129
+
130
+ $schedule = new HMBKP_Scheduled_Backup( urldecode( $_GET['hmbkp_schedule_id'] ) );
131
+
132
+ if ( ! $schedule->get_status() )
133
+ echo 0;
134
+
135
+ else
136
+ hmbkp_schedule_actions( $schedule );
137
+
138
+ exit;
139
+
140
+ }
141
+ add_action( 'wp_ajax_hmbkp_is_in_progress', 'hmbkp_ajax_is_backup_in_progress' );
142
+
143
+ /**
144
+ * Display the calculated size via ajax
145
+ */
146
+ function hmbkp_ajax_calculate_backup_size() {
147
+
148
+ if ( empty( $_GET['hmbkp_schedule_id'] ) )
149
+ return;
150
+
151
+ $schedule = new HMBKP_Scheduled_Backup( urldecode( $_GET['hmbkp_schedule_id'] ) );
152
+
153
+ $recalculate_filesize = true;
154
+
155
+ include_once( HMBKP_PLUGIN_PATH . '/admin/schedule.php' );
156
+
157
+ exit;
158
+
159
+ }
160
+ add_action( 'wp_ajax_hmbkp_calculate', 'hmbkp_ajax_calculate_backup_size' );
161
+
162
+ /**
163
+ * Test the cron response and if it's not 200 show a warning message
164
+ */
165
+ function hmbkp_ajax_cron_test() {
166
+
167
+ $response = wp_remote_get( site_url( 'wp-cron.php' ) );
168
+
169
+ if ( ! is_wp_error( $response ) && $response['response']['code'] != '200' )
170
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( '%1$s is returning a %2$s response which could mean cron jobs aren\'t getting fired properly. BackUpWordPress relies on wp-cron to run scheduled back ups. See the %3$s for more details.', 'hmbkp' ), '<code>wp-cron.php</code>', '<code>' . $response['response']['code'] . '</code>', '<a href="http://wordpress.org/extend/plugins/backupwordpress/faq/">FAQ</a>' ) . '</p></div>';
171
+
172
+ else
173
+ echo 1;
174
+
175
+ exit;
176
+
177
+ }
178
+ add_action( 'wp_ajax_hmbkp_cron_test', 'hmbkp_ajax_cron_test' );
179
+
180
+ /**
181
+ * Load the edit schedule form
182
+ */
183
+ function hmbkp_edit_schedule_load() {
184
+
185
+ $schedule = new HMBKP_Scheduled_Backup( esc_attr( $_GET['hmbkp_schedule_id'] ) );
186
+
187
+ require( HMBKP_PLUGIN_PATH . '/admin/schedule-form.php' );
188
+
189
+ exit;
190
+
191
+ }
192
+ add_action( 'wp_ajax_hmbkp_edit_schedule_load', 'hmbkp_edit_schedule_load' );
193
+
194
+ /**
195
+ * Load the edit schedule excludes form
196
+ */
197
+ function hmbkp_edit_schedule_excludes_load() {
198
+
199
+ $schedule = new HMBKP_Scheduled_Backup( esc_attr( $_GET['hmbkp_schedule_id'] ) );
200
+
201
+ require( HMBKP_PLUGIN_PATH . '/admin/schedule-form-excludes.php' );
202
+
203
+ exit;
204
+
205
+ }
206
+ add_action( 'wp_ajax_hmbkp_edit_schedule_excludes_load', 'hmbkp_edit_schedule_excludes_load' );
207
+
208
+ /**
209
+ * Load the add schedule form
210
+ */
211
+ function hmbkp_add_schedule_load() {
212
+
213
+ $schedule = new HMBKP_Scheduled_Backup( date( 'U' ) );
214
+ $is_new_schedule = true;
215
+
216
+ require( HMBKP_PLUGIN_PATH . '/admin/schedule-form.php' );
217
+
218
+ exit;
219
+
220
+ }
221
+ add_action( 'wp_ajax_hmbkp_add_schedule_load', 'hmbkp_add_schedule_load' );
222
+
223
+ /**
224
+ * Catch the edit schedule form
225
+ *
226
+ * Validate and either return errors or update the schedule
227
+ */
228
+ function hmnkp_edit_schedule_submit() {
229
+
230
+ if ( empty( $_GET['hmbkp_schedule_id'] ) )
231
+ return;
232
+
233
+ $schedule = new HMBKP_Scheduled_Backup( esc_attr( $_GET['hmbkp_schedule_id'] ) );
234
+
235
+ $errors = array();
236
+
237
+ if ( isset( $_GET['hmbkp_schedule_type'] ) ) {
238
+
239
+ if ( ! trim( $_GET['hmbkp_schedule_type'] ) )
240
+ $errors['hmbkp_schedule_type'] = __( 'Backup type cannot be empty', 'hmbkp' );
241
+
242
+ elseif ( ! in_array( $_GET['hmbkp_schedule_type'], array( 'complete', 'file', 'database' ) ) )
243
+ $errors['hmbkp_schedule_type'] = __( 'Invalid backup type', 'hmbkp' );
244
+
245
+ else
246
+ $schedule->set_type( $_GET['hmbkp_schedule_type'] );
247
+
248
+ }
249
+
250
+ if ( isset( $_GET['hmbkp_schedule_reoccurrence'] ) ) {
251
+
252
+ if ( empty( $_GET['hmbkp_schedule_reoccurrence'] ) )
253
+ $errors['hmbkp_schedule_reoccurrence'] = __( 'Schedule cannot be empty', 'hmbkp' );
254
+
255
+ elseif ( ! in_array( $_GET['hmbkp_schedule_reoccurrence'], array_keys( wp_get_schedules() ) ) && $_GET['hmbkp_schedule_reoccurrence'] !== 'manually' )
256
+ $errors['hmbkp_schedule_reoccurrence'] = __( 'Invalid schedule', 'hmbkp' );
257
+
258
+ else
259
+ $schedule->set_reoccurrence( $_GET['hmbkp_schedule_reoccurrence'] );
260
+
261
+ }
262
+
263
+ if ( isset( $_GET['hmbkp_schedule_max_backups'] ) ) {
264
+
265
+ if ( empty( $_GET['hmbkp_schedule_max_backups'] ) )
266
+ $errors['hmbkp_schedule_max_backups'] = __( 'Max backups can\'t be empty', 'hmbkp' );
267
+
268
+ elseif ( ! is_numeric( $_GET['hmbkp_schedule_max_backups'] ) )
269
+ $errors['hmbkp_schedule_max_backups'] = __( 'Max backups must be a number', 'hmbkp' );
270
+
271
+ elseif ( ! ( $_GET['hmbkp_schedule_max_backups'] >= 1 ) )
272
+ $errors['hmbkp_schedule_max_backups'] = __( 'Max backups must be greater than 0', 'hmbkp' );
273
+
274
+ else
275
+ $schedule->set_max_backups( (int) $_GET['hmbkp_schedule_max_backups'] );
276
+
277
+ $schedule->delete_old_backups();
278
+
279
+ }
280
+
281
+ foreach ( HMBKP_Services::get_services( $schedule ) as $service )
282
+ $errors = array_merge( $errors, $service->save() );
283
+
284
+ $schedule->save();
285
+
286
+ if ( $errors )
287
+ echo json_encode( $errors );
288
+
289
+ exit;
290
+
291
+ }
292
+ add_action( 'wp_ajax_hmnkp_edit_schedule_submit', 'hmnkp_edit_schedule_submit' );
293
+
294
+
295
+ /**
296
+ * Add an exclude rule
297
+ *
298
+ * @access public
299
+ * @return void
300
+ */
301
+ function hmbkp_add_exclude_rule() {
302
+
303
+ $schedule = new HMBKP_Scheduled_Backup( esc_attr( $_POST['hmbkp_schedule_id'] ) );
304
+
305
+ $schedule->set_excludes( $_POST['hmbkp_exclude_rule'], true );
306
+
307
+ $schedule->save();
308
+
309
+ include( HMBKP_PLUGIN_PATH . '/admin/schedule-form-excludes.php' );
310
+
311
+ exit;
312
+
313
+ }
314
+ add_action( 'wp_ajax_hmbkp_add_exclude_rule', 'hmbkp_add_exclude_rule' );
315
+
316
+
317
+ /**
318
+ * Delete an exclude rule
319
+ *
320
+ * @access public
321
+ * @return void
322
+ */
323
+ function hmbkp_delete_exclude_rule() {
324
+
325
+ $schedule = new HMBKP_Scheduled_Backup( esc_attr( $_POST['hmbkp_schedule_id'] ) );
326
+
327
+ $excludes = $schedule->get_excludes();
328
+
329
+ $schedule->set_excludes( array_diff( $excludes, (array) $_POST['hmbkp_exclude_rule'] ) );
330
+
331
+ $schedule->save();
332
+
333
+ include( HMBKP_PLUGIN_PATH . '/admin/schedule-form-excludes.php' );
334
+
335
+ exit;
336
+
337
+ }
338
+ add_action( 'wp_ajax_hmbkp_delete_exclude_rule', 'hmbkp_delete_exclude_rule' );
339
+
340
+
341
+ /**
342
+ * Ajax action for previewing an exclude rule.
343
+ *
344
+ * @access public
345
+ * @return void
346
+ */
347
+ function hmbkp_preview_exclude_rule() {
348
+
349
+ if ( ! empty( $_POST['hmbkp_schedule_id'] ) )
350
+ $schedule = new HMBKP_Scheduled_Backup( $_POST['hmbkp_schedule_id'] );
351
+
352
+ if ( ! empty( $_POST['hmbkp_schedule_excludes'] ) )
353
+ $excludes = explode( ',', $_POST['hmbkp_schedule_excludes'] );
354
+
355
+ if ( ! empty( $_POST['hmbkp_file_method'] ) )
356
+ $file_method = $_POST['hmbkp_file_method'];
357
+
358
+ hmbkp_file_list( $schedule, $excludes, $file_method );
359
+
360
+ foreach( $schedule->get_excluded_files() as $key => $excluded_file )
361
+ if ( strpos( $excluded_file, $schedule->get_path() ) === false )
362
+ $excluded_files[] = $excluded_file;
363
+
364
+ if ( ! empty( $excluded_files) ) { ?>
365
+
366
+ <p><?php printf( _n( '%s matches 1 file.', '%1$s matches %2$d files.', count( $excluded_files ), 'hmbkp' ), '<code>' . implode( '</code>, <code>', $excludes ) . '</code>', count( $excluded_files ) ); ?></p>
367
+
368
+ <?php } else { ?>
369
+
370
+ <p><?php printf( __( '%s didn\'t match any files.', 'hmbkp' ), '<code>' . implode( '</code>, <code>', $excludes ) . '</code>' ); ?></p>
371
+
372
+ <?php } ?>
373
+
374
+ <p><button type="button" class="button-primary hmbkp_save_exclude_rule"><?php _e( 'Exclude', 'hmbkp' ); ?></button> <button type="button" class="button-secondary hmbkp_cancel_save_exclude_rule"><?php _e( 'Cancel', 'hmbkp' ); ?></button></p>
375
+
376
+ <?php exit;
377
+
378
+ }
379
+ add_action( 'wp_ajax_hmbkp_file_list', 'hmbkp_preview_exclude_rule', 10, 0 );
380
+
381
+ /**
382
+ * Handles changes in the defined Constants
383
+ * that users can define to control advanced
384
+ * settings
385
+ */
386
+ function hmbkp_constant_changes() {
387
+
388
+ // If a custom backup path has been set or changed
389
+ if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH && HM_Backup::conform_dir( HMBKP_PATH ) !== ( $from = HM_Backup::conform_dir( get_option( 'hmbkp_path' ) ) ) )
390
+ hmbkp_path_move( $from, HMBKP_PATH );
391
+
392
+ // If a custom backup path has been removed
393
+ if ( ( ( defined( 'HMBKP_PATH' ) && ! HMBKP_PATH ) || ! defined( 'HMBKP_PATH' ) && HM_Backup::conform_dir( hmbkp_path_default() ) != ( $from = HM_Backup::conform_dir( get_option( 'hmbkp_path' ) ) ) ) )
394
+ hmbkp_path_move( $from, hmbkp_path_default() );
395
+
396
+ // If the custom path has changed and the new directory isn't writable
397
+ if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH && HM_Backup::conform_dir( HMBKP_PATH ) != ( $from = HM_Backup::conform_dir( get_option( 'hmbkp_path' ) ) ) && $from != hmbkp_path_default() && !is_writable( HMBKP_PATH ) && is_dir( $from ) )
398
+ hmbkp_path_move( $from, hmbkp_path_default() );
399
+
400
+ }
admin/backups.php ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php $schedules = new HMBKP_Schedules; ?>
2
+
3
+ <div>
4
+
5
+ <ul class="subsubsub">
6
+
7
+ <?php foreach ( $schedules->get_schedules() as $schedule ) : ?>
8
+
9
+ <li><a<?php if ( ! empty ( $_GET['hmbkp_schedule_id'] ) && $schedule->get_id() == $_GET['hmbkp_schedule_id'] ) { ?> class="current"<?php } ?> href="<?php echo esc_url( add_query_arg( 'hmbkp_schedule_id', $schedule->get_id(), HMBKP_ADMIN_URL ) ); ?> "><?php echo esc_attr( $schedule->get_name() ); ?> <span class="count">(<?php echo count( $schedule->get_backups() ); ?>)</span></a></li>
10
+
11
+ <?php endforeach; ?>
12
+
13
+ <li><a class="fancybox" href="<?php echo esc_url( add_query_arg( array( 'action' => 'hmbkp_add_schedule_load' ), admin_url( 'admin-ajax.php' ) ) ); ?>"> + <?php _e( 'add schedule', 'hmbkp' ); ?></a></li>
14
+
15
+ </ul>
16
+
17
+ <?php if ( ! empty( $_GET['hmbkp_schedule_id'] ) )
18
+ $schedule = new HMBKP_Scheduled_Backup( $_GET['hmbkp_schedule_id'] );
19
+
20
+ else
21
+ $schedule = reset( $schedules->get_schedules() );
22
+
23
+ if ( ! $schedule )
24
+ return; ?>
25
+
26
+ <div data-hmbkp-schedule-id="<?php echo esc_attr( $schedule->get_id() ); ?>" class="hmbkp_schedule">
27
+
28
+ <?php require( HMBKP_PLUGIN_PATH . '/admin/schedule.php' ); ?>
29
+
30
+ <table class="widefat">
31
+
32
+ <thead>
33
+
34
+ <tr>
35
+
36
+ <th scope="col"><?php printf( _n( '1 backup completed', '%d backups completed', count( $schedule->get_backups() ), 'hmbkp' ), count( $schedule->get_backups() ) ); ?></th>
37
+ <th scope="col"><?php _e( 'Size', 'hmbkp' ); ?></th>
38
+ <th scope="col"><?php _e( 'Type', 'hmbkp' ); ?></th>
39
+ <th scope="col"><?php _e( 'Actions', 'hmbkp' ); ?></th>
40
+
41
+ </tr>
42
+
43
+ </thead>
44
+
45
+ <tbody>
46
+
47
+ <?php if ( $schedule->get_backups() ) :
48
+
49
+ foreach ( $schedule->get_backups() as $file ) :
50
+
51
+ if ( ! file_exists( $file ) )
52
+ continue;
53
+
54
+ hmbkp_get_backup_row( $file, $schedule );
55
+
56
+ endforeach;
57
+
58
+ else : ?>
59
+
60
+ <tr>
61
+
62
+ <td class="hmbkp-no-backups" colspan="3"><?php _e( 'This is where your backups will appear once you have one.', 'hmbkp' ); ?></td>
63
+
64
+ </tr>
65
+
66
+ <?php endif; ?>
67
+
68
+ </tbody>
69
+
70
+ </table>
71
+
72
+ </div>
73
+
74
+ </div>
admin.constants.php → admin/constants.php RENAMED
@@ -13,21 +13,6 @@
13
  <dt<?php if ( defined( 'HMBKP_ZIP_PATH' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_ZIP_PATH</code></dt>
14
  <dd><p><?php printf( __( 'The path to your %1$s executable. Will be used to zip up your %2$s and %3$s if available.', 'hmbkp' ), '<code>zip</code>', '<code>' . __( 'files', 'hmbkp' ) . '</code>', '<code>' . __( 'database', 'hmbkp' ) . '</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_ZIP_PATH', '/opt/local/bin/zip' );</code></p></dd>
15
 
16
- <dt<?php if ( defined( 'HMBKP_DISABLE_AUTOMATIC_BACKUP' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_DISABLE_AUTOMATIC_BACKUP</code></dt>
17
- <dd><p><?php printf( __( 'Completely disables the automatic back up. You can still back up using the "Back Up Now" button. Defaults to %s.', 'hmbkp' ), '<code>(bool) false</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_DISABLE_AUTOMATIC_BACKUP', true );</code></p></dd>
18
-
19
- <dt<?php if ( defined( 'HMBKP_MAX_BACKUPS' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_MAX_BACKUPS</code></dt>
20
- <dd><p><?php printf( __( 'Number of backups to keep, older backups will be deleted automatically when a new backup is completed. Defaults to %s.', 'hmbkp' ), '<code>(int) 10</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_MAX_BACKUPS', 5 );</code></p></dd>
21
-
22
- <dt<?php if ( defined( 'HMBKP_FILES_ONLY' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_FILES_ONLY</code></dt>
23
- <dd><p><?php printf( __( 'Backup %1$s only, your %2$s won\'t be backed up. Defaults to %3$s.', 'hmbkp' ), '<code>' . __( 'files', 'hmbkp' ) . '</code>', '<code>' . __( 'database', 'hmbkp' ) . '</code>', '<code>(bool) false</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_FILES_ONLY', true );</code></p></dd>
24
-
25
- <dt<?php if ( defined( 'HMBKP_DATABASE_ONLY' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_DATABASE_ONLY</code></dt>
26
- <dd><p><?php printf( __( 'Backup %1$s only, your %2$s won\'t be backed up. Defaults to %3$s.', 'hmbkp' ), '<code>' . __( 'database', 'hmbkp' ) . '</code>', '<code>' . __( 'files', 'hmbkp' ) . '</code>', '<code>(bool) false</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_DATABASE_ONLY', true );</code></p></dd>
27
-
28
- <dt<?php if ( defined( 'HMBKP_DAILY_SCHEDULE_TIME' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_DAILY_SCHEDULE_TIME</code></dt>
29
- <dd><p><?php printf( __( 'The time that the daily back up should run. Defaults to %s.', 'hmbkp' ), '<code>23:00</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_DAILY_SCHEDULE_TIME', '07:30' );</code></p></dd>
30
-
31
  <dt<?php if ( defined( 'HMBKP_EMAIL' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_EMAIL</code></dt>
32
  <dd><p><?php printf( __( 'Attempt to email a copy of your backups. Value should be email address to send backups to. Defaults to %s.', 'hmbkp' ), '<code>(bool) false</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_EMAIL', 'email@example.com' );</code></p></dd>
33
 
@@ -38,7 +23,7 @@
38
  <dd><p><?php printf( __( 'The capability to use when calling %1$s. Defaults to %2$s.', 'hmbkp' ), '<code>add_menu_page</code>', '<code>manage_options</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_CAPABILITY', 'edit_posts' );</code></p></dd>
39
 
40
  <dt<?php if ( defined( 'HMBKP_ROOT' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_ROOT</code></dt>
41
- <dd><p><?php printf( __( 'The root directory that is backed up. Defaults to %s.', 'hmbkp' ), '<code>' . hmbkp_get_home_path() . '</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_ROOT', ABSPATH . 'wp/' );</code></p></dd>
42
 
43
  </dl>
44
 
13
  <dt<?php if ( defined( 'HMBKP_ZIP_PATH' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_ZIP_PATH</code></dt>
14
  <dd><p><?php printf( __( 'The path to your %1$s executable. Will be used to zip up your %2$s and %3$s if available.', 'hmbkp' ), '<code>zip</code>', '<code>' . __( 'files', 'hmbkp' ) . '</code>', '<code>' . __( 'database', 'hmbkp' ) . '</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_ZIP_PATH', '/opt/local/bin/zip' );</code></p></dd>
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  <dt<?php if ( defined( 'HMBKP_EMAIL' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_EMAIL</code></dt>
17
  <dd><p><?php printf( __( 'Attempt to email a copy of your backups. Value should be email address to send backups to. Defaults to %s.', 'hmbkp' ), '<code>(bool) false</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_EMAIL', 'email@example.com' );</code></p></dd>
18
 
23
  <dd><p><?php printf( __( 'The capability to use when calling %1$s. Defaults to %2$s.', 'hmbkp' ), '<code>add_menu_page</code>', '<code>manage_options</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_CAPABILITY', 'edit_posts' );</code></p></dd>
24
 
25
  <dt<?php if ( defined( 'HMBKP_ROOT' ) ) { ?> class="hmbkp_active"<?php } ?>><code>HMBKP_ROOT</code></dt>
26
+ <dd><p><?php printf( __( 'The root directory that is backed up. Defaults to %s.', 'hmbkp' ), '<code>' . HM_Backup::get_home_path() . '</code>' ); ?><p class="example"><?php _e( 'e.g.', 'hmbkp' ); ?> <code>define( 'HMBKP_ROOT', ABSPATH . 'wp/' );</code></p></dd>
27
 
28
  </dl>
29
 
admin.menus.php → admin/menu.php RENAMED
@@ -18,7 +18,7 @@ add_action( 'admin_menu', 'hmbkp_admin_menu' );
18
  * @return null
19
  */
20
  function hmbkp_manage_backups() {
21
- require_once( HMBKP_PLUGIN_PATH . '/admin.page.php' );
22
  }
23
 
24
  /**
@@ -31,12 +31,12 @@ function hmbkp_manage_backups() {
31
  function hmbkp_plugin_action_link( $links, $file ) {
32
 
33
  if ( strpos( $file, HMBKP_PLUGIN_SLUG ) !== false )
34
- array_push( $links, '<a href="tools.php?page=' . HMBKP_PLUGIN_SLUG . '">' . __( 'Backups', 'hmbkp' ) . '</a>' );
35
 
36
  return $links;
37
 
38
  }
39
- add_filter('plugin_action_links', 'hmbkp_plugin_action_link', 10, 2 );
40
 
41
  /**
42
  * Add Contextual Help to Backups tools page.
@@ -47,11 +47,15 @@ add_filter('plugin_action_links', 'hmbkp_plugin_action_link', 10, 2 );
47
  */
48
  function hmbkp_contextual_help() {
49
 
 
 
 
 
50
  require_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
51
 
52
  if ( ! $plugin = get_transient( 'hmbkp_plugin_data' ) ) {
53
 
54
- $plugin = plugins_api( 'plugin_information', array( 'slug' => 'backupwordpress' ) );
55
 
56
  // Cache for one day
57
  set_transient( 'hmbkp_plugin_data', $plugin, 86400 );
@@ -62,16 +66,12 @@ function hmbkp_contextual_help() {
62
 
63
  // Check if help is for the right version.
64
  if ( ! empty( $plugin->version ) && version_compare( HMBKP_VERSION, $plugin->version, '!=' ) )
65
- $warning = sprintf( '<div id="message" class="updated inline"><p><strong>' . __( 'You are not using the latest stable version of BackUpWordPress', 'hmbkp' ) . '</strong> &mdash; ' . __( 'The information below is for version %1$s. View the %2$s file for help specific to version %3$s.', 'hmbkp' ) . '</p></div>', '<code>' . $plugin->version . '</code>', '<code>readme.txt</code>', '<code>' . HMBKP_VERSION . '</code>' );
66
 
67
  ob_start();
68
- require_once( HMBKP_PLUGIN_PATH . '/admin.constants.php' );
69
  $constants = ob_get_clean();
70
 
71
- // Pre WordPress 3.3 compat
72
- if ( ! method_exists( get_current_screen(), 'add_help_tab' ) )
73
- return;
74
-
75
  get_current_screen()->add_help_tab( array( 'title' => __( 'FAQ', 'hmbkp' ), 'id' => 'hmbkp_faq', 'content' => $warning . $plugin->sections['faq'] ) );
76
  get_current_screen()->add_help_tab( array( 'title' => __( 'Constants', 'hmbkp' ), 'id' => 'hmbkp_constants', 'content' => $warning . $constants ) );
77
 
18
  * @return null
19
  */
20
  function hmbkp_manage_backups() {
21
+ require_once( HMBKP_PLUGIN_PATH . '/admin/page.php' );
22
  }
23
 
24
  /**
31
  function hmbkp_plugin_action_link( $links, $file ) {
32
 
33
  if ( strpos( $file, HMBKP_PLUGIN_SLUG ) !== false )
34
+ array_push( $links, '<a href="tools.php?page=' . esc_attr( HMBKP_PLUGIN_SLUG ) . '">' . __( 'Backups', 'hmbkp' ) . '</a>' );
35
 
36
  return $links;
37
 
38
  }
39
+ add_filter( 'plugin_action_links', 'hmbkp_plugin_action_link', 10, 2 );
40
 
41
  /**
42
  * Add Contextual Help to Backups tools page.
47
  */
48
  function hmbkp_contextual_help() {
49
 
50
+ // Pre WordPress 3.3 compat
51
+ if ( ! method_exists( get_current_screen(), 'add_help_tab' ) )
52
+ return;
53
+
54
  require_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
55
 
56
  if ( ! $plugin = get_transient( 'hmbkp_plugin_data' ) ) {
57
 
58
+ $plugin = plugins_api( 'plugin_information', array( 'slug' => HMBKP_PLUGIN_SLUG ) );
59
 
60
  // Cache for one day
61
  set_transient( 'hmbkp_plugin_data', $plugin, 86400 );
66
 
67
  // Check if help is for the right version.
68
  if ( ! empty( $plugin->version ) && version_compare( HMBKP_VERSION, $plugin->version, '!=' ) )
69
+ $warning = sprintf( '<div id="message" class="updated inline"><p><strong>' . __( 'You are not using the latest stable version of BackUpWordPress', 'hmbkp' ) . '</strong> &mdash; ' . __( 'The information below is for version %1$s. View the %2$s file for help specific to version %3$s.', 'hmbkp' ) . '</p></div>', '<code>' . esc_attr( $plugin->version ) . '</code>', '<code>readme.txt</code>', '<code>' . esc_attr( HMBKP_VERSION ) . '</code>' );
70
 
71
  ob_start();
72
+ require_once( HMBKP_PLUGIN_PATH . '/admin/constants.php' );
73
  $constants = ob_get_clean();
74
 
 
 
 
 
75
  get_current_screen()->add_help_tab( array( 'title' => __( 'FAQ', 'hmbkp' ), 'id' => 'hmbkp_faq', 'content' => $warning . $plugin->sections['faq'] ) );
76
  get_current_screen()->add_help_tab( array( 'title' => __( 'Constants', 'hmbkp' ), 'id' => 'hmbkp_constants', 'content' => $warning . $constants ) );
77
 
admin/page.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="wrap">
2
+
3
+ <?php screen_icon( HMBKP_PLUGIN_SLUG ); ?>
4
+
5
+ <h2><?php _e( 'Manage Backups', 'hmbkp' ); ?></h2>
6
+
7
+ <?php if ( hmbkp_possible() ) : ?>
8
+
9
+ <?php include_once( HMBKP_PLUGIN_PATH . '/admin/backups.php' ); ?>
10
+
11
+ <?php else : ?>
12
+
13
+ <p><strong><?php _e( 'You need to fix the issues detailed above before BackUpWordPress can start.', 'hmbkp' ); ?></strong></p>
14
+
15
+ <?php endif; ?>
16
+
17
+ <p class="howto"><?php printf( __( 'If you need help getting things working you are more than welcome to email us at %s and we\'ll do what we can.', 'hmbkp' ), '<a href="mailto:support@hmn.md">support@hmn.md</a>' ); ?></p>
18
+
19
+ </div>
admin/schedule-form-excludes.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <form method="post" class="hmbkp-form">
2
+
3
+ <input type="hidden" name="hmbkp_schedule_id" value="<?php echo esc_attr( $schedule->get_id() ); ?>" />
4
+
5
+ <fieldset class="hmbkp-edit-schedule-excludes-form">
6
+
7
+ <legend><?php _e( 'Manage Excludes', 'hmbkp' ); ?></legend>
8
+
9
+ <div class="hmbkp_add_exclude_rule">
10
+
11
+ <label for="hmbkp-new-exclude-rule">
12
+
13
+ <?php _e( 'New Exclude Rule', 'hmbkp' ); ?>
14
+
15
+ <input id="hmbkp-new-exclude-rule" type="text" class="code" placeholder=".git/, *.mp3, wp-content/uploads/" />
16
+
17
+ <button type="button" class="button-secondary hmbkp_preview_exclude_rule"><?php _e( 'Preview', 'hmbkp' ); ?></button>
18
+
19
+ </label>
20
+
21
+ </div>
22
+
23
+ <table class="widefat fixed">
24
+
25
+ <thead>
26
+ <tr>
27
+ <th><?php _e( 'Exclude Rules', 'hmbkp' ); ?></th>
28
+ </tr>
29
+ </thead>
30
+
31
+ <tbody>
32
+
33
+ <?php foreach( $schedule->get_excludes() as $key => $exclude ) : ?>
34
+
35
+ <tr>
36
+ <td data-hmbkp-exclude-rule="<?php echo esc_attr( $exclude ); ?>">
37
+
38
+ <span class="code"><?php echo esc_attr( str_ireplace( untrailingslashit( $schedule->get_root() ), '', $exclude ) ); ?></span>
39
+
40
+ <?php if ( strpos( $schedule->get_path(), untrailingslashit( $exclude ) ) !== false ) : ?>
41
+
42
+ <span class="reason"><?php _e( 'default', 'hmbkp' ); ?></span>
43
+
44
+ <?php elseif ( defined( 'HMBKP_EXCLUDE' ) && strpos( HMBKP_EXCLUDE, $exclude ) !== false ) : ?>
45
+
46
+ <span class="reason"><?php _e( 'defined', 'hmbkp' ); ?></span>
47
+
48
+ <?php else : ?>
49
+
50
+ <a href="#" class="delete-action"><?php _e( 'Remove', 'hmbkp' ); ?></a>
51
+
52
+ <?php endif; ?>
53
+
54
+ </td>
55
+ </tr>
56
+
57
+ <?php endforeach; ?>
58
+
59
+ </tbody>
60
+
61
+ </table>
62
+
63
+ <div class="hmbkp-tabs">
64
+
65
+ <ul class="subsubsub">
66
+
67
+ <?php if ( $schedule->get_excluded_files() ) : ?>
68
+
69
+ <li><a href="#hmbkp_excluded_files"><?php _e( 'Excluded', 'hmbkp' ); ?></a>(<?php echo count( $schedule->get_excluded_files() ); ?>)</li>
70
+
71
+ <?php endif; ?>
72
+
73
+ <li><a href="#hmbkp_included_files"><?php _e( 'Included', 'hmbkp' ); ?></a>(<?php echo count( $schedule->get_included_files() ); ?>)</li>
74
+
75
+ <?php if ( $schedule->get_unreadable_files() ) : ?>
76
+
77
+ <li><a href="#hmbkp_unreadable_files"><?php _e( 'Unreadable', 'hmbkp' ); ?></a>(<?php echo count( $schedule->get_unreadable_files() ); ?>)</li>
78
+
79
+ <?php endif; ?>
80
+
81
+ </ul>
82
+
83
+ <?php if ( $schedule->get_excluded_files() ) : ?>
84
+
85
+ <div id="hmbkp_excluded_files">
86
+
87
+ <?php hmbkp_file_list( $schedule, null, 'get_excluded_files' ); ?>
88
+
89
+ </div>
90
+
91
+ <?php endif; ?>
92
+
93
+ <div id="hmbkp_included_files">
94
+
95
+ <?php hmbkp_file_list( $schedule, null, 'get_included_files' ); ?>
96
+
97
+ </div>
98
+
99
+ <?php if ( $schedule->get_unreadable_files() ) : ?>
100
+
101
+ <div id="hmbkp_unreadable_files">
102
+
103
+ <?php hmbkp_file_list( $schedule, null, 'get_unreadable_files' ); ?>
104
+
105
+ <p class="description"><?php _e( 'Unreadable files can\'t be backed up', 'hmbkp' ); ?></p>
106
+
107
+ </div>
108
+
109
+ <?php endif; ?>
110
+
111
+ <p><?php printf( __( 'Your site is %s. Backups will be compressed and so will be smaller.', 'hmbkp' ), '<code>' . $schedule->get_filesize( false ) . '</code>' ); ?></p>
112
+
113
+ </div>
114
+
115
+ <p class="submit">
116
+
117
+ <button type="submit" class="button-primary"><?php _e( 'Close', 'hmbkp' ); ?></button>
118
+
119
+ </p>
120
+
121
+ </fieldset>
122
+
123
+ </form>
admin/schedule-form.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <form method="post" class="hmbkp-form" novalidate data-schedule-action="<?php if ( isset( $is_new_schedule ) ) { ?>add<?php } else { ?>edit<?php } ?>">
2
+
3
+ <input type="hidden" name="hmbkp_schedule_id" value="<?php echo esc_attr( $schedule->get_id() ); ?>" />
4
+
5
+ <fieldset class="hmbkp-edit-schedule-form">
6
+
7
+ <legend><?php _e( 'Schedule Settings', 'hmbkp' ); ?></legend>
8
+
9
+ <label>
10
+
11
+ <?php _e( 'Backup', 'hmbkp' ); ?>
12
+
13
+ <select name="hmbkp_schedule_type" id="hmbkp_schedule_type">
14
+ <option<?php selected( $schedule->get_type(), 'complete'); ?> value="complete"><?php _e( 'Both Database &amp; files', 'hmbkp' ); ?></option>
15
+ <option<?php selected( $schedule->get_type(), 'file'); ?> value="file"><?php _e( 'Files only', 'hmbkp' ); ?></option>
16
+ <option<?php selected( $schedule->get_type(), 'database'); ?> value="database"><?php _e( 'Database only', 'hmbkp' ); ?></option>
17
+ </select>
18
+
19
+ </label>
20
+
21
+ <label>
22
+
23
+ <?php _e( 'Schedule', 'hmbkp' ); ?>
24
+
25
+ <select name="hmbkp_schedule_reoccurrence" id="hmbkp_schedule_reoccurrence">
26
+
27
+ <option value="manually"><?php _e( 'Manual Only', 'hmbkp' ); ?></option>
28
+
29
+ <?php foreach( wp_get_schedules() as $cron_schedule => $cron_details ) : ?>
30
+
31
+ <option<?php selected( $schedule->get_reoccurrence(), $cron_schedule ); ?> value="<?php echo esc_attr( $cron_schedule ); ?>"><?php echo esc_attr( $cron_details['display'] ); ?></option>
32
+
33
+ <?php endforeach; ?>
34
+
35
+ </select>
36
+
37
+ </label>
38
+
39
+ <label>
40
+
41
+ <?php _e( 'Number of backups to store on this server', 'hmbkp' ); ?>
42
+
43
+ <input type="number" name="hmbkp_schedule_max_backups" min="1" step="1" value="<?php echo esc_attr( $schedule->get_max_backups() ); ?>" />
44
+
45
+ <p class="description"><?php _e( 'The number of previous backups to store on the server. past this limit older backups will be deleted automatically.', 'hmbkp' ); ?></p>
46
+
47
+ </label>
48
+
49
+ <?php foreach ( HMBKP_Services::get_services( $schedule ) as $service )
50
+ $service->field(); ?>
51
+
52
+ <p class="submit">
53
+
54
+ <button type="submit" class="button-primary"><?php _e( 'Update', 'hmbkp' ); ?></button>
55
+
56
+ </p>
57
+
58
+ </fieldset>
59
+
60
+ </form>
admin/schedule.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Calculated filesize
4
+ $filesize = $schedule->is_filesize_cached() || isset( $recalculate_filesize ) ? '<code title="' . __( 'Backups will be compressed and should be smaller than this.', 'hmbkp' ) . '">' . esc_attr( $schedule->get_filesize() ) . '</code>' : '<code class="calculating" title="' . __( 'this shouldn\'t take long&hellip;', 'hmbkp' ) . '">' . __( 'calculating the size of your site&hellip;', 'hmbkp' ) . '</code>';
5
+
6
+ // Backup Type
7
+ $type = strtolower( hmbkp_human_get_type( $schedule->get_type() ) );
8
+
9
+ // Backup Time
10
+ $day = date_i18n( 'l', $schedule->get_next_occurrence() );
11
+
12
+ $next_backup = 'title="' . sprintf( __( 'The next backup will be on %1$s at %2$s', 'hmbkp' ), date_i18n( get_option( 'date_format' ), $schedule->get_next_occurrence() ), date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence() ) ) . '"';
13
+
14
+ // Backup Re-occurrence
15
+ switch ( $schedule->get_reoccurrence() ) :
16
+
17
+ case 'hourly' :
18
+
19
+ $reoccurrence = date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence() ) === '00' ? sprintf( __( 'hourly on the hour', 'hmbkp' ) ) : sprintf( __( 'hourly at %s minutes past the hour', 'hmbkp' ), '<span ' . $next_backup . '>' . str_replace( '0', '', date_i18n( 'i', $schedule->get_next_occurrence() ) ) ) . '</span>';
20
+
21
+ break;
22
+
23
+ case 'daily' :
24
+
25
+ $reoccurrence = sprintf( __( 'daily at %s', 'hmbkp' ), '<span ' . $next_backup . '>' . date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence() ) . '</span>' );
26
+
27
+ break;
28
+
29
+
30
+ case 'twicedaily' :
31
+
32
+ $times[] = date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence() );
33
+ $times[] = date_i18n( get_option( 'time_format' ), strtotime( '+ 12 hours', $schedule->get_next_occurrence() ) );
34
+
35
+ sort( $times );
36
+
37
+ $reoccurrence = sprintf( __( 'every 12 hours at %1$s &amp; %2$s', 'hmbkp' ), '<span ' . $next_backup . '>' . reset( $times ) . '</span>', '<span>' . end( $times ) ) . '</span>';
38
+
39
+ break;
40
+
41
+ case 'weekly' :
42
+
43
+ $reoccurrence = sprintf( __( 'weekly on %1$s at %2$s', 'hmbkp' ), '<span ' . $next_backup . '>' . $day . '</span>', '<span>' . date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence() ) . '</span>' );
44
+
45
+ break;
46
+
47
+ case 'fortnightly' :
48
+
49
+ $reoccurrence = sprintf( __( 'fortnightly on %1$s at %2$s', 'hmbkp' ), '<span ' . $next_backup . '>' . $day . '</span>', '<span>' . date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence() ) . '</span>' );
50
+
51
+ break;
52
+
53
+
54
+ case 'monthly' :
55
+
56
+ $reoccurrence = sprintf( __( 'on the %1$s of each month at %2$s', 'hmbkp' ), '<span ' . $next_backup . '>' . date_i18n( 'jS', $schedule->get_next_occurrence() ) . '</span>', '<span>' . date_i18n( get_option( 'time_format' ), $schedule->get_next_occurrence() ) . '</span>' );
57
+
58
+ break;
59
+
60
+ case 'manually' :
61
+
62
+ $reoccurrence = __( 'manually', 'hmbkp' );
63
+
64
+ break;
65
+
66
+ endswitch;
67
+
68
+ $server = '<span title="' . esc_attr( hmbkp_path() ) . '">' . __( 'this server', 'hmbkp' ) . '</span>';
69
+
70
+ // Backup to keep
71
+ switch ( $schedule->get_max_backups() ) :
72
+
73
+ case 1 :
74
+
75
+ $backup_to_keep = sprintf( __( 'store the only the last backup on %s', 'hmbkp' ), $server );
76
+
77
+ break;
78
+
79
+ case 0 :
80
+
81
+ $backup_to_keep = sprintf( __( 'don\'t store any backups on %s', 'hmbkp' ), $server );
82
+
83
+ break;
84
+
85
+ default :
86
+
87
+ $backup_to_keep = sprintf( __( 'store only the last %1$s backups on %2$s', 'hmbkp' ), esc_attr( $schedule->get_max_backups() ), $server );
88
+
89
+ endswitch;
90
+
91
+ foreach ( HMBKP_Services::get_services( $schedule ) as $file => $service )
92
+ $services[] = $service->display(); ?>
93
+
94
+ <div class="hmbkp-schedule-sentence<?php if ( $schedule->get_status() ) { ?> hmbkp-running<?php } ?>">
95
+
96
+ <?php printf( __( 'Backup my %1$s %2$s %3$s, %4$s. %5$s', 'hmbkp' ), $filesize, '<span>' . $type . '</span>', $reoccurrence, $backup_to_keep, implode( '. ', $services ) ); ?>
97
+
98
+ <?php hmbkp_schedule_actions( $schedule ); ?>
99
+
100
+ </div>
assets/fancyBox/CHANGELOG.md ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fancyBox - Changelog
2
+ =========
3
+
4
+ ### Version 2.0.5 - February 21, 2012
5
+
6
+ * Fixed #155 - easing for prev/next animations
7
+ * Fixed #153 - overriding "keys" options
8
+ * Fixed #147 - IE7 problem with #hash links
9
+ * Fixed #130 - changing dynamically data-fancybox-group
10
+ * Fixed #126 - obey minWidth/minHeight
11
+ * Fixed #118 - placement of loading icon and navigation arrows
12
+ * Fixed #101 - "index" option not working
13
+ * Fixed #94 - "orig" option not working
14
+ * Fixed #80 - does not work on IE6
15
+ * Fixed #72 - can't set overlay opacity to 0
16
+ * Fixed #63 - properly set gallery index
17
+ * New option "autoCenter" - toggles centering on window resize or scroll, disabled for mobile devices by default
18
+ * New option "autoResize" - toggles responsivity, disabled for mobile devices by default
19
+ * New option "preload" - number of images to preload
20
+ * New feature to target mobile/desktop browsers using CSS, see #108
21
+ * Changed ajax option defaults to "{ dataType: 'html', headers: { 'X-fancyBox': true } }", see #150 and #128
22
+ * Updated loading icon for IE7, IE8
23
+ * Calculates height of the iframe if 'autoSize' is set to 'true' and the iframe is on the same domain as the main page
24
+
25
+ ### Version 2.0.4 - December 12, 2011
26
+
27
+ * Fixed #47 - fix overriding properties
28
+ * New option "position" to thumbnail and button helpers
29
+
30
+
31
+ ### Version 2.0.3 - November 29, 2011
32
+
33
+ * Fixed #29 - broken elastic transitions
34
+
35
+
36
+ ### Version 2.0.2 - November 28, 2011
37
+
38
+ * Fixed slidshow
39
+ * Fixed scrollbar issue when displayed a very tall image
40
+ * New option "nextClick" - navigate to next gallery item when user clicks the content
41
+ * New option "modal" - to disable navigation and closing
42
+ * Add 'metadata' plugin support
43
+ * Add ability to create groups using 'data-fancybox-group' attribute
44
+ * Updated manual usage to match earlier releases
45
+
46
+
47
+ ### Version 2.0.1 - November 23, 2011
48
+
49
+ * Fixed keyboard events inside form elements
50
+ * Fixed manual usage
51
+
52
+
53
+ ### Version 2.0.0 - November 21, 2011
54
+
55
+ First release - completely rewritten, many new features and updated graphics.
assets/fancyBox/README.md ADDED
@@ -0,0 +1,199 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fancyBox
2
+ ========
3
+
4
+ fancyBox is a tool that offers a nice and elegant way to add zooming functionality for images, html content and multi-media on your webpages.
5
+
6
+ More information and examples: http://www.fancyapps.com/fancybox/
7
+
8
+ License: http://www.fancyapps.com/fancybox/#license
9
+
10
+ Copyright (c) 2012 Janis Skarnelis - janis@fancyapps.com
11
+
12
+
13
+ How to use
14
+ ----------
15
+
16
+ To get started, download the plugin, unzip it and copy files to your website/application directory.
17
+ Load files in the <head> section of your HTML document. Make sure you also add the jQuery library.
18
+
19
+ <head>
20
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
21
+ <link rel="stylesheet" href="/fancybox/jquery.fancybox.css" type="text/css" media="screen" />
22
+ <script type="text/javascript" src="/fancybox/jquery.fancybox.pack.js"></script>
23
+ </head>
24
+
25
+ Create your links with a `title` if you want a title to be shown, and add a class:
26
+
27
+ <a href="large_image.jpg" class="fancybox" title="Sample title"><img src="small_image.jpg" /></a>
28
+
29
+ If you have a set of related items that you would like to group,
30
+ additionally include a group name in the `rel` (or `data-fancybox-group`) attribute:
31
+
32
+ <a href="large_1.jpg" class="fancybox" rel="gallery" title="Sample title 1"><img src="small_1.jpg" /></a>
33
+ <a href="large_2.jpg" class="fancybox" rel="gallery" title="Sample title 1"><img src="small_2.jpg" /></a>
34
+
35
+ Initialise the script like this:
36
+
37
+ <script>
38
+ $(document).ready(function() {
39
+ $('.fancybox').fancybox();
40
+ });
41
+ </script>
42
+
43
+ May also be passed an optional options object which will extend the default values. Example:
44
+
45
+ <script>
46
+ $(document).ready(function() {
47
+ $('.fancybox').fancybox({
48
+ padding : 5,
49
+ loop : false
50
+ });
51
+ });
52
+ </script>
53
+
54
+ Script uses the `href` attribute of the matched elements to obtain the location of the content and to figure out content type you want to display.
55
+ You can specify type directly by adding classname (fancybox.image, fancybox.iframe, etc).
56
+
57
+ //Ajax:
58
+ <a href="/example.html" class="fancybox fancybox.ajax">Example</a>
59
+
60
+ //Iframe:
61
+ <a href="example.html" class="fancybox fancybox.iframe">Example</a>
62
+
63
+ //Inline:
64
+ <a href="#example" class="fancybox">Example</a>
65
+
66
+ //SWF:
67
+ <a href="example.swf" class="fancybox">Example</a>
68
+
69
+ //Image:
70
+ <a href="example.jpg" class="fancybox">Example</a>
71
+
72
+ Note, ajax requests are subject to the [same origin policy](http://en.wikipedia.org/wiki/Same_origin_policy).
73
+ If fancyBox will not be able to get content type, error message will be displayed (this is different from previsous versions where 'ajax' was used as default type).
74
+
75
+ Advanced
76
+ --------
77
+
78
+ ### Helpers
79
+
80
+ Helpers provide a simple mechanism to extend the capabilities of fancyBox. There are two built-in helpers - 'overlay' and 'title'.
81
+ You can disable them, set custom options or enable other helpers. Examples:
82
+
83
+ //Disable title helper
84
+ $(".fancybox").fancybox({
85
+ helpers: {
86
+ title: null
87
+ }
88
+ });
89
+
90
+ //Disable overlay helper
91
+ $(".fancybox").fancybox({
92
+ helpers: {
93
+ overlay : null
94
+ }
95
+ });
96
+
97
+ //Change title position and overlay color
98
+ $(".fancybox").fancybox({
99
+ helpers: {
100
+ title : {
101
+ type : 'inside'
102
+ },
103
+ overlay : {
104
+ css : {
105
+ 'background-color' : '#fff'
106
+ }
107
+ }
108
+ }
109
+ });
110
+
111
+ //Enable thumbnail helper and set custom options
112
+ $(".fancybox").fancybox({
113
+ helpers: {
114
+ thumbs : {
115
+ width: 50,
116
+ height: 50
117
+ }
118
+ }
119
+ });
120
+
121
+
122
+ ### API
123
+
124
+ Also available are event driven callback methods. The `this` keyword refers to the current or upcoming object (depends on callback method). Here is how you can change title:
125
+
126
+ $(".fancybox").fancybox({
127
+ beforeLoad : function() {
128
+ this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
129
+
130
+ /*
131
+ "this.element" refers to current element, so you can, for example, use the "alt" attribute of the image to store the title:
132
+ this.title = $(this.element).find('img').attr('alt');
133
+ */
134
+ }
135
+ });
136
+
137
+ It`s possible to open fancyBox programmatically in various ways:
138
+
139
+ //HTML content:
140
+ $.fancybox( '<div><h1>Lorem Lipsum</h1><p>Lorem lipsum</p></div>', {
141
+ title : 'Custom Title'
142
+ });
143
+
144
+ //DOM element:
145
+ $.fancybox( $("#inline"), {
146
+ title : 'Custom Title'
147
+ });
148
+
149
+ //Custom object:
150
+ $.fancybox({
151
+ href: 'example.jpg',
152
+ title : 'Custom Title'
153
+ });
154
+
155
+ //Array of objects:
156
+ $.fancybox([
157
+ {
158
+ href: 'example1.jpg',
159
+ title : 'Custom Title 1'
160
+ },
161
+ {
162
+ href: 'example2.jpg',
163
+ title : 'Custom Title 2'
164
+ }
165
+ ], {
166
+ padding: 0
167
+ });
168
+
169
+ There are several methods that allow you to interact with and manipulate fancyBox, example:
170
+
171
+ //Close fancybox:
172
+ $.fancybox.close();
173
+
174
+ There is a simply way to access wrapping elements using JS:
175
+
176
+ $.fancybox.wrap
177
+ $.fancybox.outer
178
+ $.fancybox.inner
179
+
180
+ You can override CSS to customize the look. For example, make navigation arrows always visible
181
+ and move them outside of area (use this snippet after including fancybox.css):
182
+
183
+ .fancybox-nav span {
184
+ visibility: visible;
185
+ }
186
+
187
+ .fancybox-prev {
188
+ left: -50px;
189
+ }
190
+
191
+ .fancybox-next {
192
+ right: 50px;
193
+ }
194
+
195
+
196
+ Bug tracker
197
+ -----------
198
+
199
+ Have a bug? Please create an issue on GitHub at https://github.com/fancyapps/fancyBox/issues
assets/fancyBox/demo/1_b.jpg ADDED
Binary file
assets/fancyBox/demo/1_s.jpg ADDED
Binary file
assets/fancyBox/demo/2_b.jpg ADDED
Binary file
assets/fancyBox/demo/2_s.jpg ADDED
Binary file
assets/fancyBox/demo/3_b.jpg ADDED
Binary file
assets/fancyBox/demo/3_s.jpg ADDED
Binary file
assets/fancyBox/demo/4_b.jpg ADDED
Binary file
assets/fancyBox/demo/4_s.jpg ADDED
Binary file
assets/fancyBox/demo/5_b.jpg ADDED
Binary file
assets/fancyBox/demo/5_s.jpg ADDED
Binary file
assets/fancyBox/demo/ajax.txt ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="max-width:700px;">
2
+ <h2>Lorem ipsum dolor sit amet3</h2>
3
+ <p>
4
+ <a href="javascript:jQuery.fancybox.close();">Close me</a>
5
+ </p>
6
+ <p>
7
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas fermentum ante et sapien dignissim in viverra magna feugiat. Donec tempus ipsum nec neque dignissim quis eleifend eros gravida. Praesent nisi massa, sodales quis tincidunt ac, semper quis risus. In suscipit nisl sed leo aliquet consequat. Integer vitae augue in risus porttitor pellentesque eu eget odio. Fusce ut sagittis quam. Morbi aliquam interdum blandit. Integer pharetra tempor velit, aliquam dictum justo tempus sed. Morbi congue fringilla justo a feugiat. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent quis metus et nisl consectetur pharetra. Nam bibendum turpis eu metus luctus eu volutpat sem molestie. Nam sollicitudin porttitor lorem, ac ultricies est venenatis eu. Ut dignissim elit et orci feugiat ac placerat purus euismod. Ut mi lorem, cursus et sagittis elementum, luctus ac massa.
8
+ </p>
9
+ <p>
10
+ Phasellus et ligula vel diam ullamcorper volutpat. Integer rhoncus rhoncus aliquam. Aliquam erat volutpat. Aenean luctus vestibulum placerat. Quisque quam neque, lacinia aliquet eleifend ac, aliquet blandit felis. Curabitur porta ultricies dui, sit amet mattis quam euismod a. Ut eleifend scelerisque neque, sit amet accumsan odio consequat ut. Proin facilisis auctor elit sed accumsan. Cras dapibus nisl in nisi rhoncus laoreet. Nullam pellentesque tortor libero, eget facilisis ipsum. Donec ultricies tellus tellus, in tincidunt purus. Nullam in est aliquam velit scelerisque blandit. In tincidunt, magna a dapibus imperdiet, quam urna elementum leo, vitae rhoncus nisl velit cursus velit. In dignissim sem ac mauris rhoncus ornare.
11
+ </p>
12
+ <p>
13
+ Duis imperdiet velit vel quam malesuada suscipit imperdiet tellus hendrerit. Mauris vestibulum odio mauris, ut placerat leo. Mauris quis neque at tellus feugiat congue id non enim. Nam vehicula posuere nulla eget vehicula. Donec pretium purus nec ligula porta eu laoreet sapien venenatis. Nulla facilisi. Phasellus eget mi enim. Phasellus molestie tincidunt ultrices. Aenean id sem a tellus lobortis tincidunt. Nam laoreet nulla vel velit tincidunt ac rutrum libero malesuada. Nulla consequat dolor quis nisl tempor fermentum. Integer sodales pretium varius. Aenean a leo vitae odio dictum dignissim malesuada nec dolor. Phasellus adipiscing viverra est, ac sagittis libero sagittis quis. Sed interdum dapibus nunc et fringilla. Nunc vel velit et urna laoreet bibendum.
14
+ </p>
15
+ </div>
assets/fancyBox/demo/iframe.html ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>fancyBox - iframe demo</title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ </head>
7
+ <body>
8
+ <h1>fancyBox - iframe demo</h1>
9
+
10
+ <p>
11
+ <a href="javascript:parent.jQuery.fancybox.close();">Close iframe parent</a>
12
+ </p>
13
+
14
+ <p>
15
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam scelerisque justo ac eros consectetur bibendum. In hac habitasse platea dictumst. Nulla aliquam turpis et tellus elementum luctus. Duis sit amet rhoncus velit. Duis nisl ligula, mattis interdum blandit laoreet, mattis id ante. Cras pulvinar lacus vitae nisi egestas non euismod neque bibendum. Vestibulum faucibus libero id ante molestie ultricies. Vestibulum quis nibh felis. Vestibulum libero nisl, vehicula vel ullamcorper sit amet, tristique sit amet augue. Etiam urna neque, porttitor sed sodales lacinia, posuere a nisl. Vestibulum blandit neque in sapien volutpat ac condimentum sapien auctor. Ut imperdiet venenatis ultricies. Phasellus accumsan, sem eu placerat commodo, felis purus commodo ipsum, sit amet vulputate orci est viverra est.
16
+ </p>
17
+
18
+ <p>
19
+ Aenean velit est, condimentum ut iaculis ut, accumsan at mi. Maecenas velit mi, venenatis ut condimentum at, ultrices vel tortor. Curabitur pharetra ornare dapibus. Ut volutpat cursus semper. In hac habitasse platea dictumst. Donec eu iaculis ipsum. Morbi eu dolor velit, a semper nunc.
20
+ </p>
21
+ </body>
22
+ </html>
assets/fancyBox/demo/index.html ADDED
@@ -0,0 +1,302 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>fancyBox - Fancy jQuery Lightbox Alternative | Demonstration</title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+
7
+ <!-- Add jQuery library -->
8
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
9
+
10
+ <!-- Add mousewheel plugin (this is optional) -->
11
+ <script type="text/javascript" src="../lib/jquery.mousewheel-3.0.6.pack.js"></script>
12
+
13
+ <!-- Add fancyBox main JS and CSS files -->
14
+ <script type="text/javascript" src="../source/jquery.fancybox.js"></script>
15
+ <link rel="stylesheet" type="text/css" href="../source/jquery.fancybox.css" media="screen" />
16
+
17
+ <!-- Add Button helper (this is optional) -->
18
+ <link rel="stylesheet" type="text/css" href="../source/helpers/jquery.fancybox-buttons.css?v=1.0.2" />
19
+ <script type="text/javascript" src="../source/helpers/jquery.fancybox-buttons.js?v=1.0.2"></script>
20
+
21
+ <!-- Add Thumbnail helper (this is optional) -->
22
+ <link rel="stylesheet" type="text/css" href="../source/helpers/jquery.fancybox-thumbs.css?v=1.0.2" />
23
+ <script type="text/javascript" src="../source/helpers/jquery.fancybox-thumbs.js?v=1.0.2"></script>
24
+
25
+ <!-- Add Media helper (this is optional) -->
26
+ <script type="text/javascript" src="../source/helpers/jquery.fancybox-media.js?v=1.0.0"></script>
27
+
28
+ <script type="text/javascript">
29
+ $(document).ready(function() {
30
+ /*
31
+ * Simple image gallery. Uses default settings
32
+ */
33
+
34
+ $('.fancybox').fancybox();
35
+
36
+ /*
37
+ * Different effects
38
+ */
39
+
40
+ // Change title type, overlay opening speed and opacity
41
+ $(".fancybox-effects-a").fancybox({
42
+ helpers: {
43
+ title : {
44
+ type : 'outside'
45
+ },
46
+ overlay : {
47
+ speedIn : 500,
48
+ opacity : 0.95
49
+ }
50
+ }
51
+ });
52
+
53
+ // Disable opening and closing animations, change title type
54
+ $(".fancybox-effects-b").fancybox({
55
+ openEffect : 'none',
56
+ closeEffect : 'none',
57
+
58
+ helpers : {
59
+ title : {
60
+ type : 'over'
61
+ }
62
+ }
63
+ });
64
+
65
+ // Set custom style, close if clicked, change title type and overlay color
66
+ $(".fancybox-effects-c").fancybox({
67
+ wrapCSS : 'fancybox-custom',
68
+ closeClick : true,
69
+
70
+ helpers : {
71
+ title : {
72
+ type : 'inside'
73
+ },
74
+ overlay : {
75
+ css : {
76
+ 'background-color' : '#eee'
77
+ }
78
+ }
79
+ }
80
+ });
81
+
82
+ // Remove padding, set opening and closing animations, close if clicked and disable overlay
83
+ $(".fancybox-effects-d").fancybox({
84
+ padding: 0,
85
+
86
+ openEffect : 'elastic',
87
+ openSpeed : 150,
88
+
89
+ closeEffect : 'elastic',
90
+ closeSpeed : 150,
91
+
92
+ closeClick : true,
93
+
94
+ helpers : {
95
+ overlay : null
96
+ }
97
+ });
98
+
99
+ /*
100
+ * Button helper. Disable animations, hide close button, change title type and content
101
+ */
102
+
103
+ $('.fancybox-buttons').fancybox({
104
+ openEffect : 'none',
105
+ closeEffect : 'none',
106
+
107
+ prevEffect : 'none',
108
+ nextEffect : 'none',
109
+
110
+ closeBtn : false,
111
+
112
+ helpers : {
113
+ title : {
114
+ type : 'inside'
115
+ },
116
+ buttons : {}
117
+ },
118
+
119
+ afterLoad : function() {
120
+ this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
121
+ }
122
+ });
123
+
124
+
125
+ /*
126
+ * Thumbnail helper. Disable animations, hide close button, arrows and slide to next gallery item if clicked
127
+ */
128
+
129
+ $('.fancybox-thumbs').fancybox({
130
+ prevEffect : 'none',
131
+ nextEffect : 'none',
132
+
133
+ closeBtn : false,
134
+ arrows : false,
135
+ nextClick : true,
136
+
137
+ helpers : {
138
+ thumbs : {
139
+ width : 50,
140
+ height : 50
141
+ }
142
+ }
143
+ });
144
+
145
+ /*
146
+ * Media helper. Group items, disable animations, hide arrows, enable media and button helpers.
147
+ */
148
+ $('.fancybox-media')
149
+ .attr('rel', 'media-gallery')
150
+ .fancybox({
151
+ openEffect : 'none',
152
+ closeEffect : 'none',
153
+ prevEffect : 'none',
154
+ nextEffect : 'none',
155
+
156
+ arrows : false,
157
+ helpers : {
158
+ media : {},
159
+ buttons : {}
160
+ }
161
+ });
162
+
163
+ /*
164
+ * Open manually
165
+ */
166
+
167
+ $("#fancybox-manual-a").click(function() {
168
+ $.fancybox.open('1_b.jpg');
169
+ });
170
+
171
+ $("#fancybox-manual-b").click(function() {
172
+ $.fancybox.open({
173
+ href : 'iframe.html',
174
+ type : 'iframe',
175
+ padding : 5
176
+ });
177
+ });
178
+
179
+ $("#fancybox-manual-c").click(function() {
180
+ $.fancybox.open([
181
+ {
182
+ href : '1_b.jpg',
183
+ title : 'My title'
184
+ }, {
185
+ href : '2_b.jpg',
186
+ title : '2nd title'
187
+ }, {
188
+ href : '3_b.jpg'
189
+ }
190
+ ], {
191
+ helpers : {
192
+ thumbs : {
193
+ width: 75,
194
+ height: 50
195
+ }
196
+ }
197
+ });
198
+ });
199
+
200
+
201
+ });
202
+ </script>
203
+ <style type="text/css">
204
+ .fancybox-custom .fancybox-outer {
205
+ box-shadow: 0 0 50px #222;
206
+ }
207
+ </style>
208
+ </head>
209
+ <body>
210
+ <h1>fancyBox</h1>
211
+
212
+ <p>This is a demonstration. More information and examples: <a href="http://fancyapps.com/fancybox/">www.fancyapps.com/fancybox/</a></p>
213
+
214
+ <h3>Simple image gallery</h3>
215
+ <p>
216
+ <a class="fancybox" href="1_b.jpg" data-fancybox-group="gallery" title="Lorem ipsum dolor sit amet"><img src="1_s.jpg" alt="" /></a>
217
+
218
+ <a class="fancybox" href="2_b.jpg" data-fancybox-group="gallery" title="Etiam quis mi eu elit temp"><img src="2_s.jpg" alt="" /></a>
219
+
220
+ <a class="fancybox" href="3_b.jpg" data-fancybox-group="gallery" title="Cras neque mi, semper leon"><img src="3_s.jpg" alt="" /></a>
221
+
222
+ <a class="fancybox" href="4_b.jpg" data-fancybox-group="gallery" title="Sed vel sapien vel sem uno"><img src="4_s.jpg" alt="" /></a>
223
+ </p>
224
+
225
+ <h3>Different effects</h3>
226
+ <p>
227
+ <a class="fancybox-effects-a" href="5_b.jpg" title="Lorem ipsum dolor sit amet, consectetur adipiscing elit"><img src="5_s.jpg" alt="" /></a>
228
+
229
+ <a class="fancybox-effects-b" href="5_b.jpg" title="Lorem ipsum dolor sit amet, consectetur adipiscing elit"><img src="5_s.jpg" alt="" /></a>
230
+
231
+ <a class="fancybox-effects-c" href="5_b.jpg" title="Lorem ipsum dolor sit amet, consectetur adipiscing elit"><img src="5_s.jpg" alt="" /></a>
232
+
233
+ <a class="fancybox-effects-d" href="5_b.jpg" title="Lorem ipsum dolor sit amet, consectetur adipiscing elit"><img src="5_s.jpg" alt="" /></a>
234
+ </p>
235
+
236
+ <h3>Various types</h3>
237
+ <p>
238
+ fancyBox will try to guess content type from href attribute but you can specify it directly by adding classname (fancybox.image, fancybox.iframe, etc).
239
+ </p>
240
+ <ul>
241
+ <li><a class="fancybox" href="#inline1" title="Lorem ipsum dolor sit amet">Inline</a></li>
242
+ <li><a class="fancybox fancybox.ajax" href="ajax.txt">Ajax</a></li>
243
+ <li><a class="fancybox fancybox.iframe" href="iframe.html">Iframe</a></li>
244
+ <li><a class="fancybox" href="http://www.adobe.com/jp/events/cs3_web_edition_tour/swfs/perform.swf">Swf</a></li>
245
+ </ul>
246
+
247
+ <div id="inline1" style="width:400px;display: none;">
248
+ <h3>Etiam quis mi eu elit</h3>
249
+ <p>
250
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam quis mi eu elit tempor facilisis id et neque. Nulla sit amet sem sapien. Vestibulum imperdiet porta ante ac ornare. Nulla et lorem eu nibh adipiscing ultricies nec at lacus. Cras laoreet ultricies sem, at blandit mi eleifend aliquam. Nunc enim ipsum, vehicula non pretium varius, cursus ac tortor. Vivamus fringilla congue laoreet. Quisque ultrices sodales orci, quis rhoncus justo auctor in. Phasellus dui eros, bibendum eu feugiat ornare, faucibus eu mi. Nunc aliquet tempus sem, id aliquam diam varius ac. Maecenas nisl nunc, molestie vitae eleifend vel, iaculis sed magna. Aenean tempus lacus vitae orci posuere porttitor eget non felis. Donec lectus elit, aliquam nec eleifend sit amet, vestibulum sed nunc.
251
+ </p>
252
+ </div>
253
+
254
+ <p>
255
+ Ajax example will not run from your local computer and requires a server to run.
256
+ </p>
257
+
258
+ <h3>Button helper</h3>
259
+ <p>
260
+ <a class="fancybox-buttons" data-fancybox-group="button" href="1_b.jpg"><img src="1_s.jpg" alt="" /></a>
261
+
262
+ <a class="fancybox-buttons" data-fancybox-group="button" href="2_b.jpg"><img src="2_s.jpg" alt="" /></a>
263
+
264
+ <a class="fancybox-buttons" data-fancybox-group="button" href="3_b.jpg"><img src="3_s.jpg" alt="" /></a>
265
+
266
+ <a class="fancybox-buttons" data-fancybox-group="button" href="4_b.jpg"><img src="4_s.jpg" alt="" /></a>
267
+ </p>
268
+
269
+ <h3>Thumbnail helper</h3>
270
+ <p>
271
+ <a class="fancybox-thumbs" data-fancybox-group="thumb" href="4_b.jpg"><img src="4_s.jpg" alt="" /></a>
272
+
273
+ <a class="fancybox-thumbs" data-fancybox-group="thumb" href="3_b.jpg"><img src="3_s.jpg" alt="" /></a>
274
+
275
+ <a class="fancybox-thumbs" data-fancybox-group="thumb" href="2_b.jpg"><img src="2_s.jpg" alt="" /></a>
276
+
277
+ <a class="fancybox-thumbs" data-fancybox-group="thumb" href="1_b.jpg"><img src="1_s.jpg" alt="" /></a>
278
+ </p>
279
+
280
+ <h3>Media helper</h3>
281
+ <ul>
282
+ <li><a class="fancybox-media" href="http://www.youtube.com/watch?v=opj24KnzrWo">Youtube</a></li>
283
+ <li><a class="fancybox-media" href="http://vimeo.com/25634903">Vimeo</a></li>
284
+ <li><a class="fancybox-media" href="http://www.metacafe.com/watch/7635964/">Metacafe</a></li>
285
+ <li><a class="fancybox-media" href="http://www.dailymotion.com/video/xoeylt_electric-guest-this-head-i-hold_music">Dailymotion</a></li>
286
+ <li><a class="fancybox-media" href="http://twitvid.com/QY7MD">Twitvid</a></li>
287
+ <li><a class="fancybox-media" href="http://twitpic.com/7p93st">Twitpic</a></li>
288
+ <li><a class="fancybox-media" href="http://instagr.am/p/IejkuUGxQn">Instagram</a></li>
289
+ </ul>
290
+
291
+ <h3>Open manually</h3>
292
+ <ul>
293
+ <li><a id="fancybox-manual-a" href="javascript:;">Open single item</a></li>
294
+ <li><a id="fancybox-manual-b" href="javascript:;">Open single item, custom options</a></li>
295
+ <li><a id="fancybox-manual-c" href="javascript:;">Open gallery</a></li>
296
+ </ul>
297
+
298
+ <p>
299
+ Photo Credit: Instagrammer @whitjohns
300
+ </p>
301
+ </body>
302
+ </html>
assets/fancyBox/lib/jquery-1.7.2.min.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ /*! jQuery v1.7.2 jquery.com | jquery.org/license */
2
+ (function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cu(a){if(!cj[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){ck||(ck=c.createElement("iframe"),ck.frameBorder=ck.width=ck.height=0),b.appendChild(ck);if(!cl||!ck.createElement)cl=(ck.contentWindow||ck.contentDocument).document,cl.write((f.support.boxModel?"<!doctype html>":"")+"<html><body>"),cl.close();d=cl.createElement(a),cl.body.appendChild(d),e=f.css(d,"display"),b.removeChild(ck)}cj[a]=e}return cj[a]}function ct(a,b){var c={};f.each(cp.concat.apply([],cp.slice(0,b)),function(){c[this]=a});return c}function cs(){cq=b}function cr(){setTimeout(cs,0);return cq=f.now()}function ci(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ch(){try{return new a.XMLHttpRequest}catch(b){}}function cb(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function ca(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function b_(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bD.test(a)?d(a,e):b_(a+"["+(typeof e=="object"?b:"")+"]",e,c,d)});else if(!c&&f.type(b)==="object")for(var e in b)b_(a+"["+e+"]",b[e],c,d);else d(a,b)}function b$(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function bZ(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bS,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=bZ(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=bZ(a,c,d,e,"*",g));return l}function bY(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bO),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bB(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?1:0,g=4;if(d>0){if(c!=="border")for(;e<g;e+=2)c||(d-=parseFloat(f.css(a,"padding"+bx[e]))||0),c==="margin"?d+=parseFloat(f.css(a,c+bx[e]))||0:d-=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0;return d+"px"}d=by(a,b);if(d<0||d==null)d=a.style[b];if(bt.test(d))return d;d=parseFloat(d)||0;if(c)for(;e<g;e+=2)d+=parseFloat(f.css(a,"padding"+bx[e]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+bx[e]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+bx[e]))||0);return d+"px"}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;b.nodeType===1&&(b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase(),c==="object"?b.outerHTML=a.outerHTML:c!=="input"||a.type!=="checkbox"&&a.type!=="radio"?c==="option"?b.selected=a.defaultSelected:c==="input"||c==="textarea"?b.defaultValue=a.defaultValue:c==="script"&&b.text!==a.text&&(b.text=a.text):(a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value)),b.removeAttribute(f.expando),b.removeAttribute("_submit_attached"),b.removeAttribute("_change_attached"))}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c,i[c][d])}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?+d:j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a!=null&&a==a.window},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){if(typeof c!="string"||!c)return null;var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h,i){var j,k=d==null,l=0,m=a.length;if(d&&typeof d=="object"){for(l in d)e.access(a,c,l,d[l],1,h,f);g=1}else if(f!==b){j=i===b&&e.isFunction(f),k&&(j?(j=c,c=function(a,b,c){return j.call(e(a),c)}):(c.call(a,f),c=null));if(c)for(;l<m;l++)c(a[l],d,j?f.call(a[l],l,c(a[l],d)):f,i);g=1}return g?a:k?c.call(a):m?c(a[0],d):h},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m,n=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?n(g):h==="function"&&(!a.unique||!p.has(g))&&c.push(g)},o=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,j=!0,m=k||0,k=0,l=c.length;for(;c&&m<l;m++)if(c[m].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}j=!1,c&&(a.once?e===!0?p.disable():c=[]:d&&d.length&&(e=d.shift(),p.fireWith(e[0],e[1])))},p={add:function(){if(c){var a=c.length;n(arguments),j?l=c.length:e&&e!==!0&&(k=a,o(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){j&&f<=l&&(l--,f<=m&&m--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&p.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(j?a.once||d.push([b,c]):(!a.once||!e)&&o(b,c));return this},fire:function(){p.fireWith(this,arguments);return this},fired:function(){return!!i}};return p};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p=c.createElement("div"),q=c.documentElement;p.setAttribute("className","t"),p.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=p.getElementsByTagName("*"),e=p.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=p.getElementsByTagName("input")[0],b={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:p.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},f.boxModel=b.boxModel=c.compatMode==="CSS1Compat",i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete p.test}catch(r){b.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",function(){b.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),i.setAttribute("name","t"),p.appendChild(i),j=c.createDocumentFragment(),j.appendChild(p.lastChild),b.checkClone=j.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,j.removeChild(i),j.appendChild(p);if(p.attachEvent)for(n in{submit:1,change:1,focusin:1})m="on"+n,o=m in p,o||(p.setAttribute(m,"return;"),o=typeof p[m]=="function"),b[n+"Bubbles"]=o;j.removeChild(p),j=g=h=p=i=null,f(function(){var d,e,g,h,i,j,l,m,n,q,r,s,t,u=c.getElementsByTagName("body")[0];!u||(m=1,t="padding:0;margin:0;border:",r="position:absolute;top:0;left:0;width:1px;height:1px;",s=t+"0;visibility:hidden;",n="style='"+r+t+"5px solid #000;",q="<div "+n+"display:block;'><div style='"+t+"0;display:block;overflow:hidden;'></div></div>"+"<table "+n+"' cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",d=c.createElement("div"),d.style.cssText=s+"width:0;height:0;position:static;top:0;margin-top:"+m+"px",u.insertBefore(d,u.firstChild),p=c.createElement("div"),d.appendChild(p),p.innerHTML="<table><tr><td style='"+t+"0;display:none'></td><td>t</td></tr></table>",k=p.getElementsByTagName("td"),o=k[0].offsetHeight===0,k[0].style.display="",k[1].style.display="none",b.reliableHiddenOffsets=o&&k[0].offsetHeight===0,a.getComputedStyle&&(p.innerHTML="",l=c.createElement("div"),l.style.width="0",l.style.marginRight="0",p.style.width="2px",p.appendChild(l),b.reliableMarginRight=(parseInt((a.getComputedStyle(l,null)||{marginRight:0}).marginRight,10)||0)===0),typeof p.style.zoom!="undefined"&&(p.innerHTML="",p.style.width=p.style.padding="1px",p.style.border=0,p.style.overflow="hidden",p.style.display="inline",p.style.zoom=1,b.inlineBlockNeedsLayout=p.offsetWidth===3,p.style.display="block",p.style.overflow="visible",p.innerHTML="<div style='width:5px;'></div>",b.shrinkWrapBlocks=p.offsetWidth!==3),p.style.cssText=r+s,p.innerHTML=q,e=p.firstChild,g=e.firstChild,i=e.nextSibling.firstChild.firstChild,j={doesNotAddBorder:g.offsetTop!==5,doesAddBorderForTableAndCells:i.offsetTop===5},g.style.position="fixed",g.style.top="20px",j.fixedPosition=g.offsetTop===20||g.offsetTop===15,g.style.position=g.style.top="",e.style.overflow="hidden",e.style.position="relative",j.subtractsBorderForOverflowNotVisible=g.offsetTop===-5,j.doesNotIncludeMarginInBodyOffset=u.offsetTop!==m,a.getComputedStyle&&(p.style.marginTop="1%",b.pixelMargin=(a.getComputedStyle(p,null)||{marginTop:0}).marginTop!=="1%"),typeof d.style.zoom!="undefined"&&(d.style.zoom=1),u.removeChild(d),l=p=d=null,f.extend(b,j))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h,i,j=this[0],k=0,m=null;if(a===b){if(this.length){m=f.data(j);if(j.nodeType===1&&!f._data(j,"parsedAttrs")){g=j.attributes;for(i=g.length;k<i;k++)h=g[k].name,h.indexOf("data-")===0&&(h=f.camelCase(h.substring(5)),l(j,h,m[h]));f._data(j,"parsedAttrs",!0)}}return m}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split(".",2),d[1]=d[1]?"."+d[1]:"",e=d[1]+"!";return f.access(this,function(c){if(c===b){m=this.triggerHandler("getData"+e,[d[0]]),m===b&&j&&(m=f.data(j,a),m=l(j,a,m));return m===b&&d[1]?this.data(d[0]):m}d[1]=c,this.each(function(){var b=f(this);b.triggerHandler("setData"+e,d),f.data(this,a,c),b.triggerHandler("changeData"+e,d)})},null,c,arguments.length>1,null,!1)},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){var d=2;typeof a!="string"&&(c=a,a="fx",d--);if(arguments.length<d)return f.queue(this[0],a);return c===b?this:this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise(c)}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,f.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,f.prop,a,b,arguments.length>1)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.type]||f.valHooks[this.nodeName.toLowerCase()];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.type]||f.valHooks[g.nodeName.toLowerCase()];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h,i=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;i<g;i++)e=d[i],e&&(c=f.propFix[e]||e,h=u.test(e),h||f.attr(a,e,""),a.removeAttribute(v?e:c),h&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0,coords:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/(?:^|\s)hover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(
3
+ a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler,g=p.selector),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:g&&G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=f.event.special[c.type]||{},j=[],k,l,m,n,o,p,q,r,s,t,u;g[0]=c,c.delegateTarget=this;if(!i.preDispatch||i.preDispatch.call(this,c)!==!1){if(e&&(!c.button||c.type!=="click")){n=f(this),n.context=this.ownerDocument||this;for(m=c.target;m!=this;m=m.parentNode||this)if(m.disabled!==!0){p={},r=[],n[0]=m;for(k=0;k<e;k++)s=d[k],t=s.selector,p[t]===b&&(p[t]=s.quick?H(m,s.quick):n.is(t)),p[t]&&r.push(s);r.length&&j.push({elem:m,matches:r})}}d.length>e&&j.push({elem:this,matches:d.slice(e)});for(k=0;k<j.length&&!c.isPropagationStopped();k++){q=j[k],c.currentTarget=q.elem;for(l=0;l<q.matches.length&&!c.isImmediatePropagationStopped();l++){s=q.matches[l];if(h||!c.namespace&&!s.namespace||c.namespace_re&&c.namespace_re.test(s.namespace))c.data=s.data,c.handleObj=s,o=((f.event.special[s.origType]||{}).handle||s.handler).apply(q.elem,g),o!==b&&(c.result=o,o===!1&&(c.preventDefault(),c.stopPropagation()))}}i.postDispatch&&i.postDispatch.call(this,c);return c.result}},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){a._submit_bubble=!0}),d._submit_attached=!0)})},postDispatch:function(a){a._submit_bubble&&(delete a._submit_bubble,this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0))},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=d||c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9||d===11){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));o.match.globalPOS=p;var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.globalPOS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")[\\s/>]","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){return f.access(this,function(a){return a===b?f.text(this):this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a))},null,a,arguments.length)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f
4
+ .clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){return f.access(this,function(a){var c=this[0]||{},d=0,e=this.length;if(a===b)return c.nodeType===1?c.innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(;d<e;d++)c=this[d]||{},c.nodeType===1&&(f.cleanData(c.getElementsByTagName("*")),c.innerHTML=a);c=0}catch(g){}}c&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,function(a,b){b.src?f.ajax({type:"GET",global:!1,url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)})}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||f.isXMLDoc(a)||!bc.test("<"+a.nodeName+">")?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g,h,i,j=[];b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);for(var k=0,l;(l=a[k])!=null;k++){typeof l=="number"&&(l+="");if(!l)continue;if(typeof l=="string")if(!_.test(l))l=b.createTextNode(l);else{l=l.replace(Y,"<$1></$2>");var m=(Z.exec(l)||["",""])[1].toLowerCase(),n=bg[m]||bg._default,o=n[0],p=b.createElement("div"),q=bh.childNodes,r;b===c?bh.appendChild(p):U(b).appendChild(p),p.innerHTML=n[1]+l+n[2];while(o--)p=p.lastChild;if(!f.support.tbody){var s=$.test(l),t=m==="table"&&!s?p.firstChild&&p.firstChild.childNodes:n[1]==="<table>"&&!s?p.childNodes:[];for(i=t.length-1;i>=0;--i)f.nodeName(t[i],"tbody")&&!t[i].childNodes.length&&t[i].parentNode.removeChild(t[i])}!f.support.leadingWhitespace&&X.test(l)&&p.insertBefore(b.createTextNode(X.exec(l)[0]),p.firstChild),l=p.childNodes,p&&(p.parentNode.removeChild(p),q.length>0&&(r=q[q.length-1],r&&r.parentNode&&r.parentNode.removeChild(r)))}var u;if(!f.support.appendChecked)if(l[0]&&typeof (u=l.length)=="number")for(i=0;i<u;i++)bn(l[i]);else bn(l);l.nodeType?j.push(l):j=f.merge(j,l)}if(d){g=function(a){return!a.type||be.test(a.type)};for(k=0;j[k];k++){h=j[k];if(e&&f.nodeName(h,"script")&&(!h.type||be.test(h.type)))e.push(h.parentNode?h.parentNode.removeChild(h):h);else{if(h.nodeType===1){var v=f.grep(h.getElementsByTagName("script"),g);j.splice.apply(j,[k+1,0].concat(v))}d.appendChild(h)}}}return j},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bp=/alpha\([^)]*\)/i,bq=/opacity=([^)]*)/,br=/([A-Z]|^ms)/g,bs=/^[\-+]?(?:\d*\.)?\d+$/i,bt=/^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,bu=/^([\-+])=([\-+.\de]+)/,bv=/^margin/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Top","Right","Bottom","Left"],by,bz,bA;f.fn.css=function(a,c){return f.access(this,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)},a,c,arguments.length>1)},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=by(a,"opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bu.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(by)return by(a,c)},swap:function(a,b,c){var d={},e,f;for(f in b)d[f]=a.style[f],a.style[f]=b[f];e=c.call(a);for(f in b)a.style[f]=d[f];return e}}),f.curCSS=f.css,c.defaultView&&c.defaultView.getComputedStyle&&(bz=function(a,b){var c,d,e,g,h=a.style;b=b.replace(br,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b))),!f.support.pixelMargin&&e&&bv.test(b)&&bt.test(c)&&(g=h.width,h.width=c,c=e.width,h.width=g);return c}),c.documentElement.currentStyle&&(bA=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f==null&&g&&(e=g[b])&&(f=e),bt.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),by=bz||bA,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){if(c)return a.offsetWidth!==0?bB(a,b,d):f.swap(a,bw,function(){return bB(a,b,d)})},set:function(a,b){return bs.test(b)?b+"px":b}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bq.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bp,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bp.test(g)?g.replace(bp,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){return f.swap(a,{display:"inline-block"},function(){return b?by(a,"margin-right"):a.style.marginRight})}})}),f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)}),f.each({margin:"",padding:"",border:"Width"},function(a,b){f.cssHooks[a+b]={expand:function(c){var d,e=typeof c=="string"?c.split(" "):[c],f={};for(d=0;d<4;d++)f[a+bx[d]+b]=e[d]||e[d-2]||e[0];return f}}});var bC=/%20/g,bD=/\[\]$/,bE=/\r?\n/g,bF=/#.*$/,bG=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bH=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bI=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bJ=/^(?:GET|HEAD)$/,bK=/^\/\//,bL=/\?/,bM=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bN=/^(?:select|textarea)/i,bO=/\s+/,bP=/([?&])_=[^&]*/,bQ=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bR=f.fn.load,bS={},bT={},bU,bV,bW=["*/"]+["*"];try{bU=e.href}catch(bX){bU=c.createElement("a"),bU.href="",bU=bU.href}bV=bQ.exec(bU.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bR)return bR.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bM,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bN.test(this.nodeName)||bH.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bE,"\r\n")}}):{name:b.name,value:c.replace(bE,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b$(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b$(a,b);return a},ajaxSettings:{url:bU,isLocal:bI.test(bV[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bW},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bY(bS),ajaxTransport:bY(bT),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?ca(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cb(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bG.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bF,"").replace(bK,bV[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bO),d.crossDomain==null&&(r=bQ.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bV[1]&&r[2]==bV[2]&&(r[3]||(r[1]==="http:"?80:443))==(bV[3]||(bV[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),bZ(bS,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bJ.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bL.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bP,"$1_="+x);d.url=y+(y===d.url?(bL.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bW+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=bZ(bT,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)b_(g,a[g],c,e);return d.join("&").replace(bC,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cc=f.now(),cd=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cc++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=typeof b.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(b.contentType);if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cd.test(b.url)||e&&cd.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cd,l),b.url===j&&(e&&(k=k.replace(cd,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ce=a.ActiveXObject?function(){for(var a in cg)cg[a](0,1)}:!1,cf=0,cg;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ch()||ci()}:ch,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ce&&delete cg[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n);try{m.text=h.responseText}catch(a){}try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cf,ce&&(cg||(cg={},f(a).unload(ce)),cg[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cj={},ck,cl,cm=/^(?:toggle|show|hide)$/,cn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,co,cp=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cq;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(ct("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),(e===""&&f.css(d,"display")==="none"||!f.contains(d.ownerDocument.documentElement,d))&&f._data(d,"olddisplay",cu(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(ct("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(ct("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o,p,q;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]);if((k=f.cssHooks[g])&&"expand"in k){l=k.expand(a[g]),delete a[g];for(i in l)i in a||(a[i]=l[i])}}for(g in a){h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cu(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cm.test(h)?(q=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),q?(f._data(this,"toggle"+i,q==="show"?"hide":"show"),j[q]()):j[h]()):(m=cn.exec(h),n=j.cur(),m?(o=parseFloat(m[2]),p=m[3]||(f.cssNumber[i]?"":"px"),p!=="px"&&(f.style(this,i,(o||1)+p),n=(o||1)/j.cur()*n,f.style(this,i,n+p)),m[1]&&(o=(m[1]==="-="?-1:1)*o+n),j.custom(n,o,p)):j.custom(n,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:ct("show",1),slideUp:ct("hide",1),slideToggle:ct("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a){return a},swing:function(a){return-Math.cos(a*Math.PI)/2+.5}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cq||cr(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){f._data(e.elem,"fxshow"+e.prop)===b&&(e.options.hide?f._data(e.elem,"fxshow"+e.prop,e.start):e.options.show&&f._data(e.elem,"fxshow"+e.prop,e.end))},h()&&f.timers.push(h)&&!co&&(co=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cq||cr(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(co),co=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(cp.concat.apply([],cp),function(a,b){b.indexOf("margin")&&(f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)})}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cv,cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?cv=function(a,b,c,d){try{d=a.getBoundingClientRect()}catch(e){}if(!d||!f.contains(c,a))return d?{top:d.top,left:d.left}:{top:0,left:0};var g=b.body,h=cy(b),i=c.clientTop||g.clientTop||0,j=c.clientLeft||g.clientLeft||0,k=h.pageYOffset||f.support.boxModel&&c.scrollTop||g.scrollTop,l=h.pageXOffset||f.support.boxModel&&c.scrollLeft||g.scrollLeft,m=d.top+k-i,n=d.left+l-j;return{top:m,left:n}}:cv=function(a,b,c){var d,e=a.offsetParent,g=a,h=b.body,i=b.defaultView,j=i?i.getComputedStyle(a,null):a.currentStyle,k=a.offsetTop,l=a.offsetLeft;while((a=a.parentNode)&&a!==h&&a!==c){if(f.support.fixedPosition&&j.position==="fixed")break;d=i?i.getComputedStyle(a,null):a.currentStyle,k-=a.scrollTop,l-=a.scrollLeft,a===e&&(k+=a.offsetTop,l+=a.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(a.nodeName))&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),g=e,e=a.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"&&(k+=parseFloat(d.borderTopWidth)||0,l+=parseFloat(d.borderLeftWidth)||0),j=d}if(j.position==="relative"||j.position==="static")k+=h.offsetTop,l+=h.offsetLeft;f.support.fixedPosition&&j.position==="fixed"&&(k+=Math.max(c.scrollTop,h.scrollTop),l+=Math.max(c.scrollLeft,h.scrollLeft));return{top:k,left:l}},f.fn.offset=function(a){if(arguments.length)return a===b?this:this.each(function(b){f.offset.setOffset(this,a,b)});var c=this[0],d=c&&c.ownerDocument;if(!d)return null;if(c===d.body)return f.offset.bodyOffset(c);return cv(c,d,d.documentElement)},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,c){var d=/Y/.test(c);f.fn[a]=function(e){return f.access(this,function(a,e,g){var h=cy(a);if(g===b)return h?c in h?h[c]:f.support.boxModel&&h.document.documentElement[e]||h.document.body[e]:a[e];h?h.scrollTo(d?f(h).scrollLeft():g,d?g:f(h).scrollTop()):a[e]=g},a,e,arguments.length,null)}}),f.each({Height:"height",Width:"width"},function(a,c){var d="client"+a,e="scroll"+a,g="offset"+a;f.fn["inner"+a]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,c,"padding")):this[c]():null},f.fn["outer"+a]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,c,a?"margin":"border")):this[c]():null},f.fn[c]=function(a){return f.access(this,function(a,c,h){var i,j,k,l;if(f.isWindow(a)){i=a.document,j=i.documentElement[d];return f.support.boxModel&&j||i.body&&i.body[d]||j}if(a.nodeType===9){i=a.documentElement;if(i[d]>=i[e])return i[d];return Math.max(a.body[e],i[e],a.body[g],i[g])}if(h===b){k=f.css(a,c),l=parseFloat(k);return f.isNumeric(l)?l:k}f(a).css(c,h)},c,a,arguments.length,null)}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
assets/fancyBox/lib/jquery.mousewheel-3.0.6.pack.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! Copyright (c) 2011 Brandon Aaron (http://brandonaaron.net)
2
+ * Licensed under the MIT License (LICENSE.txt).
3
+ *
4
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
5
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
6
+ * Thanks to: Seamus Leahy for adding deltaX and deltaY
7
+ *
8
+ * Version: 3.0.6
9
+ *
10
+ * Requires: 1.2.2+
11
+ */
12
+ (function(d){function e(a){var b=a||window.event,c=[].slice.call(arguments,1),f=0,e=0,g=0,a=d.event.fix(b);a.type="mousewheel";b.wheelDelta&&(f=b.wheelDelta/120);b.detail&&(f=-b.detail/3);g=f;b.axis!==void 0&&b.axis===b.HORIZONTAL_AXIS&&(g=0,e=-1*f);b.wheelDeltaY!==void 0&&(g=b.wheelDeltaY/120);b.wheelDeltaX!==void 0&&(e=-1*b.wheelDeltaX/120);c.unshift(a,f,e,g);return(d.event.dispatch||d.event.handle).apply(this,c)}var c=["DOMMouseScroll","mousewheel"];if(d.event.fixHooks)for(var h=c.length;h;)d.event.fixHooks[c[--h]]=
13
+ d.event.mouseHooks;d.event.special.mousewheel={setup:function(){if(this.addEventListener)for(var a=c.length;a;)this.addEventListener(c[--a],e,false);else this.onmousewheel=e},teardown:function(){if(this.removeEventListener)for(var a=c.length;a;)this.removeEventListener(c[--a],e,false);else this.onmousewheel=null}};d.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})})(jQuery);
assets/fancyBox/source/blank.gif ADDED
Binary file
assets/fancyBox/source/fancybox_loading.gif ADDED
Binary file
assets/fancyBox/source/fancybox_sprite.png ADDED
Binary file
assets/fancyBox/source/helpers/fancybox_buttons.png ADDED
Binary file
assets/fancyBox/source/helpers/jquery.fancybox-buttons.css ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #fancybox-buttons {
2
+ position: fixed;
3
+ left: 0;
4
+ width: 100%;
5
+ z-index: 1005;
6
+ }
7
+
8
+ #fancybox-buttons.top {
9
+ top: 10px;
10
+ }
11
+
12
+ #fancybox-buttons.bottom {
13
+ bottom: 10px;
14
+ }
15
+
16
+ #fancybox-buttons ul {
17
+ display: block;
18
+ width: 170px;
19
+ height: 30px;
20
+ margin: 0 auto;
21
+ padding: 0;
22
+ list-style: none;
23
+ background: #111;
24
+ -webkit-box-shadow: 0 1px 3px #000,0 0 0 1px rgba(0,0,0,.7),inset 0 0 0 1px rgba(255,255,255,.05);
25
+ -moz-box-shadow: 0 1px 3px #000,0 0 0 1px rgba(0,0,0,.7),inset 0 0 0 1px rgba(255,255,255,.05);
26
+ background: #111 -webkit-gradient(linear,0% 0%,0% 100%,from(rgba(255,255,255,.2)),color-stop(.5,rgba(255,255,255,.15)),color-stop(.5,rgba(255,255,255,.1)),to(rgba(255,255,255,.15)));
27
+ background: #111 -moz-linear-gradient(top,rgba(255,255,255,.2) 0%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.1) 50%,rgba(255,255,255,.15) 100%);
28
+ border-radius: 3px;
29
+ }
30
+
31
+ #fancybox-buttons ul li {
32
+ float: left;
33
+ margin: 0;
34
+ padding: 0;
35
+ }
36
+
37
+ #fancybox-buttons a {
38
+ display: block;
39
+ width: 30px;
40
+ height: 30px;
41
+ text-indent: -9999px;
42
+ background-image: url('fancybox_buttons.png');
43
+ background-repeat: no-repeat;
44
+ outline: none;
45
+ }
46
+
47
+ #fancybox-buttons a.btnPrev {
48
+ width: 32px;
49
+ background-position: 6px 0;
50
+ }
51
+
52
+ #fancybox-buttons a.btnNext {
53
+ background-position: -33px 0;
54
+ border-right: 1px solid #3e3e3e;
55
+ }
56
+
57
+ #fancybox-buttons a.btnPlay {
58
+ background-position: 0 -30px;
59
+ }
60
+
61
+ #fancybox-buttons a.btnPlayOn {
62
+ background-position: -30px -30px;
63
+ }
64
+
65
+ #fancybox-buttons a.btnToggle {
66
+ background-position: 3px -60px;
67
+ border-left: 1px solid #111;
68
+ border-right: 1px solid #3e3e3e;
69
+ width: 35px
70
+ }
71
+
72
+ #fancybox-buttons a.btnToggleOn {
73
+ background-position: -27px -60px;
74
+ }
75
+
76
+ #fancybox-buttons a.btnClose {
77
+ border-left: 1px solid #111;
78
+ width: 38px;
79
+ background-position: -57px 0px;
80
+ }
81
+
82
+ #fancybox-buttons a.btnDisabled {
83
+ opacity : 0.5;
84
+ cursor: default;
85
+ }
assets/fancyBox/source/helpers/jquery.fancybox-buttons.js ADDED
@@ -0,0 +1,115 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Buttons helper for fancyBox
3
+ * version: 1.0.2
4
+ * @requires fancyBox v2.0 or later
5
+ *
6
+ * Usage:
7
+ * $(".fancybox").fancybox({
8
+ * buttons: {
9
+ * position : 'top'
10
+ * }
11
+ * });
12
+ *
13
+ * Options:
14
+ * tpl - HTML template
15
+ * position - 'top' or 'bottom'
16
+ *
17
+ */
18
+ (function ($) {
19
+ //Shortcut for fancyBox object
20
+ var F = $.fancybox;
21
+
22
+ //Add helper object
23
+ F.helpers.buttons = {
24
+ tpl: '<div id="fancybox-buttons"><ul><li><a class="btnPrev" title="Previous" href="javascript:;"></a></li><li><a class="btnPlay" title="Start slideshow" href="javascript:;"></a></li><li><a class="btnNext" title="Next" href="javascript:;"></a></li><li><a class="btnToggle" title="Toggle size" href="javascript:;"></a></li><li><a class="btnClose" title="Close" href="javascript:jQuery.fancybox.close();"></a></li></ul></div>',
25
+ list: null,
26
+ buttons: {},
27
+
28
+ update: function () {
29
+ var toggle = this.buttons.toggle.removeClass('btnDisabled btnToggleOn');
30
+
31
+ //Size toggle button
32
+ if (F.current.canShrink) {
33
+ toggle.addClass('btnToggleOn');
34
+
35
+ } else if (!F.current.canExpand) {
36
+ toggle.addClass('btnDisabled');
37
+ }
38
+ },
39
+
40
+ beforeLoad: function (opts) {
41
+ //Remove self if gallery do not have at least two items
42
+ if (F.group.length < 2) {
43
+ F.coming.helpers.buttons = false;
44
+ F.coming.closeBtn = true;
45
+
46
+ return;
47
+ }
48
+
49
+ //Increase top margin to give space for buttons
50
+ F.coming.margin[ opts.position === 'bottom' ? 2 : 0 ] += 30;
51
+ },
52
+
53
+ onPlayStart: function () {
54
+ if (this.list) {
55
+ this.buttons.play.attr('title', 'Pause slideshow').addClass('btnPlayOn');
56
+ }
57
+ },
58
+
59
+ onPlayEnd: function () {
60
+ if (this.list) {
61
+ this.buttons.play.attr('title', 'Start slideshow').removeClass('btnPlayOn');
62
+ }
63
+ },
64
+
65
+ afterShow: function (opts) {
66
+ var buttons;
67
+
68
+ if (!this.list) {
69
+ this.list = $(opts.tpl || this.tpl).addClass(opts.position || 'top').appendTo('body');
70
+
71
+ this.buttons = {
72
+ prev : this.list.find('.btnPrev').click( F.prev ),
73
+ next : this.list.find('.btnNext').click( F.next ),
74
+ play : this.list.find('.btnPlay').click( F.play ),
75
+ toggle : this.list.find('.btnToggle').click( F.toggle )
76
+ }
77
+ }
78
+
79
+ buttons = this.buttons;
80
+
81
+ //Prev
82
+ if (F.current.index > 0 || F.current.loop) {
83
+ buttons.prev.removeClass('btnDisabled');
84
+ } else {
85
+ buttons.prev.addClass('btnDisabled');
86
+ }
87
+
88
+ //Next / Play
89
+ if (F.current.loop || F.current.index < F.group.length - 1) {
90
+ buttons.next.removeClass('btnDisabled');
91
+ buttons.play.removeClass('btnDisabled');
92
+
93
+ } else {
94
+ buttons.next.addClass('btnDisabled');
95
+ buttons.play.addClass('btnDisabled');
96
+ }
97
+
98
+ this.update();
99
+ },
100
+
101
+ onUpdate: function () {
102
+ this.update();
103
+ },
104
+
105
+ beforeClose: function () {
106
+ if (this.list) {
107
+ this.list.remove();
108
+ }
109
+
110
+ this.list = null;
111
+ this.buttons = {};
112
+ }
113
+ };
114
+
115
+ }(jQuery));
assets/fancyBox/source/helpers/jquery.fancybox-media.js ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Media helper for fancyBox
3
+ * version: 1.0.0
4
+ * @requires fancyBox v2.0 or later
5
+ *
6
+ * Usage:
7
+ * $(".fancybox").fancybox({
8
+ * media: {}
9
+ * });
10
+ *
11
+ * Supports:
12
+ * Youtube
13
+ * http://www.youtube.com/watch?v=opj24KnzrWo
14
+ * http://youtu.be/opj24KnzrWo
15
+ * Vimeo
16
+ * http://vimeo.com/25634903
17
+ * Metacafe
18
+ * http://www.metacafe.com/watch/7635964/dr_seuss_the_lorax_movie_trailer/
19
+ * http://www.metacafe.com/watch/7635964/
20
+ * Dailymotion
21
+ * http://www.dailymotion.com/video/xoytqh_dr-seuss-the-lorax-premiere_people
22
+ * Twitvid
23
+ * http://twitvid.com/QY7MD
24
+ * Twitpic
25
+ * http://twitpic.com/7p93st
26
+ * Instagram
27
+ * http://instagr.am/p/IejkuUGxQn/
28
+ * http://instagram.com/p/IejkuUGxQn/
29
+ * Google maps
30
+ * http://maps.google.com/maps?q=Eiffel+Tower,+Avenue+Gustave+Eiffel,+Paris,+France&t=h&z=17
31
+ * http://maps.google.com/?ll=48.857995,2.294297&spn=0.007666,0.021136&t=m&z=16
32
+ * http://maps.google.com/?ll=48.859463,2.292626&spn=0.000965,0.002642&t=m&z=19&layer=c&cbll=48.859524,2.292532&panoid=YJ0lq28OOy3VT2IqIuVY0g&cbp=12,151.58,,0,-15.56
33
+ */
34
+ (function ($) {
35
+ //Shortcut for fancyBox object
36
+ var F = $.fancybox;
37
+
38
+ //Add helper object
39
+ F.helpers.media = {
40
+ beforeLoad : function(opts, obj) {
41
+ var href = obj.href || '',
42
+ type = false,
43
+ rez;
44
+
45
+ if ((rez = href.match(/(youtube\.com|youtu\.be)\/(v\/|u\/|embed\/|watch\?v=)?([^#\&\?]*).*/i))) {
46
+ href = '//www.youtube.com/embed/' + rez[3] + '?autoplay=1&fs=1&rel=0&modestbranding=1&enablejsapi=1';
47
+ type = 'iframe';
48
+
49
+ } else if ((rez = href.match(/vimeo.com\/(\d+)\/?(.*)/))) {
50
+ href = '//player.vimeo.com/video/' + rez[1] + '?hd=1&autoplay=1&show_title=1&show_byline=1&show_portrait=0&color=&fullscreen=1';
51
+ type = 'iframe';
52
+
53
+ } else if ((rez = href.match(/metacafe.com\/watch\/(\d+)\/?(.*)/))) {
54
+ href = '//www.metacafe.com/fplayer/' + rez[1] + '/.swf?playerVars=autoPlay=yes';
55
+ type = 'swf';
56
+
57
+ } else if ((rez = href.match(/dailymotion.com\/video\/(.*)\/?(.*)/))) {
58
+ href = '//www.dailymotion.com/swf/video/' + rez[1] + '?additionalInfos=0&autoStart=1';
59
+ type = 'swf';
60
+
61
+ } else if ((rez = href.match(/twitvid\.com\/([a-zA-Z0-9_\-\?\=]+)/i))) {
62
+ href = '//www.twitvid.com/embed.php?autoplay=0&guid=' + rez[1];
63
+ type = 'iframe';
64
+
65
+ } else if ((rez = href.match(/twitpic\.com\/(?!(?:place|photos|events)\/)([a-zA-Z0-9\?\=\-]+)/i))) {
66
+ href = '//twitpic.com/show/full/' + rez[1];
67
+ type = 'image';
68
+
69
+ } else if ((rez = href.match(/(instagr\.am|instagram\.com)\/p\/([a-zA-Z0-9_\-]+)\/?/i))) {
70
+ href = '//' + rez[1] + '/p/' + rez[2] + '/media/?size=l';
71
+ type = 'image';
72
+
73
+ } else if ((rez = href.match(/maps\.google\.com\/(\?ll=|maps\/?\?q=)(.*)/i))) {
74
+ href = '//maps.google.com/' + rez[1] + '' + rez[2] + '&output=' + (rez[2].indexOf('layer=c') ? 'svembed' : 'embed');
75
+ type = 'iframe';
76
+ }
77
+
78
+ if (type) {
79
+ obj.href = href;
80
+ obj.type = type;
81
+ obj.autoSize = false;
82
+ }
83
+ }
84
+ }
85
+
86
+ }(jQuery));
assets/fancyBox/source/helpers/jquery.fancybox-thumbs.css ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #fancybox-thumbs {
2
+ position: fixed;
3
+ left: 0px;
4
+ width: 100%;
5
+ overflow: hidden;
6
+ z-index: 1005;
7
+ }
8
+
9
+ #fancybox-thumbs.bottom {
10
+ bottom: 2px;
11
+ }
12
+
13
+ #fancybox-thumbs.top {
14
+ top: 2px;
15
+ }
16
+
17
+ #fancybox-thumbs ul {
18
+ position: relative;
19
+ list-style: none;
20
+ margin: 0;
21
+ padding: 0;
22
+ }
23
+
24
+ #fancybox-thumbs ul li {
25
+ float: left;
26
+ padding: 1px;
27
+ opacity: 0.5;
28
+ }
29
+
30
+ #fancybox-thumbs ul li.active {
31
+ opacity: 0.75;
32
+ padding: 0;
33
+ border: 1px solid #fff;
34
+ }
35
+
36
+ #fancybox-thumbs ul li:hover {
37
+ opacity: 1;
38
+ }
39
+
40
+ #fancybox-thumbs ul li a {
41
+ display: block;
42
+ position: relative;
43
+ overflow: hidden;
44
+ border: 1px solid #222;
45
+ background: #111;
46
+ outline: none;
47
+ }
48
+
49
+ #fancybox-thumbs ul li img {
50
+ display: block;
51
+ position: relative;
52
+ border: 0;
53
+ padding: 0;
54
+ }
assets/fancyBox/source/helpers/jquery.fancybox-thumbs.js ADDED
@@ -0,0 +1,157 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * Thumbnail helper for fancyBox
3
+ * version: 1.0.4
4
+ * @requires fancyBox v2.0 or later
5
+ *
6
+ * Usage:
7
+ * $(".fancybox").fancybox({
8
+ * thumbs: {
9
+ * width : 50,
10
+ * height : 50
11
+ * }
12
+ * });
13
+ *
14
+ * Options:
15
+ * width - thumbnail width
16
+ * height - thumbnail height
17
+ * source - function to obtain the URL of the thumbnail image
18
+ * position - 'top' or 'bottom'
19
+ *
20
+ */
21
+ (function ($) {
22
+ //Shortcut for fancyBox object
23
+ var F = $.fancybox;
24
+
25
+ //Add helper object
26
+ F.helpers.thumbs = {
27
+ wrap: null,
28
+ list: null,
29
+ width: 0,
30
+
31
+ //Default function to obtain the URL of the thumbnail image
32
+ source: function (el) {
33
+ var img;
34
+
35
+ if ($.type(el) === 'string') {
36
+ return el;
37
+ }
38
+
39
+ img = $(el).find('img');
40
+
41
+ return img.length ? img.attr('src') : el.href;
42
+ },
43
+
44
+ init: function (opts) {
45
+ var that = this,
46
+ list,
47
+ thumbWidth = opts.width || 50,
48
+ thumbHeight = opts.height || 50,
49
+ thumbSource = opts.source || this.source;
50
+
51
+ //Build list structure
52
+ list = '';
53
+
54
+ for (var n = 0; n < F.group.length; n++) {
55
+ list += '<li><a style="width:' + thumbWidth + 'px;height:' + thumbHeight + 'px;" href="javascript:jQuery.fancybox.jumpto(' + n + ');"></a></li>';
56
+ }
57
+
58
+ this.wrap = $('<div id="fancybox-thumbs"></div>').addClass(opts.position || 'bottom').appendTo('body');
59
+ this.list = $('<ul>' + list + '</ul>').appendTo(this.wrap);
60
+
61
+ //Load each thumbnail
62
+ $.each(F.group, function (i) {
63
+ $("<img />").load(function () {
64
+ var width = this.width,
65
+ height = this.height,
66
+ widthRatio, heightRatio, parent;
67
+
68
+ if (!that.list || !width || !height) {
69
+ return;
70
+ }
71
+
72
+ //Calculate thumbnail width/height and center it
73
+ widthRatio = width / thumbWidth;
74
+ heightRatio = height / thumbHeight;
75
+ parent = that.list.children().eq(i).find('a');
76
+
77
+ if (widthRatio >= 1 && heightRatio >= 1) {
78
+ if (widthRatio > heightRatio) {
79
+ width = Math.floor(width / heightRatio);
80
+ height = thumbHeight;
81
+
82
+ } else {
83
+ width = thumbWidth;
84
+ height = Math.floor(height / widthRatio);
85
+ }
86
+ }
87
+
88
+ $(this).css({
89
+ width: width,
90
+ height: height,
91
+ top: Math.floor(thumbHeight / 2 - height / 2),
92
+ left: Math.floor(thumbWidth / 2 - width / 2)
93
+ });
94
+
95
+ parent.width(thumbWidth).height(thumbHeight);
96
+
97
+ $(this).hide().appendTo(parent).fadeIn(300);
98
+
99
+ }).attr('src', thumbSource( F.group[ i ] ));
100
+ });
101
+
102
+ //Set initial width
103
+ this.width = this.list.children().eq(0).outerWidth(true);
104
+
105
+ this.list.width(this.width * (F.group.length + 1)).css('left', Math.floor($(window).width() * 0.5 - (F.current.index * this.width + this.width * 0.5)));
106
+ },
107
+
108
+ //Center list
109
+ update: function (opts) {
110
+ if (this.list) {
111
+ this.list.stop(true).animate({
112
+ 'left': Math.floor($(window).width() * 0.5 - (F.current.index * this.width + this.width * 0.5))
113
+ }, 150);
114
+ }
115
+ },
116
+
117
+ beforeLoad: function (opts) {
118
+ //Remove self if gallery do not have at least two items
119
+ if (F.group.length < 2) {
120
+ F.coming.helpers.thumbs = false;
121
+
122
+ return;
123
+ }
124
+
125
+ //Increase bottom margin to give space for thumbs
126
+ F.coming.margin[ opts.position === 'top' ? 0 : 2 ] = opts.height + 30;
127
+ },
128
+
129
+ afterShow: function (opts) {
130
+ //Check if exists and create or update list
131
+ if (this.list) {
132
+ this.update(opts);
133
+
134
+ } else {
135
+ this.init(opts);
136
+ }
137
+
138
+ //Set active element
139
+ this.list.children().removeClass('active').eq(F.current.index).addClass('active');
140
+ },
141
+
142
+ onUpdate: function () {
143
+ this.update();
144
+ },
145
+
146
+ beforeClose: function () {
147
+ if (this.wrap) {
148
+ this.wrap.remove();
149
+ }
150
+
151
+ this.wrap = null;
152
+ this.list = null;
153
+ this.width = 0;
154
+ }
155
+ }
156
+
157
+ }(jQuery));
assets/fancyBox/source/jquery.fancybox.css ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! fancyBox v2.0.5 fancyapps.com | fancyapps.com/fancybox/#license */
2
+ .fancybox-tmp iframe, .fancybox-tmp object {
3
+ vertical-align: top;
4
+ padding: 0;
5
+ margin: 0;
6
+ }
7
+
8
+ .fancybox-wrap {
9
+ position: absolute;
10
+ top: 0;
11
+ left: 0;
12
+ z-index: 1002;
13
+ }
14
+
15
+ .fancybox-outer {
16
+ position: relative;
17
+ padding: 0;
18
+ margin: 0;
19
+ background: #f9f9f9;
20
+ color: #444;
21
+ text-shadow: none;
22
+ -webkit-border-radius: 4px;
23
+ -moz-border-radius: 4px;
24
+ border-radius: 4px;
25
+ }
26
+
27
+ .fancybox-opened {
28
+ z-index: 1003;
29
+ }
30
+
31
+ .fancybox-opened .fancybox-outer {
32
+ -webkit-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
33
+ -moz-box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
34
+ box-shadow: 0 10px 25px rgba(0, 0, 0, 0.5);
35
+ }
36
+
37
+ .fancybox-inner {
38
+ width: 100%;
39
+ height: 100%;
40
+ padding: 0;
41
+ margin: 0;
42
+ position: relative;
43
+ outline: none;
44
+ overflow: hidden;
45
+ }
46
+
47
+ .fancybox-type-iframe .fancybox-inner {
48
+ -webkit-overflow-scrolling: touch
49
+ }
50
+
51
+ .fancybox-error {
52
+ color: #444;
53
+ font: 14px/20px "Helvetica Neue",Helvetica,Arial,sans-serif;
54
+ margin: 0;
55
+ padding: 10px;
56
+ }
57
+
58
+ .fancybox-image, .fancybox-iframe {
59
+ display: block;
60
+ width: 100%;
61
+ height: 100%;
62
+ border: 0;
63
+ padding: 0;
64
+ margin: 0;
65
+ vertical-align: top;
66
+ }
67
+
68
+ .fancybox-image {
69
+ max-width: 100%;
70
+ max-height: 100%;
71
+ }
72
+
73
+ #fancybox-loading, .fancybox-close, .fancybox-prev span, .fancybox-next span {
74
+ background-image: url('fancybox_sprite.png');
75
+ }
76
+
77
+ #fancybox-loading {
78
+ position: fixed;
79
+ top: 50%;
80
+ left: 50%;
81
+ margin-top: -22px;
82
+ margin-left: -22px;
83
+ background-position: 0 -108px;
84
+ opacity: 0.8;
85
+ cursor: pointer;
86
+ z-index: 1010;
87
+ }
88
+
89
+ #fancybox-loading div {
90
+ width: 44px;
91
+ height: 44px;
92
+ background: url('fancybox_loading.gif') center center no-repeat;
93
+ }
94
+
95
+ .fancybox-close {
96
+ position: absolute;
97
+ top: -18px;
98
+ right: -18px;
99
+ width: 36px;
100
+ height: 36px;
101
+ cursor: pointer;
102
+ z-index: 1004;
103
+ }
104
+
105
+ .fancybox-nav {
106
+ position: absolute;
107
+ top: 0;
108
+ width: 40%;
109
+ height: 100%;
110
+ cursor: pointer;
111
+ background: transparent url('blank.gif'); /* helps IE */
112
+ z-index: 1003;
113
+ }
114
+
115
+ .fancybox-prev {
116
+ left: 0;
117
+ }
118
+
119
+ .fancybox-next {
120
+ right: 0;
121
+ }
122
+
123
+ .fancybox-nav span {
124
+ position: absolute;
125
+ top: 50%;
126
+ width: 36px;
127
+ height: 36px;
128
+ margin-top: -18px;
129
+ cursor: pointer;
130
+ z-index: 1003;
131
+ visibility: hidden;
132
+ }
133
+
134
+ .fancybox-prev span {
135
+ left: 20px;
136
+ background-position: 0 -36px;
137
+ }
138
+
139
+ .fancybox-next span {
140
+ right: 20px;
141
+ background-position: 0 -72px;
142
+ }
143
+
144
+ .fancybox-nav:hover span {
145
+ visibility: visible;
146
+ }
147
+
148
+ .fancybox-tmp {
149
+ position: absolute;
150
+ top: -9999px;
151
+ left: -9999px;
152
+ padding: 0;
153
+ overflow: visible;
154
+ visibility: hidden;
155
+ }
156
+
157
+ /* Overlay helper */
158
+
159
+ #fancybox-overlay {
160
+ position: absolute;
161
+ top: 0;
162
+ left: 0;
163
+ overflow: hidden;
164
+ display: none;
165
+ z-index: 1001;
166
+ background: #000;
167
+ }
168
+
169
+ /* Title helper */
170
+
171
+ .fancybox-title {
172
+ visibility: hidden;
173
+ font: normal 13px/20px "Helvetica Neue",Helvetica,Arial,sans-serif;
174
+ position: relative;
175
+ text-shadow: none;
176
+ z-index: 1005;
177
+ }
178
+
179
+ .fancybox-opened .fancybox-title {
180
+ visibility: visible;
181
+ }
182
+
183
+ .fancybox-title-float-wrap {
184
+ position: absolute;
185
+ bottom: 0;
186
+ right: 50%;
187
+ margin-bottom: -35px;
188
+ z-index: 1003;
189
+ text-align: center;
190
+ }
191
+
192
+ .fancybox-title-float-wrap .child {
193
+ display: inline-block;
194
+ margin-right: -100%;
195
+ padding: 2px 20px;
196
+ background: transparent; /* Fallback for web browsers that doesn't support RGBa */
197
+ background: rgba(0, 0, 0, 0.8);
198
+ -webkit-border-radius: 15px;
199
+ -moz-border-radius: 15px;
200
+ border-radius: 15px;
201
+ text-shadow: 0 1px 2px #222;
202
+ color: #FFF;
203
+ font-weight: bold;
204
+ line-height: 24px;
205
+ white-space: nowrap;
206
+ }
207
+
208
+ .fancybox-title-outside-wrap {
209
+ position: relative;
210
+ margin-top: 10px;
211
+ color: #fff;
212
+ }
213
+
214
+ .fancybox-title-inside-wrap {
215
+ margin-top: 10px;
216
+ }
217
+
218
+ .fancybox-title-over-wrap {
219
+ position: absolute;
220
+ bottom: 0;
221
+ left: 0;
222
+ color: #fff;
223
+ padding: 10px;
224
+ background: #000;
225
+ background: rgba(0, 0, 0, .8);
226
+ }
assets/fancyBox/source/jquery.fancybox.js ADDED
@@ -0,0 +1,1449 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+ * fancyBox - jQuery Plugin
3
+ * version: 2.0.5 (27/03/2012)
4
+ * @requires jQuery v1.6 or later
5
+ *
6
+ * Examples at http://fancyapps.com/fancybox/
7
+ * License: www.fancyapps.com/fancybox/#license
8
+ *
9
+ * Copyright 2012 Janis Skarnelis - janis@fancyapps.com
10
+ *
11
+ */
12
+ (function (window, document, undefined) {
13
+ "use strict";
14
+
15
+ var $ = window.jQuery,
16
+ W = $(window),
17
+ D = $(document),
18
+ F = $.fancybox = function () {
19
+ F.open.apply( this, arguments );
20
+ },
21
+ didResize = false,
22
+ resizeTimer = null,
23
+ isMobile = document.createTouch !== undefined,
24
+ isString = function(str) {
25
+ return $.type(str) === "string";
26
+ },
27
+ isPercentage = function(str) {
28
+ return isString(str) && str.indexOf('%') > -1;
29
+ };
30
+
31
+ $.extend(F, {
32
+ // The current version of fancyBox
33
+ version: '2.0.5',
34
+
35
+ defaults: {
36
+ padding: 15,
37
+ margin: 20,
38
+
39
+ width: 800,
40
+ height: 600,
41
+ minWidth: 100,
42
+ minHeight: 100,
43
+ maxWidth: 9999,
44
+ maxHeight: 9999,
45
+
46
+ autoSize: true,
47
+ autoResize: !isMobile,
48
+ autoCenter : !isMobile,
49
+ fitToView: true,
50
+ aspectRatio: false,
51
+ topRatio: 0.5,
52
+
53
+ fixed: !($.browser.msie && $.browser.version <= 6) && !isMobile,
54
+ scrolling: 'auto', // 'auto', 'yes' or 'no'
55
+ wrapCSS: 'fancybox-default',
56
+
57
+ arrows: true,
58
+ closeBtn: true,
59
+ closeClick: false,
60
+ nextClick : false,
61
+ mouseWheel: true,
62
+ autoPlay: false,
63
+ playSpeed: 3000,
64
+ preload : 3,
65
+
66
+ modal: false,
67
+ loop: true,
68
+ ajax: { dataType: 'html', headers: { 'X-fancyBox': true } },
69
+ keys: {
70
+ next: [13, 32, 34, 39, 40], // enter, space, page down, right arrow, down arrow
71
+ prev: [8, 33, 37, 38], // backspace, page up, left arrow, up arrow
72
+ close: [27] // escape key
73
+ },
74
+
75
+ // Override some properties
76
+ index: 0,
77
+ type: null,
78
+ href: null,
79
+ content: null,
80
+ title: null,
81
+
82
+ // HTML templates
83
+ tpl: {
84
+ wrap: '<div class="fancybox-wrap"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div>',
85
+ image: '<img class="fancybox-image" src="{href}" alt="" />',
86
+ iframe: '<iframe class="fancybox-iframe" name="fancybox-frame{rnd}" frameborder="0" hspace="0"' + ($.browser.msie ? ' allowtransparency="true"' : '') + '></iframe>',
87
+ swf: '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="wmode" value="transparent" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="{href}" /><embed src="{href}" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="100%" height="100%" wmode="transparent"></embed></object>',
88
+ error: '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',
89
+ closeBtn: '<div title="Close" class="fancybox-item fancybox-close"></div>',
90
+ next: '<a title="Next" class="fancybox-nav fancybox-next"><span></span></a>',
91
+ prev: '<a title="Previous" class="fancybox-nav fancybox-prev"><span></span></a>'
92
+ },
93
+
94
+ // Properties for each animation type
95
+ // Opening fancyBox
96
+ openEffect: 'fade', // 'elastic', 'fade' or 'none'
97
+ openSpeed: 250,
98
+ openEasing: 'swing',
99
+ openOpacity: true,
100
+ openMethod: 'zoomIn',
101
+
102
+ // Closing fancyBox
103
+ closeEffect: 'fade', // 'elastic', 'fade' or 'none'
104
+ closeSpeed: 250,
105
+ closeEasing: 'swing',
106
+ closeOpacity: true,
107
+ closeMethod: 'zoomOut',
108
+
109
+ // Changing next gallery item
110
+ nextEffect: 'elastic', // 'elastic', 'fade' or 'none'
111
+ nextSpeed: 300,
112
+ nextEasing: 'swing',
113
+ nextMethod: 'changeIn',
114
+
115
+ // Changing previous gallery item
116
+ prevEffect: 'elastic', // 'elastic', 'fade' or 'none'
117
+ prevSpeed: 300,
118
+ prevEasing: 'swing',
119
+ prevMethod: 'changeOut',
120
+
121
+ // Enabled helpers
122
+ helpers: {
123
+ overlay: {
124
+ speedIn: 0,
125
+ speedOut: 300,
126
+ opacity: 0.8,
127
+ css: {
128
+ cursor: 'pointer'
129
+ },
130
+ closeClick: true
131
+ },
132
+ title: {
133
+ type: 'float' // 'float', 'inside', 'outside' or 'over'
134
+ }
135
+ },
136
+
137
+ // Callbacks
138
+ onCancel: $.noop, // If canceling
139
+ beforeLoad: $.noop, // Before loading
140
+ afterLoad: $.noop, // After loading
141
+ beforeShow: $.noop, // Before changing in current item
142
+ afterShow: $.noop, // After opening
143
+ beforeClose: $.noop, // Before closing
144
+ afterClose: $.noop // After closing
145
+ },
146
+
147
+ //Current state
148
+ group: {}, // Selected group
149
+ opts: {}, // Group options
150
+ coming: null, // Element being loaded
151
+ current: null, // Currently loaded element
152
+ isOpen: false, // Is currently open
153
+ isOpened: false, // Have been fully opened at least once
154
+ wrap: null,
155
+ outer: null,
156
+ inner: null,
157
+
158
+ player: {
159
+ timer: null,
160
+ isActive: false
161
+ },
162
+
163
+ // Loaders
164
+ ajaxLoad: null,
165
+ imgPreload: null,
166
+
167
+ // Some collections
168
+ transitions: {},
169
+ helpers: {},
170
+
171
+ /*
172
+ * Static methods
173
+ */
174
+
175
+ open: function (group, opts) {
176
+ //Kill existing instances
177
+ F.close(true);
178
+
179
+ //Normalize group
180
+ if (group && !$.isArray(group)) {
181
+ group = group instanceof $ ? $(group).get() : [group];
182
+ }
183
+
184
+ F.isActive = true;
185
+
186
+ //Extend the defaults
187
+ F.opts = $.extend(true, {}, F.defaults, opts);
188
+
189
+ //All options are merged recursive except keys
190
+ if ($.isPlainObject(opts) && opts.keys !== undefined) {
191
+ F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false;
192
+ }
193
+
194
+ F.group = group;
195
+
196
+ F._start(F.opts.index || 0);
197
+ },
198
+
199
+ cancel: function () {
200
+ if (F.coming && false === F.trigger('onCancel')) {
201
+ return;
202
+ }
203
+
204
+ F.coming = null;
205
+
206
+ F.hideLoading();
207
+
208
+ if (F.ajaxLoad) {
209
+ F.ajaxLoad.abort();
210
+ }
211
+
212
+ F.ajaxLoad = null;
213
+
214
+ if (F.imgPreload) {
215
+ F.imgPreload.onload = F.imgPreload.onabort = F.imgPreload.onerror = null;
216
+ }
217
+ },
218
+
219
+ close: function (a) {
220
+ F.cancel();
221
+
222
+ if (!F.current || false === F.trigger('beforeClose')) {
223
+ return;
224
+ }
225
+
226
+ F.unbindEvents();
227
+
228
+ //If forced or is still opening then remove immediately
229
+ if (!F.isOpen || (a && a[0] === true)) {
230
+ $(".fancybox-wrap").stop().trigger('onReset').remove();
231
+
232
+ F._afterZoomOut();
233
+
234
+ } else {
235
+ F.isOpen = F.isOpened = false;
236
+
237
+ $(".fancybox-item, .fancybox-nav").remove();
238
+
239
+ F.wrap.stop(true).removeClass('fancybox-opened');
240
+ F.inner.css('overflow', 'hidden');
241
+
242
+ F.transitions[F.current.closeMethod]();
243
+ }
244
+ },
245
+
246
+ // Start/stop slideshow
247
+ play: function (a) {
248
+ var clear = function () {
249
+ clearTimeout(F.player.timer);
250
+ },
251
+ set = function () {
252
+ clear();
253
+
254
+ if (F.current && F.player.isActive) {
255
+ F.player.timer = setTimeout(F.next, F.current.playSpeed);
256
+ }
257
+ },
258
+ stop = function () {
259
+ clear();
260
+
261
+ $('body').unbind('.player');
262
+
263
+ F.player.isActive = false;
264
+
265
+ F.trigger('onPlayEnd');
266
+ },
267
+ start = function () {
268
+ if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) {
269
+ F.player.isActive = true;
270
+
271
+ $('body').bind({
272
+ 'afterShow.player onUpdate.player': set,
273
+ 'onCancel.player beforeClose.player': stop,
274
+ 'beforeLoad.player': clear
275
+ });
276
+
277
+ set();
278
+
279
+ F.trigger('onPlayStart');
280
+ }
281
+ };
282
+
283
+ if (F.player.isActive || (a && a[0] === false)) {
284
+ stop();
285
+ } else {
286
+ start();
287
+ }
288
+ },
289
+
290
+ next: function () {
291
+ if (F.current) {
292
+ F.jumpto(F.current.index + 1);
293
+ }
294
+ },
295
+
296
+ prev: function () {
297
+ if (F.current) {
298
+ F.jumpto(F.current.index - 1);
299
+ }
300
+ },
301
+
302
+ jumpto: function (index) {
303
+ if (!F.current) {
304
+ return;
305
+ }
306
+
307
+ index = parseInt(index, 10);
308
+
309
+ if (F.group.length > 1 && F.current.loop) {
310
+ if (index >= F.group.length) {
311
+ index = 0;
312
+
313
+ } else if (index < 0) {
314
+ index = F.group.length - 1;
315
+ }
316
+ }
317
+
318
+ if (F.group[index] !== undefined) {
319
+ F.cancel();
320
+
321
+ F._start(index);
322
+ }
323
+ },
324
+
325
+ reposition: function (absolute, e) {
326
+ if (F.isOpen) {
327
+ if (e && e.type === 'scroll') {
328
+ F.wrap.stop().animate(F._getPosition(absolute), 200);
329
+ } else {
330
+ F.wrap.css(F._getPosition(absolute));
331
+ }
332
+ }
333
+ },
334
+
335
+ update: function (e) {
336
+ if (F.isOpen) {
337
+ // It's a very bad idea to attach handlers to the window scroll event, run this code after a delay
338
+ if (!didResize) {
339
+ resizeTimer = setTimeout(function () {
340
+ var current = F.current;
341
+
342
+ if (didResize) {
343
+ didResize = false;
344
+
345
+ if (current) {
346
+ if (!e || (e && (e.type === 'orientationchange' || (current.autoResize && e.type === 'resize')))) {
347
+ if (current.autoSize && current.type !== 'iframe') {
348
+ F.inner.height('auto');
349
+ current.height = F.inner.height();
350
+ }
351
+
352
+ F._setDimension();
353
+
354
+ if (current.canGrow && current.type !== 'iframe') {
355
+ F.inner.height('auto');
356
+ }
357
+ }
358
+
359
+ if (current.autoCenter) {
360
+ F.reposition(null, e);
361
+ }
362
+
363
+ F.trigger('onUpdate');
364
+ }
365
+ }
366
+ }, 100);
367
+ }
368
+
369
+ didResize = true;
370
+ }
371
+ },
372
+
373
+ toggle: function () {
374
+ if (F.isOpen) {
375
+ F.current.fitToView = !F.current.fitToView;
376
+
377
+ F.update();
378
+ }
379
+ },
380
+
381
+ hideLoading: function () {
382
+ D.unbind('keypress.fb');
383
+
384
+ $("#fancybox-loading").remove();
385
+ },
386
+
387
+ showLoading: function () {
388
+ F.hideLoading();
389
+
390
+ //If user will press the escape-button, the request will be canceled
391
+ D.bind('keypress.fb', function(e) {
392
+ if (e.keyCode === 27) {
393
+ e.preventDefault();
394
+ F.cancel();
395
+ }
396
+ });
397
+
398
+ $('<div id="fancybox-loading"><div></div></div>').click(F.cancel).appendTo('body');
399
+ },
400
+
401
+ getViewport: function () {
402
+ return {
403
+ x: W.scrollLeft(),
404
+ y: W.scrollTop(),
405
+ w: window.innerWidth ? window.innerWidth : W.width(),
406
+ h: window.innerHeight ? window.innerHeight : W.height()
407
+ };
408
+ },
409
+
410
+ // Unbind the keyboard / clicking actions
411
+ unbindEvents: function () {
412
+ if (F.wrap) {
413
+ F.wrap.unbind('.fb');
414
+ }
415
+
416
+ D.unbind('.fb');
417
+ W.unbind('.fb');
418
+ },
419
+
420
+ bindEvents: function () {
421
+ var current = F.current,
422
+ keys = current.keys;
423
+
424
+ if (!current) {
425
+ return;
426
+ }
427
+
428
+ W.bind('resize.fb, orientationchange.fb', F.update);
429
+
430
+ if (!current.fixed && current.autoCenter) {
431
+ W.bind("scroll.fb", F.update);
432
+ }
433
+
434
+ if (keys) {
435
+ D.bind('keydown.fb', function (e) {
436
+ var code;
437
+
438
+ // Ignore key combinations and key events within form elements
439
+ if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && $.inArray(e.target.tagName.toLowerCase(), ['input', 'textarea', 'select', 'button']) < 0 && !$(e.target).is('[contenteditable]')) {
440
+ code = e.keyCode;
441
+
442
+ if ($.inArray(code, keys.close) > -1) {
443
+ F.close();
444
+ e.preventDefault();
445
+
446
+ } else if ($.inArray(code, keys.next) > -1) {
447
+ F.next();
448
+ e.preventDefault();
449
+
450
+ } else if ($.inArray(code, keys.prev) > -1) {
451
+ F.prev();
452
+ e.preventDefault();
453
+ }
454
+ }
455
+ });
456
+ }
457
+
458
+ if ($.fn.mousewheel && current.mouseWheel && F.group.length > 1) {
459
+ F.wrap.bind('mousewheel.fb', function (e, delta) {
460
+ var target = e.target || null;
461
+
462
+ if (delta !== 0 && (!target || target.clientHeight === 0 || (target.scrollHeight === target.clientHeight && target.scrollWidth === target.clientWidth))) {
463
+ e.preventDefault();
464
+
465
+ F[delta > 0 ? 'prev' : 'next']();
466
+ }
467
+ });
468
+ }
469
+ },
470
+
471
+ trigger: function (event) {
472
+ var ret, obj = F[ $.inArray(event, ['onCancel', 'beforeLoad', 'afterLoad']) > -1 ? 'coming' : 'current' ];
473
+
474
+ if (!obj) {
475
+ return;
476
+ }
477
+
478
+ if ($.isFunction( obj[event] )) {
479
+ ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1));
480
+ }
481
+
482
+ if (ret === false) {
483
+ return false;
484
+ }
485
+
486
+ if (obj.helpers) {
487
+ $.each(obj.helpers, function (helper, opts) {
488
+ if (opts && $.isPlainObject(F.helpers[helper]) && $.isFunction(F.helpers[helper][event])) {
489
+ F.helpers[helper][event](opts, obj);
490
+ }
491
+ });
492
+ }
493
+
494
+ $.event.trigger(event + '.fb');
495
+ },
496
+
497
+ isImage: function (str) {
498
+ return isString(str) && str.match(/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i);
499
+ },
500
+
501
+ isSWF: function (str) {
502
+ return isString(str) && str.match(/\.(swf)(.*)?$/i);
503
+ },
504
+
505
+ _start: function (index) {
506
+ var coming = {},
507
+ element = F.group[index] || null,
508
+ isDom,
509
+ href,
510
+ type,
511
+ rez,
512
+ hrefParts;
513
+
514
+ if (element && (element.nodeType || element instanceof $)) {
515
+ isDom = true;
516
+
517
+ if ($.metadata) {
518
+ coming = $(element).metadata();
519
+ }
520
+ }
521
+
522
+ coming = $.extend(true, {}, F.opts, {index : index, element : element}, ($.isPlainObject(element) ? element : coming));
523
+
524
+ // Re-check overridable options
525
+ $.each(['href', 'title', 'content', 'type'], function(i,v) {
526
+ coming[v] = F.opts[ v ] || (isDom && $(element).attr( v )) || coming[ v ] || null;
527
+ });
528
+
529
+ // Convert margin property to array - top, right, bottom, left
530
+ if (typeof coming.margin === 'number') {
531
+ coming.margin = [coming.margin, coming.margin, coming.margin, coming.margin];
532
+ }
533
+
534
+ // 'modal' propery is just a shortcut
535
+ if (coming.modal) {
536
+ $.extend(true, coming, {
537
+ closeBtn : false,
538
+ closeClick: false,
539
+ nextClick : false,
540
+ arrows : false,
541
+ mouseWheel : false,
542
+ keys : null,
543
+ helpers: {
544
+ overlay : {
545
+ css: {
546
+ cursor : 'auto'
547
+ },
548
+ closeClick : false
549
+ }
550
+ }
551
+ });
552
+ }
553
+
554
+ //Give a chance for callback or helpers to update coming item (type, title, etc)
555
+ F.coming = coming;
556
+
557
+ if (false === F.trigger('beforeLoad')) {
558
+ F.coming = null;
559
+ return;
560
+ }
561
+
562
+ type = coming.type;
563
+ href = coming.href || element;
564
+
565
+ ///Check if content type is set, if not, try to get
566
+ if (!type) {
567
+ if (isDom) {
568
+ rez = $(element).data('fancybox-type');
569
+
570
+ if (!rez && element.className) {
571
+ rez = element.className.match(/fancybox\.(\w+)/);
572
+ type = rez ? rez[1] : null;
573
+ }
574
+ }
575
+
576
+ if (!type && isString(href)) {
577
+ if (F.isImage(href)) {
578
+ type = 'image';
579
+
580
+ } else if (F.isSWF(href)) {
581
+ type = 'swf';
582
+
583
+ } else if (href.match(/^#/)) {
584
+ type = 'inline';
585
+ }
586
+ }
587
+
588
+ // ...if not - display element itself
589
+ if (!type) {
590
+ type = isDom ? 'inline' : 'html';
591
+ }
592
+
593
+ coming.type = type;
594
+ }
595
+
596
+ // Check before try to load; 'inline' and 'html' types need content, others - href
597
+ if (type === 'inline' || type === 'html') {
598
+ if (!coming.content) {
599
+ if (type === 'inline') {
600
+ coming.content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7
601
+
602
+ } else {
603
+ coming.content = element;
604
+ }
605
+ }
606
+
607
+ if (!coming.content || !coming.content.length) {
608
+ type = null;
609
+ }
610
+
611
+ } else if (!href) {
612
+ type = null;
613
+ }
614
+
615
+ /*
616
+ * Add reference to the group, so it`s possible to access from callbacks, example:
617
+ * afterLoad : function() {
618
+ * this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
619
+ * }
620
+ */
621
+
622
+ if (type === 'ajax' && isString(href)) {
623
+ hrefParts = href.split(/\s+/, 2);
624
+
625
+ href = hrefParts.shift();
626
+ coming.selector = hrefParts.shift();
627
+ }
628
+
629
+ coming.href = href;
630
+ coming.group = F.group;
631
+ coming.isDom = isDom;
632
+
633
+ if (type === 'image') {
634
+ F._loadImage();
635
+
636
+ } else if (type === 'ajax') {
637
+ F._loadAjax();
638
+
639
+ } else if (type) {
640
+ F._afterLoad();
641
+
642
+ } else {
643
+ F._error( 'type' );
644
+ }
645
+ },
646
+
647
+ _error: function ( type ) {
648
+ F.hideLoading();
649
+
650
+ $.extend(F.coming, {
651
+ type : 'html',
652
+ autoSize : true,
653
+ minHeight : 0,
654
+ hasError : type,
655
+ content : F.coming.tpl.error
656
+ });
657
+
658
+ F._afterLoad();
659
+ },
660
+
661
+ _loadImage: function () {
662
+ // Reset preload image so it is later possible to check "complete" property
663
+ var img = F.imgPreload = new Image();
664
+
665
+ img.onload = function () {
666
+ this.onload = this.onerror = null;
667
+
668
+ F.coming.width = this.width;
669
+ F.coming.height = this.height;
670
+
671
+ F._afterLoad();
672
+ };
673
+
674
+ img.onerror = function () {
675
+ this.onload = this.onerror = null;
676
+
677
+ F._error( 'image' );
678
+ };
679
+
680
+ img.src = F.coming.href;
681
+
682
+ if (!img.width) {
683
+ F.showLoading();
684
+ }
685
+ },
686
+
687
+ _loadAjax: function () {
688
+ F.showLoading();
689
+
690
+ F.ajaxLoad = $.ajax($.extend({}, F.coming.ajax, {
691
+ url: F.coming.href,
692
+ error: function (jqXHR, textStatus) {
693
+ if (F.coming && textStatus !== 'abort') {
694
+ F._error( 'ajax', jqXHR );
695
+
696
+ } else {
697
+ F.hideLoading();
698
+ }
699
+ },
700
+ success: function (data, textStatus) {
701
+ if (textStatus === 'success') {
702
+ F.coming.content = data;
703
+
704
+ F._afterLoad();
705
+ }
706
+ }
707
+ }));
708
+ },
709
+
710
+ _preloadImages: function() {
711
+ var group = F.group,
712
+ current = F.current,
713
+ len = group.length,
714
+ item,
715
+ href,
716
+ i,
717
+ cnt = Math.min(current.preload, len - 1);
718
+
719
+ if (!current.preload || group.length < 2) {
720
+ return;
721
+ }
722
+
723
+ for (i = 1; i <= cnt; i += 1) {
724
+ item = group[ (current.index + i ) % len ];
725
+ href = $( item ).attr('href') || item;
726
+
727
+ if (item.type === 'image' || F.isImage(href)) {
728
+ new Image().src = href;
729
+ }
730
+ }
731
+ },
732
+
733
+ _afterLoad: function () {
734
+ F.hideLoading();
735
+
736
+ if (!F.coming || false === F.trigger('afterLoad', F.current)) {
737
+ F.coming = false;
738
+
739
+ return;
740
+ }
741
+
742
+ if (F.isOpened) {
743
+ $(".fancybox-item").remove();
744
+
745
+ F.wrap.stop(true).removeClass('fancybox-opened');
746
+ F.inner.css('overflow', 'hidden');
747
+
748
+ F.transitions[F.current.prevMethod]();
749
+
750
+ } else {
751
+ $(".fancybox-wrap").stop().trigger('onReset').remove();
752
+
753
+ F.trigger('afterClose');
754
+ }
755
+
756
+ F.unbindEvents();
757
+
758
+ F.isOpen = false;
759
+ F.current = F.coming;
760
+
761
+ //Build the neccessary markup
762
+ F.wrap = $(F.current.tpl.wrap).addClass('fancybox-' + (isMobile ? 'mobile' : 'desktop') + ' fancybox-type-' + F.current.type + ' fancybox-tmp ' + F.current.wrapCSS).appendTo('body');
763
+ F.outer = $('.fancybox-outer', F.wrap).css('padding', F.current.padding + 'px');
764
+ F.inner = $('.fancybox-inner', F.wrap);
765
+
766
+ F._setContent();
767
+ },
768
+
769
+ _setContent: function () {
770
+ var current = F.current,
771
+ content = current.content,
772
+ type = current.type,
773
+ loadingBay,
774
+ minWidth = current.minWidth,
775
+ minHeight = current.minHeight,
776
+ maxWidth = current.maxWidth,
777
+ maxHeight = current.maxHeight;
778
+
779
+ switch (type) {
780
+ case 'inline':
781
+ case 'ajax':
782
+ case 'html':
783
+ if (current.selector) {
784
+ content = $('<div>').html(content).find(current.selector);
785
+
786
+ } else if (content instanceof $) {
787
+ if (content.parent().hasClass('fancybox-inner')) {
788
+ content.parents('.fancybox-wrap').unbind('onReset');
789
+ }
790
+
791
+ content = content.show().detach();
792
+
793
+ $(F.wrap).bind('onReset', function () {
794
+ content.appendTo('body').hide();
795
+ });
796
+ }
797
+
798
+ if (current.autoSize) {
799
+ loadingBay = $('<div class="fancybox-wrap ' + F.current.wrapCSS + ' fancybox-tmp"></div>')
800
+ .appendTo('body')
801
+ .css({
802
+ minWidth : isPercentage(minWidth) ? minWidth : minWidth + 'px',
803
+ minHeight : isPercentage(minHeight) ? minHeight : minHeight + 'px',
804
+ maxWidth : isPercentage(maxWidth) ? maxWidth : maxWidth + 'px',
805
+ maxHeight : isPercentage(maxHeight) ? maxHeight : maxHeight + 'px'
806
+ })
807
+ .append(content);
808
+
809
+ current.width = loadingBay.width();
810
+ current.height = loadingBay.height();
811
+
812
+ // Re-check to fix 1px bug in some browsers
813
+ loadingBay.width( F.current.width );
814
+
815
+ if (loadingBay.height() > current.height) {
816
+ loadingBay.width(current.width + 1);
817
+
818
+ current.width = loadingBay.width();
819
+ current.height = loadingBay.height();
820
+ }
821
+
822
+ content = loadingBay.contents().detach();
823
+
824
+ loadingBay.remove();
825
+ }
826
+
827
+ break;
828
+
829
+ case 'image':
830
+ content = current.tpl.image.replace('{href}', current.href);
831
+
832
+ current.aspectRatio = true;
833
+ break;
834
+
835
+ case 'swf':
836
+ content = current.tpl.swf.replace(/\{width\}/g, current.width).replace(/\{height\}/g, current.height).replace(/\{href\}/g, current.href);
837
+ break;
838
+
839
+ case 'iframe':
840
+ content = $(current.tpl.iframe.replace('{rnd}', new Date().getTime()) )
841
+ .attr('scrolling', current.scrolling)
842
+ .attr('src', current.href);
843
+
844
+ current.scrolling = isMobile ? 'scroll' : 'auto';
845
+
846
+ break;
847
+ }
848
+
849
+ if (type === 'image' || type === 'swf') {
850
+ current.autoSize = false;
851
+ current.scrolling = 'visible';
852
+ }
853
+
854
+ if (type === 'iframe' && current.autoSize) {
855
+ F.showLoading();
856
+
857
+ F.inner
858
+ .width(current.width)
859
+ .height(current.height)
860
+ .css('overflow', current.scrolling);
861
+
862
+ content.bind({
863
+ onCancel : function() {
864
+ $(this).unbind();
865
+
866
+ F._afterZoomOut();
867
+ },
868
+ load : function() {
869
+ F.hideLoading();
870
+
871
+ try {
872
+ if (this.contentWindow.document.location) {
873
+ F.current.height = $(this).contents().find('body').height();
874
+ }
875
+ } catch (e) {
876
+ F.current.autoSize = false;
877
+ }
878
+
879
+ if (F.isOpened) {
880
+ F.update();
881
+
882
+ } else {
883
+ F._beforeShow();
884
+ }
885
+ }
886
+ }).appendTo(F.inner);
887
+
888
+ } else {
889
+ F.inner.append(content);
890
+
891
+ F._beforeShow();
892
+ }
893
+ },
894
+
895
+ _beforeShow : function() {
896
+ F.coming = null;
897
+
898
+ //Give a chance for helpers or callbacks to update elements
899
+ F.trigger('beforeShow');
900
+
901
+ //Set initial dimensions and hide
902
+ F._setDimension();
903
+ F.wrap.hide().removeClass('fancybox-tmp');
904
+
905
+ F.bindEvents();
906
+
907
+ F._preloadImages();
908
+
909
+ F.transitions[ F.isOpened ? F.current.nextMethod : F.current.openMethod ]();
910
+ },
911
+
912
+ _setDimension: function () {
913
+ var wrap = F.wrap,
914
+ outer = F.outer,
915
+ inner = F.inner,
916
+ current = F.current,
917
+ viewport = F.getViewport(),
918
+ margin = current.margin,
919
+ padding2 = current.padding * 2,
920
+ width = current.width,
921
+ height = current.height,
922
+ maxWidth = current.maxWidth + padding2,
923
+ maxHeight = current.maxHeight + padding2,
924
+ minWidth = current.minWidth + padding2,
925
+ minHeight = current.minHeight + padding2,
926
+ ratio,
927
+ height_,
928
+ space;
929
+
930
+ viewport.w -= (margin[1] + margin[3]);
931
+ viewport.h -= (margin[0] + margin[2]);
932
+
933
+ if (isPercentage(width)) {
934
+ width = (((viewport.w - padding2) * parseFloat(width)) / 100);
935
+ }
936
+
937
+ if (isPercentage(height)) {
938
+ height = (((viewport.h - padding2) * parseFloat(height)) / 100);
939
+ }
940
+
941
+ ratio = width / height;
942
+ width += padding2;
943
+ height += padding2;
944
+
945
+ if (current.fitToView) {
946
+ maxWidth = Math.min(viewport.w, maxWidth);
947
+ maxHeight = Math.min(viewport.h, maxHeight);
948
+ }
949
+
950
+ if (current.aspectRatio) {
951
+ if (width > maxWidth) {
952
+ width = maxWidth;
953
+ height = ((width - padding2) / ratio) + padding2;
954
+ }
955
+
956
+ if (height > maxHeight) {
957
+ height = maxHeight;
958
+ width = ((height - padding2) * ratio) + padding2;
959
+ }
960
+
961
+ if (width < minWidth) {
962
+ width = minWidth;
963
+ height = ((width - padding2) / ratio) + padding2;
964
+ }
965
+
966
+ if (height < minHeight) {
967
+ height = minHeight;
968
+ width = ((height - padding2) * ratio) + padding2;
969
+ }
970
+
971
+ } else {
972
+ width = Math.max(minWidth, Math.min(width, maxWidth));
973
+ height = Math.max(minHeight, Math.min(height, maxHeight));
974
+ }
975
+
976
+ width = Math.round(width);
977
+ height = Math.round(height);
978
+
979
+ //Reset dimensions
980
+ $(wrap.add(outer).add(inner)).width('auto').height('auto');
981
+
982
+ inner.width(width - padding2).height(height - padding2);
983
+ wrap.width(width);
984
+
985
+ height_ = wrap.height(); // Real wrap height
986
+
987
+ //Fit wrapper inside
988
+ if (width > maxWidth || height_ > maxHeight) {
989
+ while ((width > maxWidth || height_ > maxHeight) && width > minWidth && height_ > minHeight) {
990
+ height = height - 10;
991
+
992
+ if (current.aspectRatio) {
993
+ width = Math.round(((height - padding2) * ratio) + padding2);
994
+
995
+ if (width < minWidth) {
996
+ width = minWidth;
997
+ height = ((width - padding2) / ratio) + padding2;
998
+ }
999
+
1000
+ } else {
1001
+ width = width - 10;
1002
+ }
1003
+
1004
+ inner.width(width - padding2).height(height - padding2);
1005
+ wrap.width(width);
1006
+
1007
+ height_ = wrap.height();
1008
+ }
1009
+ }
1010
+
1011
+ current.dim = {
1012
+ width: width,
1013
+ height: height_
1014
+ };
1015
+
1016
+ current.canGrow = current.autoSize && height > minHeight && height < maxHeight;
1017
+ current.canShrink = false;
1018
+ current.canExpand = false;
1019
+
1020
+ if ((width - padding2) < current.width || (height - padding2) < current.height) {
1021
+ current.canExpand = true;
1022
+
1023
+ } else if ((width > viewport.w || height_ > viewport.h) && width > minWidth && height > minHeight) {
1024
+ current.canShrink = true;
1025
+ }
1026
+
1027
+ space = height_ - padding2;
1028
+
1029
+ F.innerSpace = space - inner.height();
1030
+ F.outerSpace = space - outer.height();
1031
+ },
1032
+
1033
+ _getPosition: function (a) {
1034
+ var current = F.current,
1035
+ viewport = F.getViewport(),
1036
+ margin = current.margin,
1037
+ width = F.wrap.width() + margin[1] + margin[3],
1038
+ height = F.wrap.height() + margin[0] + margin[2],
1039
+ rez = {
1040
+ position: 'absolute',
1041
+ top: margin[0] + viewport.y,
1042
+ left: margin[3] + viewport.x
1043
+ };
1044
+
1045
+ if (current.autoCenter && current.fixed && (!a || a[0] === false) && height <= viewport.h && width <= viewport.w) {
1046
+ rez = {
1047
+ position: 'fixed',
1048
+ top: margin[0],
1049
+ left: margin[3]
1050
+ };
1051
+ }
1052
+
1053
+ rez.top = Math.ceil(Math.max(rez.top, rez.top + ((viewport.h - height) * current.topRatio))) + 'px';
1054
+ rez.left = Math.ceil(Math.max(rez.left, rez.left + ((viewport.w - width) * 0.5))) + 'px';
1055
+
1056
+ return rez;
1057
+ },
1058
+
1059
+ _afterZoomIn: function () {
1060
+ var current = F.current, scrolling = current ? current.scrolling : 'no';
1061
+
1062
+ if (!current) {
1063
+ return;
1064
+ }
1065
+
1066
+ F.isOpen = F.isOpened = true;
1067
+
1068
+ F.wrap.addClass('fancybox-opened').css('overflow', 'visible');
1069
+
1070
+ F.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling));
1071
+
1072
+ //Assign a click event
1073
+ if (current.closeClick || current.nextClick) {
1074
+ //This is not the perfect solution but arrows have to be next to content so their height will match
1075
+ // and I do not want another wrapper around content
1076
+ F.inner.css('cursor', 'pointer').bind('click.fb', function(e) {
1077
+ if (!$(e.target).is('a') && !$(e.target).parent().is('a')) {
1078
+ F[ current.closeClick ? 'close' : 'next' ]();
1079
+ }
1080
+ });
1081
+ }
1082
+
1083
+ //Create a close button
1084
+ if (current.closeBtn) {
1085
+ $(current.tpl.closeBtn).appendTo(F.outer).bind('click.fb', F.close);
1086
+ }
1087
+
1088
+ //Create navigation arrows
1089
+ if (current.arrows && F.group.length > 1) {
1090
+ if (current.loop || current.index > 0) {
1091
+ $(current.tpl.prev).appendTo(F.inner).bind('click.fb', F.prev);
1092
+ }
1093
+
1094
+ if (current.loop || current.index < F.group.length - 1) {
1095
+ $(current.tpl.next).appendTo(F.inner).bind('click.fb', F.next);
1096
+ }
1097
+ }
1098
+
1099
+ F.trigger('afterShow');
1100
+
1101
+ F.update();
1102
+
1103
+ if (F.opts.autoPlay && !F.player.isActive) {
1104
+ F.opts.autoPlay = false;
1105
+
1106
+ F.play();
1107
+ }
1108
+ },
1109
+
1110
+ _afterZoomOut: function () {
1111
+ F.trigger('afterClose');
1112
+
1113
+ F.wrap.trigger('onReset').remove();
1114
+
1115
+ $.extend(F, {
1116
+ group: {},
1117
+ opts: {},
1118
+ current: null,
1119
+ isActive: false,
1120
+ isOpened: false,
1121
+ isOpen: false,
1122
+ wrap: null,
1123
+ outer: null,
1124
+ inner: null
1125
+ });
1126
+ }
1127
+ });
1128
+
1129
+ /*
1130
+ * Default transitions
1131
+ */
1132
+
1133
+ F.transitions = {
1134
+ getOrigPosition: function () {
1135
+ var current = F.current,
1136
+ element = current.element,
1137
+ padding = current.padding,
1138
+ orig = $(current.orig),
1139
+ pos = {},
1140
+ width = 50,
1141
+ height = 50,
1142
+ viewport;
1143
+
1144
+ if (!orig.length && current.isDom && $(element).is(':visible')) {
1145
+ orig = $(element).find('img:first');
1146
+
1147
+ if (!orig.length) {
1148
+ orig = $(element);
1149
+ }
1150
+ }
1151
+
1152
+ if (orig.length) {
1153
+ pos = orig.offset();
1154
+
1155
+ if (orig.is('img')) {
1156
+ width = orig.outerWidth();
1157
+ height = orig.outerHeight();
1158
+ }
1159
+
1160
+ } else {
1161
+ viewport = F.getViewport();
1162
+
1163
+ pos.top = viewport.y + (viewport.h - height) * 0.5;
1164
+ pos.left = viewport.x + (viewport.w - width) * 0.5;
1165
+ }
1166
+
1167
+ pos = {
1168
+ top: Math.ceil(pos.top - padding) + 'px',
1169
+ left: Math.ceil(pos.left - padding) + 'px',
1170
+ width: Math.ceil(width + padding * 2) + 'px',
1171
+ height: Math.ceil(height + padding * 2) + 'px'
1172
+ };
1173
+
1174
+ return pos;
1175
+ },
1176
+
1177
+ step: function (now, fx) {
1178
+ var ratio, innerValue, outerValue;
1179
+
1180
+ if (fx.prop === 'width' || fx.prop === 'height') {
1181
+ innerValue = outerValue = Math.ceil(now - (F.current.padding * 2));
1182
+
1183
+ if (fx.prop === 'height') {
1184
+ ratio = (now - fx.start) / (fx.end - fx.start);
1185
+
1186
+ if (fx.start > fx.end) {
1187
+ ratio = 1 - ratio;
1188
+ }
1189
+
1190
+ innerValue -= F.innerSpace * ratio;
1191
+ outerValue -= F.outerSpace * ratio;
1192
+ }
1193
+
1194
+ F.inner[fx.prop](innerValue);
1195
+ F.outer[fx.prop](outerValue);
1196
+ }
1197
+ },
1198
+
1199
+ zoomIn: function () {
1200
+ var wrap = F.wrap,
1201
+ current = F.current,
1202
+ effect = current.openEffect,
1203
+ elastic = effect === 'elastic',
1204
+ dim = current.dim,
1205
+ startPos = $.extend({}, dim, F._getPosition( elastic )),
1206
+ endPos = $.extend({opacity : 1}, startPos);
1207
+
1208
+ //Remove "position" property that breaks older IE
1209
+ delete endPos.position;
1210
+
1211
+ if (elastic) {
1212
+ startPos = this.getOrigPosition();
1213
+
1214
+ if (current.openOpacity) {
1215
+ startPos.opacity = 0;
1216
+ }
1217
+
1218
+ F.outer.add(F.inner).width('auto').height('auto');
1219
+ } else if (effect === 'fade') {
1220
+ startPos.opacity = 0;
1221
+ }
1222
+
1223
+ wrap.css(startPos)
1224
+ .show()
1225
+ .animate(endPos, {
1226
+ duration : effect === 'none' ? 0 : current.openSpeed,
1227
+ easing : current.openEasing,
1228
+ step: elastic ? this.step : null,
1229
+ complete: F._afterZoomIn
1230
+ });
1231
+ },
1232
+
1233
+ zoomOut: function () {
1234
+ var wrap = F.wrap,
1235
+ current = F.current,
1236
+ effect = current.openEffect,
1237
+ elastic = effect === 'elastic',
1238
+ endPos = {opacity : 0};
1239
+
1240
+ if (elastic) {
1241
+ if (wrap.css('position') === 'fixed') {
1242
+ wrap.css(F._getPosition(true));
1243
+ }
1244
+
1245
+ endPos = this.getOrigPosition();
1246
+
1247
+ if (current.closeOpacity) {
1248
+ endPos.opacity = 0;
1249
+ }
1250
+ }
1251
+
1252
+ wrap.animate(endPos, {
1253
+ duration: effect === 'none' ? 0 : current.closeSpeed,
1254
+ easing: current.closeEasing,
1255
+ step: elastic ? this.step : null,
1256
+ complete: F._afterZoomOut
1257
+ });
1258
+ },
1259
+
1260
+ changeIn: function () {
1261
+ var wrap = F.wrap,
1262
+ current = F.current,
1263
+ effect = current.nextEffect,
1264
+ startPos = F._getPosition( effect === 'elastic' ),
1265
+ endPos = { opacity : 1 };
1266
+
1267
+ if (effect === 'elastic') {
1268
+ startPos.top = (parseInt(startPos.top, 10) - 200) + 'px';
1269
+ endPos.top = '+=200px';
1270
+ startPos.opacity = 0;
1271
+ }
1272
+
1273
+ wrap.css(startPos)
1274
+ .show()
1275
+ .animate(endPos, {
1276
+ duration : effect === 'none' ? 0 : current.nextSpeed,
1277
+ easing : current.nextEasing,
1278
+ complete: function() {
1279
+ //Somehow this helps to restore overflow
1280
+ setTimeout( F._afterZoomIn, 1);
1281
+ }
1282
+ });
1283
+ },
1284
+
1285
+ changeOut: function () {
1286
+ var wrap = F.wrap,
1287
+ current = F.current,
1288
+ effect = current.nextEffect,
1289
+ endPos = { opacity : 0 },
1290
+ cleanUp = function () {
1291
+ $(this).trigger('onReset').remove();
1292
+ };
1293
+
1294
+ wrap.removeClass('fancybox-opened');
1295
+
1296
+ if (effect === 'elastic') {
1297
+ endPos.top = '+=200px';
1298
+ }
1299
+
1300
+ wrap.animate(endPos, {
1301
+ duration: effect === 'none' ? 0 : current.prevSpeed,
1302
+ easing: current.prevEasing,
1303
+ complete: cleanUp
1304
+ });
1305
+ }
1306
+ };
1307
+
1308
+ /*
1309
+ * Overlay helper
1310
+ */
1311
+
1312
+ F.helpers.overlay = {
1313
+ overlay: null,
1314
+
1315
+ update: function () {
1316
+ var width, scrollWidth, offsetWidth;
1317
+
1318
+ if (!isMobile) {
1319
+ //Reset width/height so it will not mess
1320
+ this.overlay.width(0).height(0);
1321
+ }
1322
+
1323
+ if ($.browser.msie) {
1324
+ scrollWidth = Math.max(document.documentElement.scrollWidth, document.body.scrollWidth);
1325
+ offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth);
1326
+
1327
+ width = scrollWidth < offsetWidth ? W.width() : scrollWidth;
1328
+
1329
+ } else {
1330
+ width = D.width();
1331
+ }
1332
+
1333
+ this.overlay.width(width).height(D.height());
1334
+ },
1335
+
1336
+ beforeShow: function (opts) {
1337
+ if (this.overlay) {
1338
+ return;
1339
+ }
1340
+
1341
+ opts = $.extend(true, {
1342
+ speedIn : 'fast',
1343
+ closeClick : true,
1344
+ opacity : 1,
1345
+ css : {
1346
+ background: 'black'
1347
+ }
1348
+ }, opts);
1349
+
1350
+ this.overlay = $('<div id="fancybox-overlay"></div>').css(opts.css).appendTo('body');
1351
+
1352
+ this.update();
1353
+
1354
+ if (opts.closeClick) {
1355
+ this.overlay.bind('click.fb', F.close);
1356
+ }
1357
+
1358
+ W.bind("resize.fb", $.proxy(this.update, this));
1359
+
1360
+ this.overlay.fadeTo(opts.speedIn, opts.opacity);
1361
+ },
1362
+
1363
+ onUpdate: function () {
1364
+ //Update as content may change document dimensions
1365
+ this.update();
1366
+ },
1367
+
1368
+ afterClose: function (opts) {
1369
+ if (this.overlay) {
1370
+ this.overlay.fadeOut(opts.speedOut || 0, function () {
1371
+ $(this).remove();
1372
+ });
1373
+ }
1374
+
1375
+ this.overlay = null;
1376
+ }
1377
+ };
1378
+
1379
+ /*
1380
+ * Title helper
1381
+ */
1382
+
1383
+ F.helpers.title = {
1384
+ beforeShow: function (opts) {
1385
+ var title, text = F.current.title;
1386
+
1387
+ if (text) {
1388
+ title = $('<div class="fancybox-title fancybox-title-' + opts.type + '-wrap">' + text + '</div>').appendTo('body');
1389
+
1390
+ if (opts.type === 'float') {
1391
+ //This helps for some browsers
1392
+ title.width(title.width());
1393
+
1394
+ title.wrapInner('<span class="child"></span>');
1395
+
1396
+ //Increase bottom margin so this title will also fit into viewport
1397
+ F.current.margin[2] += Math.abs(parseInt(title.css('margin-bottom'), 10));
1398
+ }
1399
+
1400
+ title.appendTo(opts.type === 'over' ? F.inner : (opts.type === 'outside' ? F.wrap : F.outer));
1401
+ }
1402
+ }
1403
+ };
1404
+
1405
+ // jQuery plugin initialization
1406
+ $.fn.fancybox = function (options) {
1407
+ var that = $(this),
1408
+ selector = this.selector || '',
1409
+ index,
1410
+ run = function(e) {
1411
+ var what = this, idx = index, relType, relVal;
1412
+
1413
+ if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey)) {
1414
+ e.preventDefault();
1415
+
1416
+ relType = options.groupAttr || 'data-fancybox-group';
1417
+ relVal = $(what).attr(relType);
1418
+
1419
+ if (!relVal) {
1420
+ relType = 'rel';
1421
+ relVal = what[ relType ];
1422
+ }
1423
+
1424
+ if (relVal && relVal !== '' && relVal !== 'nofollow') {
1425
+ what = selector.length ? $(selector) : that;
1426
+ what = what.filter('[' + relType + '="' + relVal + '"]');
1427
+ idx = what.index(this);
1428
+ }
1429
+
1430
+ options.index = idx;
1431
+
1432
+ F.open(what, options);
1433
+ }
1434
+ };
1435
+
1436
+ options = options || {};
1437
+ index = options.index || 0;
1438
+
1439
+ if (selector) {
1440
+ D.undelegate(selector, 'click.fb-start').delegate(selector, 'click.fb-start', run);
1441
+
1442
+ } else {
1443
+ that.unbind('click.fb-start').bind('click.fb-start', run);
1444
+ }
1445
+
1446
+ return this;
1447
+ };
1448
+
1449
+ }(window, document));
assets/fancyBox/source/jquery.fancybox.pack.js ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*! fancyBox v2.0.5 fancyapps.com | fancyapps.com/fancybox/#license */
2
+ (function(n,q,v){var d=n.jQuery,l=d(n),m=d(q),a=d.fancybox=function(){a.open.apply(this,arguments)},u=!1,r=q.createTouch!==v,s=function(a){return"string"===d.type(a)},t=function(a){return s(a)&&-1<a.indexOf("%")};d.extend(a,{version:"2.0.5",defaults:{padding:15,margin:20,width:800,height:600,minWidth:100,minHeight:100,maxWidth:9999,maxHeight:9999,autoSize:!0,autoResize:!r,autoCenter:!r,fitToView:!0,aspectRatio:!1,topRatio:0.5,fixed:!(d.browser.msie&&6>=d.browser.version)&&!r,scrolling:"auto",wrapCSS:"fancybox-default",
3
+ arrows:!0,closeBtn:!0,closeClick:!1,nextClick:!1,mouseWheel:!0,autoPlay:!1,playSpeed:3E3,preload:3,modal:!1,loop:!0,ajax:{dataType:"html",headers:{"X-fancyBox":!0}},keys:{next:[13,32,34,39,40],prev:[8,33,37,38],close:[27]},tpl:{wrap:'<div class="fancybox-wrap"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div>',image:'<img class="fancybox-image" src="{href}" alt="" />',iframe:'<iframe class="fancybox-iframe" name="fancybox-frame{rnd}" frameborder="0" hspace="0"'+(d.browser.msie?
4
+ ' allowtransparency="true"':"")+"></iframe>",swf:'<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="wmode" value="transparent" /><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="{href}" /><embed src="{href}" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="100%" height="100%" wmode="transparent"></embed></object>',error:'<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',
5
+ closeBtn:'<div title="Close" class="fancybox-item fancybox-close"></div>',next:'<a title="Next" class="fancybox-nav fancybox-next"><span></span></a>',prev:'<a title="Previous" class="fancybox-nav fancybox-prev"><span></span></a>'},openEffect:"fade",openSpeed:250,openEasing:"swing",openOpacity:!0,openMethod:"zoomIn",closeEffect:"fade",closeSpeed:250,closeEasing:"swing",closeOpacity:!0,closeMethod:"zoomOut",nextEffect:"elastic",nextSpeed:300,nextEasing:"swing",nextMethod:"changeIn",prevEffect:"elastic",
6
+ prevSpeed:300,prevEasing:"swing",prevMethod:"changeOut",helpers:{overlay:{speedIn:0,speedOut:300,opacity:0.8,css:{cursor:"pointer"},closeClick:!0},title:{type:"float"}}},group:{},opts:{},coming:null,current:null,isOpen:!1,isOpened:!1,wrap:null,outer:null,inner:null,player:{timer:null,isActive:!1},ajaxLoad:null,imgPreload:null,transitions:{},helpers:{},open:function(b,c){a.close(!0);b&&!d.isArray(b)&&(b=b instanceof d?d(b).get():[b]);a.isActive=!0;a.opts=d.extend(!0,{},a.defaults,c);d.isPlainObject(c)&&
7
+ c.keys!==v&&(a.opts.keys=c.keys?d.extend({},a.defaults.keys,c.keys):!1);a.group=b;a._start(a.opts.index||0)},cancel:function(){a.coming&&!1===a.trigger("onCancel")||(a.coming=null,a.hideLoading(),a.ajaxLoad&&a.ajaxLoad.abort(),a.ajaxLoad=null,a.imgPreload&&(a.imgPreload.onload=a.imgPreload.onabort=a.imgPreload.onerror=null))},close:function(b){a.cancel();a.current&&!1!==a.trigger("beforeClose")&&(a.unbindEvents(),!a.isOpen||b&&!0===b[0]?(d(".fancybox-wrap").stop().trigger("onReset").remove(),a._afterZoomOut()):
8
+ (a.isOpen=a.isOpened=!1,d(".fancybox-item, .fancybox-nav").remove(),a.wrap.stop(!0).removeClass("fancybox-opened"),a.inner.css("overflow","hidden"),a.transitions[a.current.closeMethod]()))},play:function(b){var c=function(){clearTimeout(a.player.timer)},g=function(){c();a.current&&a.player.isActive&&(a.player.timer=setTimeout(a.next,a.current.playSpeed))},e=function(){c();d("body").unbind(".player");a.player.isActive=!1;a.trigger("onPlayEnd")};if(a.player.isActive||b&&!1===b[0])e();else if(a.current&&
9
+ (a.current.loop||a.current.index<a.group.length-1))a.player.isActive=!0,d("body").bind({"afterShow.player onUpdate.player":g,"onCancel.player beforeClose.player":e,"beforeLoad.player":c}),g(),a.trigger("onPlayStart")},next:function(){a.current&&a.jumpto(a.current.index+1)},prev:function(){a.current&&a.jumpto(a.current.index-1)},jumpto:function(b){a.current&&(b=parseInt(b,10),1<a.group.length&&a.current.loop&&(b>=a.group.length?b=0:0>b&&(b=a.group.length-1)),a.group[b]!==v&&(a.cancel(),a._start(b)))},
10
+ reposition:function(b,c){a.isOpen&&(c&&"scroll"===c.type?a.wrap.stop().animate(a._getPosition(b),200):a.wrap.css(a._getPosition(b)))},update:function(b){a.isOpen&&(u||setTimeout(function(){var c=a.current;if(u&&(u=!1,c)){if(!b||b&&("orientationchange"===b.type||c.autoResize&&"resize"===b.type))c.autoSize&&"iframe"!==c.type&&(a.inner.height("auto"),c.height=a.inner.height()),a._setDimension(),c.canGrow&&"iframe"!==c.type&&a.inner.height("auto");c.autoCenter&&a.reposition(null,b);a.trigger("onUpdate")}},
11
+ 100),u=!0)},toggle:function(){a.isOpen&&(a.current.fitToView=!a.current.fitToView,a.update())},hideLoading:function(){m.unbind("keypress.fb");d("#fancybox-loading").remove()},showLoading:function(){a.hideLoading();m.bind("keypress.fb",function(b){27===b.keyCode&&(b.preventDefault(),a.cancel())});d('<div id="fancybox-loading"><div></div></div>').click(a.cancel).appendTo("body")},getViewport:function(){return{x:l.scrollLeft(),y:l.scrollTop(),w:n.innerWidth?n.innerWidth:l.width(),h:n.innerHeight?n.innerHeight:
12
+ l.height()}},unbindEvents:function(){a.wrap&&a.wrap.unbind(".fb");m.unbind(".fb");l.unbind(".fb")},bindEvents:function(){var b=a.current,c=b.keys;b&&(l.bind("resize.fb, orientationchange.fb",a.update),!b.fixed&&b.autoCenter&&l.bind("scroll.fb",a.update),c&&m.bind("keydown.fb",function(b){var e;!b.ctrlKey&&!b.altKey&&!b.shiftKey&&!b.metaKey&&0>d.inArray(b.target.tagName.toLowerCase(),["input","textarea","select","button"])&&!d(b.target).is("[contenteditable]")&&(e=b.keyCode,-1<d.inArray(e,c.close)?
13
+ (a.close(),b.preventDefault()):-1<d.inArray(e,c.next)?(a.next(),b.preventDefault()):-1<d.inArray(e,c.prev)&&(a.prev(),b.preventDefault()))}),d.fn.mousewheel&&b.mouseWheel&&1<a.group.length&&a.wrap.bind("mousewheel.fb",function(b,c){var d=b.target||null;if(0!==c&&(!d||0===d.clientHeight||d.scrollHeight===d.clientHeight&&d.scrollWidth===d.clientWidth))b.preventDefault(),a[0<c?"prev":"next"]()}))},trigger:function(b){var c,g=a[-1<d.inArray(b,["onCancel","beforeLoad","afterLoad"])?"coming":"current"];
14
+ if(g){d.isFunction(g[b])&&(c=g[b].apply(g,Array.prototype.slice.call(arguments,1)));if(!1===c)return!1;g.helpers&&d.each(g.helpers,function(c,f){if(f&&d.isPlainObject(a.helpers[c])&&d.isFunction(a.helpers[c][b]))a.helpers[c][b](f,g)});d.event.trigger(b+".fb")}},isImage:function(a){return s(a)&&a.match(/\.(jpg|gif|png|bmp|jpeg)(.*)?$/i)},isSWF:function(a){return s(a)&&a.match(/\.(swf)(.*)?$/i)},_start:function(b){var c={},g=a.group[b]||null,e,f,i;if(g&&(g.nodeType||g instanceof d))e=!0,d.metadata&&
15
+ (c=d(g).metadata());c=d.extend(!0,{},a.opts,{index:b,element:g},d.isPlainObject(g)?g:c);d.each(["href","title","content","type"],function(b,f){c[f]=a.opts[f]||e&&d(g).attr(f)||c[f]||null});"number"===typeof c.margin&&(c.margin=[c.margin,c.margin,c.margin,c.margin]);c.modal&&d.extend(!0,c,{closeBtn:!1,closeClick:!1,nextClick:!1,arrows:!1,mouseWheel:!1,keys:null,helpers:{overlay:{css:{cursor:"auto"},closeClick:!1}}});a.coming=c;if(!1===a.trigger("beforeLoad"))a.coming=null;else{f=c.type;b=c.href||g;
16
+ f||(e&&(i=d(g).data("fancybox-type"),!i&&g.className&&(f=(i=g.className.match(/fancybox\.(\w+)/))?i[1]:null)),!f&&s(b)&&(a.isImage(b)?f="image":a.isSWF(b)?f="swf":b.match(/^#/)&&(f="inline")),f||(f=e?"inline":"html"),c.type=f);if("inline"===f||"html"===f){if(c.content||(c.content="inline"===f?d(s(b)?b.replace(/.*(?=#[^\s]+$)/,""):b):g),!c.content||!c.content.length)f=null}else b||(f=null);"ajax"===f&&s(b)&&(i=b.split(/\s+/,2),b=i.shift(),c.selector=i.shift());c.href=b;c.group=a.group;c.isDom=e;"image"===
17
+ f?a._loadImage():"ajax"===f?a._loadAjax():f?a._afterLoad():a._error("type")}},_error:function(b){a.hideLoading();d.extend(a.coming,{type:"html",autoSize:!0,minHeight:0,hasError:b,content:a.coming.tpl.error});a._afterLoad()},_loadImage:function(){var b=a.imgPreload=new Image;b.onload=function(){this.onload=this.onerror=null;a.coming.width=this.width;a.coming.height=this.height;a._afterLoad()};b.onerror=function(){this.onload=this.onerror=null;a._error("image")};b.src=a.coming.href;b.width||a.showLoading()},
18
+ _loadAjax:function(){a.showLoading();a.ajaxLoad=d.ajax(d.extend({},a.coming.ajax,{url:a.coming.href,error:function(b,c){a.coming&&"abort"!==c?a._error("ajax",b):a.hideLoading()},success:function(b,c){"success"===c&&(a.coming.content=b,a._afterLoad())}}))},_preloadImages:function(){var b=a.group,c=a.current,g=b.length,e,f,i,h=Math.min(c.preload,g-1);if(c.preload&&!(2>b.length))for(i=1;i<=h;i+=1)if(e=b[(c.index+i)%g],f=d(e).attr("href")||e,"image"===e.type||a.isImage(f))(new Image).src=f},_afterLoad:function(){a.hideLoading();
19
+ !a.coming||!1===a.trigger("afterLoad",a.current)?a.coming=!1:(a.isOpened?(d(".fancybox-item").remove(),a.wrap.stop(!0).removeClass("fancybox-opened"),a.inner.css("overflow","hidden"),a.transitions[a.current.prevMethod]()):(d(".fancybox-wrap").stop().trigger("onReset").remove(),a.trigger("afterClose")),a.unbindEvents(),a.isOpen=!1,a.current=a.coming,a.wrap=d(a.current.tpl.wrap).addClass("fancybox-"+(r?"mobile":"desktop")+" fancybox-type-"+a.current.type+" fancybox-tmp "+a.current.wrapCSS).appendTo("body"),
20
+ a.outer=d(".fancybox-outer",a.wrap).css("padding",a.current.padding+"px"),a.inner=d(".fancybox-inner",a.wrap),a._setContent())},_setContent:function(){var b=a.current,c=b.content,g=b.type,e;e=b.minWidth;var f=b.minHeight,i=b.maxWidth,h=b.maxHeight;switch(g){case "inline":case "ajax":case "html":b.selector?c=d("<div>").html(c).find(b.selector):c instanceof d&&(c.parent().hasClass("fancybox-inner")&&c.parents(".fancybox-wrap").unbind("onReset"),c=c.show().detach(),d(a.wrap).bind("onReset",function(){c.appendTo("body").hide()}));
21
+ b.autoSize&&(e=d('<div class="fancybox-wrap '+a.current.wrapCSS+' fancybox-tmp"></div>').appendTo("body").css({minWidth:t(e)?e:e+"px",minHeight:t(f)?f:f+"px",maxWidth:t(i)?i:i+"px",maxHeight:t(h)?h:h+"px"}).append(c),b.width=e.width(),b.height=e.height(),e.width(a.current.width),e.height()>b.height&&(e.width(b.width+1),b.width=e.width(),b.height=e.height()),c=e.contents().detach(),e.remove());break;case "image":c=b.tpl.image.replace("{href}",b.href);b.aspectRatio=!0;break;case "swf":c=b.tpl.swf.replace(/\{width\}/g,
22
+ b.width).replace(/\{height\}/g,b.height).replace(/\{href\}/g,b.href);break;case "iframe":c=d(b.tpl.iframe.replace("{rnd}",(new Date).getTime())).attr("scrolling",b.scrolling).attr("src",b.href),b.scrolling=r?"scroll":"auto"}if("image"===g||"swf"===g)b.autoSize=!1,b.scrolling="visible";"iframe"===g&&b.autoSize?(a.showLoading(),a.inner.width(b.width).height(b.height).css("overflow",b.scrolling),c.bind({onCancel:function(){d(this).unbind();a._afterZoomOut()},load:function(){a.hideLoading();try{this.contentWindow.document.location&&
23
+ (a.current.height=d(this).contents().find("body").height())}catch(b){a.current.autoSize=!1}a.isOpened?a.update():a._beforeShow()}}).appendTo(a.inner)):(a.inner.append(c),a._beforeShow())},_beforeShow:function(){a.coming=null;a.trigger("beforeShow");a._setDimension();a.wrap.hide().removeClass("fancybox-tmp");a.bindEvents();a._preloadImages();a.transitions[a.isOpened?a.current.nextMethod:a.current.openMethod]()},_setDimension:function(){var b=a.wrap,c=a.outer,g=a.inner,e=a.current,f=a.getViewport(),
24
+ i=e.margin,h=2*e.padding,j=e.width,k=e.height,l=e.maxWidth+h,o=e.maxHeight+h,m=e.minWidth+h,n=e.minHeight+h,p;f.w-=i[1]+i[3];f.h-=i[0]+i[2];t(j)&&(j=(f.w-h)*parseFloat(j)/100);t(k)&&(k=(f.h-h)*parseFloat(k)/100);i=j/k;j+=h;k+=h;e.fitToView&&(l=Math.min(f.w,l),o=Math.min(f.h,o));if(e.aspectRatio){if(j>l&&(j=l,k=(j-h)/i+h),k>o&&(k=o,j=(k-h)*i+h),j<m&&(j=m,k=(j-h)/i+h),k<n)k=n,j=(k-h)*i+h}else j=Math.max(m,Math.min(j,l)),k=Math.max(n,Math.min(k,o));j=Math.round(j);k=Math.round(k);d(b.add(c).add(g)).width("auto").height("auto");
25
+ g.width(j-h).height(k-h);b.width(j);p=b.height();if(j>l||p>o)for(;(j>l||p>o)&&j>m&&p>n;)k-=10,e.aspectRatio?(j=Math.round((k-h)*i+h),j<m&&(j=m,k=(j-h)/i+h)):j-=10,g.width(j-h).height(k-h),b.width(j),p=b.height();e.dim={width:j,height:p};e.canGrow=e.autoSize&&k>n&&k<o;e.canShrink=!1;e.canExpand=!1;if(j-h<e.width||k-h<e.height)e.canExpand=!0;else if((j>f.w||p>f.h)&&j>m&&k>n)e.canShrink=!0;b=p-h;a.innerSpace=b-g.height();a.outerSpace=b-c.height()},_getPosition:function(b){var c=a.current,d=a.getViewport(),
26
+ e=c.margin,f=a.wrap.width()+e[1]+e[3],i=a.wrap.height()+e[0]+e[2],h={position:"absolute",top:e[0]+d.y,left:e[3]+d.x};if(c.autoCenter&&c.fixed&&(!b||!1===b[0])&&i<=d.h&&f<=d.w)h={position:"fixed",top:e[0],left:e[3]};h.top=Math.ceil(Math.max(h.top,h.top+(d.h-i)*c.topRatio))+"px";h.left=Math.ceil(Math.max(h.left,h.left+0.5*(d.w-f)))+"px";return h},_afterZoomIn:function(){var b=a.current,c=b?b.scrolling:"no";if(b&&(a.isOpen=a.isOpened=!0,a.wrap.addClass("fancybox-opened").css("overflow","visible"),a.inner.css("overflow",
27
+ "yes"===c?"scroll":"no"===c?"hidden":c),(b.closeClick||b.nextClick)&&a.inner.css("cursor","pointer").bind("click.fb",function(c){if(!d(c.target).is("a")&&!d(c.target).parent().is("a"))a[b.closeClick?"close":"next"]()}),b.closeBtn&&d(b.tpl.closeBtn).appendTo(a.outer).bind("click.fb",a.close),b.arrows&&1<a.group.length&&((b.loop||0<b.index)&&d(b.tpl.prev).appendTo(a.inner).bind("click.fb",a.prev),(b.loop||b.index<a.group.length-1)&&d(b.tpl.next).appendTo(a.inner).bind("click.fb",a.next)),a.trigger("afterShow"),
28
+ a.update(),a.opts.autoPlay&&!a.player.isActive))a.opts.autoPlay=!1,a.play()},_afterZoomOut:function(){a.trigger("afterClose");a.wrap.trigger("onReset").remove();d.extend(a,{group:{},opts:{},current:null,isActive:!1,isOpened:!1,isOpen:!1,wrap:null,outer:null,inner:null})}});a.transitions={getOrigPosition:function(){var b=a.current,c=b.element,g=b.padding,e=d(b.orig),f={},i=50,h=50;!e.length&&b.isDom&&d(c).is(":visible")&&(e=d(c).find("img:first"),e.length||(e=d(c)));e.length?(f=e.offset(),e.is("img")&&
29
+ (i=e.outerWidth(),h=e.outerHeight())):(b=a.getViewport(),f.top=b.y+0.5*(b.h-h),f.left=b.x+0.5*(b.w-i));return f={top:Math.ceil(f.top-g)+"px",left:Math.ceil(f.left-g)+"px",width:Math.ceil(i+2*g)+"px",height:Math.ceil(h+2*g)+"px"}},step:function(b,c){var d,e,f;if("width"===c.prop||"height"===c.prop)e=f=Math.ceil(b-2*a.current.padding),"height"===c.prop&&(d=(b-c.start)/(c.end-c.start),c.start>c.end&&(d=1-d),e-=a.innerSpace*d,f-=a.outerSpace*d),a.inner[c.prop](e),a.outer[c.prop](f)},zoomIn:function(){var b=
30
+ a.wrap,c=a.current,g=c.openEffect,e="elastic"===g,f=d.extend({},c.dim,a._getPosition(e)),i=d.extend({opacity:1},f);delete i.position;e?(f=this.getOrigPosition(),c.openOpacity&&(f.opacity=0),a.outer.add(a.inner).width("auto").height("auto")):"fade"===g&&(f.opacity=0);b.css(f).show().animate(i,{duration:"none"===g?0:c.openSpeed,easing:c.openEasing,step:e?this.step:null,complete:a._afterZoomIn})},zoomOut:function(){var b=a.wrap,c=a.current,d=c.openEffect,e="elastic"===d,f={opacity:0};e&&("fixed"===b.css("position")&&
31
+ b.css(a._getPosition(!0)),f=this.getOrigPosition(),c.closeOpacity&&(f.opacity=0));b.animate(f,{duration:"none"===d?0:c.closeSpeed,easing:c.closeEasing,step:e?this.step:null,complete:a._afterZoomOut})},changeIn:function(){var b=a.wrap,c=a.current,d=c.nextEffect,e=a._getPosition("elastic"===d),f={opacity:1};"elastic"===d&&(e.top=parseInt(e.top,10)-200+"px",f.top="+=200px",e.opacity=0);b.css(e).show().animate(f,{duration:"none"===d?0:c.nextSpeed,easing:c.nextEasing,complete:function(){setTimeout(a._afterZoomIn,
32
+ 1)}})},changeOut:function(){var b=a.wrap,c=a.current,g=c.nextEffect,e={opacity:0};b.removeClass("fancybox-opened");"elastic"===g&&(e.top="+=200px");b.animate(e,{duration:"none"===g?0:c.prevSpeed,easing:c.prevEasing,complete:function(){d(this).trigger("onReset").remove()}})}};a.helpers.overlay={overlay:null,update:function(){var a,c;r||this.overlay.width(0).height(0);d.browser.msie?(a=Math.max(q.documentElement.scrollWidth,q.body.scrollWidth),c=Math.max(q.documentElement.offsetWidth,q.body.offsetWidth),
33
+ a=a<c?l.width():a):a=m.width();this.overlay.width(a).height(m.height())},beforeShow:function(b){this.overlay||(b=d.extend(!0,{speedIn:"fast",closeClick:!0,opacity:1,css:{background:"black"}},b),this.overlay=d('<div id="fancybox-overlay"></div>').css(b.css).appendTo("body"),this.update(),b.closeClick&&this.overlay.bind("click.fb",a.close),l.bind("resize.fb",d.proxy(this.update,this)),this.overlay.fadeTo(b.speedIn,b.opacity))},onUpdate:function(){this.update()},afterClose:function(a){this.overlay&&
34
+ this.overlay.fadeOut(a.speedOut||0,function(){d(this).remove()});this.overlay=null}};a.helpers.title={beforeShow:function(b){var c;if(c=a.current.title)c=d('<div class="fancybox-title fancybox-title-'+b.type+'-wrap">'+c+"</div>").appendTo("body"),"float"===b.type&&(c.width(c.width()),c.wrapInner('<span class="child"></span>'),a.current.margin[2]+=Math.abs(parseInt(c.css("margin-bottom"),10))),c.appendTo("over"===b.type?a.inner:"outside"===b.type?a.wrap:a.outer)}};d.fn.fancybox=function(b){var c=d(this),
35
+ g=this.selector||"",e,f=function(f){var h=this,j=e,k;!f.ctrlKey&&!f.altKey&&!f.shiftKey&&!f.metaKey&&(f.preventDefault(),f=b.groupAttr||"data-fancybox-group",k=d(h).attr(f),k||(f="rel",k=h[f]),k&&""!==k&&"nofollow"!==k&&(h=g.length?d(g):c,h=h.filter("["+f+'="'+k+'"]'),j=h.index(this)),b.index=j,a.open(h,b))},b=b||{};e=b.index||0;g?m.undelegate(g,"click.fb-start").delegate(g,"click.fb-start",f):c.unbind("click.fb-start").bind("click.fb-start",f);return this}})(window,document);
assets/hmbkp.css CHANGED
@@ -1,9 +1,6 @@
1
- #icon-backupwordpress.icon32 { background: url(icon_backupwordpress_32x32.png); }
2
- .hmbkp_running .add-new-h2 img { margin: 0 3px -4px -6px; opacity: 0.3; }
3
- .add-new-h2[disabled="disabled"], add-new-h2[disabled="disabled"]:hover, .add-new-h2[disabled="disabled"]:active, .add-new-h2[disabled="disabled"]:focus { cursor: default; color: #666; }
4
  tfoot p { margin: 0; font-weight: normal; }
5
- #hmbkp-settings { display: none; }
6
- #hmbkp-settings.show_form { display: block; }
7
  #hmbkp-constants dl { overflow: hidden; margin: 20px 0; }
8
  #hmbkp-constants dt { float: left; min-width: 250px; clear: both; padding: 6px; margin: 1px 0; cursor: pointer; }
9
  #hmbkp-constants dd { color: #666; padding: 7px 0 7px 250px; border-top: 1px solid #DFDFDF; margin: 0; cursor: pointer; min-height: 40px; }
@@ -14,10 +11,71 @@ tfoot p { margin: 0; font-weight: normal; }
14
  #hmbkp-constants dt:not(.hmbkp_active):hover + dd, #hmbkp-constants dt:not(.hmbkp_active) + dd:hover { background-color: #FFF; }
15
  #hmbkp-constants dd:hover p, #hmbkp-constants dt:hover + dd p { display: none; }
16
  #hmbkp-constants dd:hover .example, #hmbkp-constants dt:hover + dd .example { display: inline; }
17
- .hmbkp_manage_backups_row .delete { color: #BC0B0B; }
18
- .hmbkp_manage_backups_row .delete:hover { color: red; }
19
  .completed th, .completed td { background-color: #FFFFE0; }
20
  .hmbkp_active:before { content: "\00a0 \2713 "; font-size: 11px; }
21
  .hmbkp_active, .hmbkp_active code, #hmbkp-constants .hmbkp_active + dd { background: #E5F7E8; }
22
  .contextual-help-tabs-wrap .updated { margin: 15px 0 0; }
23
- #hmbkp_backup.hmbkp_running { background-image: url('../../../../wp-admin/images/wpspin_light.gif'); background-repeat: no-repeat; background-position: 2px 2px; padding-left: 20px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #icon-backupwordpress.icon32 { background: url(icon_backupwordpress_32x32.png); }
2
+
 
3
  tfoot p { margin: 0; font-weight: normal; }
 
 
4
  #hmbkp-constants dl { overflow: hidden; margin: 20px 0; }
5
  #hmbkp-constants dt { float: left; min-width: 250px; clear: both; padding: 6px; margin: 1px 0; cursor: pointer; }
6
  #hmbkp-constants dd { color: #666; padding: 7px 0 7px 250px; border-top: 1px solid #DFDFDF; margin: 0; cursor: pointer; min-height: 40px; }
11
  #hmbkp-constants dt:not(.hmbkp_active):hover + dd, #hmbkp-constants dt:not(.hmbkp_active) + dd:hover { background-color: #FFF; }
12
  #hmbkp-constants dd:hover p, #hmbkp-constants dt:hover + dd p { display: none; }
13
  #hmbkp-constants dd:hover .example, #hmbkp-constants dt:hover + dd .example { display: inline; }
14
+
 
15
  .completed th, .completed td { background-color: #FFFFE0; }
16
  .hmbkp_active:before { content: "\00a0 \2713 "; font-size: 11px; }
17
  .hmbkp_active, .hmbkp_active code, #hmbkp-constants .hmbkp_active + dd { background: #E5F7E8; }
18
  .contextual-help-tabs-wrap .updated { margin: 15px 0 0; }
19
+
20
+ .subsubsub { width: 100%; margin: 20px 0px 0px 0px; border-bottom: 1px solid #EEE; }
21
+ .subsubsub li + li::before { content: "| "; }
22
+ .subsubsub .add-new-h2 { top: 0; }
23
+
24
+ .ui-tabs-nav .ui-tabs-selected a, .ui-tabs-nav .ui-state-active a { font-weight: bold; color: #000; }
25
+ .hmbkp_schedule { clear: both; overflow: hidden; }
26
+
27
+ .fancybox-inner { overflow-x: hidden !important; }
28
+ .fancybox-inner fieldset { max-width: 100%; }
29
+ .hmbkp-form fieldset { float: left; }
30
+ .js .hmbkp-form fieldset + fieldset { display: none; margin-right: -100%; }
31
+
32
+ .hmbkp-form label { display: block; line-height: 25px; padding-bottom: 20px; border-bottom: 1px dotted #CCC; margin-bottom: 20px; width: 320px; position: relative; }
33
+
34
+ .hmbkp-form legend { padding: 0 0 20px; font-size: 1.17em; font-weight: bold; }
35
+ .hmbkp-form label > * { float: right; }
36
+ .hmbkp-form label.hidden { display: none; }
37
+ .hmbkp-form label > input, .hmbkp-form label > select { min-width: 200px; }
38
+ .hmbkp-form label .description { line-height: 16px; margin-top: 10px; float: none; }
39
+ .hmbkp-form p.submit { margin: 20px 0 0; padding: 0; }
40
+ .hmbkp-form .button-primary { float: right; }
41
+ .hmbkp-form [type="number"] { min-width: 40px; width: 40px; }
42
+ .hmbkp-error span { position: absolute; top: -18px; left: 0; color: red; }
43
+ .hmbkp-error input[type], .hmbkp-error select { border-color: red; }
44
+
45
+ .hmbkp-form ul { width: 320px; overflow: hidden; }
46
+ .hmbkp-form ul.hmbkp_file_list { background-color: #FFF; max-height: 200px; overflow-y: scroll; display: block; border-radius: 4px; box-sizing: border-box; clear: both; box-shadow: inset 0px 0px 2px #CCC; font-size: 11px; }
47
+ .hmbkp_file_list li { margin: 0; padding: 5px; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 16px; }
48
+ .hmbkp_file_list li + li { border-top: 1px dotted #CCC; }
49
+
50
+ .hmbkp-schedule-sentence { margin: 0; font-size: 16px; font-weight: lighter; margin: 30px 0 10px; clear: both; margin-left: 10px; }
51
+ .hmbkp-schedule-sentence::before { content: "\2714"; margin-right: 10px; width: 16px; height: 47px; display: block; float: left; }
52
+ .hmbkp-schedule-sentence.hmbkp-running::before { background-image: url('wpspin_light.gif'); background-repeat: no-repeat; margin-right: 10px; content: " "; }
53
+ .hmbkp-schedule-sentence .hmbkp-status { display: block; font-size: 12px; color: #666; margin: 2px 0 0 26px; }
54
+ .hmbkp-schedule-sentence [title] { border-bottom: 1px dotted #CCC; cursor: help; }
55
+
56
+ .hmbkp-schedule-sentence .hmbkp-schedule-actions { visibility: visible; }
57
+ .hmbkp-schedule-actions { font-size: 12px; font-weight: normal; margin: 0 0 0 26px; }
58
+
59
+ button.hmbkp-ajax-loading { padding-left: 20px; }
60
+ button.hmbkp-ajax-loading::before { background-image: url('wpspin_light.gif'); background-repeat: no-repeat; background-position: 1px -1px; margin-left: -20px; display: inline-block; width: 16px; height: 16px; content: " "; vertical-align: middle; padding-right: 3px; }
61
+
62
+ button { height: 14px; }
63
+
64
+ .delete-action { color: #BC0B0B; }
65
+ .delete-action:hover .delete-action:focus { color: red; }
66
+
67
+ label[for="hmbkp-new-exclude-rule"] { overflow: hidden; }
68
+ .hmbkp_preview_exclude_rule { float: right; margin-top: 1px; }
69
+ .hmbkp_preview_exclude_rule.hmbkp-ajax-loading { width: 44px; }
70
+ div.hmbkp_add_exclude_rule { display: block; line-height: 25px; width: 320px; overflow: hidden; }
71
+ div.hmbkp_add_exclude_rule input { min-width: 240px; float: left; }
72
+ .hmbkp_preview_exclude_rule { float: right; width: 56px; }
73
+ .hmbkp_save_exclude_rule, .hmbkp_cancel_save_exclude_rule { float: right; }
74
+
75
+ .hmbkp-exclude-preview-open table, .hmbkp-exclude-preview-open .hmbkp-tabs, .hmbkp-exclude-preview-open p.submit { display: none; }
76
+ .hmbkp-exclude-preview-open .hmbkp_add_exclude_rule { margin: 0; }
77
+
78
+ table.widefat tbody td { padding: 8px 7px; }
79
+ .hmbkp-edit-schedule-excludes-form td a, .hmbkp-edit-schedule-excludes-form td span.reason { float: right; }
80
+ .hmbkp-edit-schedule-excludes-form td span.reason { color: #CCC; }
81
+ input[type="datetime-local"] { border-radius: 3px; border-width: 1px; border-style: solid; box-sizing: border-box; border-color: #DFDFDF; background-color: white; }
assets/hmbkp.js CHANGED
@@ -1,70 +1,337 @@
1
  jQuery( document ).ready( function( $ ) {
2
 
3
- if ( $( '.hmbkp_running' ).size() ) {
4
- hmbkpRedirectOnBackupComplete();
5
- }
6
 
7
- if ( $( '.hmbkp_estimated-size .calculate' ).size() ) {
8
- $.get( ajaxurl, { 'action' : 'hmbkp_calculate' },
9
- function( data ) {
10
- $( '.hmbkp_estimated-size .calculate' ).fadeOut( function() {
11
- $( this ).empty().append( data );
12
- } ).fadeIn();
13
- }
14
- );
15
- }
16
 
17
- $.get( ajaxurl, { 'action' : 'hmbkp_cron_test' },
18
- function( data ) {
19
- if ( data != 1 ) {
20
- $( '.wrap > h2' ).after( data );
21
- }
22
- }
23
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
 
25
- $( '#hmbkp_backup:not(.hmbkp_running)' ).live( 'click', function( e ) {
 
 
 
 
 
26
 
27
- $.ajaxSetup( { 'cache' : false } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- ajaxRequest = $.get( ajaxurl, { 'action' : 'hmbkp_backup' } );
 
30
 
31
- $( this ).text( 'Starting Backup' ).addClass( 'hmbkp_running' );
32
 
33
- setTimeout( function() {
 
 
 
 
 
 
 
 
34
 
35
- ajaxRequest.abort();
36
 
37
- hmbkpRedirectOnBackupComplete();
 
38
 
39
- }, 500 );
40
 
41
  e.preventDefault();
42
 
 
 
 
 
 
 
 
 
 
 
43
  } );
44
 
45
- $( '.hmbkp-settings-toggle' ).click( function( e ) {
 
 
 
 
46
 
47
- $( '#hmbkp-settings' ).toggle();
 
 
 
 
 
 
 
48
 
49
  e.preventDefault();
50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  } );
52
 
53
- if ( typeof( screenMeta ) != 'undefined' ) {
54
- $( '.hmbkp-show-help-tab' ).click( screenMeta.toggleEvent );
55
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
 
57
- if ( window.location.hash == '#hmbkp-settings' ){
58
- $( '#hmbkp-settings' ).show();
 
 
 
 
 
59
  }
60
 
 
 
61
 
62
- } );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
 
64
- function hmbkpRedirectOnBackupComplete() {
 
 
 
 
 
 
65
 
66
- jQuery.get( ajaxurl, { 'action' : 'hmbkp_is_in_progress' },
67
 
 
 
 
68
  function( data ) {
69
 
70
  if ( data == 0 ) {
@@ -73,9 +340,9 @@ function hmbkpRedirectOnBackupComplete() {
73
 
74
  } else {
75
 
76
- setTimeout( 'hmbkpRedirectOnBackupComplete();', 1000 );
77
 
78
- jQuery( '#hmbkp_backup' ).replaceWith( data );
79
 
80
  }
81
  }
1
  jQuery( document ).ready( function( $ ) {
2
 
3
+ // Don't ever cache ajax requests
4
+ $.ajaxSetup( { 'cache' : false } );
 
5
 
6
+ // Remove the loading class when ajax requests complete
7
+ $( document ).ajaxComplete( function() {
8
+ $( '.hmbkp-ajax-loading' ).removeClass( 'hmbkp-ajax-loading' );
9
+ } );
 
 
 
 
 
10
 
11
+ // Setup the tabs
12
+ $( '.hmbkp-tabs' ).tabs();
13
+
14
+ // Set the first tab to be active
15
+ if ( ! $( '.subsubsub a.current' ).size() )
16
+ $( '.subsubsub li:first a').addClass( 'current' );
17
+
18
+ // Initialize fancybox
19
+ $( '.fancybox' ).fancybox( {
20
+
21
+ 'modal' : true,
22
+ 'type' : 'ajax',
23
+ 'maxWidth' : 320,
24
+ 'afterShow' : function() {
25
+
26
+ $( '.hmbkp-tabs' ).tabs();
27
+
28
+ if ( $( '.hmbkp-form p.submit:contains(\'Update\')' ).size() )
29
+ $( '<button type="button" class="button-secondary hmbkp_cancel">' + objectL10n.cancel + '</button></p>' ).appendTo( '.hmbkp-form p.submit' );
30
+
31
+ $( '.hmbkp_cancel' ).click( function() {
32
+ $.fancybox.close();
33
+ } );
34
+
35
+ }
36
+
37
+ } );
38
+
39
+ // Show delete confirm message for delete schedule
40
+ $( document ).on( 'click', '.hmbkp-schedule-actions .delete-action', function( e ) {
41
+
42
+ if ( ! confirm( objectL10n.delete_schedule ) )
43
+ e.preventDefault();
44
+
45
+ } );
46
+
47
+ // Show delete confirm message for delete backup
48
+ $( document ).on( 'click', '.hmbkp_manage_backups_row .delete-action', function( e ) {
49
+
50
+ if ( ! confirm( objectL10n.delete_backup ) )
51
+ e.preventDefault();
52
+
53
+ } );
54
+
55
+ // Show delete confirm message for remove exclude rule
56
+ $( document ).on( 'click', '.hmbkp-edit-schedule-excludes-form .delete-action', function( e ) {
57
+
58
+ if ( ! confirm( objectL10n.remove_exclude_rule ) )
59
+ e.preventDefault();
60
+
61
+ } );
62
+
63
+ // Preview exclude rule
64
+ $( document ).on( 'click', '.hmbkp_preview_exclude_rule', function() {
65
+
66
+ if ( ! $( '.hmbkp_add_exclude_rule input' ).val() ) {
67
+ $( '.hmbkp_add_exclude_rule ul' ).remove();
68
+ $( '.hmbkp_add_exclude_rule p' ).remove();
69
+ return;
70
+ }
71
+
72
+ $( this ).addClass( 'hmbkp-ajax-loading' );
73
+
74
+ $.post(
75
+ ajaxurl,
76
+ { 'action' : 'hmbkp_file_list', 'hmbkp_schedule_excludes' : $( '.hmbkp_add_exclude_rule input' ).val(), 'hmbkp_schedule_id' : $( '[name="hmbkp_schedule_id"]' ).val(), 'hmbkp_file_method' : 'get_excluded_files' },
77
+ function( data ) {
78
+
79
+ $( '.hmbkp_add_exclude_rule ul' ).remove();
80
+ $( '.hmbkp_add_exclude_rule p' ).remove();
81
+
82
+ if ( data.indexOf( 'hmbkp_file_list' ) != -1 )
83
+ $( '.hmbkp_add_exclude_rule' ).append( data );
84
+
85
+ else
86
+ $( '.hmbkp_add_exclude_rule' ).append( '<p>There was an error previewing the exclude rule.</p>' );
87
+
88
+ $( '.hmbkp-edit-schedule-excludes-form' ).addClass( 'hmbkp-exclude-preview-open' );
89
+
90
+ }
91
+ ).error( function() {
92
+
93
+
94
+
95
+ } );
96
+
97
+ } );
98
+
99
+ // Fire the preview button when the enter key is pressed in the preview input
100
+ $( document ).on( 'keypress', '.hmbkp_add_exclude_rule input', function( e ) {
101
+
102
+ if ( ! $( '.hmbkp_add_exclude_rule input' ).val() )
103
+ return true;
104
+
105
+ var code = ( e.keyCode ? e.keyCode : e.which );
106
+
107
+ if ( code != 13 )
108
+ return true;
109
+
110
+ $( '.hmbkp_preview_exclude_rule' ).click();
111
+
112
+ e.preventDefault();
113
+
114
+ } );
115
+
116
+ // Cancel add exclude rule
117
+ $( document ).on( 'click', '.hmbkp_cancel_save_exclude_rule, .hmbkp-edit-schedule-excludes-form .submit button', function() {
118
+
119
+ $( '.hmbkp_add_exclude_rule ul' ).remove();
120
+ $( '.hmbkp_add_exclude_rule p' ).remove();
121
+
122
+ $( '.hmbkp-edit-schedule-excludes-form' ).removeClass( 'hmbkp-exclude-preview-open' );
123
+
124
+ } );
125
+
126
+ // Toggle additional fieldsets on
127
+ $( document ).on( 'click', '.hmbkp-toggle-fieldset', function() {
128
+
129
+ // Get the current fieldset
130
+ var fromFieldset = 'fieldset.' + $( this ).closest( 'fieldset' ).attr( 'class' );
131
+ var toFieldset = 'fieldset.' + $( this ).attr( 'data-hmbkp-fieldset' );
132
+
133
+ // Show the one we are moving too
134
+ $( toFieldset ).show().find( 'p.submit button' ).data( 'hmbkp-previous-fieldset', fromFieldset );
135
 
136
+ // Animate
137
+ $( fromFieldset ).animate( {
138
+ marginLeft : '-100%'
139
+ }, 'fast', function() {
140
+ $( this ).hide();
141
+ } );
142
 
143
+ } );
144
+
145
+ // Toggle additional fieldsets off
146
+ $( document ).on( 'click', '.hmbkp-form fieldset + fieldset p.submit button', function() {
147
+
148
+ // Get the current fieldset
149
+ var fromFieldset = 'fieldset.' + $( this ).closest( 'fieldset' ).attr( 'class' );
150
+ var toFieldset = $( this ).data( 'hmbkp-previous-fieldset' );
151
+
152
+ // Show the one we are moving too
153
+ $( toFieldset ).show();
154
+
155
+ $( toFieldset ).animate( {
156
+ marginLeft : '0'
157
+ }, 'fast', function() {
158
+ $( fromFieldset ).hide();
159
+ }
160
+ );
161
+
162
+ } );
163
 
164
+ // Add exclude rule
165
+ $( document ).on( 'click', '.hmbkp_save_exclude_rule', function() {
166
 
167
+ $( this ).addClass( 'hmbkp-ajax-loading' );
168
 
169
+ $.post(
170
+ ajaxurl,
171
+ { 'action' : 'hmbkp_add_exclude_rule', 'hmbkp_exclude_rule' : $( '.hmbkp_add_exclude_rule input' ).val(), 'hmbkp_schedule_id' : $( '[name="hmbkp_schedule_id"]' ).val() },
172
+ function( data ) {
173
+ $( '.hmbkp-edit-schedule-excludes-form' ).replaceWith( data );
174
+ $( '.hmbkp-edit-schedule-excludes-form' ).show();
175
+ $( '.hmbkp-tabs' ).tabs();
176
+ }
177
+ );
178
 
179
+ } );
180
 
181
+ // Remove exclude rule
182
+ $( document ).on( 'click', '.hmbkp-edit-schedule-excludes-form td a', function( e ) {
183
 
184
+ $( this ).addClass( 'hmbkp-ajax-loading' );
185
 
186
  e.preventDefault();
187
 
188
+ $.post(
189
+ ajaxurl,
190
+ { 'action' : 'hmbkp_delete_exclude_rule', 'hmbkp_exclude_rule' : $( this ).closest( 'td' ).attr( 'data-hmbkp-exclude-rule' ), 'hmbkp_schedule_id' : $( '[name="hmbkp_schedule_id"]' ).val() },
191
+ function( data ) {
192
+ $( '.hmbkp-edit-schedule-excludes-form' ).replaceWith( data );
193
+ $( '.hmbkp-edit-schedule-excludes-form' ).show();
194
+ $( '.hmbkp-tabs' ).tabs();
195
+ }
196
+ );
197
+
198
  } );
199
 
200
+ // Edit schedule form submit
201
+ $( document ).on( 'submit', 'form.hmbkp-form', function( e ) {
202
+
203
+ isNewSchedule = $( this ).closest( 'form' ).attr( 'data-schedule-action' ) == 'add' ? true : false;
204
+ scheduleId = $( this ).closest( 'form' ).find( '[name="hmbkp_schedule_id"]' ).val();
205
 
206
+ // Warn that backups will be deleted if max backups has been set to less than the number of backups currently stored
207
+ if ( ! isNewSchedule && Number( $( 'input[name="hmbkp_schedule_max_backups"]' ).val() ) < Number( $( '.hmbkp_manage_backups_row' ).size() ) && ! confirm( objectL10n.remove_old_backups ) )
208
+ return false;
209
+
210
+ $( this ).find( 'button[type="submit"]' ).addClass( 'hmbkp-ajax-loading' );
211
+
212
+ $( '.hmbkp-error span' ).remove();
213
+ $( '.hmbkp-error' ).removeClass( 'hmbkp-error' );
214
 
215
  e.preventDefault();
216
 
217
+ $.post(
218
+ ajaxurl + '?' + $( this ).serialize(),
219
+ { 'action' : 'hmnkp_edit_schedule_submit' },
220
+ function( data ) {
221
+
222
+ // Assume success if no data passed back
223
+ if ( ! data ) {
224
+
225
+ $.fancybox.close();
226
+
227
+ // Reload the page so we see changes
228
+ if ( isNewSchedule )
229
+ location.replace( '//' + location.host + location.pathname + '?page=backupwordpress&hmbkp_schedule_id=' + scheduleId );
230
+
231
+ else
232
+ location.reload( true );
233
+
234
+ } else {
235
+
236
+ // Get the errors json string
237
+ errors = JSON.parse( data );
238
+
239
+ // Loop through the errors
240
+ $.each( errors, function( key, value ) {
241
+
242
+ // Focus the first field that errored
243
+ if ( typeof( hmbkp_focused ) == 'undefined' ) {
244
+
245
+ $( '[name="' + key + '"]' ).focus();
246
+
247
+ hmbkp_focused = true;
248
+
249
+ }
250
+
251
+ // Add an error class to all fields with errors
252
+ $( '[name="' + key + '"]' ).closest( 'label' ).addClass( 'hmbkp-error' );
253
+
254
+ // Add the error message
255
+ $( '[name="' + key + '"]' ).after( '<span>' + value + '</span>' );
256
+
257
+ } );
258
+
259
+ }
260
+
261
+ }
262
+ );
263
+
264
  } );
265
 
266
+ // Text the cron response using ajax
267
+ $.get( ajaxurl, { 'action' : 'hmbkp_cron_test' },
268
+ function( data ) {
269
+ if ( data != 1 ) {
270
+ $( '.wrap > h2' ).after( data );
271
+ }
272
+ }
273
+ );
274
+
275
+ // Calculate the estimated backup size
276
+ if ( $( '.hmbkp-schedule-sentence .calculating' ).size() ) {
277
+ $.get( ajaxurl, { 'action' : 'hmbkp_calculate', 'hmbkp_schedule_id' : $( '[data-hmbkp-schedule-id]' ).attr( 'data-hmbkp-schedule-id' ) },
278
+ function( data ) {
279
+
280
+ if ( data.indexOf( 'title' ) != -1 )
281
+ $( '.hmbkp-schedule-sentence' ).replaceWith( data );
282
+
283
+ // Fail silently for now
284
+ else
285
+ $( '.calculating' ).remove();
286
 
287
+ }
288
+ ).error( function() {
289
+
290
+ // Fail silently for now
291
+ $( '.calculating' ).remove();
292
+
293
+ } );
294
  }
295
 
296
+ if ( $( '.hmbkp-running' ).size() )
297
+ hmbkpRedirectOnBackupComplete();
298
 
299
+ $( '.hmbkp-run' ).live( 'click', function( e ) {
300
+
301
+ scheduleId = $( '[data-hmbkp-schedule-id]' ).attr( 'data-hmbkp-schedule-id' );
302
+
303
+ ajaxRequest = $.get(
304
+ ajaxurl,
305
+ { 'action' : 'hmbkp_run_schedule', 'hmbkp_schedule_id' : scheduleId },
306
+ function( data ) {
307
+
308
+ if ( data.indexOf( 'hmbkp-schedule-actions' ) != -1 )
309
+ location.reload( true );
310
+
311
+ // The backup failed so just redirect back
312
+ else
313
+ location.replace( '//' + location.host + location.pathname + '?page=backupwordpress&action=hmbkp_cancel&reason=broken&hmbkp_schedule_id=' + scheduleId );
314
+
315
+ }
316
+ ).error( function() {
317
+ location.replace( '//' + location.host + location.pathname + '?page=backupwordpress&action=hmbkp_cancel&reason=broken&hmbkp_schedule_id=' + scheduleId );
318
+ } );
319
+
320
+ $( this ).closest( '.hmbkp-schedule-sentence' ).addClass( 'hmbkp-running' );
321
 
322
+ hmbkpRedirectOnBackupComplete();
323
+
324
+ e.preventDefault();
325
+
326
+ } );
327
+
328
+ } );
329
 
330
+ function hmbkpRedirectOnBackupComplete( schedule_id ) {
331
 
332
+ jQuery.get(
333
+ ajaxurl,
334
+ { 'action' : 'hmbkp_is_in_progress', 'hmbkp_schedule_id' : jQuery( '[data-hmbkp-schedule-id]' ).attr( 'data-hmbkp-schedule-id' ) },
335
  function( data ) {
336
 
337
  if ( data == 0 ) {
340
 
341
  } else {
342
 
343
+ setTimeout( 'hmbkpRedirectOnBackupComplete();', 500 );
344
 
345
+ jQuery( '.hmbkp-schedule-actions' ).replaceWith( data );
346
 
347
  }
348
  }
assets/wpspin_light.gif ADDED
Binary file
backupwordpress.mo CHANGED
Binary file
backupwordpress.po CHANGED
@@ -2,516 +2,563 @@ msgid ""
2
  msgstr ""
3
  "Project-Id-Version: BackUpWordPress\n"
4
  "Report-Msgid-Bugs-To: \n"
5
- "POT-Creation-Date: 2012-08-14 14:01+0100\n"
6
- "PO-Revision-Date: 2012-08-14 14:18+0100\n"
7
- "Last-Translator: Flo Edelmann <florian-edelmann@online.de>\n"
8
  "Language-Team: Human Made Limited <support@humanmade.co.uk>\n"
9
- "Language: \n"
10
  "MIME-Version: 1.0\n"
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
- "X-Poedit-KeywordsList: __;_e;_n:1,2\n"
14
  "X-Poedit-Basepath: .\n"
15
- "X-Poedit-Language: English\n"
16
- "X-Poedit-Country: UNITED KINGDOM\n"
17
- "Plural-Forms: nplurals=2; plural=n != 1;\n"
18
- "X-Poedit-SourceCharset: utf-8\n"
19
  "X-Poedit-SearchPath-0: .\n"
20
 
21
- #: admin.settings.php:3
22
- #: admin.page.php:11
23
- msgid "Settings"
24
  msgstr ""
25
 
26
- #: admin.settings.php:5
27
  #, php-format
28
- msgid "You can define %1$s in your %2$s to control some settings. A full list of %3$s can be found in the %4$s. Defined settings will not be editable below."
29
  msgstr ""
30
 
31
- #: admin.settings.php:5
32
- #: admin.constants.php:3
33
- #: admin.menus.php:76
34
- msgid "Constants"
35
  msgstr ""
36
 
37
- #: admin.settings.php:5
38
- msgid "help panel"
39
  msgstr ""
40
 
41
- #: admin.settings.php:16
42
- msgid "Automatic Backups"
 
 
 
 
43
  msgstr ""
44
 
45
- #: admin.settings.php:22
46
- msgid "Backup my site automatically."
 
 
 
47
  msgstr ""
48
 
49
- #: admin.settings.php:27
50
- msgid "No automatic backups."
 
 
 
51
  msgstr ""
52
 
53
- #: admin.settings.php:36
54
- msgid "Frequency of backups"
 
 
 
 
 
55
  msgstr ""
56
 
57
- #: admin.settings.php:40
58
- msgid "Automatic backups will occur"
 
59
  msgstr ""
60
 
61
- #: admin.settings.php:43
62
- msgid "Daily"
 
 
 
 
63
  msgstr ""
64
 
65
- #: admin.settings.php:44
66
- msgid "Weekly"
67
  msgstr ""
68
 
69
- #: admin.settings.php:45
70
- msgid "Fortnightly"
71
  msgstr ""
72
 
73
- #: admin.settings.php:46
74
- msgid "Monthly"
75
  msgstr ""
76
 
77
- #: admin.settings.php:55
78
- msgid "What to Backup"
79
  msgstr ""
80
 
81
- #: admin.settings.php:59
82
- msgid "Backup my"
83
  msgstr ""
84
 
85
- #: admin.settings.php:62
86
- msgid "database &amp; files"
87
  msgstr ""
88
 
89
- #: admin.settings.php:63
90
- msgid "database only"
 
91
  msgstr ""
92
 
93
- #: admin.settings.php:64
94
- msgid "files only"
95
  msgstr ""
96
 
97
- #: admin.settings.php:72
98
- msgid "Number of backups"
99
  msgstr ""
100
 
101
- #: admin.settings.php:73
102
- #, php-format
103
- msgid "The last %s backups will be stored on the server."
104
  msgstr ""
105
 
106
- #: admin.settings.php:77
107
- msgid "Email backups"
108
  msgstr ""
109
 
110
- #: admin.settings.php:78
111
- msgid "A copy of the backup file will be emailed to this address. Disabled if left blank."
112
  msgstr ""
113
 
114
- #: admin.settings.php:82
115
- msgid "Excludes"
 
 
 
116
  msgstr ""
117
 
118
- #: admin.settings.php:85
119
- msgid "A comma separated list of file and directory paths that you do <strong>not</strong> want to backup."
120
  msgstr ""
121
 
122
- #: admin.settings.php:86
123
- #: admin.constants.php:8
124
- #: admin.constants.php:11
125
- #: admin.constants.php:14
126
- #: admin.constants.php:17
127
- #: admin.constants.php:20
128
- #: admin.constants.php:23
129
- #: admin.constants.php:26
130
- #: admin.constants.php:29
131
- #: admin.constants.php:32
132
- #: admin.constants.php:35
133
- #: admin.constants.php:38
134
- #: admin.constants.php:41
135
- msgid "e.g."
136
  msgstr ""
137
 
138
- #: admin.settings.php:94
139
- msgid "Save Changes"
 
 
 
 
 
 
 
 
 
 
140
  msgstr ""
141
 
142
- #: admin.backups-table.php:12
143
  #, php-format
144
- msgid "1 backup completed"
145
- msgid_plural "%d backups completed"
146
- msgstr[0] ""
147
- msgstr[1] ""
148
 
149
- #: admin.backups-table.php:13
150
- msgid "Size"
 
151
  msgstr ""
152
 
153
- #: admin.backups-table.php:14
154
- msgid "Actions"
 
 
 
 
 
 
 
155
  msgstr ""
156
 
157
- #: admin.backups-table.php:20
158
  #, php-format
159
- msgid "Only the most recent backup will be saved"
160
- msgid_plural "The %d most recent backups will be saved"
161
- msgstr[0] ""
162
- msgstr[1] ""
163
 
164
- #: admin.backups-table.php:21
165
  #, php-format
166
- msgid "Total %s"
 
 
167
  msgstr ""
168
 
169
- #: admin.page.php:7
170
- #: admin.menus.php:10
171
- msgid "Manage Backups"
172
  msgstr ""
173
 
174
- #: admin.page.php:23
175
- msgid "You need to fix the issues detailed above before BackUpWordPress can start."
 
176
  msgstr ""
177
 
178
- #: admin.page.php:29
179
  #, php-format
180
- msgid "If you need help getting things working you are more than welcome to email us at %s and we'll do what we can to help."
 
 
181
  msgstr ""
182
 
183
- #: admin.backup-button.php:3
184
- msgid "cancel"
 
 
185
  msgstr ""
186
 
187
- #: admin.backup-button.php:7
188
- msgid "Back Up Now"
 
189
  msgstr ""
190
 
191
- #: admin.constants.php:3
192
  #, php-format
193
- msgid "You can %1$s any of the following %2$s in your %3$s to control advanced settings. %4$s. Defined %5$s will be highlighted."
194
  msgstr ""
195
 
196
- #: admin.constants.php:3
197
- msgid "The Codex can help"
198
  msgstr ""
199
 
200
- #: admin.constants.php:8
201
- #, php-format
202
- msgid "The path to folder you would like to store your backup files in, defaults to %s."
 
 
 
203
  msgstr ""
204
 
205
- #: admin.constants.php:11
206
  #, php-format
207
- msgid "The path to your %1$s executable. Will be used for the %2$s part of the back up if available."
 
 
208
  msgstr ""
209
 
210
- #: admin.constants.php:11
211
- #: admin.constants.php:14
212
- #: admin.constants.php:23
213
- #: admin.constants.php:26
214
- #: admin.status.php:14
215
- #: admin.status.php:18
216
- msgid "database"
217
  msgstr ""
218
 
219
- #: admin.constants.php:14
220
- #, php-format
221
- msgid "The path to your %1$s executable. Will be used to zip up your %2$s and %3$s if available."
222
  msgstr ""
223
 
224
- #: admin.constants.php:14
225
- #: admin.constants.php:23
226
- #: admin.constants.php:26
227
- #: admin.status.php:14
228
- #: admin.status.php:22
229
- msgid "files"
230
  msgstr ""
231
 
232
- #: admin.constants.php:17
233
- #, php-format
234
- msgid "Completely disables the automatic back up. You can still back up using the \"Back Up Now\" button. Defaults to %s."
235
  msgstr ""
236
 
237
- #: admin.constants.php:20
238
- #, php-format
239
- msgid "Number of backups to keep, older backups will be deleted automatically when a new backup is completed. Defaults to %s."
240
  msgstr ""
241
 
242
- #: admin.constants.php:23
243
- #: admin.constants.php:26
244
  #, php-format
245
- msgid "Backup %1$s only, your %2$s won't be backed up. Defaults to %3$s."
 
 
246
  msgstr ""
247
 
248
- #: admin.constants.php:29
249
- #, php-format
250
- msgid "The time that the daily back up should run. Defaults to %s."
251
  msgstr ""
252
 
253
- #: admin.constants.php:32
254
- #, php-format
255
- msgid "Attempt to email a copy of your backups. Value should be email address to send backups to. Defaults to %s."
256
  msgstr ""
257
 
258
- #: admin.constants.php:35
259
- msgid "Comma separated list of files or directories to exclude, the backups directory is automatically excluded."
260
  msgstr ""
261
 
262
- #: admin.constants.php:38
263
- #, php-format
264
- msgid "The capability to use when calling %1$s. Defaults to %2$s."
265
  msgstr ""
266
 
267
- #: admin.constants.php:41
268
- #, php-format
269
- msgid "The root directory that is backed up. Defaults to %s."
270
  msgstr ""
271
 
272
- #: admin.actions.php:70
273
- msgid "You have entered an invalid number of backups."
274
  msgstr ""
275
 
276
- #: admin.actions.php:79
277
- #, php-format
278
- msgid "%s is an invalid email address."
279
  msgstr ""
280
 
281
- #: admin.actions.php:249
282
- #: functions/interface.functions.php:89
283
- #: functions/interface.functions.php:99
284
- #: functions/interface.functions.php:110
285
- #: functions/interface.functions.php:120
286
- #: functions/interface.functions.php:130
287
- #: functions/interface.functions.php:140
288
- #: functions/interface.functions.php:150
289
- msgid "BackUpWordPress has detected a problem."
290
  msgstr ""
291
 
292
- #: admin.actions.php:249
 
 
 
 
293
  #, php-format
294
- msgid "%1$s is returning a %2$s response which could mean cron jobs aren't getting fired properly. BackUpWordPress relies on wp-cron to run scheduled back ups. See the %3$s for more details."
295
  msgstr ""
296
 
297
- #: admin.menus.php:10
298
- #: admin.menus.php:34
299
- msgid "Backups"
300
  msgstr ""
301
 
302
- #: admin.menus.php:65
303
- msgid "You are not using the latest stable version of BackUpWordPress"
304
  msgstr ""
305
 
306
- #: admin.menus.php:65
307
- #, php-format
308
- msgid "The information below is for version %1$s. View the <code>readme.txt</code> file for help specific to version %2$s."
309
  msgstr ""
310
 
311
- #: admin.menus.php:75
312
- msgid "FAQ"
313
  msgstr ""
314
 
315
- #: admin.menus.php:79
316
- msgid "For more information:"
317
  msgstr ""
318
 
319
- #: admin.menus.php:81
320
- msgid "Support Forums"
321
  msgstr ""
322
 
323
- #: admin.menus.php:82
324
- msgid "Help with translation"
325
  msgstr ""
326
 
327
- #: plugin.php:47
328
- msgid "BackUpWordPress requires PHP version 5.2.4 or greater."
329
  msgstr ""
330
 
331
- #: plugin.php:58
332
- #, php-format
333
- msgid "BackUpWordPress requires WordPress version %s."
 
 
 
 
 
334
  msgstr ""
335
 
336
- #: admin.status.php:9
337
  #, php-format
338
- msgid "Automatic backups are %s."
339
  msgstr ""
340
 
341
- #: admin.status.php:9
342
- msgid "disabled"
 
343
  msgstr ""
344
 
345
- #: admin.status.php:14
346
- msgid "&amp;"
 
347
  msgstr ""
348
 
349
- #: admin.status.php:32
350
  #, php-format
351
- msgid "Your %1$s will be automatically backed up %2$s. The next backup will occur at %3$s on %4$s and be saved to %5$s."
352
- msgid_plural "Your %1$s will be automatically backed up %2$s. The next backup will occur at %3$s on %4$s and be saved to %5$s."
353
- msgstr[0] ""
354
- msgstr[1] ""
355
 
356
- #: admin.status.php:39
357
  #, php-format
358
- msgid "It's currently %s"
359
  msgstr ""
360
 
361
- #: admin.status.php:47
362
  #, php-format
363
- msgid "Your site is %s. Backups will be compressed and should be smaller than this."
364
  msgstr ""
365
 
366
- #: admin.status.php:47
367
- msgid "Calculating Size..."
368
  msgstr ""
369
 
370
- #: admin.status.php:50
371
  #, php-format
372
- msgid "A copy of each backup will be emailed to %s."
373
  msgstr ""
374
 
375
- #: admin.status.php:54
376
  #, php-format
377
- msgid "The following paths will be excluded from your backups %s."
378
  msgstr ""
379
 
380
- #: hm-backup/hm-backup.php:532
381
- msgid "The backup file was not created"
 
382
  msgstr ""
383
 
384
- #: hm-backup/hm-backup.php:603
385
- msgid "The following files are unreadable and couldn't be backed up: "
 
386
  msgstr ""
387
 
388
- #: functions/interface.functions.php:25
389
- msgid "Download"
390
  msgstr ""
391
 
392
- #: functions/interface.functions.php:26
393
- msgid "Delete"
394
  msgstr ""
395
 
396
- #: functions/interface.functions.php:48
397
- msgid "Settings saved."
 
398
  msgstr ""
399
 
400
- #: functions/interface.functions.php:67
401
- #: functions/interface.functions.php:79
402
- msgid "BackUpWordPress is almost ready."
403
  msgstr ""
404
 
405
- #: functions/interface.functions.php:67
406
  #, php-format
407
- msgid "The backups directory can't be created because your %1$s directory isn't writable, run %2$s or %3$s or create the folder yourself."
408
  msgstr ""
409
 
410
- #: functions/interface.functions.php:79
411
  #, php-format
412
- msgid "Your backups directory isn't writable, run %1$s or %2$s or set the permissions yourself."
413
  msgstr ""
414
 
415
- #: functions/interface.functions.php:89
416
- #, php-format
417
- msgid " %1$s is running in %2$s. Please contact your host and ask them to disable %3$s."
418
  msgstr ""
419
 
420
- #: functions/interface.functions.php:89
421
- msgid "http://php.net/manual/en/features.safe-mode.php"
422
  msgstr ""
423
 
424
- #: functions/interface.functions.php:89
425
- msgid "Safe Mode"
 
 
 
 
426
  msgstr ""
427
 
428
- #: functions/interface.functions.php:99
 
 
 
 
 
 
 
429
  #, php-format
430
- msgid "You have both %1$s and %2$s defined so there isn't anything to back up."
 
 
 
 
 
 
 
 
 
 
 
 
 
431
  msgstr ""
432
 
433
- #: functions/interface.functions.php:110
434
  #, php-format
435
- msgid "The following email address is not valid: %s."
436
- msgid_plural "The following email addresses are not valid: %s."
437
- msgstr[0] ""
438
- msgstr[1] ""
439
 
440
- #: functions/interface.functions.php:120
441
- msgid "The last backup email failed to send. It's likely that the file is too large."
 
 
 
442
  msgstr ""
443
 
444
- #: functions/interface.functions.php:130
445
  #, php-format
446
- msgid "Your custom backups directory %1$s doesn't exist and can't be created, your backups will be saved to %2$s instead."
 
 
 
 
 
 
447
  msgstr ""
448
 
449
- #: functions/interface.functions.php:140
 
 
 
 
450
  #, php-format
451
- msgid "Your custom backups directory %1$s isn't writable, new backups will be saved to %2$s instead."
 
 
452
  msgstr ""
453
 
454
- #: functions/interface.functions.php:150
455
  #, php-format
456
- msgid "You have defined a custom exclude list but the following paths don't exist %s, are you sure you entered them correctly?"
 
 
457
  msgstr ""
458
 
459
- #: functions/interface.functions.php:160
460
  msgid "BackUpWordPress detected issues with your last backup."
461
  msgstr ""
462
 
463
- #: functions/backup.actions.php:12
464
- msgid "Dumping database"
465
  msgstr ""
466
 
467
- #: functions/backup.actions.php:22
468
- msgid "Creating zip archive"
469
  msgstr ""
470
 
471
- #: functions/backup.functions.php:19
472
- msgid "Removing old backups"
473
  msgstr ""
474
 
475
- #: functions/backup.functions.php:147
476
- #: functions/backup.functions.php:157
477
- #, php-format
478
- msgid "Backup of %s"
479
  msgstr ""
480
 
481
- #: functions/backup.functions.php:148
482
- #, php-format
483
- msgid ""
484
- "BackUpWordPress has completed a backup of your site %1$s.\\n"
485
- "\\n"
486
- "The backup file should be attached to this email.\\n"
487
- "\\n"
488
- "You can also download the backup file by clicking the link below:\\n"
489
- "\\n"
490
- "%2$s\\n"
491
- "\\n"
492
- "Kind Regards\\n"
493
- "\\n"
494
- " The Happy BackUpWordPress Backup Emailing Robot"
495
  msgstr ""
496
 
497
- #: functions/backup.functions.php:158
498
- #, php-format
499
- msgid ""
500
- "BackUpWordPress has completed a backup of your site %1$s.\\n"
501
- "\\n"
502
- "Unfortunately the backup file was too large to attach to this email.\\n"
503
- "\\n"
504
- "You can download the backup file by clicking the link below:\\n"
505
- "\\n"
506
- "%2$s\\n"
507
- "\\n"
508
- "Kind Regards\\n"
509
- "\\n"
510
- " The Happy BackUpWordPress Backup Emailing Robot"
511
  msgstr ""
512
 
513
- #: functions/core.functions.php:339
514
- #, php-format
515
- msgid "This %s file ensures that other people cannot download your backup files."
516
  msgstr ""
517
 
 
 
 
 
 
 
 
 
 
 
 
2
  msgstr ""
3
  "Project-Id-Version: BackUpWordPress\n"
4
  "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2012-08-22 15:46-0000\n"
6
+ "PO-Revision-Date: 2012-08-22 15:47-0000\n"
7
+ "Last-Translator: Tom Willmot <tom@humanmade.co.uk>\n"
8
  "Language-Team: Human Made Limited <support@humanmade.co.uk>\n"
9
+ "Language: en_GB\n"
10
  "MIME-Version: 1.0\n"
11
  "Content-Type: text/plain; charset=UTF-8\n"
12
  "Content-Transfer-Encoding: 8bit\n"
13
+ "X-Poedit-KeywordsList: __;_e\n"
14
  "X-Poedit-Basepath: .\n"
 
 
 
 
15
  "X-Poedit-SearchPath-0: .\n"
16
 
17
+ #: plugin.php:52
18
+ msgid "BackUpWordPress requires PHP version 5.2.4 or greater."
 
19
  msgstr ""
20
 
21
+ #: plugin.php:63
22
  #, php-format
23
+ msgid "BackUpWordPress requires WordPress version %s or greater."
24
  msgstr ""
25
 
26
+ #: plugin.php:95 admin/schedule-form.php:52
27
+ msgid "Update"
 
 
28
  msgstr ""
29
 
30
+ #: plugin.php:96
31
+ msgid "Cancel"
32
  msgstr ""
33
 
34
+ #: plugin.php:97
35
+ msgid ""
36
+ "Are you sure you want to delete this schedule? All of it's backups will also "
37
+ "be deleted.\n"
38
+ "\n"
39
+ "'Cancel' to go back, 'OK' to delete.\n"
40
  msgstr ""
41
 
42
+ #: plugin.php:98
43
+ msgid ""
44
+ "Are you sure you want to delete this backup?\n"
45
+ "\n"
46
+ "'Cancel' to go back, 'OK' to delete.\n"
47
  msgstr ""
48
 
49
+ #: plugin.php:99
50
+ msgid ""
51
+ "Are you sure you want to remove this exclude rule?\n"
52
+ "\n"
53
+ "'Cancel' to go back, 'OK' to delete.\n"
54
  msgstr ""
55
 
56
+ #: plugin.php:100
57
+ msgid ""
58
+ "Reducing the number of backups that are stored on this server will cause "
59
+ "some of your existing backups to be deleted, are you sure that's what you "
60
+ "want?\n"
61
+ "\n"
62
+ "'Cancel' to go back, 'OK' to delete.\n"
63
  msgstr ""
64
 
65
+ #: admin/actions.php:163 functions/interface.php:72 functions/interface.php:82
66
+ #: functions/interface.php:92
67
+ msgid "BackUpWordPress has detected a problem."
68
  msgstr ""
69
 
70
+ #: admin/actions.php:163
71
+ #, php-format
72
+ msgid ""
73
+ "%1$s is returning a %2$s response which could mean cron jobs aren't getting "
74
+ "fired properly. BackUpWordPress relies on wp-cron to run scheduled back ups. "
75
+ "See the %3$s for more details."
76
  msgstr ""
77
 
78
+ #: admin/actions.php:232
79
+ msgid "Backup type cannot be empty"
80
  msgstr ""
81
 
82
+ #: admin/actions.php:235
83
+ msgid "Invalid backup type"
84
  msgstr ""
85
 
86
+ #: admin/actions.php:245
87
+ msgid "Schedule cannot be empty"
88
  msgstr ""
89
 
90
+ #: admin/actions.php:248
91
+ msgid "Invalid schedule"
92
  msgstr ""
93
 
94
+ #: admin/actions.php:258
95
+ msgid "Max backups must be more than 1"
96
  msgstr ""
97
 
98
+ #: admin/actions.php:261
99
+ msgid "Max backups must be a number"
100
  msgstr ""
101
 
102
+ #: admin/actions.php:338
103
+ #, php-format
104
+ msgid "%s didn't match any files."
105
  msgstr ""
106
 
107
+ #: admin/backups.php:13
108
+ msgid "add schedule"
109
  msgstr ""
110
 
111
+ #: admin/backups.php:37
112
+ msgid "Size"
113
  msgstr ""
114
 
115
+ #: admin/backups.php:38
116
+ msgid "Type"
 
117
  msgstr ""
118
 
119
+ #: admin/backups.php:39
120
+ msgid "Actions"
121
  msgstr ""
122
 
123
+ #: admin/backups.php:62
124
+ msgid "This is where your backups will appear once you have one."
125
  msgstr ""
126
 
127
+ #: admin/constants.php:3
128
+ #, php-format
129
+ msgid ""
130
+ "You can %1$s any of the following %2$s in your %3$s to control advanced "
131
+ "settings. %4$s. Defined %5$s will be highlighted."
132
  msgstr ""
133
 
134
+ #: admin/constants.php:3 admin/menu.php:76
135
+ msgid "Constants"
136
  msgstr ""
137
 
138
+ #: admin/constants.php:3
139
+ msgid "The Codex can help"
 
 
 
 
 
 
 
 
 
 
 
 
140
  msgstr ""
141
 
142
+ #: admin/constants.php:8
143
+ #, php-format
144
+ msgid ""
145
+ "The path to folder you would like to store your backup files in, defaults to "
146
+ "%s."
147
+ msgstr ""
148
+
149
+ #: admin/constants.php:8 admin/constants.php:11 admin/constants.php:14
150
+ #: admin/constants.php:17 admin/constants.php:20 admin/constants.php:23
151
+ #: admin/constants.php:26 admin/constants.php:29 admin/constants.php:32
152
+ #: admin/constants.php:35 admin/constants.php:38 admin/constants.php:41
153
+ msgid "e.g."
154
  msgstr ""
155
 
156
+ #: admin/constants.php:11
157
  #, php-format
158
+ msgid ""
159
+ "The path to your %1$s executable. Will be used for the %2$s part of the back "
160
+ "up if available."
161
+ msgstr ""
162
 
163
+ #: admin/constants.php:11 admin/constants.php:14 admin/constants.php:23
164
+ #: admin/constants.php:26
165
+ msgid "database"
166
  msgstr ""
167
 
168
+ #: admin/constants.php:14
169
+ #, php-format
170
+ msgid ""
171
+ "The path to your %1$s executable. Will be used to zip up your %2$s and %3$s "
172
+ "if available."
173
+ msgstr ""
174
+
175
+ #: admin/constants.php:14 admin/constants.php:23 admin/constants.php:26
176
+ msgid "files"
177
  msgstr ""
178
 
179
+ #: admin/constants.php:17
180
  #, php-format
181
+ msgid ""
182
+ "Completely disables the automatic back up. You can still back up using the "
183
+ "\"Back Up Now\" button. Defaults to %s."
184
+ msgstr ""
185
 
186
+ #: admin/constants.php:20
187
  #, php-format
188
+ msgid ""
189
+ "Number of backups to keep, older backups will be deleted automatically when "
190
+ "a new backup is completed. Defaults to %s."
191
  msgstr ""
192
 
193
+ #: admin/constants.php:23 admin/constants.php:26
194
+ #, php-format
195
+ msgid "Backup %1$s only, your %2$s won't be backed up. Defaults to %3$s."
196
  msgstr ""
197
 
198
+ #: admin/constants.php:29
199
+ #, php-format
200
+ msgid "The time that the daily back up should run. Defaults to %s."
201
  msgstr ""
202
 
203
+ #: admin/constants.php:32
204
  #, php-format
205
+ msgid ""
206
+ "Attempt to email a copy of your backups. Value should be email address to "
207
+ "send backups to. Defaults to %s."
208
  msgstr ""
209
 
210
+ #: admin/constants.php:35
211
+ msgid ""
212
+ "Comma separated list of files or directories to exclude, the backups "
213
+ "directory is automatically excluded."
214
  msgstr ""
215
 
216
+ #: admin/constants.php:38
217
+ #, php-format
218
+ msgid "The capability to use when calling %1$s. Defaults to %2$s."
219
  msgstr ""
220
 
221
+ #: admin/constants.php:41
222
  #, php-format
223
+ msgid "The root directory that is backed up. Defaults to %s."
224
  msgstr ""
225
 
226
+ #: admin/menu.php:10 admin/page.php:5
227
+ msgid "Manage Backups"
228
  msgstr ""
229
 
230
+ #: admin/menu.php:10 admin/menu.php:34
231
+ msgid "Backups"
232
+ msgstr ""
233
+
234
+ #: admin/menu.php:69
235
+ msgid "You are not using the latest stable version of BackUpWordPress"
236
  msgstr ""
237
 
238
+ #: admin/menu.php:69
239
  #, php-format
240
+ msgid ""
241
+ "The information below is for version %1$s. View the %2$s file for help "
242
+ "specific to version %3$s."
243
  msgstr ""
244
 
245
+ #: admin/menu.php:75
246
+ msgid "FAQ"
 
 
 
 
 
247
  msgstr ""
248
 
249
+ #: admin/menu.php:79
250
+ msgid "For more information:"
 
251
  msgstr ""
252
 
253
+ #: admin/menu.php:81
254
+ msgid "Support Forums"
 
 
 
 
255
  msgstr ""
256
 
257
+ #: admin/menu.php:82
258
+ msgid "Help with translation"
 
259
  msgstr ""
260
 
261
+ #: admin/page.php:13
262
+ msgid ""
263
+ "You need to fix the issues detailed above before BackUpWordPress can start."
264
  msgstr ""
265
 
266
+ #: admin/page.php:17
 
267
  #, php-format
268
+ msgid ""
269
+ "If you need help getting things working you are more than welcome to email "
270
+ "us at %s and we'll do what we can."
271
  msgstr ""
272
 
273
+ #: admin/schedule-form-excludes.php:7
274
+ msgid "Manage Exclude"
 
275
  msgstr ""
276
 
277
+ #: admin/schedule-form-excludes.php:13
278
+ msgid "New Exclude Rule"
 
279
  msgstr ""
280
 
281
+ #: admin/schedule-form-excludes.php:17
282
+ msgid "Preview"
283
  msgstr ""
284
 
285
+ #: admin/schedule-form-excludes.php:27
286
+ msgid "Exclude Rules"
 
287
  msgstr ""
288
 
289
+ #: admin/schedule-form-excludes.php:42
290
+ msgid "Remove"
 
291
  msgstr ""
292
 
293
+ #: admin/schedule-form-excludes.php:59
294
+ msgid "Excluded"
295
  msgstr ""
296
 
297
+ #: admin/schedule-form-excludes.php:60
298
+ msgid "Included"
 
299
  msgstr ""
300
 
301
+ #: admin/schedule-form-excludes.php:63
302
+ msgid "Unreadable"
 
 
 
 
 
 
 
303
  msgstr ""
304
 
305
+ #: admin/schedule-form-excludes.php:86
306
+ msgid "Unreadable files can't be backed up"
307
+ msgstr ""
308
+
309
+ #: admin/schedule-form-excludes.php:92
310
  #, php-format
311
+ msgid "Your site is %s. Backups will be compressed and so will be smaller."
312
  msgstr ""
313
 
314
+ #: admin/schedule-form-excludes.php:98
315
+ msgid "Close"
 
316
  msgstr ""
317
 
318
+ #: admin/schedule-form.php:7
319
+ msgid "Schedule Settings"
320
  msgstr ""
321
 
322
+ #: admin/schedule-form.php:11
323
+ msgid "Backup"
 
324
  msgstr ""
325
 
326
+ #: admin/schedule-form.php:14
327
+ msgid "Both Database &amp; files"
328
  msgstr ""
329
 
330
+ #: admin/schedule-form.php:15
331
+ msgid "Files only"
332
  msgstr ""
333
 
334
+ #: admin/schedule-form.php:16
335
+ msgid "Database only"
336
  msgstr ""
337
 
338
+ #: admin/schedule-form.php:23
339
+ msgid "Schedule"
340
  msgstr ""
341
 
342
+ #: admin/schedule-form.php:39
343
+ msgid "Number of backups to store on this server"
344
  msgstr ""
345
 
346
+ #: admin/schedule-form.php:43
347
+ msgid ""
348
+ "The number of previous backups to store on the server. past this limit the "
349
+ "oldest backups will be deleted automatically."
350
+ msgstr ""
351
+
352
+ #: admin/schedule.php:16
353
+ msgid "hourly on the hour"
354
  msgstr ""
355
 
356
+ #: admin/schedule.php:16
357
  #, php-format
358
+ msgid "hourly at %s minutes past the hour"
359
  msgstr ""
360
 
361
+ #: admin/schedule.php:22
362
+ #, php-format
363
+ msgid "daily at %s"
364
  msgstr ""
365
 
366
+ #: admin/schedule.php:34
367
+ #, php-format
368
+ msgid "every 12 hours at %s &amp; %s"
369
  msgstr ""
370
 
371
+ #: admin/schedule.php:40
372
  #, php-format
373
+ msgid "weekly on %s at %s"
374
+ msgstr ""
 
 
375
 
376
+ #: admin/schedule.php:46
377
  #, php-format
378
+ msgid "fortnightly on %s at %s"
379
  msgstr ""
380
 
381
+ #: admin/schedule.php:53
382
  #, php-format
383
+ msgid "on the %s of each month at %s"
384
  msgstr ""
385
 
386
+ #: admin/schedule.php:59
387
+ msgid "server"
388
  msgstr ""
389
 
390
+ #: admin/schedule.php:66
391
  #, php-format
392
+ msgid "store the only the last backup %s"
393
  msgstr ""
394
 
395
+ #: admin/schedule.php:72
396
  #, php-format
397
+ msgid "don't store any backups %s"
398
  msgstr ""
399
 
400
+ #: admin/schedule.php:78
401
+ #, php-format
402
+ msgid "store only the last %s backups %s"
403
  msgstr ""
404
 
405
+ #: admin/schedule.php:87
406
+ #, php-format
407
+ msgid "Backup my %s %s %s, %s. %s"
408
  msgstr ""
409
 
410
+ #: admin/schedule.php:87
411
+ msgid "Backups will be compressed and should be smaller than this."
412
  msgstr ""
413
 
414
+ #: classes/email.php:19
415
+ msgid "Email notification"
416
  msgstr ""
417
 
418
+ #: classes/email.php:50
419
+ #, php-format
420
+ msgid "Send an email notification to %s"
421
  msgstr ""
422
 
423
+ #: classes/email.php:72
424
+ #, php-format
425
+ msgid "%s isn't a valid email"
426
  msgstr ""
427
 
428
+ #: classes/email.php:127
429
  #, php-format
430
+ msgid "Backup of %s Failed"
431
  msgstr ""
432
 
433
+ #: classes/email.php:137
434
  #, php-format
435
+ msgid "Backup of %s"
436
  msgstr ""
437
 
438
+ #: classes/schedule.php:460
439
+ msgid "Backup started"
 
440
  msgstr ""
441
 
442
+ #: classes/schedule.php:511
443
+ msgid "Creating zip archive"
444
  msgstr ""
445
 
446
+ #: classes/schedule.php:517
447
+ msgid "Dumping database"
448
+ msgstr ""
449
+
450
+ #: functions/core.php:192
451
+ msgid "BackUpWordPress has setup your default schedules."
452
  msgstr ""
453
 
454
+ #: functions/core.php:192
455
+ msgid ""
456
+ "By default BackUpWordPress performs a daily backup of your database and a "
457
+ "weekly backup of your database &amp; files. You can modify these schedules "
458
+ "below."
459
+ msgstr ""
460
+
461
+ #: functions/core.php:273
462
  #, php-format
463
+ msgid ""
464
+ "This %s file ensures that other people cannot download your backup files."
465
+ msgstr ""
466
+
467
+ #: functions/interface.php:27
468
+ msgid "Download"
469
+ msgstr ""
470
+
471
+ #: functions/interface.php:28 functions/interface.php:215
472
+ msgid "Delete"
473
+ msgstr ""
474
+
475
+ #: functions/interface.php:50 functions/interface.php:62
476
+ msgid "BackUpWordPress is almost ready."
477
  msgstr ""
478
 
479
+ #: functions/interface.php:50
480
  #, php-format
481
+ msgid ""
482
+ "The backups directory can't be created because your %1$s directory isn't "
483
+ "writable, run %2$s or %3$s or create the folder yourself."
484
+ msgstr ""
485
 
486
+ #: functions/interface.php:62
487
+ #, php-format
488
+ msgid ""
489
+ "Your backups directory isn't writable, run %1$s or %2$s or set the "
490
+ "permissions yourself."
491
  msgstr ""
492
 
493
+ #: functions/interface.php:72
494
  #, php-format
495
+ msgid ""
496
+ "%1$s is running in %2$s. Please contact your host and ask them to disable "
497
+ "%3$s."
498
+ msgstr ""
499
+
500
+ #: functions/interface.php:72
501
+ msgid "http://php.net/manual/en/features.safe-mode.php"
502
  msgstr ""
503
 
504
+ #: functions/interface.php:72
505
+ msgid "Safe Mode"
506
+ msgstr ""
507
+
508
+ #: functions/interface.php:82
509
  #, php-format
510
+ msgid ""
511
+ "Your custom backups directory %1$s doesn't exist and can't be created, your "
512
+ "backups will be saved to %2$s instead."
513
  msgstr ""
514
 
515
+ #: functions/interface.php:92
516
  #, php-format
517
+ msgid ""
518
+ "Your custom backups directory %1$s isn't writable, new backups will be saved "
519
+ "to %2$s instead."
520
  msgstr ""
521
 
522
+ #: functions/interface.php:102
523
  msgid "BackUpWordPress detected issues with your last backup."
524
  msgstr ""
525
 
526
+ #: functions/interface.php:182
527
+ msgid "Database and Files"
528
  msgstr ""
529
 
530
+ #: functions/interface.php:185
531
+ msgid "Files"
532
  msgstr ""
533
 
534
+ #: functions/interface.php:188
535
+ msgid "Database"
536
  msgstr ""
537
 
538
+ #: functions/interface.php:193
539
+ msgid "Unknown"
 
 
540
  msgstr ""
541
 
542
+ #: functions/interface.php:201
543
+ msgid "cancel"
 
 
 
 
 
 
 
 
 
 
 
 
544
  msgstr ""
545
 
546
+ #: functions/interface.php:207
547
+ msgid "Settings"
 
 
 
 
 
 
 
 
 
 
 
 
548
  msgstr ""
549
 
550
+ #: functions/interface.php:210
551
+ msgid "Excludes"
 
552
  msgstr ""
553
 
554
+ #: functions/interface.php:213
555
+ msgid "Run now"
556
+ msgstr ""
557
+
558
+ #: hm-backup/hm-backup.php:892
559
+ msgid "The backup file was not created"
560
+ msgstr ""
561
+
562
+ #: hm-backup/hm-backup.php:963
563
+ msgid "The following files are unreadable and couldn't be backed up: "
564
+ msgstr ""
classes/email.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Email notifications for backups
5
+ *
6
+ * @extends HMBKP_Service
7
+ */
8
+ class HMBKP_Email_Service extends HMBKP_Service {
9
+
10
+ /**
11
+ * Output the email form field
12
+ *
13
+ * @access public
14
+ */
15
+ public function field() { ?>
16
+
17
+ <label>
18
+
19
+ <?php _e( 'Email notification', 'hmbkp' ); ?>
20
+
21
+ <input type="email" name="<?php echo $this->get_field_name( 'email' ); ?>" value="<?php echo $this->get_field_value( 'email' ); ?>" />
22
+
23
+ <p class="description"><?php _e( 'Receive a notification email when a backup completes, if the backup is small enough (&lt; 10mb) then it will be attached to the email. Separate multiple email address\'s with a comma.', 'hmbkp' ); ?></p>
24
+
25
+ </label>
26
+
27
+ <?php }
28
+
29
+ /**
30
+ * Not used as we only need a field
31
+ *
32
+ * @see field
33
+ * @return string Empty string
34
+ */
35
+ public function form() {
36
+ return '';
37
+ }
38
+
39
+ /**
40
+ * The sentence fragment that is output as part of the schedule sentence
41
+ *
42
+ * @return string The sentence fragment
43
+ */
44
+ public function display() {
45
+
46
+ if ( $emails = $this->get_email_address_array() ) {
47
+
48
+ $email = '<code>' . implode( '</code>, <code>', $emails ) . '</code>';
49
+
50
+ return sprintf( __( 'Send an email notification to %s', 'hmbkp' ), $email );
51
+
52
+ }
53
+
54
+ }
55
+
56
+ /**
57
+ * Validate the email and return an error if validation fails
58
+ *
59
+ * @param array &$new_data Array of new data, passed by reference
60
+ * @param array $old_data The data we are replacing
61
+ * @return null|array Null on success, array of errors if validation failed
62
+ */
63
+ public function update( &$new_data, $old_data ) {
64
+
65
+ $errors = array();
66
+
67
+ if ( isset( $new_data['email'] ) ) {
68
+
69
+ if ( ! empty( $new_data['email'] ) )
70
+ foreach( explode( ',', $new_data['email'] ) as $email )
71
+ if ( ! is_email( trim( $email ) ) )
72
+ $errors['email'] = sprintf( __( '%s isn\'t a valid email', 'hmbkp' ), esc_attr( $email ) );
73
+
74
+
75
+ if ( ! empty( $errors['email'] ) )
76
+ $new_data['email'] = '';
77
+
78
+ }
79
+
80
+ return $errors;
81
+
82
+ }
83
+
84
+ /**
85
+ * Get an array or validated email address's
86
+ * @return array An array of validated email address's
87
+ */
88
+ private function get_email_address_array() {
89
+
90
+ $emails = array_map( 'trim', explode( ',', $this->get_field_value( 'email' ) ) );
91
+
92
+ return array_filter( array_unique( $emails ), 'is_email' );
93
+
94
+ }
95
+
96
+ /**
97
+ * Fire the email notification on the hmbkp_backup_complete
98
+ *
99
+ * @see HM_Backup::do_action
100
+ * @param string $action The action received from the backup
101
+ * @return void
102
+ */
103
+ public function action( $action ) {
104
+
105
+ if ( $action == 'hmbkp_backup_complete' && $this->get_email_address_array() ) {
106
+
107
+ $file = $this->schedule->get_archive_filepath();
108
+
109
+ $sent = false;
110
+
111
+ $download = add_query_arg( 'hmbkp_download', base64_encode( $file ), HMBKP_ADMIN_URL );
112
+ $domain = parse_url( home_url(), PHP_URL_HOST ) . parse_url( home_url(), PHP_URL_PATH );
113
+
114
+ $headers = 'From: BackUpWordPress <' . get_bloginfo( 'admin_email' ) . '>' . "\r\n";
115
+
116
+ // The backup failed, send a message saying as much
117
+ if ( file_exists( $file ) && ( $errors = array_merge( $this->schedule->get_errors(), $this->schedule->get_warnings() ) ) ) {
118
+
119
+ $error_message = '';
120
+
121
+ foreach ( $errors as $error_set )
122
+ $error_message .= implode( "\n - ", $error_set );
123
+
124
+ if ( $error_message )
125
+ $error_message = ' - ' . $error_message;
126
+
127
+ $subject = sprintf( __( 'Backup of %s Failed', 'hmbkp' ), $domain );
128
+
129
+ $message = sprintf( __( 'BackUpWordPress was unable to backup your site %1$s.', 'hmbkp' ) . "\n\n" . __( 'Here are the errors that we\'re encountered:', 'hmbkp' ) . "\n\n" . '%2$s' . "\n\n" . __( 'If the errors above look like Martian, forward this email to %3$s and we\'ll take a look', 'hmbkp' ) . "\n\n" . __( "Kind Regards,\nThe Apologetic BackUpWordPress Backup Emailing Robot", 'hmbkp' ), home_url(), $error_message, 'support@hmn.md' );
130
+
131
+ $sent = wp_mail( $this->get_email_address_array(), $subject, $message, $headers );
132
+
133
+ return;
134
+
135
+ }
136
+
137
+ $subject = sprintf( __( 'Backup of %s', 'hmbkp' ), $domain );
138
+
139
+ // If it's larger than 10MB assume it's not going to be able to send the backup
140
+ if ( filesize( $file ) < 1000 * 1000 * 10 ) {
141
+
142
+ $message = sprintf( __( 'BackUpWordPress has completed a backup of your site %1$s.', 'hmbkp' ) . "\n\n" . __( 'The backup file should be attached to this email.', 'hmbkp' ) . "\n\n" . __( 'You can download the backup file by clicking the link below:', 'hmbkp' ) . "\n\n" . '%2$s' . "\n\n" . __( "Kind Regards,\nThe Happy BackUpWordPress Backup Emailing Robot", 'hmbkp' ), home_url(), $download );
143
+
144
+ $sent = wp_mail( $this->get_email_address_array(), $subject, $message, $headers, $file );
145
+
146
+ }
147
+
148
+ // If we didn't send the email above then send just the notification
149
+ if ( ! $sent ) {
150
+
151
+ $message = sprintf( __( 'BackUpWordPress has completed a backup of your site %1$s.', 'hmbkp' ) . "\n\n" . __( 'Unfortunately the backup file was too large to attach to this email.', 'hmbkp' ) . "\n\n" . __( 'You can download the backup file by clicking the link below:', 'hmbkp' ) . "\n\n" . '%2$s' . "\n\n" . __( "Kind Regards,\nThe Happy BackUpWordPress Backup Emailing Robot", 'hmbkp' ), home_url(), $download );
152
+
153
+ $sent = wp_mail( $this->get_email_address_array(), $subject, $message, $headers );
154
+
155
+ }
156
+
157
+ }
158
+
159
+ }
160
+
161
+ }
162
+
163
+ // Register the service
164
+ HMBKP_Services::register( __FILE__, 'HMBKP_Email_Service' );
classes/schedule.php ADDED
@@ -0,0 +1,779 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Extend HM Backup with scheduling and backup file management
5
+ *
6
+ * @extends HM_Backup
7
+ */
8
+ class HMBKP_Scheduled_Backup extends HM_Backup {
9
+
10
+ /**
11
+ * The unique schedule id
12
+ *
13
+ * @var string
14
+ * @access private
15
+ */
16
+ private $id = '';
17
+
18
+ /**
19
+ * The slugified version of the schedule name
20
+ *
21
+ * @var string
22
+ * @access private
23
+ */
24
+ private $slug = '';
25
+
26
+ /**
27
+ * The raw schedule options from the database
28
+ *
29
+ * @var array
30
+ * @access private
31
+ */
32
+ private $options = array();
33
+
34
+ /**
35
+ * The unique hook name for this schedule
36
+ *
37
+ * @var string
38
+ * @access private
39
+ */
40
+ private $schedule_hook = '';
41
+
42
+ /**
43
+ * The filepath for the .running file which
44
+ * is used to track whether a backup is currently in
45
+ * progress
46
+ */
47
+ private $schedule_running_filepath = '';
48
+
49
+ /**
50
+ * The schedule start time
51
+ *
52
+ * (default value: current_time( 'timestamp' ))
53
+ *
54
+ * @var mixed
55
+ * @access private
56
+ */
57
+ private $schedule_start_time = 0;
58
+
59
+ /**
60
+ * Take a file size and return a human readable
61
+ * version
62
+ *
63
+ * @access public
64
+ * @static
65
+ * @param int $size
66
+ * @param string $unit. (default: null)
67
+ * @param string $format. (default: '%01.2f %s')
68
+ * @param bool $si. (default: true)
69
+ * @return int
70
+ */
71
+ public static function human_filesize( $size, $unit = null, $format = '%01.2f %s', $si = true ) {
72
+
73
+ // Units
74
+ if ( $si === true ) :
75
+ $sizes = array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB' );
76
+ $mod = 1000;
77
+
78
+ else :
79
+ $sizes = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB');
80
+ $mod = 1024;
81
+
82
+ endif;
83
+
84
+ $ii = count( $sizes ) - 1;
85
+
86
+ // Max unit
87
+ $unit = array_search( (string) $unit, $sizes );
88
+
89
+ if ( is_null( $unit ) || $unit === false )
90
+ $unit = $ii;
91
+
92
+ // Loop
93
+ $i = 0;
94
+
95
+ while ( $unit != $i && $size >= 1024 && $i < $ii ) {
96
+ $size /= $mod;
97
+ $i++;
98
+ }
99
+
100
+ return sprintf( $format, $size, $sizes[$i] );
101
+
102
+ }
103
+
104
+ /**
105
+ * Setup the schedule object
106
+ *
107
+ * Loads the options from the database and populates properties
108
+ *
109
+ * @access public
110
+ * @param string $id
111
+ */
112
+ public function __construct( $id ) {
113
+
114
+ // Verify the schedule id
115
+ if ( ! is_string( $id ) || ! trim( $id ) || ! is_string( $id ) )
116
+ throw new Exception( 'Argument 1 for ' . __METHOD__ . ' must be a non empty string' );
117
+
118
+ // Setup HM Backup
119
+ parent::__construct();
120
+
121
+ // Store id for later
122
+ $this->id = $id;
123
+
124
+ // Load the options
125
+ $this->options = array_filter( (array) get_option( 'hmbkp_schedule_' . $this->get_id() ) );
126
+
127
+ // Setup the schedule hook
128
+ $this->schedule_hook = 'hmbkp_schedule_' . $this->get_id() . '_hook';
129
+
130
+ // Some properties can be overridden with defines
131
+ if ( defined( 'HMBKP_ROOT' ) && HMBKP_ROOT )
132
+ $this->set_root( HMBKP_ROOT );
133
+
134
+ if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH )
135
+ $this->set_path( HMBKP_PATH );
136
+
137
+ if ( defined( 'HMBKP_EXCLUDE' ) && HMBKP_EXCLUDE )
138
+ parent::set_excludes( HMBKP_EXCLUDE, true );
139
+
140
+ if ( defined( 'HMBKP_MYSQLDUMP_PATH' ) )
141
+ $this->set_mysqldump_command_path( HMBKP_MYSQLDUMP_PATH );
142
+
143
+ if ( defined( 'HMBKP_ZIP_PATH' ) )
144
+ $this->set_zip_command_path( HMBKP_ZIP_PATH );
145
+
146
+ if ( defined( 'HMBKP_ZIP_PATH' ) && HMBKP_ZIP_PATH === 'PclZip' && $this->skip_zip_archive = true )
147
+ $this->set_zip_command_path( false );
148
+
149
+ // Set the path - TODO remove external function dependancy
150
+ $this->set_path( hmbkp_path() );
151
+
152
+ // Set the archive filename to site name + schedule slug + date
153
+ $this->set_archive_filename( implode( '-', array( get_bloginfo( 'name' ), $this->get_id(), $this->get_type(), date( 'Y-m-d-H-i-s', current_time( 'timestamp' ) ) ) ) . '.zip' );
154
+
155
+ }
156
+
157
+ /**
158
+ * Get the id for this schedule
159
+ *
160
+ * @access public
161
+ */
162
+ public function get_id() {
163
+ return esc_attr( $this->id );
164
+ }
165
+
166
+ /**
167
+ * Get a slugified version of name
168
+ *
169
+ * @access public
170
+ */
171
+ public function get_slug() {
172
+
173
+ // We cache slug in $this to save expensive calls to sanitize_title
174
+ if ( isset( $this->slug ) )
175
+ return $this->slug;
176
+
177
+ return $this->slug = sanitize_title( $this->get_name() );
178
+
179
+ }
180
+
181
+ /**
182
+ * Get the name of this backup schedule
183
+ *
184
+ * @access public
185
+ * @return string
186
+ */
187
+ public function get_name() {
188
+
189
+ return ucwords( $this->get_type() ) . ' ' . $this->get_reoccurrence();
190
+
191
+ }
192
+
193
+ /**
194
+ * Get the type of backup
195
+ *
196
+ * @access public
197
+ * @return string
198
+ */
199
+ public function get_type() {
200
+
201
+ if ( empty( $this->options['type'] ) )
202
+ $this->set_type( 'complete' );
203
+
204
+ return $this->options['type'];
205
+
206
+ }
207
+
208
+ /**
209
+ * Set the type of backup
210
+ *
211
+ * @access public
212
+ * @param string $type
213
+ */
214
+ public function set_type( $type ) {
215
+
216
+ parent::set_type( $type );
217
+
218
+ $this->options['type'] = $type;
219
+
220
+ $this->clear_filesize_cache();
221
+
222
+ }
223
+
224
+ /**
225
+ * Get the exclude rules
226
+ *
227
+ * @access public
228
+ * @return array
229
+ */
230
+ public function get_excludes() {
231
+
232
+ if ( ! empty( $this->options['excludes'] ) )
233
+ parent::set_excludes( $this->options['excludes'] );
234
+
235
+ return parent::get_excludes();
236
+
237
+ }
238
+
239
+ /**
240
+ * Set the exclude rules
241
+ *
242
+ * @access public
243
+ * @param mixed $excludes A comma separated list or array of exclude rules
244
+ * @param bool $append Whether to replace or append to existing rules
245
+ * @return string
246
+ */
247
+ public function set_excludes( $excludes, $append = false ) {
248
+
249
+ // Use the validation from HM_Backup::set_excludes
250
+ parent::set_excludes( $excludes, $append );
251
+
252
+ // If these are valid excludes and they are different save them
253
+ if ( parent::get_excludes() && ( empty( $this->options['excludes'] ) || $this->options['excludes'] !== parent::get_excludes() ) ) {
254
+
255
+ $this->options['excludes'] = $append && ! empty( $this->options['excludes'] ) ? array_merge( (array) $this->options['excludes'], parent::get_excludes() ) : parent::get_excludes();;
256
+
257
+ parent::set_excludes( $this->options['excludes'] );
258
+
259
+ $this->clear_filesize_cache();
260
+
261
+ }
262
+
263
+ }
264
+
265
+ /**
266
+ * Get the maximum number of backups to keep
267
+ *
268
+ * @access public
269
+ */
270
+ public function get_max_backups() {
271
+
272
+ if ( empty( $this->options['max_backups'] ) )
273
+ $this->set_max_backups( 10 );
274
+
275
+ return (int) esc_attr( $this->options['max_backups'] );
276
+
277
+ }
278
+
279
+ /**
280
+ * Set the maximum number of backups to keep
281
+ *
282
+ * @access public
283
+ * @param int $max
284
+ */
285
+ public function set_max_backups( $max ) {
286
+
287
+ if ( empty( $max ) || ! is_int( $max ) )
288
+ throw new Exception( 'Argument 1 for ' . __METHOD__ . ' must be a valid integer' );
289
+
290
+ $this->options['max_backups'] = $max;
291
+
292
+ }
293
+
294
+ /**
295
+ * Get the array of services options for this schedule
296
+ *
297
+ * @access public
298
+ * @return array
299
+ */
300
+ public function get_service_options( $service, $option = null ) {
301
+
302
+ if ( ! is_null( $option ) && isset( $this->options[$service][$option] ) )
303
+ return $this->options[$service][$option];
304
+
305
+ if ( isset( $this->options[$service] ) )
306
+ return $this->options[$service];
307
+
308
+ return array();
309
+
310
+ }
311
+
312
+ /**
313
+ * Set the service options for this schedule
314
+ *
315
+ * @access public
316
+ */
317
+ public function set_service_options( $service, Array $options ) {
318
+
319
+ $this->options[$service] = $options;
320
+
321
+ }
322
+
323
+ /**
324
+ * Calculate the size of the backup
325
+ *
326
+ * Doesn't account for
327
+ * compression
328
+ *
329
+ * @access public
330
+ * @param bool $cached Whether to return from cache
331
+ * @return string
332
+ */
333
+ public function get_filesize( $cached = true ) {
334
+
335
+ if ( ! $cached || ! $filesize = get_transient( 'hmbkp_schedule_' . $this->get_id() . '_filesize' ) ) {
336
+
337
+ $filesize = 0;
338
+
339
+ // Don't include database if file only
340
+ if ( $this->get_type() != 'file' ) {
341
+
342
+ global $wpdb;
343
+
344
+ $res = $wpdb->get_results( 'SHOW TABLE STATUS FROM `' . DB_NAME . '`', ARRAY_A );
345
+
346
+ foreach ( $res as $r )
347
+ $filesize += (float) $r['Data_length'];
348
+
349
+ }
350
+
351
+ // Don't include files if database only
352
+ if ( $this->get_type() != 'database' ) {
353
+
354
+ // Get rid of any cached filesizes
355
+ clearstatcache();
356
+
357
+ $excludes = $this->exclude_string( 'regex' );
358
+
359
+ foreach ( $this->get_files() as $file ) {
360
+
361
+ if ( $file === '.' || $file === '..' || ! $file->isReadable() )
362
+ continue;
363
+
364
+ // Excludes
365
+ if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) ) )
366
+ continue;
367
+
368
+ $filesize += (float) $file->getSize();
369
+
370
+ }
371
+
372
+ }
373
+
374
+ // Cache for a day
375
+ set_transient( 'hmbkp_schedule_' . $this->get_id() . '_filesize', $filesize, time() + 60 * 60 * 24 );
376
+
377
+ }
378
+
379
+ return self::human_filesize( $filesize, null, '%01u %s' );
380
+
381
+ }
382
+
383
+ /**
384
+ * Check whether the filesize has already been calculated and cached.
385
+ *
386
+ * @access public
387
+ * @return void
388
+ */
389
+ public function is_filesize_cached() {
390
+ return (bool) get_transient( 'hmbkp_schedule_' . $this->get_id() . '_filesize' );
391
+ }
392
+
393
+ /**
394
+ * Clear the cached filesize, forces the filesize to be re-calculated the next
395
+ * time get_filesize is called
396
+ *
397
+ * @access public
398
+ * @return void
399
+ */
400
+ public function clear_filesize_cache() {
401
+ delete_transient( 'hmbkp_schedule_' . $this->get_id() . '_filesize' );
402
+ }
403
+
404
+ /**
405
+ * Get the start time for the schedule
406
+ *
407
+ * @access public
408
+ * @return int timestamp || 0 for manual only schedules
409
+ */
410
+ public function get_schedule_start_time() {
411
+
412
+ if ( $this->get_reoccurrence() === 'manually' )
413
+ return 0;
414
+
415
+ if ( ! $this->schedule_start_time )
416
+ $this->set_schedule_start_time( current_time( 'timestamp' ) );
417
+
418
+ return $this->schedule_start_time;
419
+
420
+ }
421
+
422
+ /**
423
+ * Set the schedule start time.
424
+ *
425
+ * @access public
426
+ * @param int $timestamp
427
+ * @return void
428
+ */
429
+ public function set_schedule_start_time( $timestamp ) {
430
+
431
+ if ( (string) (int) $timestamp !== (string) $timestamp )
432
+ throw new Exception( 'Argument 1 for ' . __METHOD__ . ' must be a valid UNIX timestamp' );
433
+
434
+ $this->schedule_start_time = $timestamp;
435
+
436
+ }
437
+
438
+ /**
439
+ * Get the schedule reoccurrence
440
+ *
441
+ * @access public
442
+ */
443
+ public function get_reoccurrence() {
444
+
445
+ // Default to no reoccurrence
446
+ if ( empty( $this->options['reoccurrence'] ) )
447
+ $this->set_reoccurrence( 'manually' );
448
+
449
+ return esc_attr( $this->options['reoccurrence'] );
450
+
451
+ }
452
+
453
+ /**
454
+ * Set the schedule reoccurrence
455
+ *
456
+ * @access public
457
+ * @param string $reoccurrence
458
+ */
459
+ public function set_reoccurrence( $reoccurrence ) {
460
+
461
+ // Check it's valid
462
+ if ( ! is_string( $reoccurrence ) || ! trim( $reoccurrence ) || ( ! in_array( $reoccurrence, array_keys( wp_get_schedules() ) ) ) && $reoccurrence !== 'manually' )
463
+ throw new Exception( 'Argument 1 for ' . __METHOD__ . ' must be a valid cron reoccurrence or "manually"' );
464
+
465
+ if ( isset( $this->options['reoccurrence'] ) && $this->options['reoccurrence'] === $reoccurrence )
466
+ return;
467
+
468
+ $this->options['reoccurrence'] = $reoccurrence;
469
+
470
+ if ( $reoccurrence === 'manually' )
471
+ $this->unschedule();
472
+
473
+ else
474
+ $this->schedule();
475
+
476
+ }
477
+
478
+ /**
479
+ * Get the interval between backups
480
+ *
481
+ * @access public
482
+ * @return int
483
+ */
484
+ public function get_interval() {
485
+
486
+ $schedules = wp_get_schedules();
487
+
488
+ if ( $this->get_reoccurrence() === 'manually' )
489
+ return 0;
490
+
491
+ return $schedules[$this->get_reoccurrence()]['interval'];
492
+
493
+ }
494
+
495
+ /**
496
+ * Get the next occurrence of this scheduled backup
497
+ *
498
+ * @access public
499
+ */
500
+ public function get_next_occurrence() {
501
+
502
+ return wp_next_scheduled( $this->schedule_hook );
503
+
504
+ }
505
+
506
+ private function get_schedule_running_path() {
507
+ return $this->get_path() . '/.schedule-' . $this->get_id() . '-running';
508
+ }
509
+
510
+ /**
511
+ * Schedule the cron
512
+ *
513
+ * @access public
514
+ */
515
+ public function schedule() {
516
+
517
+ // Clear any existing hooks
518
+ $this->unschedule();
519
+
520
+ wp_schedule_event( $this->get_schedule_start_time() + $this->get_interval(), $this->get_reoccurrence(), $this->schedule_hook );
521
+
522
+ // Hook the backu into the schedule hook
523
+ add_action( $this->schedule_hook, array( $this, 'run' ) );
524
+
525
+ }
526
+
527
+ public function unschedule() {
528
+ wp_clear_scheduled_hook( $this->schedule_hook );
529
+ }
530
+
531
+ /**
532
+ * Run the backup
533
+ *
534
+ * @access public
535
+ */
536
+ public function run() {
537
+
538
+ // Mark the backup as started
539
+ $this->set_status( __( 'Backup started', 'hmbkp' ) );
540
+
541
+ $this->backup();
542
+
543
+ // Delete the backup running file
544
+ if ( file_exists( $this->get_schedule_running_path() ) )
545
+ unlink( $this->get_schedule_running_path() );
546
+
547
+ $this->delete_old_backups();
548
+
549
+ }
550
+
551
+ /**
552
+ * Get the status of the running backup.
553
+ *
554
+ * @access public
555
+ * @return string
556
+ */
557
+ public function get_status() {
558
+
559
+ if ( ! file_exists( $this->get_schedule_running_path() ) )
560
+ return '';
561
+
562
+ return end( explode( '::', file_get_contents( $this->get_schedule_running_path() ) ) );
563
+
564
+ }
565
+
566
+ /**
567
+ * Get the filename that the running status is stored in.
568
+ *
569
+ * @access public
570
+ * @return string
571
+ */
572
+ public function get_running_backup_filename() {
573
+
574
+ if ( ! file_exists( $this->get_schedule_running_path() ) )
575
+ return '';
576
+
577
+ return reset( explode( '::', file_get_contents( $this->get_schedule_running_path() ) ) );
578
+ }
579
+
580
+ /**
581
+ * Set the status of the running backup
582
+ *
583
+ * @access public
584
+ * @param string $message
585
+ * @return void
586
+ */
587
+ protected function set_status( $message ) {
588
+
589
+ if ( ! $handle = fopen( $this->get_schedule_running_path(), 'w' ) )
590
+ return;
591
+
592
+ fwrite( $handle, $this->get_archive_filename() . '::' . $message );
593
+
594
+ fclose( $handle );
595
+
596
+ }
597
+
598
+ /**
599
+ * Hook into the actions fired in HM Backup and set the status
600
+ *
601
+ * @return null
602
+ */
603
+ protected function do_action( $action ) {
604
+
605
+ switch ( $action ) :
606
+
607
+ case 'hmbkp_archive_started' :
608
+
609
+ $this->set_status( __( 'Creating zip archive', 'hmbkp' ) );
610
+
611
+ break;
612
+
613
+ case 'hmbkp_mysqldump_started' :
614
+
615
+ $this->set_status( __( 'Dumping database', 'hmbkp' ) );
616
+
617
+ break;
618
+
619
+ case 'hmbkp_backup_complete' :
620
+
621
+ if ( $this->get_errors() ) {
622
+
623
+ $file = $this->get_path() . '/.backup_errors';
624
+
625
+ if ( file_exists( $file ) )
626
+ unlink( $file );
627
+
628
+ if ( ! $handle = @fopen( $file, 'w' ) )
629
+ return;
630
+
631
+ fwrite( $handle, json_encode( $this->get_errors() ) );
632
+
633
+ fclose( $handle );
634
+
635
+ }
636
+
637
+ if ( $this->get_warnings() ) {
638
+
639
+ $file = $this->get_path() . '/.backup_warnings';
640
+
641
+ if ( file_exists( $file ) )
642
+ unlink( $file );
643
+
644
+ if ( ! $handle = @fopen( $file, 'w' ) )
645
+ return;
646
+
647
+ fwrite( $handle, json_encode( $this->get_warnings() ) );
648
+
649
+ fclose( $handle );
650
+
651
+ }
652
+
653
+ break;
654
+
655
+ endswitch;
656
+
657
+ // Pass the actions to all the services
658
+ foreach ( HMBKP_Services::get_services( $this ) as $service )
659
+ $service->action( $action );
660
+
661
+ // Fire the parent function as well
662
+ parent::do_action( $action );
663
+
664
+ }
665
+
666
+ /**
667
+ * Get the backups created by this schedule
668
+ *
669
+ * @todo look into using recursiveDirectoryIterator and recursiveRegexIterator
670
+ * @access public
671
+ */
672
+ public function get_backups() {
673
+
674
+ $files = array();
675
+
676
+ if ( $handle = @opendir( $this->get_path() ) ) {
677
+
678
+ while ( false !== ( $file = readdir( $handle ) ) )
679
+ if ( pathinfo( $file, PATHINFO_EXTENSION ) === 'zip' && strpos( $file, $this->get_id() ) !== false && $this->get_running_backup_filename() != $file )
680
+ $files[@filemtime( trailingslashit( $this->get_path() ) . $file )] = trailingslashit( $this->get_path() ) . $file;
681
+
682
+ closedir( $handle );
683
+
684
+ }
685
+
686
+ krsort( $files );
687
+
688
+ return $files;
689
+
690
+ }
691
+
692
+ /**
693
+ * Delete old backups
694
+ *
695
+ * @access private
696
+ */
697
+ public function delete_old_backups() {
698
+
699
+ if ( count( $this->get_backups() ) <= $this->get_max_backups() )
700
+ return;
701
+
702
+ array_map( array( $this, 'delete_backup' ), array_slice( $this->get_backups(), $this->get_max_backups() ) );
703
+
704
+ }
705
+
706
+ /**
707
+ * Delete a specific back up file created by this schedule
708
+ *
709
+ * @access public
710
+ * @param string $filepath
711
+ */
712
+ public function delete_backup( $filepath ) {
713
+
714
+ // Check that it's a valid filepath
715
+ if ( empty( $filepath ) || ! is_string( $filepath ) )
716
+ throw new Exception( 'Argument 1 for ' . __METHOD__ . ' must be a non empty string' );
717
+
718
+ // Make sure it exists
719
+ if ( ! file_exists( $filepath ) )
720
+ throw new Exception( $filepath . ' doesn\'t exist' );
721
+
722
+ // Make sure it was created by this schedule
723
+ if ( strpos( $filepath, $this->get_id() ) === false )
724
+ throw new Exception( 'That backup wasn\'t created by this schedule' );
725
+
726
+ unlink( $filepath );
727
+
728
+ }
729
+
730
+ /**
731
+ * Delete all back up files created by this schedule
732
+ *
733
+ * @access public
734
+ */
735
+ public function delete_backups() {
736
+
737
+ array_map( array( $this, 'delete_backup' ), $this->get_backups() );
738
+
739
+ }
740
+
741
+ /**
742
+ * Save the schedules options.
743
+ *
744
+ * @access public
745
+ */
746
+ public function save() {
747
+
748
+ // Only save them if they have changed
749
+ if ( $this->options !== get_option( 'hmbkp_schedule_' . $this->get_id() ) )
750
+ update_option( 'hmbkp_schedule_' . $this->get_id(), $this->options );
751
+
752
+ }
753
+
754
+ /**
755
+ * Cancel this schedule
756
+ *
757
+ * Cancels the cron job, removes the schedules options
758
+ * and optionally deletes all backups crated by
759
+ * this schedule.
760
+ *
761
+ * @access public
762
+ */
763
+ public function cancel() {
764
+
765
+ // Delete the schedule options
766
+ delete_option( 'hmbkp_schedule_' . $this->get_id() );
767
+
768
+ // Clear any existing schedules
769
+ $this->unschedule();
770
+
771
+ // Clear the filesize transient
772
+ $this->clear_filesize_cache();
773
+
774
+ // Delete it's backups
775
+ $this->delete_backups();
776
+
777
+ }
778
+
779
+ }
classes/schedules.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * A simple class for loading schedules
5
+ */
6
+ class HMBKP_Schedules {
7
+
8
+ /**
9
+ * An array of schedules
10
+ *
11
+ * @var mixed
12
+ * @access private
13
+ */
14
+ private $schedules;
15
+
16
+ /**
17
+ * Load the schedules from wp_options and store in $this->schedules
18
+ *
19
+ * @access public
20
+ */
21
+ public function __construct() {
22
+
23
+ global $wpdb;
24
+
25
+ // Load all schedule options from the database
26
+ $schedules = $wpdb->get_col( "SELECT option_name from $wpdb->options WHERE option_name LIKE 'hmbkp\_schedule\_%'" );
27
+
28
+ // Instantiate each one as a HMBKP_Scheduled_Backup
29
+ $this->schedules = array_map( array( $this, 'instantiate' ), array_filter( (array) $schedules ) );
30
+
31
+ }
32
+
33
+ /**
34
+ * Get an array of schedules
35
+ *
36
+ * @access public
37
+ * @return array
38
+ */
39
+ public function get_schedules() {
40
+ return $this->schedules;
41
+ }
42
+
43
+ /**
44
+ * Instantiate the individual scheduled backup objects
45
+ *
46
+ * @access private
47
+ * @param string $id
48
+ * @return array An array of HMBKP_Scheduled_Backup objects
49
+ */
50
+ private function instantiate( $id ) {
51
+
52
+ return new HMBKP_Scheduled_Backup( str_replace( 'hmbkp_schedule_', '', $id ) );
53
+
54
+ }
55
+
56
+ }
classes/services.php ADDED
@@ -0,0 +1,233 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * An abstract service class, individual services should
5
+ * extend this class
6
+ */
7
+ abstract class HMBKP_Service {
8
+
9
+ /**
10
+ * The instance HMBKP_Backup_Schedule that this service is
11
+ * is currently working with
12
+ */
13
+ protected $schedule;
14
+
15
+ /**
16
+ * The form to output as part of the schedule settings
17
+ *
18
+ * If you don't want a whole form return ''; here and use @field instead
19
+ */
20
+ abstract protected function form();
21
+
22
+ /**
23
+ * The field to output as part of the schedule settings
24
+ *
25
+ * If you don't want a field return ''; here and use @field instead
26
+ */
27
+ abstract protected function field();
28
+
29
+ /**
30
+ * Validate and sanitize data before it's saved.
31
+ *
32
+ * @param array &$new_data An array or data from $_GET, passed by reference so it can be modified,
33
+ * @param array $old_data The old data thats going to be overwritten
34
+ * @return array $error Array of validation errors e.g. return array( 'email' => 'not valid' );
35
+ */
36
+ abstract protected function update( &$new_data, $old_data );
37
+
38
+ /**
39
+ * The string to be output as part of the schedule sentence
40
+ *
41
+ * @return string
42
+ */
43
+ abstract protected function display();
44
+
45
+ /**
46
+ * Receives actions from the backup
47
+ *
48
+ * This is where the service should do it's thing
49
+ *
50
+ * @see HM_Backup::do_action for a list of the actions
51
+ */
52
+ abstract protected function action( $action );
53
+
54
+ /**
55
+ * Utility for getting a formated html input name attribute
56
+ *
57
+ * @param string $name The name of the field
58
+ * @return string The formated name
59
+ */
60
+ protected function get_field_name( $name ) {
61
+ return esc_attr( get_class( $this ) . '[' . $name . ']' );
62
+ }
63
+
64
+ /**
65
+ * Get the value of a field
66
+ * @param string $name The name of the field
67
+ * @return string The field value
68
+ */
69
+ protected function get_field_value( $name, $esc = 'esc_attr' ) {
70
+
71
+ if ( $this->schedule->get_service_options( get_class( $this ), $name ) )
72
+ return $esc( $this->schedule->get_service_options( get_class( $this ), $name ) );
73
+
74
+ return '';
75
+
76
+ }
77
+
78
+ /**
79
+ * Save the settings for this service
80
+ *
81
+ * @return null|array returns null on success, array of errors on failure
82
+ */
83
+ public function save() {
84
+
85
+ $classname = get_class( $this );
86
+
87
+ $old_data = $this->schedule->get_service_options( $classname );
88
+
89
+ $new_data = isset( $_GET[$classname] ) ? $_GET[$classname] : $old_data;
90
+
91
+ $errors = $this->update( $new_data, $old_data );
92
+
93
+ if ( $errors = array_flip( $errors ) ) {
94
+
95
+ foreach( $errors as $error => &$field )
96
+ $field = get_class( $this ) . '[' . $field . ']';
97
+
98
+ return array_flip( $errors );
99
+
100
+ }
101
+
102
+ $this->schedule->set_service_options( $classname, $new_data );
103
+
104
+ return array();
105
+
106
+ }
107
+
108
+ /**
109
+ * Set the current schedule object
110
+ *
111
+ * @param HMBKP_Scheduled_Backup $schedule An instantiated schedule object
112
+ */
113
+ public function set_schedule( HMBKP_Scheduled_Backup $schedule ) {
114
+ $this->schedule = $schedule;
115
+ }
116
+
117
+ }
118
+
119
+ /**
120
+ * A singleton to handle the registering, unregistering
121
+ * and storage of services
122
+ */
123
+ class HMBKP_Services {
124
+
125
+ /**
126
+ * Store the current instance
127
+ *
128
+ * @access private
129
+ * @var object HMBKP_Services
130
+ * @static
131
+ */
132
+ private static $instance;
133
+
134
+ /**
135
+ * The array of services
136
+ *
137
+ * Should be of the format array( __FILE__ => __CLASS__ );
138
+ *
139
+ * @access private
140
+ * @var array
141
+ * @static
142
+ */
143
+ private $services = array();
144
+
145
+ /**
146
+ * The current schedule object
147
+ *
148
+ * @access private
149
+ * @var object HMBKP_Scheduled_Backup
150
+ */
151
+ private $schedule;
152
+
153
+ /**
154
+ * Get the current instance
155
+ *
156
+ * @access public
157
+ * @static
158
+ */
159
+ public static function instance() {
160
+
161
+ if ( ! isset( self::$instance ) )
162
+ self::$instance = new HMBKP_Services;
163
+
164
+ return self::$instance;
165
+
166
+ }
167
+
168
+ /**
169
+ * Get the array of registered services
170
+ *
171
+ * @access public
172
+ */
173
+ public function get_services( HMBKP_Scheduled_Backup $schedule = null ) {
174
+
175
+ if ( is_null( $schedule ) )
176
+ return self::instance()->services;
177
+
178
+ self::instance()->schedule = $schedule;
179
+
180
+ return array_map( array( self::instance(), 'instantiate' ), self::instance()->services );
181
+
182
+ }
183
+
184
+ /**
185
+ * Register a new service
186
+ *
187
+ * @access public
188
+ */
189
+ public function register( $filepath, $classname ) {
190
+
191
+ if ( ! file_exists( $filepath ) )
192
+ throw new Exception( 'Argument 1 for ' . __METHOD__ . ' must be a valid filepath' );
193
+
194
+ self::instance()->services[$filepath] = $classname;
195
+
196
+ }
197
+
198
+ /**
199
+ * Unregister an existing service
200
+ *
201
+ * @access public
202
+ */
203
+ public function unregister( $filepath ) {
204
+
205
+ if ( ! isset( self::instance()->services[$filepath] ) )
206
+ throw new Exception( 'Argument 1 for ' . __METHOD__ . ' must be a registered service' );
207
+
208
+ unset( self::instance()->services[$filepath] );
209
+
210
+ }
211
+
212
+ /**
213
+ * Instantiate the individual service classes
214
+ *
215
+ * @access private
216
+ * @param string $class
217
+ * @return array An array of instantiated classes
218
+ */
219
+ private function instantiate( $class ) {
220
+
221
+ if ( ! class_exists( $class ) )
222
+ throw new Exception( 'Argument 1 for ' . __METHOD__ . ' must be a valid class' );
223
+
224
+ $$class = new $class;
225
+
226
+ if ( self::instance()->schedule )
227
+ $$class->set_schedule( self::instance()->schedule );
228
+
229
+ return $$class;
230
+
231
+ }
232
+
233
+ }
classes/wp-cli.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Implement backup command
5
+ *
6
+ * @todo fix
7
+ * @package wp-cli
8
+ * @subpackage commands/third-party
9
+ */
10
+ class BackUpCommand extends WP_CLI_Command {
11
+
12
+ public function __construct( $args, $assoc_args ) {
13
+
14
+ // Make sure it's possible to do a backup
15
+ if ( HM_Backup::is_safe_mode_active() ) {
16
+ WP_CLI::error( __( 'Backup not possible when php is running safe_mode on', 'hmbkp' ) );
17
+ return false;
18
+ }
19
+
20
+ add_action( 'hmbkp_mysqldump_started', function() {
21
+ WP_CLI::line( __( 'Backup: Dumping database...', 'hmbkp' ) );
22
+ } );
23
+
24
+ add_action( 'hmbkp_archive_started', function() {
25
+ WP_CLI::line( __( 'Backup: Zipping everything up...', 'hmbkp' ) );
26
+ } );
27
+
28
+ // Clean up any mess left by a previous backup
29
+ hmbkp_cleanup();
30
+
31
+ $hm_backup = new HM_Backup();
32
+
33
+ if ( ! empty( $assoc_args['path'] ) )
34
+ $hm_backup->set_path( $assoc_args['path'] );
35
+
36
+ if ( ! empty( $assoc_args['root'] ) )
37
+ $hm_backup->set_root( $assoc_args['root'] );
38
+
39
+ if ( ( ! is_dir( $hm_backup->get_path() ) && ( ! is_writable( dirname( $hm_backup->get_path() ) ) || ! mkdir( $hm_backup->get_path() ) ) ) || ! is_writable( $hm_backup->get_path() ) ) {
40
+ WP_CLI::error( __( 'Invalid backup path', 'hmbkp' ) );
41
+ return false;
42
+ }
43
+
44
+ if ( ! is_dir( $hm_backup->get_root() ) || ! is_readable( $hm_backup->get_root() ) ) {
45
+ WP_CLI::error( __( 'Invalid root path', 'hmbkp' ) );
46
+ return false;
47
+ }
48
+
49
+ if ( ! empty( $assoc_args['files_only'] ) )
50
+ $hm_backup->set_type( 'file' );
51
+
52
+ if ( ! empty( $assoc_args['database_only'] ) )
53
+ $hm_backup->set_type( 'database' );
54
+
55
+ if ( isset( $assoc_args['mysqldump_command_path'] ) )
56
+ $hm_backup->set_mysqldump_command_path( $assoc_args['mysqldump_command_path'] );
57
+
58
+ if ( isset( $assoc_args['zip_command_path'] ) )
59
+ $hm_backup->set_zip_command_path( $assoc_args['zip_command_path'] );
60
+
61
+ if ( ! empty( $assoc_args['excludes'] ) )
62
+ $hm_backup->set_excludes( $assoc_args['excludes'] );
63
+
64
+ $hm_backup->backup();
65
+
66
+ // Delete any old backup files
67
+ //hmbkp_delete_old_backups();
68
+
69
+ if ( file_exists( $hm_backup->get_archive_filepath() ) )
70
+ WP_CLI::success( __( 'Backup Complete: ', 'hmbkp' ) . $hm_backup->get_archive_filepath() );
71
+
72
+ else
73
+ WP_CLI::error( __( 'Backup Failed', 'hmbkp' ) );
74
+
75
+ }
76
+
77
+ static function help() {
78
+
79
+ WP_CLI::line( <<<EOB
80
+ usage: wp backup [--files_only] [--database_only] [--path<dir>] [--root<dir>] [--zip_command_path=<path>] [--mysqldump_command_path=<path>]
81
+
82
+ --files_only Backup files only, default to off
83
+ --database_only Backup database only, defaults to off
84
+ --path dir that the backup should be save in, defaults to wp-content/backups/
85
+ --root dir that should be backed up, defaults to site root.
86
+ --zip_command_path path to your zip binary, standard locations are automatically used
87
+ --mysqldump_command_path path to your mysqldump binary, standard locations are automatically used
88
+
89
+ EOB
90
+ );
91
+
92
+ }
93
+
94
+ }
95
+ WP_CLI::addCommand( 'backup', 'BackUpCommand' );
functions/backup.actions.php DELETED
@@ -1,61 +0,0 @@
1
- <?php
2
-
3
- // Mark the backup as started
4
- add_action( 'hmbkp_backup_started', 'hmbkp_set_status', 10, 0 );
5
-
6
- /**
7
- * Set the backup status to dumping database
8
- *
9
- * @return null
10
- */
11
- function hmbkp_set_status_dumping_database() {
12
- hmbkp_set_status( __( 'Dumping database', 'hmbkp' ) );
13
- }
14
- add_action( 'hmbkp_mysqldump_started', 'hmbkp_set_status_dumping_database' );
15
-
16
- /**
17
- * Set the backup status to archiving
18
- *
19
- * @return null
20
- */
21
- function hmbkp_set_status_archiving() {
22
- hmbkp_set_status( __( 'Creating zip archive', 'hmbkp' ) );
23
- }
24
- add_action( 'hmbkp_archive_started', 'hmbkp_set_status_archiving' );
25
-
26
- function hmbkp_backup_complete( $backup ) {
27
-
28
- if ( $backup->errors() ) {
29
-
30
- hmbkp_cleanup();
31
-
32
- $file = hmbkp_path() . '/.backup_errors';
33
-
34
- if ( file_exists( $file ) )
35
- unlink( $file );
36
-
37
- if ( ! $handle = @fopen( $file, 'w' ) )
38
- return;
39
-
40
- fwrite( $handle, json_encode( $backup->errors() ) );
41
-
42
- fclose( $handle );
43
-
44
- } elseif ( $backup->warnings() ) {
45
-
46
- $file = hmbkp_path() . '/.backup_warnings';
47
-
48
- if ( file_exists( $file ) )
49
- unlink( $file );
50
-
51
- if ( ! $handle = @fopen( $file, 'w' ) )
52
- return;
53
-
54
- fwrite( $handle, json_encode( $backup->warnings() ) );
55
-
56
- fclose( $handle );
57
-
58
- }
59
-
60
- }
61
- add_action( 'hmbkp_backup_complete', 'hmbkp_backup_complete' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
functions/backup.functions.php DELETED
@@ -1,294 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Run HM Backup
5
- *
6
- * @return null
7
- */
8
- function hmbkp_do_backup() {
9
-
10
- // Make sure it's possible to do a backup
11
- if ( ! hmbkp_possible() )
12
- return;
13
-
14
- // Clean up any mess left by a previous backup
15
- hmbkp_cleanup();
16
-
17
- HM_Backup::get_instance()->backup();
18
-
19
- hmbkp_set_status( __( 'Removing old backups', 'hmbkp' ) );
20
-
21
- // Delete any old backup files
22
- hmbkp_delete_old_backups();
23
-
24
- if ( file_exists( hmbkp_path() . '/.backup_running' ) )
25
- unlink( hmbkp_path() . '/.backup_running' );
26
-
27
- if ( file_exists( HM_Backup::get_instance()->archive_filepath() ) ) {
28
-
29
- $file = hmbkp_path() . '/.backup_complete';
30
-
31
- if ( ! $handle = @fopen( $file, 'w' ) )
32
- return;
33
-
34
- fwrite( $handle, HM_Backup::get_instance()->archive_filename() );
35
-
36
- fclose( $handle );
37
-
38
- }
39
-
40
- hmbkp_email_backup();
41
-
42
- }
43
-
44
- /**
45
- * Deletes old backup files
46
- *
47
- * @return null
48
- */
49
- function hmbkp_delete_old_backups() {
50
-
51
- $files = hmbkp_get_backups();
52
-
53
- if ( count( $files ) <= hmbkp_max_backups() )
54
- return;
55
-
56
- foreach( array_slice( $files, hmbkp_max_backups() ) as $file )
57
- hmbkp_delete_backup( base64_encode( $file ) );
58
-
59
- }
60
-
61
- /**
62
- * Returns an array of backup files
63
- *
64
- * @todo use RecursiveDirectoryIterator
65
- * @return array $files
66
- */
67
- function hmbkp_get_backups() {
68
-
69
- $files = array();
70
-
71
- $hmbkp_path = hmbkp_path();
72
-
73
- if ( $handle = @opendir( $hmbkp_path ) ) :
74
-
75
- while ( false !== ( $file = readdir( $handle ) ) )
76
- if ( end( explode( '.', $file ) ) == 'zip' )
77
- $files[@filemtime( trailingslashit( $hmbkp_path ) . $file )] = trailingslashit( $hmbkp_path ) . $file;
78
-
79
- closedir( $handle );
80
-
81
- endif;
82
-
83
- // If there is a custom backups directory and it's not writable then include those backups as well
84
- if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH && is_dir( HMBKP_PATH ) && ! is_writable( HMBKP_PATH ) ) :
85
-
86
- if ( $handle = opendir( HMBKP_PATH ) ) :
87
-
88
- while ( false !== ( $file = readdir( $handle ) ) )
89
- if ( strpos( $file, '.zip' ) !== false )
90
- $files[@filemtime( trailingslashit( HMBKP_PATH ) . $file )] = trailingslashit( HMBKP_PATH ) . $file;
91
-
92
- closedir( $handle );
93
-
94
- endif;
95
-
96
- endif;
97
-
98
- krsort( $files );
99
-
100
- // Don't include the currently running backup
101
- if ( $key = array_search( trailingslashit( hmbkp_path() ) . hmbkp_in_progress(), $files ) )
102
- unset( $files[$key] );
103
-
104
- return $files;
105
-
106
- }
107
-
108
- /**
109
- * Delete a backup file
110
- *
111
- * @param $file base64 encoded filename
112
- */
113
- function hmbkp_delete_backup( $file ) {
114
-
115
- $file = base64_decode( $file );
116
-
117
- // Delete the file
118
- if ( ( strpos( $file, hmbkp_path() ) !== false || strpos( $file, WP_CONTENT_DIR . '/backups' ) !== false ) && file_exists( $file ) )
119
- unlink( $file );
120
-
121
- }
122
-
123
- /**
124
- * Email backup.
125
- *
126
- * @param $file
127
- * @return bool
128
- */
129
- function hmbkp_email_backup() {
130
-
131
- $file = HM_Backup::get_instance()->archive_filepath();
132
-
133
- if ( ! hmbkp_get_email_address() || ! file_exists( $file ) )
134
- return;
135
-
136
- update_option( 'hmbkp_email_error', 'hmbkp_email_failed' );
137
-
138
- // Raise the memory and time limit
139
- @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
140
- @set_time_limit( 0 );
141
-
142
- // @todo admin_url?
143
- $download = get_bloginfo( 'wpurl' ) . '/wp-admin/tools.php?page=' . HMBKP_PLUGIN_SLUG . '&hmbkp_download=' . base64_encode( $file );
144
-
145
- $domain = parse_url( get_bloginfo( 'url' ), PHP_URL_HOST ) . parse_url( get_bloginfo( 'url' ), PHP_URL_PATH );
146
-
147
- $subject = sprintf( __( 'Backup of %s', 'hmbkp' ), $domain );
148
- $message = sprintf( __( 'BackUpWordPress has completed a backup of your site %1$s.\n\nThe backup file should be attached to this email.\n\nYou can also download the backup file by clicking the link below:\n\n%2$s\n\nKind Regards\n\n The Happy BackUpWordPress Backup Emailing Robot', 'hmbkp' ), get_bloginfo( 'url' ), $download );
149
- $headers = 'From: BackUpWordPress <' . get_bloginfo( 'admin_email' ) . '>' . "\r\n";
150
-
151
- // Try to send the email
152
- $sent = wp_mail( array_filter( hmbkp_get_email_address(), 'is_email' ), $subject, $message, $headers, $file );
153
-
154
- // If it failed- Try to send a download link - The file was probably too large.
155
- if ( ! $sent ) :
156
-
157
- $subject = sprintf( __( 'Backup of %s', 'hmbkp' ), $domain );
158
- $message = sprintf( __( 'BackUpWordPress has completed a backup of your site %1$s.\n\nUnfortunately the backup file was too large to attach to this email.\n\nYou can download the backup file by clicking the link below:\n\n%2$s\n\nKind Regards\n\n The Happy BackUpWordPress Backup Emailing Robot', 'hmbkp' ), get_bloginfo( 'url' ), $download );
159
-
160
- $sent = wp_mail( array_filter( hmbkp_get_email_address(), 'is_email' ), $subject, $message, $headers );
161
-
162
- endif;
163
-
164
- // Set option for email not sent error
165
- if ( $sent )
166
- delete_option( 'hmbkp_email_error' );
167
-
168
- return true;
169
-
170
- }
171
-
172
- /**
173
- * Set the status of the running backup
174
- *
175
- * @param string $message. (default: '')
176
- * @return void
177
- */
178
- function hmbkp_set_status( $message = '' ) {
179
-
180
- $file = hmbkp_path() . '/.backup_running';
181
-
182
- if ( ! $handle = @fopen( $file, 'w' ) )
183
- return;
184
-
185
- fwrite( $handle, HM_Backup::get_instance()->archive_filename() . '::' . $message );
186
-
187
- fclose( $handle );
188
-
189
- }
190
-
191
- /**
192
- * Get the status of the running backup
193
- *
194
- * @return string
195
- */
196
- function hmbkp_get_status() {
197
-
198
- if ( ! file_exists( hmbkp_path() . '/.backup_running' ) )
199
- return '';
200
-
201
- return end( explode( '::', file_get_contents( hmbkp_path() . '/.backup_running' ) ) );
202
-
203
- }
204
-
205
- /**
206
- * Get the list of excludes
207
- *
208
- * @return bool
209
- */
210
- function hmbkp_get_excludes() {
211
-
212
- if ( defined( 'HMBKP_EXCLUDE' ) && HMBKP_EXCLUDE )
213
- return HMBKP_EXCLUDE;
214
-
215
- if ( get_option( 'hmbkp_excludes' ) )
216
- return get_option( 'hmbkp_excludes' );
217
-
218
- return '';
219
-
220
- }
221
-
222
- /**
223
- * Return an array of invalid custom exclude rules
224
- *
225
- * @return array
226
- */
227
- function hmbkp_invalid_custom_excludes() {
228
-
229
- $invalid_rules = array();
230
-
231
- // Check if any absolute path excludes actually exist
232
- if ( $excludes = hmbkp_get_excludes() )
233
-
234
- foreach ( explode( ',', $excludes ) as $rule )
235
- if ( ( $rule = trim( $rule ) ) && in_array( substr( $rule, 0, 1 ), array( '/', '\\' ) ) && ! file_exists( $rule ) && ! file_exists( hmbkp_get_home_path() . $rule ) && ! file_exists( trailingslashit( hmbkp_get_home_path() ) . $rule ) )
236
- $invalid_rules[] = $rule;
237
-
238
- return array_filter( $invalid_rules );
239
-
240
- }
241
-
242
- /**
243
- * Return an array of valid custom exclude rules
244
- *
245
- * @return array
246
- */
247
- function hmbkp_valid_custom_excludes() {
248
-
249
- $valid_rules = array();
250
-
251
- $excludes = hmbkp_get_excludes();
252
-
253
- $valid_rules = array_diff( explode( ',', $excludes ), hmbkp_invalid_custom_excludes() );
254
-
255
- return array_filter( array_map( 'trim', $valid_rules ) );
256
-
257
- }
258
-
259
- /**
260
- * Check if a backup is running
261
- *
262
- * @return bool
263
- */
264
- function hmbkp_in_progress() {
265
- return file_exists( hmbkp_path() . '/.backup_running' ) ? reset( explode( '::', file_get_contents( hmbkp_path() .'/.backup_running' ) ) ) : '';
266
- }
267
-
268
- /**
269
- * Get the exclude string from HM Backup
270
- *
271
- * @param string $context
272
- * @return string
273
- */
274
- function hmbkp_exclude_string( $context ) {
275
- return HM_Backup::get_instance()->exclude_string( $context );
276
- }
277
-
278
- function hmbkp_backup_errors() {
279
-
280
- if ( ! file_exists( hmbkp_path() . '/.backup_errors' ) )
281
- return '';
282
-
283
- return file_get_contents( hmbkp_path() . '/.backup_errors' );
284
-
285
- }
286
-
287
- function hmbkp_backup_warnings() {
288
-
289
- if ( ! file_exists( hmbkp_path() . '/.backup_warnings' ) )
290
- return '';
291
-
292
- return file_get_contents( hmbkp_path() . '/.backup_warnings' );
293
-
294
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
functions/core.functions.php DELETED
@@ -1,558 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Setup the plugin defaults on activation
5
- */
6
- function hmbkp_activate() {
7
-
8
- hmbkp_deactivate();
9
-
10
- hmbkp_setup_schedule();
11
-
12
- }
13
-
14
- /**
15
- * Cleanup on plugin deactivation
16
- *
17
- * Removes options and clears all cron schedules
18
- */
19
- function hmbkp_deactivate() {
20
-
21
- hmbkp_setup_hm_backup();
22
-
23
- // Options to delete
24
- $options = array(
25
- 'hmbkp_zip_path',
26
- 'hmbkp_mysqldump_path',
27
- 'hmbkp_path',
28
- 'hmbkp_running',
29
- 'hmbkp_status',
30
- 'hmbkp_complete',
31
- 'hmbkp_email_error'
32
- );
33
-
34
- foreach ( $options as $option )
35
- delete_option( $option );
36
-
37
- delete_transient( 'hmbkp_running' );
38
- delete_transient( 'hmbkp_estimated_filesize' );
39
-
40
- // Clear cron
41
- wp_clear_scheduled_hook( 'hmbkp_schedule_backup_hook' );
42
- wp_clear_scheduled_hook( 'hmbkp_schedule_single_backup_hook' );
43
-
44
- hmbkp_cleanup();
45
-
46
- }
47
-
48
- /**
49
- * Handles anything that needs to be
50
- * done when the plugin is updated
51
- */
52
- function hmbkp_update() {
53
-
54
- // Every update
55
- if ( version_compare( HMBKP_VERSION, get_option( 'hmbkp_plugin_version' ), '>' ) ) {
56
-
57
- hmbkp_deactivate();
58
-
59
- // Force .htaccess to be re-written
60
- if ( file_exists( hmbkp_path() . '/.htaccess' ) )
61
- unlink( hmbkp_path() . '/.htaccess' );
62
-
63
- }
64
-
65
- // Update from backUpWordPress 0.4.5
66
- if ( get_option( 'bkpwp_max_backups' ) ) :
67
-
68
- // Carry over the custom path
69
- if ( $legacy_path = get_option( 'bkpwppath' ) )
70
- update_option( 'hmbkp_path', $legacy_path );
71
-
72
- // Options to remove
73
- $legacy_options = array(
74
- 'bkpwp_archive_types',
75
- 'bkpwp_automail_from',
76
- 'bkpwp_domain',
77
- 'bkpwp_domain_path',
78
- 'bkpwp_easy_mode',
79
- 'bkpwp_excludelists',
80
- 'bkpwp_install_user',
81
- 'bkpwp_listmax_backups',
82
- 'bkpwp_max_backups',
83
- 'bkpwp_presets',
84
- 'bkpwp_reccurrences',
85
- 'bkpwp_schedules',
86
- 'bkpwp_calculation',
87
- 'bkpwppath',
88
- 'bkpwp_status_config',
89
- 'bkpwp_status'
90
- );
91
-
92
- foreach ( $legacy_options as $option )
93
- delete_option( $option );
94
-
95
- global $wp_roles;
96
-
97
- $wp_roles->remove_cap( 'administrator','manage_backups' );
98
- $wp_roles->remove_cap( 'administrator','download_backups' );
99
-
100
- wp_clear_scheduled_hook( 'bkpwp_schedule_bkpwp_hook' );
101
-
102
- endif;
103
-
104
- // Update the stored version
105
- if ( get_option( 'hmbkp_plugin_version' ) !== HMBKP_VERSION )
106
- update_option( 'hmbkp_plugin_version', HMBKP_VERSION );
107
-
108
- }
109
-
110
- /**
111
- * Take a file size and return a human readable
112
- * version
113
- *
114
- * @param int $size
115
- * @param string $unit. (default: null)
116
- * @param string $retstring. (default: null)
117
- * @param bool $si. (default: true)
118
- * @return int
119
- */
120
- function hmbkp_size_readable( $size, $unit = null, $retstring = '%01.2f %s', $si = true ) {
121
-
122
- // Units
123
- if ( $si === true ) :
124
- $sizes = array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB' );
125
- $mod = 1000;
126
-
127
- else :
128
- $sizes = array('B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB');
129
- $mod = 1024;
130
-
131
- endif;
132
-
133
- $ii = count( $sizes ) - 1;
134
-
135
- // Max unit
136
- $unit = array_search( (string) $unit, $sizes );
137
-
138
- if ( is_null( $unit ) || $unit === false )
139
- $unit = $ii;
140
-
141
- // Loop
142
- $i = 0;
143
-
144
- while ( $unit != $i && $size >= 1024 && $i < $ii ) {
145
- $size /= $mod;
146
- $i++;
147
- }
148
-
149
- return sprintf( $retstring, $size, $sizes[$i] );
150
- }
151
-
152
- /**
153
- * Add daily as a cron schedule choice
154
- *
155
- * @todo can we not use the built in schedules
156
- * @param array $recc
157
- * @return array $recc
158
- */
159
- function hmbkp_more_reccurences( $recc ) {
160
-
161
- $hmbkp_reccurrences = array(
162
- 'hmbkp_weekly' => array( 'interval' => 604800, 'display' => 'every week' ),
163
- 'hmbkp_fortnightly' => array( 'interval' => 1209600, 'display' => 'once a fortnight' ),
164
- 'hmbkp_monthly' => array( 'interval' => 2629743.83 , 'display' => 'once a month' )
165
- );
166
-
167
- return array_merge( $recc, $hmbkp_reccurrences );
168
- }
169
- add_filter( 'cron_schedules', 'hmbkp_more_reccurences' );
170
-
171
- /**
172
- * Recursively delete a directory including
173
- * all the files and sub-directories.
174
- *
175
- * @param string $dir
176
- */
177
- function hmbkp_rmdirtree( $dir ) {
178
-
179
- if ( is_file( $dir ) )
180
- unlink( $dir );
181
-
182
- if ( ! is_dir( $dir ) )
183
- return false;
184
-
185
- $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir ), RecursiveIteratorIterator::CHILD_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD );
186
-
187
- foreach ( $files as $file ) {
188
-
189
- if ( $file->isDir() )
190
- @rmdir( $file->getPathname() );
191
-
192
- else
193
- @unlink( $file->getPathname() );
194
-
195
- }
196
-
197
- @rmdir( $dir );
198
-
199
- }
200
-
201
- /**
202
- * Calculate the size of the backup
203
- *
204
- * Doesn't currently take into account for
205
- * compression
206
- *
207
- * @return string
208
- */
209
- function hmbkp_calculate() {
210
-
211
- @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
212
-
213
- // Check cache
214
- if ( $filesize = get_transient( 'hmbkp_estimated_filesize' ) )
215
- return hmbkp_size_readable( $filesize, null, '%01u %s' );
216
-
217
- $filesize = 0;
218
-
219
- // Don't include database if files only
220
- if ( ! hmbkp_get_files_only() ) {
221
-
222
- global $wpdb;
223
-
224
- $res = $wpdb->get_results( 'SHOW TABLE STATUS FROM ' . DB_NAME, ARRAY_A );
225
-
226
- foreach ( $res as $r )
227
- $filesize += (float) $r['Data_length'];
228
-
229
- }
230
-
231
- if ( ! hmbkp_get_database_only() ) {
232
-
233
- // Get rid of any cached filesizes
234
- clearstatcache();
235
-
236
- foreach ( HM_Backup::get_instance()->files() as $file )
237
- $filesize += (float) @filesize( hmbkp_get_home_path() . $file );
238
-
239
- }
240
-
241
- // Cache in a transient for a week
242
- set_transient( 'hmbkp_estimated_filesize', $filesize, 604800 );
243
-
244
- return hmbkp_size_readable( $filesize, null, '%01u %s' );
245
-
246
- }
247
-
248
- /**
249
- * Calculate the total filesize of all backups
250
- *
251
- * @return string
252
- */
253
- function hmbkp_total_filesize() {
254
-
255
- $files = hmbkp_get_backups();
256
- $filesize = 0;
257
-
258
- clearstatcache();
259
-
260
- foreach ( $files as $f )
261
- $filesize += @filesize( $f );
262
-
263
- return hmbkp_size_readable( $filesize );
264
-
265
- }
266
-
267
-
268
- /**
269
- * Set Up the shedule.
270
- * This should runn according to the Frequency defined, or set in the option.
271
- *
272
- * @access public
273
- * @return void
274
- */
275
- function hmbkp_setup_schedule() {
276
-
277
- // Clear any old schedules
278
- wp_clear_scheduled_hook( 'hmbkp_schedule_backup_hook' );
279
-
280
- if( hmbkp_get_disable_automatic_backup() )
281
- return;
282
-
283
- // Default to 11 in the evening
284
- $time = '23:00';
285
-
286
- // Allow it to be overridden
287
- if ( defined( 'HMBKP_DAILY_SCHEDULE_TIME' ) && HMBKP_DAILY_SCHEDULE_TIME )
288
- $time = HMBKP_DAILY_SCHEDULE_TIME;
289
-
290
- $offset = current_time( 'timestamp' ) - time();
291
- $scheduletime_UTC = strtotime( $time ) - $offset;
292
-
293
- if( defined( 'HMBKP_SCHEDULE_FREQUENCY' ) && HMBKP_SCHEDULE_FREQUENCY )
294
- $schedule_frequency = HMBKP_SCHEDULE_FREQUENCY;
295
- elseif( get_option('hmbkp_schedule_frequency') )
296
- $schedule_frequency = get_option('hmbkp_schedule_frequency');
297
- else
298
- $schedule_frequency = 'daily';
299
-
300
- // Advance by the interval. (except daily, when it will only happen if shcheduled time is in the past. )
301
- if( $schedule_frequency != 'daily' || $schedule_frequency == 'daily' && $scheduletime_UTC < time() ) {
302
- $interval = wp_get_schedules('hmbkp_schedule_backup_hook');
303
- $interval = $interval[ $schedule_frequency ]['interval'];
304
- $scheduletime_UTC = $scheduletime_UTC + $interval;
305
- }
306
-
307
- wp_schedule_event( $scheduletime_UTC, $schedule_frequency, 'hmbkp_schedule_backup_hook' );
308
- }
309
-
310
-
311
- /**
312
- * Get the absolute filesystem path to the root of the WordPress installation
313
- * A clone of the get_home_path function found in wp-admin
314
- *
315
- * @uses get_option
316
- * @return string Full filesystem path to the root of the WordPress installation
317
- */
318
- function hmbkp_get_home_path() {
319
- $home = get_option( 'home' );
320
- $siteurl = get_option( 'siteurl' );
321
- if ( $home != '' && $home != $siteurl ) {
322
- $wp_path_rel_to_home = str_replace( $home, '', $siteurl ); /* $siteurl - $home */
323
- $pos = strrpos( $_SERVER["SCRIPT_FILENAME"], $wp_path_rel_to_home );
324
- $home_path = substr( $_SERVER["SCRIPT_FILENAME"], 0, $pos );
325
- $home_path = trailingslashit( $home_path );
326
- } else {
327
- $home_path = ABSPATH;
328
- }
329
-
330
- return $home_path;
331
- }
332
-
333
-
334
- /**
335
- * Get the path to the backups directory
336
- *
337
- * Will try to create it if it doesn't exist
338
- * and will fallback to default if a custom dir
339
- * isn't writable.
340
- */
341
- function hmbkp_path() {
342
-
343
- $path = get_option( 'hmbkp_path' );
344
-
345
- // Allow the backups path to be defined
346
- if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH )
347
- $path = HMBKP_PATH;
348
-
349
- // If the dir doesn't exist or isn't writable then use wp-content/backups instead
350
- if ( ( ! $path || ! is_writable( $path ) ) && hmbkp_conform_dir( $path ) != hmbkp_path_default() )
351
- $path = hmbkp_path_default();
352
-
353
- // Create the backups directory if it doesn't exist
354
- if ( is_writable( dirname( $path ) ) && ! is_dir( $path ) )
355
- mkdir( $path, 0755 );
356
-
357
- if ( get_option( 'hmbkp_path' ) != $path )
358
- update_option( 'hmbkp_path', $path );
359
-
360
- // Secure the directory with a .htaccess file
361
- $htaccess = $path . '/.htaccess';
362
-
363
- $contents[] = '# ' . sprintf( __( 'This %s file ensures that other people cannot download your backup files.', 'hmbkp' ), '.htaccess' );
364
- $contents[] = '';
365
- $contents[] = '<IfModule mod_rewrite.c>';
366
- $contents[] = 'RewriteEngine On';
367
- $contents[] = 'RewriteCond %{QUERY_STRING} !key=' . md5( HMBKP_SECURE_KEY );
368
- $contents[] = 'RewriteRule (.*) - [F]';
369
- $contents[] = '</IfModule>';
370
- $contents[] = '';
371
-
372
- if ( ! file_exists( $htaccess ) && is_writable( $path ) && require_once( ABSPATH . '/wp-admin/includes/misc.php' ) )
373
- insert_with_markers( $htaccess, 'BackUpWordPress', $contents );
374
-
375
- return hmbkp_conform_dir( $path );
376
- }
377
-
378
- /**
379
- * Return the default backup path
380
- *
381
- * @return string path
382
- */
383
- function hmbkp_path_default() {
384
- return hmbkp_conform_dir( WP_CONTENT_DIR . '/backups' );
385
- }
386
-
387
- /**
388
- * Move the backup directory and all existing backup files to a new
389
- * location
390
- *
391
- * @param string $from path to move the backups dir from
392
- * @param string $to path to move the backups dir to
393
- * @return void
394
- */
395
- function hmbkp_path_move( $from, $to ) {
396
-
397
- // Create the custom backups directory if it doesn't exist
398
- if ( is_writable( dirname( $to ) ) && ! is_dir( $to ) )
399
- mkdir( $to, 0755 );
400
-
401
- if ( ! is_dir( $to ) || ! is_writable( $to ) || ! is_dir( $from ) )
402
- return false;
403
-
404
- hmbkp_cleanup();
405
-
406
- if ( $handle = opendir( $from ) ) :
407
-
408
- while ( false !== ( $file = readdir( $handle ) ) )
409
- if ( $file != '.' && $file != '..' )
410
- rename( trailingslashit( $from ) . $file, trailingslashit( $to ) . $file );
411
-
412
- closedir( $handle );
413
-
414
- endif;
415
-
416
- hmbkp_rmdirtree( $from );
417
-
418
- }
419
-
420
- /**
421
- * The maximum number of backups to keep
422
- * defaults to 10
423
- *
424
- * @return int
425
- */
426
- function hmbkp_max_backups() {
427
-
428
- if ( defined( 'HMBKP_MAX_BACKUPS' ) && is_numeric( HMBKP_MAX_BACKUPS ) )
429
- return (int) HMBKP_MAX_BACKUPS;
430
-
431
- if ( get_option( 'hmbkp_max_backups' ) )
432
- return (int) get_option( 'hmbkp_max_backups', 10 );
433
-
434
- return 10;
435
-
436
- }
437
-
438
- /**
439
- * Whether to only backup files
440
- *
441
- * @return bool
442
- */
443
- function hmbkp_get_files_only() {
444
-
445
- if ( defined( 'HMBKP_FILES_ONLY' ) && HMBKP_FILES_ONLY )
446
- return true;
447
-
448
- if ( get_option( 'hmbkp_files_only' ) )
449
- return true;
450
-
451
- return false;
452
- }
453
-
454
- /**
455
- * Whether to only backup the database
456
- *
457
- * @return bool
458
- */
459
- function hmbkp_get_database_only() {
460
-
461
- if ( defined( 'HMBKP_DATABASE_ONLY' ) && HMBKP_DATABASE_ONLY )
462
- return true;
463
-
464
- if ( get_option( 'hmbkp_database_only' ) )
465
- return true;
466
-
467
- return false;
468
-
469
- }
470
-
471
- /**
472
- * Returns defined email address or email address saved in options.
473
- * If none set, return empty string.
474
- */
475
- function hmbkp_get_email_address( $type = 'array' ) {
476
-
477
- $email = '';
478
-
479
- if ( defined( 'HMBKP_EMAIL' ) && HMBKP_EMAIL )
480
- $email = HMBKP_EMAIL;
481
-
482
- elseif ( get_option( 'hmbkp_email_address' ) )
483
- $email = get_option( 'hmbkp_email_address' );
484
-
485
- if ( ! empty( $email ) && $type == 'array' )
486
- $email = array_filter( array_map( 'trim', explode( ',', $email ) ) );
487
-
488
- return $email;
489
-
490
- }
491
-
492
- /**
493
- * Are automatic backups disabled
494
- *
495
- * @return bool
496
- */
497
- function hmbkp_get_disable_automatic_backup() {
498
-
499
- if ( defined( 'HMBKP_DISABLE_AUTOMATIC_BACKUP' ) && HMBKP_DISABLE_AUTOMATIC_BACKUP )
500
- return true;
501
-
502
- if ( get_option( 'hmbkp_disable_automatic_backup' ) )
503
- return true;
504
-
505
- return false;
506
-
507
- }
508
-
509
- /**
510
- * Check if a backup is possible with regards to file
511
- * permissions etc.
512
- *
513
- * @return bool
514
- */
515
- function hmbkp_possible() {
516
-
517
- if ( ! is_writable( hmbkp_path() ) || ! is_dir( hmbkp_path() ) || hmbkp_is_safe_mode_active() )
518
- return false;
519
-
520
- if ( defined( 'HMBKP_FILES_ONLY' ) && HMBKP_FILES_ONLY && defined( 'HMBKP_DATABASE_ONLY' ) && HMBKP_DATABASE_ONLY )
521
- return false;
522
-
523
- return true;
524
- }
525
-
526
- /**
527
- * Remove any non backup.zip files from the backups dir.
528
- *
529
- * @return void
530
- */
531
- function hmbkp_cleanup() {
532
-
533
- delete_option( 'hmbkp_email_error' );
534
-
535
- $hmbkp_path = hmbkp_path();
536
-
537
- if ( ! is_dir( $hmbkp_path ) )
538
- return;
539
-
540
- if ( $handle = opendir( $hmbkp_path ) ) :
541
-
542
- while ( false !== ( $file = readdir( $handle ) ) )
543
- if ( ! in_array( $file, array( '.', '..', '.htaccess' ) ) && pathinfo( $file, PATHINFO_EXTENSION ) !== 'zip' )
544
- hmbkp_rmdirtree( trailingslashit( $hmbkp_path ) . $file );
545
-
546
- closedir( $handle );
547
-
548
- endif;
549
-
550
- }
551
-
552
- function hmbkp_conform_dir( $dir ) {
553
- return HM_Backup::get_instance()->conform_dir( $dir );
554
- }
555
-
556
- function hmbkp_is_safe_mode_active() {
557
- return HM_Backup::get_instance()->is_safe_mode_active();
558
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
functions/core.php ADDED
@@ -0,0 +1,362 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Setup the plugin defaults on activation
5
+ */
6
+ function hmbkp_activate() {
7
+
8
+ hmbkp_deactivate();
9
+
10
+ }
11
+
12
+ /**
13
+ * Cleanup on plugin deactivation
14
+ *
15
+ * Removes options and clears all cron schedules
16
+ */
17
+ function hmbkp_deactivate() {
18
+
19
+ // Options to delete
20
+ $options = array(
21
+ 'hmbkp_zip_path',
22
+ 'hmbkp_mysqldump_path',
23
+ 'hmbkp_path',
24
+ 'hmbkp_running',
25
+ 'hmbkp_status',
26
+ 'hmbkp_complete',
27
+ 'hmbkp_email_error'
28
+ );
29
+
30
+ foreach ( $options as $option )
31
+ delete_option( $option );
32
+
33
+ delete_transient( 'hmbkp_running' );
34
+ delete_transient( 'hmbkp_estimated_filesize' );
35
+
36
+ // Clear cron
37
+ wp_clear_scheduled_hook( 'hmbkp_schedule_backup_hook' );
38
+ wp_clear_scheduled_hook( 'hmbkp_schedule_single_backup_hook' );
39
+
40
+ hmbkp_cleanup();
41
+
42
+ }
43
+
44
+ /**
45
+ * Handles anything that needs to be
46
+ * done when the plugin is updated
47
+ */
48
+ function hmbkp_update() {
49
+
50
+ // Update from backUpWordPress 0.4.5
51
+ if ( get_option( 'bkpwp_max_backups' ) ) {
52
+
53
+ // Carry over the custom path
54
+ if ( $legacy_path = get_option( 'bkpwppath' ) )
55
+ update_option( 'hmbkp_path', $legacy_path );
56
+
57
+ // Options to remove
58
+ $legacy_options = array(
59
+ 'bkpwp_archive_types',
60
+ 'bkpwp_automail_from',
61
+ 'bkpwp_domain',
62
+ 'bkpwp_domain_path',
63
+ 'bkpwp_easy_mode',
64
+ 'bkpwp_excludelists',
65
+ 'bkpwp_install_user',
66
+ 'bkpwp_listmax_backups',
67
+ 'bkpwp_max_backups',
68
+ 'bkpwp_presets',
69
+ 'bkpwp_reccurrences',
70
+ 'bkpwp_schedules',
71
+ 'bkpwp_calculation',
72
+ 'bkpwppath',
73
+ 'bkpwp_status_config',
74
+ 'bkpwp_status'
75
+ );
76
+
77
+ foreach ( $legacy_options as $option )
78
+ delete_option( $option );
79
+
80
+ global $wp_roles;
81
+
82
+ $wp_roles->remove_cap( 'administrator','manage_backups' );
83
+ $wp_roles->remove_cap( 'administrator','download_backups' );
84
+
85
+ wp_clear_scheduled_hook( 'bkpwp_schedule_bkpwp_hook' );
86
+
87
+ }
88
+
89
+ // Version 1 to 2
90
+ if ( version_compare ( '2.0' , get_option( 'hmbkp_plugin_version' ) ) ) {
91
+
92
+ /**
93
+ * Setup a backwards compatible schedule
94
+ */
95
+ $legacy_schedule = new HMBKP_Scheduled_Backup( 'backup' );
96
+
97
+ // Backup type
98
+ if ( ( defined( 'HMBKP_FILES_ONLY' ) && HMBKP_FILES_ONLY ) || get_option( 'hmbkp_files_only' ) )
99
+ $legacy_schedule->set_type( 'file' );
100
+
101
+ elseif ( ( defined( 'HMBKP_DATABASE_ONLY' ) && HMBKP_DATABASE_ONLY ) || get_option( 'hmbkp_database_only' ) )
102
+ $legacy_schedule->set_type( 'database' );
103
+
104
+ else
105
+ $legacy_schedule->set_type( 'complete' );
106
+
107
+ // Daily schedule time
108
+ if ( defined( 'HMBKP_DAILY_SCHEDULE_TIME' ) && HMBKP_DAILY_SCHEDULE_TIME )
109
+ $legacy_schedule->set_schedule_start_time( strtotime( HMBKP_DAILY_SCHEDULE_TIME ) );
110
+
111
+ // Backup schedule
112
+ $legacy_schedule->set_reoccurrence( str_replace( 'hmbkp_', '', get_option( 'hmbkp_schedule_frequency', 'daily' ) ) );
113
+
114
+ // Automatic backups disabled?
115
+ if ( ( defined( 'HMBKP_DISABLE_AUTOMATIC_BACKUP' ) && HMBKP_DISABLE_AUTOMATIC_BACKUP ) || get_option( 'hmbkp_disable_automatic_backup' ) )
116
+ $legacy_schedule->set_reoccurrence( 'manually' );
117
+
118
+ // Max backups
119
+ if ( defined( 'HMBKP_MAX_BACKUPS' ) && is_numeric( HMBKP_MAX_BACKUPS ) )
120
+ $legacy_schedule->set_max_backups( (int) HMBKP_MAX_BACKUPS );
121
+
122
+ else
123
+ $legacy_schedule->set_max_backups( (int) get_option( 'hmbkp_max_backups', 10 ) );
124
+
125
+ // Excludes
126
+ if ( get_option( 'hmbkp_excludes' ) )
127
+ $legacy_schedule->set_excludes( get_option( 'hmbkp_excludes' ) );
128
+
129
+ // Backup email
130
+ if ( defined( 'HMBKP_EMAIL' ) && is_email( HMBKP_EMAIL ) )
131
+ $legacy_schedule->set_service_options( 'HMBKP_Email_Service', array( 'email' => HMBKP_EMAIL ) );
132
+
133
+ elseif ( is_email( get_option( 'hmbkp_email_address' ) ) )
134
+ $legacy_schedule->set_service_options( 'HMBKP_Email_Service', array( 'email' => get_option( 'hmbkp_email_address' ) ) );
135
+
136
+ // Set the archive filename to what it used to be
137
+ $legacy_schedule->set_archive_filename( implode( '-', array( get_bloginfo( 'name' ), 'backup', date( 'Y-m-d-H-i-s', current_time( 'timestamp' ) ) ) ) . '.zip' );
138
+
139
+ $legacy_schedule->save();
140
+
141
+ // Remove the legacy options
142
+ foreach ( array( 'hmbkp_email', 'hmbkp_database_only', 'hmbkp_files_only', 'hmbkp_max_backups', 'hmbkp_email_address', 'hmbkp_email', 'hmbkp_schedule_frequency', 'hmbkp_disable_automatic_backup' ) as $option_name )
143
+ delete_option( $option_name );
144
+
145
+
146
+ }
147
+
148
+ // Every update
149
+ if ( version_compare( HMBKP_VERSION, get_option( 'hmbkp_plugin_version' ), '>' ) ) {
150
+
151
+ hmbkp_deactivate();
152
+
153
+ // Force .htaccess to be re-written
154
+ if ( file_exists( hmbkp_path() . '/.htaccess' ) )
155
+ unlink( hmbkp_path() . '/.htaccess' );
156
+
157
+ }
158
+
159
+ // Update the stored version
160
+ if ( get_option( 'hmbkp_plugin_version' ) !== HMBKP_VERSION )
161
+ update_option( 'hmbkp_plugin_version', HMBKP_VERSION );
162
+
163
+ }
164
+
165
+ /**
166
+ * Setup the default backup schedules
167
+ */
168
+ function hmbkp_setup_default_schedules() {
169
+
170
+ $schedules = new HMBKP_Schedules;
171
+
172
+ if ( $schedules->get_schedules() )
173
+ return;
174
+
175
+ /**
176
+ * Schedule a database backup daily and store backups
177
+ * for the last 2 weeks
178
+ */
179
+ $database_daily = new HMBKP_Scheduled_Backup( 'default-1' );
180
+ $database_daily->set_type( 'database' );
181
+ $database_daily->set_reoccurrence( 'daily' );
182
+ $database_daily->set_max_backups( 14 );
183
+ $database_daily->save();
184
+
185
+ /**
186
+ * Schedule a complete backup to run weekly and store backups for
187
+ * the last 3 months
188
+ */
189
+ $complete_weekly = new HMBKP_Scheduled_Backup( 'default-2' );
190
+ $complete_weekly->set_type( 'complete' );
191
+ $complete_weekly->set_reoccurrence( 'weekly' );
192
+ $complete_weekly->set_max_backups( 12 );
193
+ $complete_weekly->save();
194
+
195
+ function hmbkp_default_schedules_setup_warning() {
196
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has setup your default schedules.', 'hmbkp' ) . '</strong> ' . __( 'By default BackUpWordPress performs a daily backup of your database and a weekly backup of your database &amp; files. You can modify these schedules.', 'hmbkp' ) . '</p></div>';
197
+ }
198
+ add_action( 'admin_notices', 'hmbkp_default_schedules_setup_warning' );
199
+
200
+ }
201
+
202
+ /**
203
+ * Add weekly, fortnightly and monthly as a cron schedule choices
204
+ *
205
+ * @param array $reccurrences
206
+ * @return array $reccurrences
207
+ */
208
+ function hmbkp_more_reccurences( $reccurrences ) {
209
+
210
+ return array_merge( $reccurrences, array(
211
+ 'weekly' => array( 'interval' => 604800, 'display' => 'Once Weekly' ),
212
+ 'fortnightly' => array( 'interval' => 1209600, 'display' => 'Once Fortnightly' ),
213
+ 'monthly' => array( 'interval' => 2629743.83 , 'display' => 'Once Monthly' )
214
+ ) );
215
+ }
216
+ add_filter( 'cron_schedules', 'hmbkp_more_reccurences' );
217
+
218
+ /**
219
+ * Recursively delete a directory including
220
+ * all the files and sub-directories.
221
+ *
222
+ * @param string $dir
223
+ */
224
+ function hmbkp_rmdirtree( $dir ) {
225
+
226
+ if ( is_file( $dir ) )
227
+ @unlink( $dir );
228
+
229
+ if ( ! is_dir( $dir ) )
230
+ return false;
231
+
232
+ $files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dir ), RecursiveIteratorIterator::CHILD_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD );
233
+
234
+ foreach ( $files as $file ) {
235
+
236
+ if ( $file->isDir() )
237
+ @rmdir( $file->getPathname() );
238
+
239
+ else
240
+ @unlink( $file->getPathname() );
241
+
242
+ }
243
+
244
+ @rmdir( $dir );
245
+
246
+ }
247
+
248
+ /**
249
+ * Get the path to the backups directory
250
+ *
251
+ * Will try to create it if it doesn't exist
252
+ * and will fallback to default if a custom dir
253
+ * isn't writable.
254
+ */
255
+ function hmbkp_path() {
256
+
257
+ $path = get_option( 'hmbkp_path' );
258
+
259
+ // Allow the backups path to be defined
260
+ if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH )
261
+ $path = HMBKP_PATH;
262
+
263
+ // If the dir doesn't exist or isn't writable then use wp-content/backups instead
264
+ if ( ( ! $path || ! is_writable( $path ) ) && HM_Backup::conform_dir( $path ) !== hmbkp_path_default() )
265
+ $path = hmbkp_path_default();
266
+
267
+ // Create the backups directory if it doesn't exist
268
+ if ( is_writable( dirname( $path ) ) && ! is_dir( $path ) )
269
+ mkdir( $path, 0755 );
270
+
271
+ if ( get_option( 'hmbkp_path' ) !== $path )
272
+ update_option( 'hmbkp_path', $path );
273
+
274
+ // Protect against directory browsing by including a index.html file
275
+ $index = $path . '/index.html';
276
+
277
+ if ( ! file_exists( $index ) && is_writable( $path ) )
278
+ file_put_contents( $index, '' );
279
+
280
+ return HM_Backup::conform_dir( $path );
281
+
282
+ }
283
+
284
+ /**
285
+ * Return the default backup path
286
+ *
287
+ * @return string path
288
+ */
289
+ function hmbkp_path_default() {
290
+ return HM_Backup::conform_dir( WP_CONTENT_DIR . '/backups' );
291
+ }
292
+
293
+ /**
294
+ * Move the backup directory and all existing backup files to a new
295
+ * location
296
+ *
297
+ * @param string $from path to move the backups dir from
298
+ * @param string $to path to move the backups dir to
299
+ * @return void
300
+ */
301
+ function hmbkp_path_move( $from, $to ) {
302
+
303
+ // Create the custom backups directory if it doesn't exist
304
+ if ( is_writable( dirname( $to ) ) && ! is_dir( $to ) )
305
+ mkdir( $to, 0755 );
306
+
307
+ if ( ! is_dir( $to ) || ! is_writable( $to ) || ! is_dir( $from ) )
308
+ return false;
309
+
310
+ hmbkp_cleanup();
311
+
312
+ if ( $handle = opendir( $from ) ) :
313
+
314
+ while ( false !== ( $file = readdir( $handle ) ) )
315
+ if ( $file !== '.' && $file !== '..' )
316
+ rename( trailingslashit( $from ) . $file, trailingslashit( $to ) . $file );
317
+
318
+ closedir( $handle );
319
+
320
+ endif;
321
+
322
+ hmbkp_rmdirtree( $from );
323
+
324
+ }
325
+
326
+ /**
327
+ * Check if a backup is possible with regards to file
328
+ * permissions etc.
329
+ *
330
+ * @return bool
331
+ */
332
+ function hmbkp_possible() {
333
+
334
+ if ( ! is_writable( hmbkp_path() ) || ! is_dir( hmbkp_path() ) || HM_Backup::is_safe_mode_active() )
335
+ return false;
336
+
337
+ return true;
338
+ }
339
+
340
+ /**
341
+ * Remove any non backup.zip files from the backups dir.
342
+ *
343
+ * @return void
344
+ */
345
+ function hmbkp_cleanup() {
346
+
347
+ $hmbkp_path = hmbkp_path();
348
+
349
+ if ( ! is_dir( $hmbkp_path ) )
350
+ return;
351
+
352
+ if ( $handle = opendir( $hmbkp_path ) ) :
353
+
354
+ while ( false !== ( $file = readdir( $handle ) ) )
355
+ if ( ! in_array( $file, array( '.', '..', 'index.html' ) ) && pathinfo( $file, PATHINFO_EXTENSION ) !== 'zip' )
356
+ hmbkp_rmdirtree( trailingslashit( $hmbkp_path ) . $file );
357
+
358
+ closedir( $handle );
359
+
360
+ endif;
361
+
362
+ }
functions/interface.functions.php DELETED
@@ -1,202 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Displays a row in the manage backups table
5
- *
6
- * @param string $file
7
- */
8
- function hmbkp_get_backup_row( $file ) {
9
-
10
- $encode = base64_encode( $file );
11
- $offset = current_time( 'timestamp' ) - time(); ?>
12
-
13
- <tr class="hmbkp_manage_backups_row<?php if ( file_exists( hmbkp_path() . '/.backup_complete' ) ) : ?> completed<?php unlink( hmbkp_path() . '/.backup_complete' ); endif; ?>">
14
-
15
- <th scope="row">
16
- <?php echo date_i18n( get_option( 'date_format' ) . ' - ' . get_option( 'time_format' ), @filemtime( $file ) + $offset ); ?>
17
- </th>
18
-
19
- <td>
20
- <?php echo hmbkp_size_readable( filesize( $file ) ); ?>
21
- </td>
22
-
23
- <td>
24
-
25
- <a href="tools.php?page=<?php echo HMBKP_PLUGIN_SLUG; ?>&amp;hmbkp_download=<?php echo $encode; ?>"><?php _e( 'Download', 'hmbkp' ); ?></a> |
26
- <a href="tools.php?page=<?php echo HMBKP_PLUGIN_SLUG; ?>&amp;hmbkp_delete=<?php echo $encode ?>" class="delete"><?php _e( 'Delete', 'hmbkp' ); ?></a>
27
-
28
- </td>
29
-
30
- </tr>
31
-
32
- <?php }
33
-
34
- /**
35
- * Displays admin notices for various error / warning
36
- * conditions
37
- *
38
- * @return void
39
- */
40
- function hmbkp_admin_notices() {
41
-
42
- // If the form has been submitted, display updated notification
43
- // Display notifications for any errors in the settings form.
44
- if ( ! empty( $_POST['hmbkp_settings_submit'] ) ) :
45
-
46
- function hmbkp_advanced_settings_saved() { ?>
47
-
48
- <div id="setting-error-settings_updated" class="updated settings-error"><p><strong><?php _e( 'Settings saved.', 'hmbkp' ); ?></strong></p></div>
49
-
50
- <?php global $hmbkp_errors;
51
-
52
- if ( ! empty( $hmbkp_errors ) && $hmbkp_errors->get_error_code() )
53
- foreach( $hmbkp_errors->get_error_messages() as $hmbkp_error )
54
- echo '<div class="error"><p>' . $hmbkp_error . '</p></div>';
55
-
56
- }
57
- add_action( 'admin_notices', 'hmbkp_advanced_settings_saved' );
58
-
59
- endif;
60
-
61
- // If the backups directory doesn't exist and can't be automatically created
62
- if ( ! is_dir( hmbkp_path() ) ) :
63
-
64
- function hmbkp_path_exists_warning() {
65
- $php_user = exec( 'whoami' );
66
- $php_group = reset( explode( ' ', exec( 'groups' ) ) );
67
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress is almost ready.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'The backups directory can\'t be created because your %1$s directory isn\'t writable, run %2$s or %3$s or create the folder yourself.', 'hmbkp' ), '<code>wp-content</code>', '<code>chown ' . $php_user . ':' . $php_group . ' ' . WP_CONTENT_DIR . '</code>', '<code>chmod 777 ' . WP_CONTENT_DIR . '</code>' ) . '</p></div>';
68
- }
69
- add_action( 'admin_notices', 'hmbkp_path_exists_warning' );
70
-
71
- endif;
72
-
73
- // If the backups directory exists but isn't writable
74
- if ( is_dir( hmbkp_path() ) && ! is_writable( hmbkp_path() ) ) :
75
-
76
- function hmbkp_writable_path_warning() {
77
- $php_user = exec( 'whoami' );
78
- $php_group = reset( explode( ' ', exec( 'groups' ) ) );
79
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress is almost ready.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'Your backups directory isn\'t writable, run %1$s or %2$s or set the permissions yourself.', 'hmbkp' ), '<code>chown -R ' . $php_user . ':' . $php_group . ' ' . hmbkp_path() . '</code>', '<code>chmod -R 777 ' . hmbkp_path() . '</code>' ) . '</p></div>';
80
- }
81
- add_action( 'admin_notices', 'hmbkp_writable_path_warning' );
82
-
83
- endif;
84
-
85
- // If safe mode is active
86
- if ( hmbkp_is_safe_mode_active() ) :
87
-
88
- function hmbkp_safe_mode_warning() {
89
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( '%1$s is running in %2$s. Please contact your host and ask them to disable %3$s.', 'hmbkp' ), '<code>PHP</code>', sprintf( '<a href="%1$s">%2$s</a>', __( 'http://php.net/manual/en/features.safe-mode.php', 'hmbkp' ), __( 'Safe Mode', 'hmbkp' ) ), '<code>' . __( 'Safe Mode', 'hmbkp' ) . '</code>' ) . '</p></div>';
90
- }
91
- add_action( 'admin_notices', 'hmbkp_safe_mode_warning' );
92
-
93
- endif;
94
-
95
- // If both HMBKP_FILES_ONLY & HMBKP_DATABASE_ONLY are defined at the same time
96
- if ( hmbkp_get_files_only() && hmbkp_get_database_only() ) :
97
-
98
- function hmbkp_nothing_to_backup_warning() {
99
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'You have both %1$s and %2$s defined so there isn\'t anything to back up.', 'hmbkp' ), '<code>HMBKP_DATABASE_ONLY</code>', '<code>HMBKP_FILES_ONLY</code>' ) . '</p></div>';
100
- }
101
- add_action( 'admin_notices', 'hmbkp_nothing_to_backup_warning' );
102
-
103
- endif;
104
-
105
- // If the email address is invalid
106
- if ( hmbkp_get_email_address() && array_diff( hmbkp_get_email_address(), array_filter( hmbkp_get_email_address(), 'is_email' ) ) ) :
107
-
108
- function hmbkp_email_invalid_warning() {
109
- $invalid_emails = array_diff( hmbkp_get_email_address(), array_filter( hmbkp_get_email_address(), 'is_email' ) );
110
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( _n( 'The following email address is not valid: %s.', 'The following email addresses are not valid: %s.', count( $invalid_emails ), 'hmbkp' ), '<code>' . implode( '</code>, <code>', $invalid_emails ) . '</code>' ) . '</p></div>';
111
- }
112
- add_action( 'admin_notices', 'hmbkp_email_invalid_warning' );
113
-
114
- endif;
115
-
116
- // If the email failed to send
117
- if ( hmbkp_get_email_address() && get_option( 'hmbkp_email_error' ) ) :
118
-
119
- function hmbkp_email_failed_warning() {
120
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . __( 'The last backup email failed to send. It\'s likely that the file is too large.', 'hmbkp' ) . '</p></div>';
121
- }
122
- add_action( 'admin_notices', 'hmbkp_email_failed_warning' );
123
-
124
- endif;
125
-
126
- // If a custom backups directory is defined and it doesn't exist and can't be created
127
- if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH && ! is_dir( HMBKP_PATH ) ) :
128
-
129
- function hmbkp_custom_path_exists_warning() {
130
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'Your custom backups directory %1$s doesn\'t exist and can\'t be created, your backups will be saved to %2$s instead.', 'hmbkp' ), '<code>' . HMBKP_PATH . '</code>', '<code>' . hmbkp_path() . '</code>' ) . '</p></div>';
131
- }
132
- add_action( 'admin_notices', 'hmbkp_custom_path_exists_warning' );
133
-
134
- endif;
135
-
136
- // If a custom backups directory is defined and exists but isn't writable
137
- if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH && is_dir( HMBKP_PATH ) && ! is_writable( HMBKP_PATH ) ) :
138
-
139
- function hmbkp_custom_path_writable_notice() {
140
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'Your custom backups directory %1$s isn\'t writable, new backups will be saved to %2$s instead.', 'hmbkp' ), '<code>' . HMBKP_PATH . '</code>', '<code>' . hmbkp_path() . '</code>' ) . '</p></div>';
141
- }
142
- add_action( 'admin_notices', 'hmbkp_custom_path_writable_notice' );
143
-
144
- endif;
145
-
146
- // If there are custom excludes defined and any of the files or directories don't exist
147
- if ( hmbkp_invalid_custom_excludes() ) :
148
-
149
- function hmbkp_invalid_exclude_notice() {
150
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'You have defined a custom exclude list but the following paths don\'t exist %s, are you sure you entered them correctly?', 'hmbkp' ), '<code>' . implode( '</code>, <code>', (array) hmbkp_invalid_custom_excludes() ) . '</code>' ) . '</p></div>';
151
- }
152
- add_action( 'admin_notices', 'hmbkp_invalid_exclude_notice' );
153
-
154
- endif;
155
-
156
- // If there are any errors reported in the backup
157
- if ( hmbkp_backup_errors_message() ) :
158
-
159
- function hmbkp_backup_errors_notice() {
160
- echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress detected issues with your last backup.', 'hmbkp' ) . '</strong><a href="' . add_query_arg( 'action', 'hmbkp_dismiss_error' ) . '" style="float: right;" class="button">Dismiss</a></p>' . hmbkp_backup_errors_message() . '</div>';
161
- }
162
- add_action( 'admin_notices', 'hmbkp_backup_errors_notice' );
163
-
164
- endif;
165
-
166
- }
167
- add_action( 'admin_head', 'hmbkp_admin_notices' );
168
-
169
- /**
170
- * Hook in an change the plugin description when BackUpWordPress is activated
171
- *
172
- * @param array $plugins
173
- * @return $plugins
174
- */
175
- function hmbkp_plugin_row( $plugins ) {
176
-
177
- if ( isset( $plugins[HMBKP_PLUGIN_SLUG . '/plugin.php'] ) )
178
- $plugins[HMBKP_PLUGIN_SLUG . '/plugin.php']['Description'] = str_replace( 'Once activated you\'ll find me under <strong>Tools &rarr; Backups</strong>', 'Find me under <strong><a href="' . admin_url( 'tools.php?page=' . HMBKP_PLUGIN_SLUG ) . '">Tools &rarr; Backups</a></strong>', $plugins[HMBKP_PLUGIN_SLUG . '/plugin.php']['Description'] );
179
-
180
- return $plugins;
181
-
182
- }
183
- add_filter( 'all_plugins', 'hmbkp_plugin_row', 10 );
184
-
185
- /**
186
- * Parse the json string of errors and
187
- * output as a human readable message
188
- *
189
- * @access public
190
- * @return null
191
- */
192
- function hmbkp_backup_errors_message() {
193
-
194
- $message = '';
195
-
196
- foreach ( (array) json_decode( hmbkp_backup_errors() ) as $key => $errors )
197
- foreach ( $errors as $error )
198
- $message .= '<p><strong>' . $key . '</strong>: <code>' . implode( ':', (array) $error ) . '</code></p>';
199
-
200
- return $message;
201
-
202
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
functions/interface.php ADDED
@@ -0,0 +1,284 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Displays a row in the manage backups table
5
+ *
6
+ * @param string $file
7
+ */
8
+ function hmbkp_get_backup_row( $file, HMBKP_Scheduled_Backup $schedule ) {
9
+
10
+ $encoded_file = urlencode( base64_encode( $file ) );
11
+ $offset = current_time( 'timestamp' ) - time(); ?>
12
+
13
+ <tr class="hmbkp_manage_backups_row<?php if ( file_exists( hmbkp_path() . '/.backup_complete' ) ) : ?> completed<?php unlink( hmbkp_path() . '/.backup_complete' ); endif; ?>">
14
+
15
+ <th scope="row">
16
+ <?php echo esc_attr( date_i18n( get_option( 'date_format' ) . ' - ' . get_option( 'time_format' ), @filemtime( $file ) + $offset ) ); ?>
17
+ </th>
18
+
19
+ <td class="code">
20
+ <?php echo esc_attr( HMBKP_Scheduled_Backup::human_filesize( @filesize( $file ) ) ); ?>
21
+ </td>
22
+
23
+ <td><?php echo esc_attr( hmbkp_human_get_type( $file, $schedule ) ); ?></td>
24
+
25
+ <td>
26
+
27
+ <a href="<?php echo wp_nonce_url( admin_url( 'tools.php?page=' . HMBKP_PLUGIN_SLUG . '&amp;hmbkp_download_backup=' . $encoded_file . '&amp;hmbkp_schedule_id=' . $schedule->get_id() ), 'hmbkp-download_backup' ); ?>"><?php _e( 'Download', 'hmbkp' ); ?></a> |
28
+ <a href="<?php echo wp_nonce_url( admin_url( 'tools.php?page=' . HMBKP_PLUGIN_SLUG . '&amp;hmbkp_delete_backup=' . $encoded_file . '&amp;hmbkp_schedule_id=' . $schedule->get_id() ), 'hmbkp-delete_backup' ); ?>" class="delete-action"><?php _e( 'Delete', 'hmbkp' ); ?></a>
29
+
30
+ </td>
31
+
32
+ </tr>
33
+
34
+ <?php }
35
+
36
+ /**
37
+ * Displays admin notices for various error / warning
38
+ * conditions
39
+ *
40
+ * @return void
41
+ */
42
+ function hmbkp_admin_notices() {
43
+
44
+ // If the backups directory doesn't exist and can't be automatically created
45
+ if ( ! is_dir( hmbkp_path() ) ) :
46
+
47
+ function hmbkp_path_exists_warning() {
48
+ $php_user = exec( 'whoami' );
49
+ $php_group = reset( explode( ' ', exec( 'groups' ) ) );
50
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress is almost ready.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'The backups directory can\'t be created because your %1$s directory isn\'t writable, run %2$s or %3$s or create the folder yourself.', 'hmbkp' ), '<code>wp-content</code>', '<code>chown ' . $php_user . ':' . $php_group . ' ' . WP_CONTENT_DIR . '</code>', '<code>chmod 777 ' . WP_CONTENT_DIR . '</code>' ) . '</p></div>';
51
+ }
52
+ add_action( 'admin_notices', 'hmbkp_path_exists_warning' );
53
+
54
+ endif;
55
+
56
+ // If the backups directory exists but isn't writable
57
+ if ( is_dir( hmbkp_path() ) && ! is_writable( hmbkp_path() ) ) :
58
+
59
+ function hmbkp_writable_path_warning() {
60
+ $php_user = exec( 'whoami' );
61
+ $php_group = reset( explode( ' ', exec( 'groups' ) ) );
62
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress is almost ready.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'Your backups directory isn\'t writable, run %1$s or %2$s or set the permissions yourself.', 'hmbkp' ), '<code>chown -R ' . esc_attr( $php_user ) . ':' . esc_attr( $php_group ) . ' ' . esc_attr( hmbkp_path() ) . '</code>', '<code>chmod -R 777 ' . esc_attr( hmbkp_path() ) . '</code>' ) . '</p></div>';
63
+ }
64
+ add_action( 'admin_notices', 'hmbkp_writable_path_warning' );
65
+
66
+ endif;
67
+
68
+ // If safe mode is active
69
+ if ( HM_Backup::is_safe_mode_active() ) :
70
+
71
+ function hmbkp_safe_mode_warning() {
72
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( '%1$s is running in %2$s. Please contact your host and ask them to disable %3$s.', 'hmbkp' ), '<code>PHP</code>', sprintf( '<a href="%1$s">%2$s</a>', __( 'http://php.net/manual/en/features.safe-mode.php', 'hmbkp' ), __( 'Safe Mode', 'hmbkp' ) ), '<code>' . __( 'Safe Mode', 'hmbkp' ) . '</code>' ) . '</p></div>';
73
+ }
74
+ add_action( 'admin_notices', 'hmbkp_safe_mode_warning' );
75
+
76
+ endif;
77
+
78
+ // If a custom backups directory is defined and it doesn't exist and can't be created
79
+ if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH && ! is_dir( HMBKP_PATH ) ) :
80
+
81
+ function hmbkp_custom_path_exists_warning() {
82
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'Your custom backups directory %1$s doesn\'t exist and can\'t be created, your backups will be saved to %2$s instead.', 'hmbkp' ), '<code>' . esc_attr( HMBKP_PATH ) . '</code>', '<code>' . esc_attr( hmbkp_path() ) . '</code>' ) . '</p></div>';
83
+ }
84
+ add_action( 'admin_notices', 'hmbkp_custom_path_exists_warning' );
85
+
86
+ endif;
87
+
88
+ // If a custom backups directory is defined and exists but isn't writable
89
+ if ( defined( 'HMBKP_PATH' ) && HMBKP_PATH && is_dir( HMBKP_PATH ) && ! is_writable( HMBKP_PATH ) ) :
90
+
91
+ function hmbkp_custom_path_writable_notice() {
92
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress has detected a problem.', 'hmbkp' ) . '</strong> ' . sprintf( __( 'Your custom backups directory %1$s isn\'t writable, new backups will be saved to %2$s instead.', 'hmbkp' ), '<code>' . esc_attr( HMBKP_PATH ) . '</code>', '<code>' . esc_attr( hmbkp_path() ) . '</code>' ) . '</p></div>';
93
+ }
94
+ add_action( 'admin_notices', 'hmbkp_custom_path_writable_notice' );
95
+
96
+ endif;
97
+
98
+ // If there are any errors reported in the backup
99
+ if ( hmbkp_backup_errors_message() ) :
100
+
101
+ function hmbkp_backup_errors_notice() {
102
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress detected issues with your last backup.', 'hmbkp' ) . '</strong><a href="' . add_query_arg( 'action', 'hmbkp_dismiss_error' ) . '" style="float: right;" class="button">Dismiss</a></p>' . hmbkp_backup_errors_message() . '</div>';
103
+ }
104
+ add_action( 'admin_notices', 'hmbkp_backup_errors_notice' );
105
+
106
+ endif;
107
+
108
+ if ( ! empty( $_GET['reason'] ) ) :
109
+
110
+ function hmbkp_backup_failed_notice() {
111
+ echo '<div id="hmbkp-warning" class="updated fade"><p><strong>' . __( 'BackUpWordPress failed to perform the backup.', 'hmbkp' ) . '</strong> ' . __( 'You have likely hit a memory limit.', 'hmbkp' ) . '<a href="' . add_query_arg( 'action', 'hmbkp_dismiss_error' ) . '" style="float: right;" class="button">Dismiss</a></p></div>';
112
+ }
113
+ add_action( 'admin_notices', 'hmbkp_backup_failed_notice' );
114
+
115
+ endif;
116
+
117
+ }
118
+ add_action( 'admin_head', 'hmbkp_admin_notices' );
119
+
120
+ /**
121
+ * Hook in an change the plugin description when BackUpWordPress is activated
122
+ *
123
+ * @param array $plugins
124
+ * @return $plugins
125
+ */
126
+ function hmbkp_plugin_row( $plugins ) {
127
+
128
+ if ( isset( $plugins[HMBKP_PLUGIN_SLUG . '/plugin.php'] ) )
129
+ $plugins[HMBKP_PLUGIN_SLUG . '/plugin.php']['Description'] = str_replace( 'Once activated you\'ll find me under <strong>Tools &rarr; Backups</strong>', 'Find me under <strong><a href="' . admin_url( 'tools.php?page=' . HMBKP_PLUGIN_SLUG ) . '">Tools &rarr; Backups</a></strong>', $plugins[HMBKP_PLUGIN_SLUG . '/plugin.php']['Description'] );
130
+
131
+ return $plugins;
132
+
133
+ }
134
+ add_filter( 'all_plugins', 'hmbkp_plugin_row', 10 );
135
+
136
+ /**
137
+ * Parse the json string of errors and
138
+ * output as a human readable message
139
+ *
140
+ * @access public
141
+ * @return null
142
+ */
143
+ function hmbkp_backup_errors_message() {
144
+
145
+ $message = '';
146
+
147
+ foreach ( (array) json_decode( hmbkp_backup_errors() ) as $key => $errors )
148
+ foreach ( $errors as $error )
149
+ $message .= '<p><strong>' . $key . '</strong>: <code>' . implode( ':', (array) $error ) . '</code></p>';
150
+
151
+ return $message;
152
+
153
+ }
154
+
155
+ /**
156
+ * Display a html list of files
157
+ *
158
+ * @param HMBKP_Scheduled_Backup $schedule
159
+ * @param mixed $excludes (default: null)
160
+ * @param string $file_method (default: 'get_included_files')
161
+ * @return void
162
+ */
163
+ function hmbkp_file_list( HMBKP_Scheduled_Backup $schedule, $excludes = null, $file_method = 'get_included_files' ) {
164
+
165
+ if ( ! is_null( $excludes ) )
166
+ $schedule->set_excludes( $excludes );
167
+
168
+ $files = $schedule->$file_method();
169
+
170
+ if ( $files ) : ?>
171
+
172
+ <ul class="hmbkp_file_list code">
173
+
174
+ <?php foreach( $files as $file ) :
175
+
176
+ if ( ! is_null( $excludes ) && strpos( $file, str_ireplace( $schedule->get_root(), '', $schedule->get_path() ) ) !== false )
177
+ continue; ?>
178
+
179
+ <?php if ( $file->isDir() ) { ?>
180
+
181
+ <li title="<?php echo esc_attr( HM_Backup::conform_dir( trailingslashit( $file->getPathName() ) ) ); ?>"><?php echo trailingslashit( str_ireplace( HM_Backup::conform_dir( trailingslashit( $schedule->get_root() ) ), '', HM_Backup::conform_dir( $file->getPathName() ) ) ); ?></li>
182
+
183
+ <?php } else { ?>
184
+
185
+ <li title="<?php echo esc_attr( HM_Backup::conform_dir( $file->getPathName() ) ); ?>"><?php echo str_ireplace( HM_Backup::conform_dir( trailingslashit( $schedule->get_root() ) ), '', HM_Backup::conform_dir( $file->getPathName() ) ); ?></li>
186
+
187
+ <?php }
188
+
189
+ endforeach; ?>
190
+
191
+ </ul>
192
+
193
+ <?php endif;
194
+
195
+ }
196
+
197
+
198
+ /**
199
+ * Get the human readable backup type in.
200
+ *
201
+ * @access public
202
+ * @param string $type
203
+ * @param HMBKP_Scheduled_Backup $schedule (default: null)
204
+ * @return string
205
+ */
206
+ function hmbkp_human_get_type( $type, HMBKP_Scheduled_Backup $schedule = null ) {
207
+
208
+ if ( strpos( $type, 'complete' ) !== false )
209
+ return __( 'Database and Files', 'hmbkp' );
210
+
211
+ if ( strpos( $type, 'file' ) !== false )
212
+ return __( 'Files', 'hmbkp' );
213
+
214
+ if ( strpos( $type, 'database' ) !== false )
215
+ return __( 'Database', 'hmbkp' );
216
+
217
+ if ( ! is_null( $schedule ) )
218
+ return hmbkp_human_get_type( $schedule->get_type() );
219
+
220
+ return __( 'Legacy', 'hmbkp' );
221
+
222
+ }
223
+
224
+
225
+ /**
226
+ * Display the row of actions for a schedule
227
+ *
228
+ * @access public
229
+ * @param HMBKP_Scheduled_Backup $schedule
230
+ * @return void
231
+ */
232
+ function hmbkp_schedule_actions( HMBKP_Scheduled_Backup $schedule ) {
233
+
234
+ if ( $status = $schedule->get_status() ) { ?>
235
+
236
+ <span class="hmbkp-status"><?php echo $status; ?> <a href="<?php echo add_query_arg( array( 'action' => 'hmbkp_cancel', 'hmbkp_schedule_id' => $schedule->get_id() ), HMBKP_ADMIN_URL ); ?>"><?php _e( 'cancel', 'hmbkp' ); ?></a></span>
237
+
238
+ <?php } else { ?>
239
+
240
+ <div class="hmbkp-schedule-actions row-actions">
241
+
242
+ <a class="fancybox" href="<?php echo add_query_arg( array( 'action' => 'hmbkp_edit_schedule_load', 'hmbkp_schedule_id' => $schedule->get_id() ), admin_url( 'admin-ajax.php' ) ); ?>"><?php _e( 'Settings', 'hmbkp' ); ?></a> |
243
+
244
+ <?php if ( $schedule->get_type() !== 'database' ) { ?>
245
+ <a class="fancybox" href="<?php echo add_query_arg( array( 'action' => 'hmbkp_edit_schedule_excludes_load', 'hmbkp_schedule_id' => $schedule->get_id() ), admin_url( 'admin-ajax.php' ) ); ?>"><?php _e( 'Excludes', 'hmbkp' ); ?></a> |
246
+ <?php } ?>
247
+
248
+ <a class="hmbkp-run" href="<?php echo add_query_arg( array( 'action' => 'hmbkp_run_schedule', 'hmbkp_schedule_id' => $schedule->get_id() ), admin_url( 'admin-ajax.php' ) ); ?>"><?php _e( 'Run now', 'hmbkp' ); ?></a> |
249
+
250
+ <a class="delete-action" href="<?php echo wp_nonce_url( add_query_arg( array( 'action' => 'hmbkp_delete_schedule', 'hmbkp_schedule_id' => $schedule->get_id() ), HMBKP_ADMIN_URL ), 'hmbkp-delete_schedule' ); ?>"><?php _e( 'Delete', 'hmbkp' ); ?></a>
251
+
252
+ </div>
253
+
254
+ <?php }
255
+
256
+ }
257
+
258
+ /**
259
+ * Load the backup errors file
260
+ *
261
+ * @return string
262
+ */
263
+ function hmbkp_backup_errors() {
264
+
265
+ if ( ! file_exists( hmbkp_path() . '/.backup_errors' ) )
266
+ return '';
267
+
268
+ return file_get_contents( hmbkp_path() . '/.backup_errors' );
269
+
270
+ }
271
+
272
+ /**
273
+ * Load the backup warnings file
274
+ *
275
+ * @return string
276
+ */
277
+ function hmbkp_backup_warnings() {
278
+
279
+ if ( ! file_exists( hmbkp_path() . '/.backup_warnings' ) )
280
+ return '';
281
+
282
+ return file_get_contents( hmbkp_path() . '/.backup_warnings' );
283
+
284
+ }
functions/wp-cli.php DELETED
@@ -1,105 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Implement backup command
5
- *
6
- * @package wp-cli
7
- * @subpackage commands/third-party
8
- */
9
- class BackUpCommand extends WP_CLI_Command {
10
-
11
- function __construct( $args, $assoc_args ) {
12
-
13
- // Make sure it's possible to do a backup
14
- if ( hmbkp_is_safe_mode_active() ) {
15
- WP_CLI::error( 'Backup not possible when php is running safe_mode on' );
16
- return false;
17
- }
18
-
19
- remove_action( 'hmbkp_backup_started', 'hmbkp_set_status', 10, 0 );
20
- remove_action( 'hmbkp_mysqldump_started', 'hmbkp_set_status_dumping_database' );
21
- remove_action( 'hmbkp_archive_started', 'hmbkp_set_status_archiving' );
22
-
23
- add_action( 'hmbkp_mysqldump_started', function() {
24
- WP_CLI::line( 'Backup: Dumping database...' );
25
- } );
26
-
27
- add_action( 'hmbkp_archive_started', function() {
28
- WP_CLI::line( 'Backup: Zipping everything up...' );
29
- } );
30
-
31
- // Clean up any mess left by a previous backup
32
- hmbkp_cleanup();
33
-
34
- $hm_backup = HM_Backup::get_instance();
35
-
36
- if ( ! empty( $assoc_args['path'] ) )
37
- $hm_backup->path = $assoc_args['path'];
38
-
39
- if ( ! empty( $assoc_args['root'] ) )
40
- $hm_backup->root = $assoc_args['root'];
41
-
42
- if ( ( ! is_dir( $hm_backup->path() ) && ( ! is_writable( dirname( $hm_backup->path() ) ) || ! mkdir( $hm_backup->path() ) ) ) || ! is_writable( $hm_backup->path() ) ) {
43
- WP_CLI::error( 'Invalid backup path' );
44
- return false;
45
- }
46
-
47
-
48
- if ( ! is_dir( $hm_backup->root() ) || ! is_readable( $hm_backup->root() ) ) {
49
- WP_CLI::error( 'Invalid root path' );
50
- return false;
51
- }
52
-
53
- // Default to both
54
- $hm_backup->files_only = false;
55
- $hm_backup->database_only = false;
56
-
57
- if ( ! empty( $assoc_args['files_only'] ) )
58
- $hm_backup->files_only = true;
59
-
60
- if ( ! empty( $assoc_args['database_only'] ) )
61
- $hm_backup->database_only = true;
62
-
63
- if ( ! empty( $assoc_args['mysqldump_command_path'] ) )
64
- $hm_backup->mysqldump_command_path = empty( $assoc_args['mysqldump_command_path'] ) || $assoc_args['mysqldump_command_path'] === 'false' ? false : true;
65
-
66
- if ( ! empty( $assoc_args['zip_command_path'] ) )
67
- $hm_backup->zip_command_path = empty( $assoc_args['zip_command_path'] ) || $assoc_args['zip_command_path'] === 'false' ? false : true;
68
-
69
- if ( ! empty( $assoc_args['excludes'] ) )
70
- $hm_backup->excludes = $valid_rules = array_filter( array_map( 'trim', explode( ',', $assoc_args['excludes'] ) ) );
71
-
72
- $hm_backup->backup();
73
-
74
- WP_CLI::line( 'Backup: Deleting old backups...' );
75
-
76
- // Delete any old backup files
77
- hmbkp_delete_old_backups();
78
-
79
- if ( file_exists( HM_Backup::get_instance()->archive_filepath() ) )
80
- WP_CLI::success( 'Backup Complete: ' . HM_Backup::get_instance()->archive_filepath() );
81
-
82
- else
83
- WP_CLI::error( 'Backup Failed' );
84
-
85
- }
86
-
87
- static function help() {
88
-
89
- WP_CLI::line( <<<EOB
90
- usage: wp backup [--files_only] [--database_only] [--path<dir>] [--root<dir>] [--zip_command_path=<path>] [--mysqldump_command_path=<path>]
91
-
92
- --files_only Backup files only, default to off
93
- --database_only Backup database only, defaults to off
94
- --path dir that the backup should be save in, defaults to wp-content/backups/
95
- --root dir that should be backed up, defaults to site root.
96
- --zip_command_path path to your zip binary, standard locations are automatically used
97
- --mysqldump_command_path path to your mysqldump binary, standard locations are automatically used
98
-
99
- EOB
100
- );
101
-
102
- }
103
-
104
- }
105
- WP_CLI::addCommand( 'backup', 'BackUpCommand' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
hm-backup/hm-backup.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  * Generic file and database backup class
5
  *
6
- * @version 1.5.2
7
  */
8
  class HM_Backup {
9
 
@@ -11,73 +11,65 @@ class HM_Backup {
11
  * The path where the backup file should be saved
12
  *
13
  * @string
14
- * @access public
15
- */
16
- public $path;
17
-
18
- /**
19
- * Whether the backup should be files only
20
- *
21
- * @bool
22
- * @access public
23
  */
24
- public $files_only;
25
 
26
  /**
27
- * Whether the backup should be database only
28
  *
29
- * @bool
30
- * @access public
31
  */
32
- public $database_only;
33
 
34
  /**
35
  * The filename of the backup file
36
  *
37
  * @string
38
- * @access public
39
  */
40
- public $archive_filename;
41
 
42
  /**
43
  * The filename of the database dump
44
  *
45
  * @string
46
- * @access public
47
  */
48
- public $database_dump_filename;
49
 
50
  /**
51
  * The path to the zip command
52
  *
53
  * @string
54
- * @access public
55
  */
56
- public $zip_command_path;
57
 
58
  /**
59
  * The path to the mysqldump command
60
  *
61
  * @string
62
- * @access public
63
  */
64
- public $mysqldump_command_path;
65
 
66
  /**
67
  * An array of exclude rules
68
  *
69
  * @array
70
- * @access public
71
  */
72
- public $excludes;
73
 
74
  /**
75
  * The path that should be backed up
76
  *
77
  * @var string
78
- * @access public
79
  */
80
- public $root;
81
 
82
  /**
83
  * Holds the current db connection
@@ -88,22 +80,31 @@ class HM_Backup {
88
  private $db;
89
 
90
  /**
91
- * Store the current backup instance
 
92
  *
93
- * @var object
94
- * @static
95
- * @access public
96
  */
97
- private static $instance;
98
 
99
  /**
100
  * An array of all the files in root
101
- * excluding excludes
102
  *
103
  * @var array
104
  * @access private
105
  */
106
- private $files;
 
 
 
 
 
 
 
 
 
107
 
108
  /**
109
  * Contains an array of errors
@@ -111,7 +112,7 @@ class HM_Backup {
111
  * @var mixed
112
  * @access private
113
  */
114
- private $errors;
115
 
116
  /**
117
  * Contains an array of warnings
@@ -119,7 +120,7 @@ class HM_Backup {
119
  * @var mixed
120
  * @access private
121
  */
122
- private $warnings;
123
 
124
  /**
125
  * The archive method used
@@ -127,7 +128,7 @@ class HM_Backup {
127
  * @var string
128
  * @access private
129
  */
130
- private $archive_method;
131
 
132
  /**
133
  * The mysqldump method used
@@ -135,107 +136,470 @@ class HM_Backup {
135
  * @var string
136
  * @access private
137
  */
138
- private $mysqldump_method;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
 
140
  /**
141
  * Sets up the default properties
142
  *
143
  * @access public
144
- * @return null
145
  */
146
  public function __construct() {
147
 
148
- // Raise the memory limit and max_execution_time time
149
  @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
150
  @set_time_limit( 0 );
151
 
152
- $this->errors = array();
153
-
154
  set_error_handler( array( &$this, 'error_handler' ) );
155
 
156
- // Defaults
157
- $this->root = $this->conform_dir( ABSPATH );
158
 
159
- $this->path = $this->conform_dir( WP_CONTENT_DIR . '/backups' );
 
 
 
 
 
 
160
 
161
- $this->database_dump_filename = 'database_' . DB_NAME . '.sql';
162
 
163
- $this->archive_filename = strtolower( sanitize_file_name( get_bloginfo( 'name' ) . '.backup.' . date( 'Y-m-d-H-i-s', time() + ( current_time( 'timestamp' ) - time() ) ) . '.zip' ) );
164
 
165
- $this->mysqldump_command_path = $this->guess_mysqldump_command_path();
166
- $this->zip_command_path = $this->guess_zip_command_path();
 
 
 
 
 
 
 
 
167
 
168
- $this->database_only = false;
169
- $this->files_only = false;
170
 
171
  }
172
 
173
  /**
174
- * Return the current instance
175
  *
176
  * @access public
177
- * @static
178
- * @return object
179
  */
180
- public static function get_instance() {
 
 
 
181
 
182
- if ( empty( self::$instance ) )
183
- self::$instance = new HM_Backup();
184
 
185
- return self::$instance;
186
 
187
  }
188
 
189
  /**
190
- * The full filepath to the archive file.
191
  *
192
  * @access public
193
  * @return string
194
  */
195
- public function archive_filepath() {
196
- return trailingslashit( $this->path() ) . $this->archive_filename();
 
 
197
  }
198
 
199
  /**
200
- * The full filepath to the archive file.
201
  *
202
  * @access public
203
  * @return string
204
  */
205
- public function archive_filename() {
206
- return strtolower( sanitize_file_name( remove_accents( $this->archive_filename ) ) );
 
 
 
 
 
207
  }
208
 
209
  /**
210
- * The full filepath to the database dump file.
211
  *
212
  * @access public
213
- * @return string
214
  */
215
- public function database_dump_filepath() {
216
- return trailingslashit( $this->path() ) . $this->database_dump_filename();
217
- }
 
 
 
 
 
 
218
 
219
- public function database_dump_filename() {
220
- return strtolower( sanitize_file_name( remove_accents( $this->database_dump_filename ) ) );
221
  }
222
 
223
- public function root() {
224
- return $this->conform_dir( $this->root );
 
 
 
 
 
 
 
 
 
 
 
 
 
225
  }
226
 
227
- public function path() {
228
- return $this->conform_dir( $this->path );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  }
230
 
231
- public function archive_method() {
 
 
 
 
 
 
 
232
  return $this->archive_method;
233
  }
234
 
235
- public function mysqldump_method() {
 
 
 
 
 
 
 
236
  return $this->mysqldump_method;
237
  }
238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  /**
240
  * Kick off a backup
241
  *
@@ -244,16 +608,16 @@ class HM_Backup {
244
  */
245
  public function backup() {
246
 
247
- do_action( 'hmbkp_backup_started', $this );
248
 
249
  // Backup database
250
- if ( ! $this->files_only )
251
- $this->mysqldump();
252
 
253
  // Zip everything up
254
  $this->archive();
255
 
256
- do_action( 'hmbkp_backup_complete', $this );
257
 
258
  }
259
 
@@ -264,62 +628,64 @@ class HM_Backup {
264
  * if not.
265
  *
266
  * @access public
267
- * @return null
268
  */
269
- public function mysqldump() {
270
 
271
- do_action( 'hmbkp_mysqldump_started' );
272
 
273
- $this->mysqldump_method = 'mysqldump';
 
274
 
275
- // Use mysqldump if we can
276
- if ( $this->mysqldump_command_path ) {
277
 
278
- $host = reset( explode( ':', DB_HOST ) );
279
- $port = strpos( DB_HOST, ':' ) ? end( explode( ':', DB_HOST ) ) : '';
280
 
281
- // Path to the mysqldump executable
282
- $cmd = escapeshellarg( $this->mysqldump_command_path );
283
 
284
- // No Create DB command
285
- $cmd .= ' --no-create-db';
286
 
287
- // Make sure binary data is exported properly
288
- $cmd .= ' --hex-blob';
289
 
290
- // Username
291
- $cmd .= ' -u ' . escapeshellarg( DB_USER );
292
 
293
- // Don't pass the password if it's blank
294
- if ( DB_PASSWORD )
295
- $cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
296
 
297
- // Set the host
298
- $cmd .= ' -h ' . escapeshellarg( $host );
299
 
300
- // Set the port if it was set
301
- if ( ! empty( $port ) )
302
- $cmd .= ' -P ' . $port;
303
 
304
- // The file we're saving too
305
- $cmd .= ' -r ' . escapeshellarg( $this->database_dump_filepath() );
306
 
307
- // The database we're dumping
308
- $cmd .= ' ' . escapeshellarg( DB_NAME );
 
309
 
310
- // Pipe STDERR to STDOUT
311
- $cmd .= ' 2>&1';
312
 
313
- // Store any returned data in warning
314
- $this->warning( $this->mysqldump_method, shell_exec( $cmd ) );
 
315
 
316
- }
 
317
 
318
- // If not or if the shell mysqldump command failed, use the PHP fallback
319
- if ( ! file_exists( $this->database_dump_filepath() ) )
320
- $this->mysqldump_fallback();
 
 
321
 
322
- do_action( 'hmbkp_mysqldump_finished' );
 
 
 
323
 
324
  }
325
 
@@ -327,11 +693,10 @@ class HM_Backup {
327
  * PHP mysqldump fallback functions, exports the database to a .sql file
328
  *
329
  * @access public
330
- * @return null
331
  */
332
  public function mysqldump_fallback() {
333
 
334
- $this->errors_to_warnings( $this->mysqldump_method );
335
 
336
  $this->mysqldump_method = 'mysqldump_fallback';
337
 
@@ -369,18 +734,17 @@ class HM_Backup {
369
  * Zip up all the files.
370
  *
371
  * Attempts to use the shell zip command, if
372
- * thats not available then it fallsback to
373
  * PHP ZipArchive and finally PclZip.
374
  *
375
  * @access public
376
- * @return null
377
  */
378
  public function archive() {
379
 
380
- do_action( 'hmbkp_archive_started' );
381
 
382
  // Do we have the path to the zip command
383
- if ( $this->zip_command_path )
384
  $this->zip();
385
 
386
  // If not or if the shell zip failed then use ZipArchive
@@ -392,10 +756,10 @@ class HM_Backup {
392
  $this->pcl_zip();
393
 
394
  // Delete the database dump file
395
- if ( file_exists( $this->database_dump_filepath() ) )
396
- unlink( $this->database_dump_filepath() );
397
 
398
- do_action( 'hmbkp_archive_finished' );
399
 
400
  }
401
 
@@ -403,31 +767,30 @@ class HM_Backup {
403
  * Zip using the native zip command
404
  *
405
  * @access public
406
- * @return null
407
  */
408
  public function zip() {
409
 
410
  $this->archive_method = 'zip';
411
 
412
  // Zip up $this->root with excludes
413
- if ( ! $this->database_only && $this->exclude_string( 'zip' ) )
414
- $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->root() ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -rq ' . escapeshellarg( $this->archive_filepath() ) . ' ./' . ' -x ' . $this->exclude_string( 'zip' ) . ' 2>&1' ) );
415
 
416
  // Zip up $this->root without excludes
417
- elseif ( ! $this->database_only )
418
- $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->root() ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -rq ' . escapeshellarg( $this->archive_filepath() ) . ' ./' . ' 2>&1' ) );
419
 
420
  // Add the database dump to the archive
421
- if ( ! $this->files_only )
422
- $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->path() ) . ' && ' . escapeshellarg( $this->zip_command_path ) . ' -uq ' . escapeshellarg( $this->archive_filepath() ) . ' ' . escapeshellarg( $this->database_dump_filename() ) . ' 2>&1' ) );
423
 
424
- $this->check_archive();
425
 
426
  }
427
 
428
  /**
429
  * Fallback for creating zip archives if zip command is
430
- * unnavailable.
431
  *
432
  * @access public
433
  * @param string $path
@@ -439,23 +802,32 @@ class HM_Backup {
439
 
440
  $zip = new ZipArchive();
441
 
442
- if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->archive_filepath(), ZIPARCHIVE::CREATE ) )
443
  return;
444
 
445
- if ( ! $this->database_only ) {
 
 
446
 
447
  $files_added = 0;
448
 
449
- foreach ( $this->files() as $file ) {
 
 
 
 
 
 
 
450
 
451
- if ( is_dir( trailingslashit( $this->root() ) . $file ) )
452
- $zip->addEmptyDir( trailingslashit( $file ) );
453
 
454
- elseif ( is_file( trailingslashit( $this->root() ) . $file ) )
455
- $zip->addFile( trailingslashit( $this->root() ) . $file, $file );
456
 
457
  if ( ++$files_added % 500 === 0 )
458
- if ( ! $zip->close() || ! $zip->open( $this->archive_filepath(), ZIPARCHIVE::CREATE ) )
459
  return;
460
 
461
  }
@@ -463,8 +835,8 @@ class HM_Backup {
463
  }
464
 
465
  // Add the database
466
- if ( ! $this->files_only )
467
- $zip->addFile( $this->database_dump_filepath(), $this->database_dump_filename() );
468
 
469
  if ( $zip->status )
470
  $this->warning( $this->archive_method, $zip->status );
@@ -474,13 +846,13 @@ class HM_Backup {
474
 
475
  $zip->close();
476
 
477
- $this->check_archive();
478
 
479
  }
480
 
481
  /**
482
  * Fallback for creating zip archives if zip command and ZipArchive are
483
- * unnavailable.
484
  *
485
  * Uses the PclZip library that ships with WordPress
486
  *
@@ -498,21 +870,38 @@ class HM_Backup {
498
 
499
  $this->load_pclzip();
500
 
501
- $archive = new PclZip( $this->archive_filepath() );
502
 
503
  // Zip up everything
504
- if ( ! $this->database_only )
505
- if ( ! $archive->add( $this->root(), PCLZIP_OPT_REMOVE_PATH, $this->root(), PCLZIP_CB_PRE_ADD, 'hmbkp_pclzip_callback' ) )
506
  $this->warning( $this->archive_method, $archive->errorInfo( true ) );
507
 
508
  // Add the database
509
- if ( ! $this->files_only )
510
- if ( ! $archive->add( $this->database_dump_filepath(), PCLZIP_OPT_REMOVE_PATH, $this->path() ) )
511
  $this->warning( $this->archive_method, $archive->errorInfo( true ) );
512
 
513
  unset( $GLOBALS['_hmbkp_exclude_string'] );
514
 
515
- $this->check_archive();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
516
 
517
  }
518
 
@@ -522,85 +911,57 @@ class HM_Backup {
522
  * @access public
523
  * @return bool
524
  */
525
- public function check_archive() {
526
 
527
  // If we've already passed then no need to check again
528
  if ( ! empty( $this->archive_verified ) )
529
  return true;
530
 
531
- if ( ! file_exists( $this->archive_filepath() ) )
532
- $this->error( $this->archive_method(), __( 'The backup file was not created', 'hmbkp' ) );
533
 
534
  // Verify using the zip command if possible
535
- if ( $this->zip_command_path ) {
536
 
537
- $verify = shell_exec( escapeshellarg( $this->zip_command_path ) . ' -T ' . escapeshellarg( $this->archive_filepath() ) . ' 2> /dev/null' );
538
 
539
  if ( strpos( $verify, 'OK' ) === false )
540
- $this->error( $this->archive_method(), $verify );
541
 
542
  }
543
 
544
  // If there are errors delete the backup file.
545
- if ( $this->errors( $this->archive_method() ) && file_exists( $this->archive_filepath() ) )
546
- unlink( $this->archive_filepath() );
547
 
548
- if ( $this->errors( $this->archive_method() ) )
549
  return false;
550
 
 
 
 
551
  return $this->archive_verified = true;
552
 
553
  }
554
 
555
  /**
556
- * Generate the array of files to be backed up by looping through
557
- * root, ignored unreadable files and excludes
558
  *
559
  * @access public
560
  * @return array
561
  */
562
- public function files() {
563
 
564
  if ( ! empty( $this->files ) )
565
  return $this->files;
566
 
567
  $this->files = array();
568
 
569
- if ( defined( 'RecursiveDirectoryIterator::FOLLOW_SYMLINKS' ) ) {
570
-
571
- $filesystem = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $this->root(), RecursiveDirectoryIterator::FOLLOW_SYMLINKS ), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD );
572
-
573
- $excludes = $this->exclude_string( 'regex' );
574
-
575
- foreach ( $filesystem as $file ) {
576
-
577
- if ( ! $file->isReadable() ) {
578
- $this->unreadable_files[] = $file->getPathName();
579
- continue;
580
- }
581
-
582
- $pathname = str_ireplace( trailingslashit( $this->root() ), '', $this->conform_dir( $file->getPathname() ) );
583
-
584
- // Excludes
585
- if ( $excludes && preg_match( '(' . $excludes . ')', $pathname ) )
586
- continue;
587
-
588
- // Don't include database dump as it's added separately
589
- if ( basename( $pathname ) == $this->database_dump_filename() )
590
- continue;
591
-
592
- $this->files[] = $pathname;
593
-
594
- }
595
-
596
- } else {
597
 
598
- $this->files = $this->files_fallback( $this->root() );
599
-
600
- }
601
-
602
- if ( ! empty( $this->unreadable_files ) )
603
- $this->warning( $this->archive_method(), __( 'The following files are unreadable and couldn\'t be backed up: ', 'hmbkp' ) . implode( ', ', $this->unreadable_files ) );
604
 
605
  return $this->files;
606
 
@@ -613,11 +974,11 @@ class HM_Backup {
613
  * Used if RecursiveDirectoryIterator::FOLLOW_SYMLINKS isn't available
614
  *
615
  * @access private
616
- * @param stromg $dir
617
  * @param array $files. (default: array())
618
  * @return array
619
  */
620
- private function files_fallback( $dir, $files = array() ) {
621
 
622
  $handle = opendir( $dir );
623
 
@@ -626,25 +987,16 @@ class HM_Backup {
626
  while ( $file = readdir( $handle ) ) :
627
 
628
  // Ignore current dir and containing dir and any unreadable files or directories
629
- if ( $file == '.' || $file == '..' )
630
  continue;
631
 
632
  $filepath = $this->conform_dir( trailingslashit( $dir ) . $file );
633
- $file = str_ireplace( trailingslashit( $this->root() ), '', $filepath );
634
 
635
- if ( ! is_readable( $filepath ) ) {
636
- $this->unreadable_files[] = $filepath;
637
- continue;
638
- }
639
-
640
- // Skip the backups dir and any excluded paths
641
- if ( ( $excludes && preg_match( '(' . $excludes . ')', $file ) ) )
642
- continue;
643
-
644
- $files[] = $file;
645
 
646
  if ( is_dir( $filepath ) )
647
- $files = $this->files_fallback( $filepath, $files );
648
 
649
  endwhile;
650
 
@@ -652,84 +1004,144 @@ class HM_Backup {
652
 
653
  }
654
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  private function load_pclzip() {
656
 
657
  // Load PclZip
658
  if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
659
- define( 'PCLZIP_TEMPORARY_DIR', trailingslashit( $this->path() ) );
660
 
661
  require_once( ABSPATH . 'wp-admin/includes/class-pclzip.php' );
662
 
663
  }
664
 
665
  /**
666
- * Attempt to work out the path to mysqldump
 
 
667
  *
668
  * @access public
669
- * @return bool
670
  */
671
- public function guess_mysqldump_command_path() {
672
-
673
- if ( ! $this->shell_exec_available() )
674
- return '';
675
 
676
- // List of possible mysqldump locations
677
- $mysqldump_locations = array(
678
- '/usr/local/bin/mysqldump',
679
- '/usr/local/mysql/bin/mysqldump',
680
- '/usr/mysql/bin/mysqldump',
681
- '/usr/bin/mysqldump',
682
- '/opt/local/lib/mysql6/bin/mysqldump',
683
- '/opt/local/lib/mysql5/bin/mysqldump',
684
- '/opt/local/lib/mysql4/bin/mysqldump',
685
- '/xampp/mysql/bin/mysqldump',
686
- '/Program Files/xampp/mysql/bin/mysqldump',
687
- '/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
688
- '/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
689
- '/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump',
690
- '/Program Files/MySQL/MySQL Server 5.1/bin/mysqldump',
691
- '/Program Files/MySQL/MySQL Server 5.0/bin/mysqldump',
692
- '/Program Files/MySQL/MySQL Server 4.1/bin/mysqldump'
693
- );
694
 
695
- if ( is_null( shell_exec( 'hash mysqldump 2>&1' ) ) )
696
- return 'mysqldump';
697
 
698
- // Find the one which works
699
- foreach ( $mysqldump_locations as $location )
700
- if ( @file_exists( $this->conform_dir( $location ) ) )
701
- return $location;
702
 
703
- return '';
704
 
705
  }
706
 
707
  /**
708
- * Attempt to work out the path to the zip command
709
  *
710
  * @access public
711
- * @return bool
 
712
  */
713
- public function guess_zip_command_path() {
714
 
715
- // Check shell_exec is available and hasn't been explicitly bypassed
716
- if ( ! $this->shell_exec_available() )
717
- return '';
718
-
719
- // List of possible zip locations
720
- $zip_locations = array(
721
- '/usr/bin/zip'
722
- );
723
 
724
- if ( is_null( shell_exec( 'hash zip 2>&1' ) ) )
725
- return 'zip';
726
 
727
- // Find the one which works
728
- foreach ( $zip_locations as $location )
729
- if ( @file_exists( $this->conform_dir( $location ) ) )
730
- return $location;
731
-
732
- return '';
733
 
734
  }
735
 
@@ -743,30 +1155,25 @@ class HM_Backup {
743
  * @param string $context. (default: 'zip')
744
  * @return string
745
  */
746
- public function exclude_string( $context = 'zip' ) {
747
 
748
  // Return a comma separated list by default
749
  $separator = ', ';
750
  $wildcard = '';
751
 
752
  // The zip command
753
- if ( $context == 'zip' ) {
754
  $wildcard = '*';
755
  $separator = ' -x ';
756
 
757
  // The PclZip fallback library
758
- } elseif ( $context == 'regex' ) {
759
  $wildcard = '([\s\S]*?)';
760
  $separator = '|';
761
 
762
  }
763
 
764
- // Sanitize the excludes
765
- $excludes = array_filter( array_unique( array_map( 'trim', (array) $this->excludes ) ) );
766
-
767
- // If path() is inside root(), exclude it
768
- if ( strpos( $this->path(), $this->root() ) !== false )
769
- $excludes[] = trailingslashit( $this->path() );
770
 
771
  foreach( $excludes as $key => &$rule ) {
772
 
@@ -785,40 +1192,40 @@ class HM_Backup {
785
  $fragment = true;
786
 
787
  // Strip $this->root and conform
788
- $rule = str_ireplace( $this->root(), '', untrailingslashit( $this->conform_dir( $rule ) ) );
789
 
790
  // Strip the preceeding slash
791
  if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) )
792
  $rule = substr( $rule, 1 );
793
 
794
  // Escape string for regex
795
- if ( $context == 'regex' )
796
  $rule = str_replace( '.', '\.', $rule );
797
 
798
  // Convert any existing wildcards
799
- if ( $wildcard != '*' && strpos( $rule, '*' ) !== false )
800
  $rule = str_replace( '*', $wildcard, $rule );
801
 
802
  // Wrap directory fragments and files in wildcards for zip
803
- if ( $context == 'zip' && ( $fragment || $file ) )
804
  $rule = $wildcard . $rule . $wildcard;
805
 
806
  // Add a wildcard to the end of absolute url for zips
807
- if ( $context == 'zip' && $absolute )
808
  $rule .= $wildcard;
809
 
810
  // Add and end carrot to files for pclzip but only if it doesn't end in a wildcard
811
- if ( $file && $context == 'regex' )
812
  $rule .= '$';
813
 
814
  // Add a start carrot to absolute urls for pclzip
815
- if ( $absolute && $context == 'regex' )
816
  $rule = '^' . $rule;
817
 
818
  }
819
 
820
  // Escape shell args for zip command
821
- if ( $context == 'zip' )
822
  $excludes = array_map( 'escapeshellarg', array_unique( $excludes ) );
823
 
824
  return implode( $separator, $excludes );
@@ -826,83 +1233,14 @@ class HM_Backup {
826
  }
827
 
828
  /**
829
- * Check whether safe mode is active or not
830
- *
831
- * @access private
832
- * @return bool
833
- */
834
- public function is_safe_mode_active() {
835
-
836
- if ( $safe_mode = ini_get( 'safe_mode' ) && strtolower( $safe_mode ) != 'off' )
837
- return true;
838
-
839
- return false;
840
-
841
- }
842
-
843
- /**
844
- * Check whether shell_exec has been disabled.
845
- *
846
- * @access private
847
- * @return bool
848
- */
849
- private function shell_exec_available() {
850
-
851
- // Are we in Safe Mode
852
- if ( $this->is_safe_mode_active() )
853
- return false;
854
-
855
- // Is shell_exec disabled?
856
- if ( in_array( 'shell_exec', array_map( 'trim', explode( ',', ini_get( 'disable_functions' ) ) ) ) )
857
- return false;
858
-
859
- // Can we issue a simple echo command?
860
- if ( ! @shell_exec( 'echo backupwordpress' ) )
861
- return false;
862
-
863
- return true;
864
-
865
- }
866
-
867
- /**
868
- * Sanitize a directory path
869
- *
870
- * @access public
871
- * @param string $dir
872
- * @param bool $rel. (default: false)
873
- * @return string $dir
874
- */
875
- public function conform_dir( $dir, $recursive = false ) {
876
-
877
- // Assume empty dir is root
878
- if ( ! $dir )
879
- $dir = '/';
880
-
881
- // Replace single forward slash (looks like double slash because we have to escape it)
882
- $dir = str_replace( '\\', '/', $dir );
883
- $dir = str_replace( '//', '/', $dir );
884
-
885
- // Remove the trailing slash
886
- if ( $dir !== '/' )
887
- $dir = untrailingslashit( $dir );
888
-
889
- // Carry on until completely normalized
890
- if ( ! $recursive && $this->conform_dir( $dir, true ) != $dir )
891
- return $this->conform_dir( $dir );
892
-
893
- return (string) $dir;
894
-
895
- }
896
-
897
- /**
898
- * Add backquotes to tables and db-names inSQL queries. Taken from phpMyAdmin.
899
  *
900
  * @access private
901
  * @param mixed $a_name
902
  */
903
  private function sql_backquote( $a_name ) {
904
 
905
- if ( ! empty( $a_name ) && $a_name != '*' ) {
906
 
907
  if ( is_array( $a_name ) ) {
908
 
@@ -1001,7 +1339,7 @@ class HM_Backup {
1001
  $field_set[$j] = $this->sql_backquote( mysql_field_name( $result, $j ) );
1002
  $type = mysql_field_type( $result, $j );
1003
 
1004
- if ( $type == 'tinyint' || $type == 'smallint' || $type == 'mediumint' || $type == 'int' || $type == 'bigint' || $type == 'timestamp')
1005
  $field_num[$j] = true;
1006
 
1007
  else
@@ -1026,7 +1364,7 @@ class HM_Backup {
1026
  if ( ! isset($row[$j] ) ) {
1027
  $values[] = 'NULL';
1028
 
1029
- } elseif ( $row[$j] == '0' || $row[$j] != '' ) {
1030
 
1031
  // a number
1032
  if ( $field_num[$j] )
@@ -1045,7 +1383,7 @@ class HM_Backup {
1045
  $sql_file .= " \n" . $entries . implode( ', ', $values ) . ") ;";
1046
 
1047
  // write the rows in batches of 100
1048
- if ( $batch_write == 100 ) {
1049
  $batch_write = 0;
1050
  $this->write_sql( $sql_file );
1051
  $sql_file = '';
@@ -1099,12 +1437,12 @@ class HM_Backup {
1099
  */
1100
  private function write_sql( $sql ) {
1101
 
1102
- $sqlname = $this->database_dump_filepath();
1103
 
1104
  // Actually write the sql file
1105
  if ( is_writable( $sqlname ) || ! file_exists( $sqlname ) ) {
1106
 
1107
- if ( ! $handle = fopen( $sqlname, 'a' ) )
1108
  return;
1109
 
1110
  if ( ! fwrite( $handle, $sql ) )
@@ -1122,9 +1460,8 @@ class HM_Backup {
1122
  * Get the errors
1123
  *
1124
  * @access public
1125
- * @return null
1126
  */
1127
- public function errors( $context = null ) {
1128
 
1129
  if ( ! empty( $context ) )
1130
  return isset( $this->errors[$context] ) ? $this->errors[$context] : array();
@@ -1133,14 +1470,12 @@ class HM_Backup {
1133
 
1134
  }
1135
 
1136
-
1137
  /**
1138
  * Add an error to the errors stack
1139
  *
1140
  * @access private
1141
  * @param string $context
1142
  * @param mixed $error
1143
- * @return null
1144
  */
1145
  private function error( $context, $error ) {
1146
 
@@ -1156,11 +1491,10 @@ class HM_Backup {
1156
  *
1157
  * @access private
1158
  * @param string $context. (default: null)
1159
- * @return null
1160
  */
1161
  private function errors_to_warnings( $context = null ) {
1162
 
1163
- $errors = empty( $context ) ? $this->errors() : array( $context => $this->errors( $context ) );
1164
 
1165
  if ( empty( $errors ) )
1166
  return;
@@ -1181,9 +1515,8 @@ class HM_Backup {
1181
  * Get the warnings
1182
  *
1183
  * @access public
1184
- * @return null
1185
  */
1186
- public function warnings( $context = null ) {
1187
 
1188
  if ( ! empty( $context ) )
1189
  return isset( $this->warnings[$context] ) ? $this->warnings[$context] : array();
@@ -1192,14 +1525,12 @@ class HM_Backup {
1192
 
1193
  }
1194
 
1195
-
1196
  /**
1197
  * Add an warning to the warnings stack
1198
  *
1199
  * @access private
1200
  * @param string $context
1201
  * @param mixed $warning
1202
- * @return null
1203
  */
1204
  private function warning( $context, $warning ) {
1205
 
@@ -1210,7 +1541,6 @@ class HM_Backup {
1210
 
1211
  }
1212
 
1213
-
1214
  /**
1215
  * Custom error handler for catching errors
1216
  *
@@ -1219,11 +1549,10 @@ class HM_Backup {
1219
  * @param string $message
1220
  * @param string $file
1221
  * @param string $line
1222
- * @return null
1223
  */
1224
  public function error_handler( $type ) {
1225
 
1226
- if ( ( defined( 'E_DEPRECATED' ) && $type == E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type == E_STRICT ) || error_reporting() === 0 )
1227
  return false;
1228
 
1229
  $args = func_get_args();
3
  /**
4
  * Generic file and database backup class
5
  *
6
+ * @version 2.0 RC1
7
  */
8
  class HM_Backup {
9
 
11
  * The path where the backup file should be saved
12
  *
13
  * @string
14
+ * @access private
 
 
 
 
 
 
 
 
15
  */
16
+ private $path = '';
17
 
18
  /**
19
+ * The backup type, must be either complete, file or database
20
  *
21
+ * @string
22
+ * @access private
23
  */
24
+ private $type = '';
25
 
26
  /**
27
  * The filename of the backup file
28
  *
29
  * @string
30
+ * @access private
31
  */
32
+ private $archive_filename = '';
33
 
34
  /**
35
  * The filename of the database dump
36
  *
37
  * @string
38
+ * @access private
39
  */
40
+ private $database_dump_filename = '';
41
 
42
  /**
43
  * The path to the zip command
44
  *
45
  * @string
46
+ * @access private
47
  */
48
+ private $zip_command_path;
49
 
50
  /**
51
  * The path to the mysqldump command
52
  *
53
  * @string
54
+ * @access private
55
  */
56
+ private $mysqldump_command_path;
57
 
58
  /**
59
  * An array of exclude rules
60
  *
61
  * @array
62
+ * @access private
63
  */
64
+ private $excludes = array();
65
 
66
  /**
67
  * The path that should be backed up
68
  *
69
  * @var string
70
+ * @access private
71
  */
72
+ private $root = '';
73
 
74
  /**
75
  * Holds the current db connection
80
  private $db;
81
 
82
  /**
83
+ * An array of all the files in root
84
+ * excluding excludes and unreadable files
85
  *
86
+ * @var array
87
+ * @access private
 
88
  */
89
+ private $files = array();
90
 
91
  /**
92
  * An array of all the files in root
93
+ * that match the exclude rules
94
  *
95
  * @var array
96
  * @access private
97
  */
98
+ private $excluded_files = array();
99
+
100
+ /**
101
+ * An array of all the files in root
102
+ * that are unreadable
103
+ *
104
+ * @var array
105
+ * @access private
106
+ */
107
+ private $unreadable_files = array();
108
 
109
  /**
110
  * Contains an array of errors
112
  * @var mixed
113
  * @access private
114
  */
115
+ private $errors = array();
116
 
117
  /**
118
  * Contains an array of warnings
120
  * @var mixed
121
  * @access private
122
  */
123
+ private $warnings = array();
124
 
125
  /**
126
  * The archive method used
128
  * @var string
129
  * @access private
130
  */
131
+ private $archive_method = '';
132
 
133
  /**
134
  * The mysqldump method used
136
  * @var string
137
  * @access private
138
  */
139
+ private $mysqldump_method = '';
140
+
141
+ /**
142
+ * Check whether safe mode is active or not
143
+ *
144
+ * @access public
145
+ * @static
146
+ * @return bool
147
+ */
148
+ public static function is_safe_mode_active() {
149
+
150
+ if ( ( $safe_mode = @ini_get( 'safe_mode' ) ) && strtolower( $safe_mode ) != 'off' )
151
+ return true;
152
+
153
+ return false;
154
+
155
+ }
156
+
157
+ /**
158
+ * Check whether shell_exec has been disabled.
159
+ *
160
+ * @access public
161
+ * @static
162
+ * @return bool
163
+ */
164
+ public static function is_shell_exec_available() {
165
+
166
+ // Are we in Safe Mode
167
+ if ( self::is_safe_mode_active() )
168
+ return false;
169
+
170
+ // Is shell_exec disabled?
171
+ if ( in_array( 'shell_exec', array_map( 'trim', explode( ',', @ini_get( 'disable_functions' ) ) ) ) )
172
+ return false;
173
+
174
+ // Can we issue a simple echo command?
175
+ if ( ! @shell_exec( 'echo backupwordpress' ) )
176
+ return false;
177
+
178
+ return true;
179
+
180
+ }
181
+
182
+
183
+ /**
184
+ * Attempt to work out the root directory of the site, that
185
+ * is, the path equivelant of home_url().
186
+ *
187
+ * @access public
188
+ * @static
189
+ * @return string $home_path
190
+ */
191
+ public static function get_home_path() {
192
+
193
+ $home = get_option( 'home' );
194
+ $siteurl = get_option( 'siteurl' );
195
+
196
+ $home_path = ABSPATH;
197
+
198
+ if ( ! empty( $home ) && $home !== $siteurl )
199
+ $home_path = trailingslashit( substr( ABSPATH, 0, strrpos( ABSPATH, str_replace( $home, '', $siteurl ) ) ) );
200
+
201
+ return self::conform_dir( $home_path );
202
+
203
+ }
204
+
205
+ /**
206
+ * Sanitize a directory path
207
+ *
208
+ * @access public
209
+ * @static
210
+ * @param string $dir
211
+ * @param bool $rel. (default: false)
212
+ * @return string $dir
213
+ */
214
+ public static function conform_dir( $dir, $recursive = false ) {
215
+
216
+ // Assume empty dir is root
217
+ if ( ! $dir )
218
+ $dir = '/';
219
+
220
+ // Replace single forward slash (looks like double slash because we have to escape it)
221
+ $dir = str_replace( '\\', '/', $dir );
222
+ $dir = str_replace( '//', '/', $dir );
223
+
224
+ // Remove the trailing slash
225
+ if ( $dir !== '/' )
226
+ $dir = untrailingslashit( $dir );
227
+
228
+ // Carry on until completely normalized
229
+ if ( ! $recursive && self::conform_dir( $dir, true ) != $dir )
230
+ return self::conform_dir( $dir );
231
+
232
+ return (string) $dir;
233
+
234
+ }
235
 
236
  /**
237
  * Sets up the default properties
238
  *
239
  * @access public
 
240
  */
241
  public function __construct() {
242
 
243
+ // Raise the memory limit and max_execution time
244
  @ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
245
  @set_time_limit( 0 );
246
 
247
+ // Set a custom error handler so we can track errors
 
248
  set_error_handler( array( &$this, 'error_handler' ) );
249
 
250
+ }
 
251
 
252
+ /**
253
+ * Get the full filepath to the archive file
254
+ *
255
+ * @access public
256
+ * @return string
257
+ */
258
+ public function get_archive_filepath() {
259
 
260
+ return trailingslashit( $this->get_path() ) . $this->get_archive_filename();
261
 
262
+ }
263
 
264
+ /**
265
+ * Get the filename of the archive file
266
+ *
267
+ * @access public
268
+ * @return string
269
+ */
270
+ public function get_archive_filename() {
271
+
272
+ if ( empty( $this->archive_filename ) )
273
+ $this->set_archive_filename( implode( '-', array( get_bloginfo( 'name' ), 'backup', date( 'Y-m-d-H-i-s', current_time( 'timestamp' ) ) ) ) . '.zip' );
274
 
275
+ return $this->archive_filename;
 
276
 
277
  }
278
 
279
  /**
280
+ * Set the filename of the archive file
281
  *
282
  * @access public
283
+ * @param string $filename
 
284
  */
285
+ public function set_archive_filename( $filename ) {
286
+
287
+ if ( empty( $filename ) || ! is_string( $filename ) )
288
+ throw new Exception( 'archive filename must be a non empty string' );
289
 
290
+ if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'zip' )
291
+ throw new Exception( 'invalid file extension for archive filename <code>' . $filename . '</code>' );
292
 
293
+ $this->archive_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
294
 
295
  }
296
 
297
  /**
298
+ * Get the full filepath to the database dump file.
299
  *
300
  * @access public
301
  * @return string
302
  */
303
+ public function get_database_dump_filepath() {
304
+
305
+ return trailingslashit( $this->get_path() ) . $this->get_database_dump_filename();
306
+
307
  }
308
 
309
  /**
310
+ * Get the filename of the database dump file
311
  *
312
  * @access public
313
  * @return string
314
  */
315
+ public function get_database_dump_filename() {
316
+
317
+ if ( empty( $this->database_dump_filename ) )
318
+ $this->set_database_dump_filename( 'database_' . DB_NAME . '.sql' );
319
+
320
+ return $this->database_dump_filename;
321
+
322
  }
323
 
324
  /**
325
+ * Set the filename of the database dump file
326
  *
327
  * @access public
328
+ * @param string $filename
329
  */
330
+ public function set_database_dump_filename( $filename ) {
331
+
332
+ if ( empty( $filename ) || ! is_string( $filename ) )
333
+ throw new Exception( 'database dump filename must be a non empty string' );
334
+
335
+ if ( pathinfo( $filename, PATHINFO_EXTENSION ) !== 'sql' )
336
+ throw new Exception( 'invalid file extension for database dump filename <code>' . $filename . '</code>' );
337
+
338
+ $this->database_dump_filename = strtolower( sanitize_file_name( remove_accents( $filename ) ) );
339
 
 
 
340
  }
341
 
342
+ /**
343
+ * Get the root directory to backup from
344
+ *
345
+ * Defaults to the root of the path equivalent of your home_url
346
+ *
347
+ * @access public
348
+ * @return string
349
+ */
350
+ public function get_root() {
351
+
352
+ if ( empty( $this->root ) )
353
+ $this->set_root( $this->conform_dir( self::get_home_path() ) );
354
+
355
+ return $this->root;
356
+
357
  }
358
 
359
+ /**
360
+ * Set the root directory to backup from
361
+ *
362
+ * @access public
363
+ * @param string $path
364
+ * @return null
365
+ */
366
+ public function set_root( $path ) {
367
+
368
+ if ( empty( $path ) || ! is_string( $path ) || ! is_dir ( $path ) )
369
+ throw new Exception( 'Invalid root path <code>' . $path . '</code> must be a valid directory path' );
370
+
371
+ $this->root = $this->conform_dir( $path );
372
+
373
+ }
374
+
375
+ /**
376
+ * Get the directory backups are saved to
377
+ *
378
+ * @access public
379
+ * @return string
380
+ */
381
+ public function get_path() {
382
+
383
+ if ( empty( $this->path ) )
384
+ $this->set_path( $this->conform_dir( WP_CONTENT_DIR . '/backups' ) );
385
+
386
+ return $this->path;
387
+
388
+ }
389
+
390
+ /**
391
+ * Set the directory backups are saved to
392
+ *
393
+ * @access public
394
+ * @param string $path
395
+ * @return null
396
+ */
397
+ public function set_path( $path ) {
398
+
399
+ if ( empty( $path ) || ! is_string( $path ) )
400
+ throw new Exception( 'Invalid backup path <code>' . $path . '</code> must be a non empty (string)' );
401
+
402
+ $this->path = $this->conform_dir( $path );
403
+
404
  }
405
 
406
+ /**
407
+ * Get the archive method that was used for the backup
408
+ *
409
+ * Will be either zip, ZipArchive or PclZip
410
+ *
411
+ * @access public
412
+ */
413
+ public function get_archive_method() {
414
  return $this->archive_method;
415
  }
416
 
417
+ /**
418
+ * Get the database dump method that was used for the backup
419
+ *
420
+ * Will be either mysqldump or mysqldump_fallback
421
+ *
422
+ * @access public
423
+ */
424
+ public function get_mysqldump_method() {
425
  return $this->mysqldump_method;
426
  }
427
 
428
+ /**
429
+ * Get the backup type
430
+ *
431
+ * Defaults to complete
432
+ *
433
+ * @access public
434
+ */
435
+ public function get_type() {
436
+
437
+ if ( empty( $this->type ) )
438
+ $this->set_type( 'complete' );
439
+
440
+ return $this->type;
441
+
442
+ }
443
+
444
+ /**
445
+ * Set the backup type
446
+ *
447
+ * $type must be one of complete, database or file
448
+ *
449
+ * @access public
450
+ * @param string $type
451
+ */
452
+ public function set_type( $type ) {
453
+
454
+ if ( ! is_string( $type ) || ! in_array( $type, array( 'file', 'database', 'complete' ) ) )
455
+ throw new Exception( 'Invalid backup type <code>' . $type . '</code> must be one of (string) file, database or complete' );
456
+
457
+ $this->type = $type;
458
+
459
+ }
460
+
461
+ /**
462
+ * Get the path to the mysqldump bin
463
+ *
464
+ * If not explicitly set will attempt to work
465
+ * it out by checking common locations
466
+ *
467
+ * @access public
468
+ * @return string
469
+ */
470
+ public function get_mysqldump_command_path() {
471
+
472
+ // Check shell_exec is available
473
+ if ( ! self::is_shell_exec_available() )
474
+ return '';
475
+
476
+ // Return now if it's already been set
477
+ if ( isset( $this->mysqldump_command_path ) )
478
+ return $this->mysqldump_command_path;
479
+
480
+ $this->mysqldump_command_path = '';
481
+
482
+ // Does mysqldump work
483
+ if ( is_null( shell_exec( 'hash mysqldump 2>&1' ) ) ) {
484
+
485
+ // If so store it for later
486
+ $this->set_mysqldump_command_path( 'mysqldump' );
487
+
488
+ // And return now
489
+ return $this->mysqldump_command_path;
490
+
491
+ }
492
+
493
+ // List of possible mysqldump locations
494
+ $mysqldump_locations = array(
495
+ '/usr/local/bin/mysqldump',
496
+ '/usr/local/mysql/bin/mysqldump',
497
+ '/usr/mysql/bin/mysqldump',
498
+ '/usr/bin/mysqldump',
499
+ '/opt/local/lib/mysql6/bin/mysqldump',
500
+ '/opt/local/lib/mysql5/bin/mysqldump',
501
+ '/opt/local/lib/mysql4/bin/mysqldump',
502
+ '/xampp/mysql/bin/mysqldump',
503
+ '/Program Files/xampp/mysql/bin/mysqldump',
504
+ '/Program Files/MySQL/MySQL Server 6.0/bin/mysqldump',
505
+ '/Program Files/MySQL/MySQL Server 5.5/bin/mysqldump',
506
+ '/Program Files/MySQL/MySQL Server 5.4/bin/mysqldump',
507
+ '/Program Files/MySQL/MySQL Server 5.1/bin/mysqldump',
508
+ '/Program Files/MySQL/MySQL Server 5.0/bin/mysqldump',
509
+ '/Program Files/MySQL/MySQL Server 4.1/bin/mysqldump'
510
+ );
511
+
512
+ // Find the one which works
513
+ foreach ( $mysqldump_locations as $location )
514
+ if ( is_executable( $this->conform_dir( $location ) ) )
515
+ $this->set_mysqldump_command_path( $location );
516
+
517
+ return $this->mysqldump_command_path;
518
+
519
+ }
520
+
521
+ /**
522
+ * Set the path to the mysqldump bin
523
+ *
524
+ * Setting the path to false will cause the database
525
+ * dump to use the php fallback
526
+ *
527
+ * @access public
528
+ * @param mixed $path
529
+ */
530
+ public function set_mysqldump_command_path( $path ) {
531
+
532
+ $this->mysqldump_command_path = $path;
533
+
534
+ }
535
+
536
+ /**
537
+ * Get the path to the zip bin
538
+ *
539
+ * If not explicitly set will attempt to work
540
+ * it out by checking common locations
541
+ *
542
+ * @access public
543
+ * @return string
544
+ */
545
+ public function get_zip_command_path() {
546
+
547
+ // Check shell_exec is available
548
+ if ( ! self::is_shell_exec_available() )
549
+ return '';
550
+
551
+ // Return now if it's already been set
552
+ if ( isset( $this->zip_command_path ) )
553
+ return $this->zip_command_path;
554
+
555
+ $this->zip_command_path = '';
556
+
557
+ // Does zip work
558
+ if ( is_null( shell_exec( 'hash zip 2>&1' ) ) ) {
559
+
560
+ // If so store it for later
561
+ $this->set_zip_command_path( 'zip' );
562
+
563
+ // And return now
564
+ return $this->zip_command_path;
565
+
566
+ }
567
+
568
+ // List of possible zip locations
569
+ $zip_locations = array(
570
+ '/usr/bin/zip'
571
+ );
572
+
573
+ // Find the one which works
574
+ foreach ( $zip_locations as $location )
575
+ if ( is_executable( $this->conform_dir( $location ) ) )
576
+ $this->set_zip_command_path( $location );
577
+
578
+ return $this->zip_command_path;
579
+
580
+ }
581
+
582
+ /**
583
+ * Set the path to the zip bin
584
+ *
585
+ * Setting the path to false will cause the database
586
+ * dump to use the php fallback
587
+ *
588
+ * @access public
589
+ * @param mixed $path
590
+ */
591
+ public function set_zip_command_path( $path ) {
592
+
593
+ $this->zip_command_path = $path;
594
+
595
+ }
596
+
597
+ protected function do_action( $action ) {
598
+
599
+ do_action( $action, $this );
600
+
601
+ }
602
+
603
  /**
604
  * Kick off a backup
605
  *
608
  */
609
  public function backup() {
610
 
611
+ $this->do_action( 'hmbkp_backup_started' );
612
 
613
  // Backup database
614
+ if ( $this->get_type() !== 'file' )
615
+ $this->dump_database();
616
 
617
  // Zip everything up
618
  $this->archive();
619
 
620
+ $this->do_action( 'hmbkp_backup_complete' );
621
 
622
  }
623
 
628
  * if not.
629
  *
630
  * @access public
 
631
  */
632
+ public function dump_database() {
633
 
634
+ $this->do_action( 'hmbkp_mysqldump_started' );
635
 
636
+ if ( $this->get_mysqldump_command_path() )
637
+ $this->mysqldump();
638
 
639
+ if ( empty( $this->mysqldump_verified ) )
640
+ $this->mysqldump_fallback();
641
 
642
+ $this->do_action( 'hmbkp_mysqldump_finished' );
 
643
 
644
+ }
 
645
 
646
+ public function mysqldump() {
 
647
 
648
+ $this->mysqldump_method = 'mysqldump';
 
649
 
650
+ $host = reset( explode( ':', DB_HOST ) );
651
+ $port = strpos( DB_HOST, ':' ) ? end( explode( ':', DB_HOST ) ) : '';
652
 
653
+ // Path to the mysqldump executable
654
+ $cmd = escapeshellarg( $this->get_mysqldump_command_path() );
 
655
 
656
+ // No Create DB command
657
+ $cmd .= ' --no-create-db';
658
 
659
+ // Make sure binary data is exported properly
660
+ $cmd .= ' --hex-blob';
 
661
 
662
+ // Username
663
+ $cmd .= ' -u ' . escapeshellarg( DB_USER );
664
 
665
+ // Don't pass the password if it's blank
666
+ if ( DB_PASSWORD )
667
+ $cmd .= ' -p' . escapeshellarg( DB_PASSWORD );
668
 
669
+ // Set the host
670
+ $cmd .= ' -h ' . escapeshellarg( $host );
671
 
672
+ // Set the port if it was set
673
+ if ( ! empty( $port ) )
674
+ $cmd .= ' -P ' . $port;
675
 
676
+ // The file we're saving too
677
+ $cmd .= ' -r ' . escapeshellarg( $this->get_database_dump_filepath() );
678
 
679
+ // The database we're dumping
680
+ $cmd .= ' ' . escapeshellarg( DB_NAME );
681
+
682
+ // Pipe STDERR to STDOUT
683
+ $cmd .= ' 2>&1';
684
 
685
+ // Store any returned data in warning
686
+ $this->warning( $this->get_mysqldump_method(), shell_exec( $cmd ) );
687
+
688
+ $this->verify_mysqldump();
689
 
690
  }
691
 
693
  * PHP mysqldump fallback functions, exports the database to a .sql file
694
  *
695
  * @access public
 
696
  */
697
  public function mysqldump_fallback() {
698
 
699
+ $this->errors_to_warnings( $this->get_mysqldump_method() );
700
 
701
  $this->mysqldump_method = 'mysqldump_fallback';
702
 
734
  * Zip up all the files.
735
  *
736
  * Attempts to use the shell zip command, if
737
+ * thats not available then it falls back to
738
  * PHP ZipArchive and finally PclZip.
739
  *
740
  * @access public
 
741
  */
742
  public function archive() {
743
 
744
+ $this->do_action( 'hmbkp_archive_started' );
745
 
746
  // Do we have the path to the zip command
747
+ if ( $this->get_zip_command_path() )
748
  $this->zip();
749
 
750
  // If not or if the shell zip failed then use ZipArchive
756
  $this->pcl_zip();
757
 
758
  // Delete the database dump file
759
+ if ( file_exists( $this->get_database_dump_filepath() ) )
760
+ unlink( $this->get_database_dump_filepath() );
761
 
762
+ $this->do_action( 'hmbkp_archive_finished' );
763
 
764
  }
765
 
767
  * Zip using the native zip command
768
  *
769
  * @access public
 
770
  */
771
  public function zip() {
772
 
773
  $this->archive_method = 'zip';
774
 
775
  // Zip up $this->root with excludes
776
+ if ( $this->get_type() !== 'database' && $this->exclude_string( 'zip' ) )
777
+ $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->get_root() ) . ' && ' . escapeshellarg( $this->get_zip_command_path() ) . ' -rq ' . escapeshellarg( $this->get_archive_filepath() ) . ' ./' . ' -x ' . $this->exclude_string( 'zip' ) . ' 2>&1' ) );
778
 
779
  // Zip up $this->root without excludes
780
+ elseif ( $this->get_type() !== 'database' )
781
+ $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->get_root() ) . ' && ' . escapeshellarg( $this->get_zip_command_path() ) . ' -rq ' . escapeshellarg( $this->get_archive_filepath() ) . ' ./' . ' 2>&1' ) );
782
 
783
  // Add the database dump to the archive
784
+ if ( $this->get_type() !== 'file' )
785
+ $this->warning( $this->archive_method, shell_exec( 'cd ' . escapeshellarg( $this->get_path() ) . ' && ' . escapeshellarg( $this->get_zip_command_path() ) . ' -uq ' . escapeshellarg( $this->get_archive_filepath() ) . ' ' . escapeshellarg( $this->get_database_dump_filename() ) . ' 2>&1' ) );
786
 
787
+ $this->verify_archive();
788
 
789
  }
790
 
791
  /**
792
  * Fallback for creating zip archives if zip command is
793
+ * unavailable.
794
  *
795
  * @access public
796
  * @param string $path
802
 
803
  $zip = new ZipArchive();
804
 
805
+ if ( ! class_exists( 'ZipArchive' ) || ! $zip->open( $this->get_archive_filepath(), ZIPARCHIVE::CREATE ) )
806
  return;
807
 
808
+ $excludes = $this->exclude_string( 'regex' );
809
+
810
+ if ( $this->get_type() !== 'database' ) {
811
 
812
  $files_added = 0;
813
 
814
+ foreach ( $this->get_files() as $file ) {
815
+
816
+ if ( $file === '.' || $file === '..' || ! $file->isReadable() )
817
+ continue;
818
+
819
+ // Excludes
820
+ if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) ) )
821
+ continue;
822
 
823
+ if ( $file->isDir() )
824
+ $zip->addEmptyDir( trailingslashit( str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) ) );
825
 
826
+ elseif ( $file->isFile() )
827
+ $zip->addFile( $file->getPathname(), str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) );
828
 
829
  if ( ++$files_added % 500 === 0 )
830
+ if ( ! $zip->close() || ! $zip->open( $this->get_archive_filepath(), ZIPARCHIVE::CREATE ) )
831
  return;
832
 
833
  }
835
  }
836
 
837
  // Add the database
838
+ if ( $this->get_type() !== 'file' )
839
+ $zip->addFile( $this->get_database_dump_filepath(), $this->get_database_dump_filename() );
840
 
841
  if ( $zip->status )
842
  $this->warning( $this->archive_method, $zip->status );
846
 
847
  $zip->close();
848
 
849
+ $this->verify_archive();
850
 
851
  }
852
 
853
  /**
854
  * Fallback for creating zip archives if zip command and ZipArchive are
855
+ * unavailable.
856
  *
857
  * Uses the PclZip library that ships with WordPress
858
  *
870
 
871
  $this->load_pclzip();
872
 
873
+ $archive = new PclZip( $this->get_archive_filepath() );
874
 
875
  // Zip up everything
876
+ if ( $this->get_type() !== 'database' )
877
+ if ( ! $archive->add( $this->get_root(), PCLZIP_OPT_REMOVE_PATH, $this->get_root(), PCLZIP_CB_PRE_ADD, 'hmbkp_pclzip_callback' ) )
878
  $this->warning( $this->archive_method, $archive->errorInfo( true ) );
879
 
880
  // Add the database
881
+ if ( $this->get_type() !== 'file' )
882
+ if ( ! $archive->add( $this->get_database_dump_filepath(), PCLZIP_OPT_REMOVE_PATH, $this->get_path() ) )
883
  $this->warning( $this->archive_method, $archive->errorInfo( true ) );
884
 
885
  unset( $GLOBALS['_hmbkp_exclude_string'] );
886
 
887
+ $this->verify_archive();
888
+
889
+ }
890
+
891
+ public function verify_mysqldump() {
892
+
893
+ // If we've already passed then no need to check again
894
+ if ( ! empty( $this->mysqldump_verified ) )
895
+ return true;
896
+
897
+ if ( ! file_exists( $this->get_database_dump_filepath() ) )
898
+ $this->error( $this->get_mysqldump_method(), __( 'The mysqldump file was not created', 'hmbkp' ) );
899
+
900
+ if ( $this->get_errors( $this->get_mysqldump_method() ) )
901
+ return false;
902
+
903
+ return $this->mysqldump_verified = true;
904
+
905
 
906
  }
907
 
911
  * @access public
912
  * @return bool
913
  */
914
+ public function verify_archive() {
915
 
916
  // If we've already passed then no need to check again
917
  if ( ! empty( $this->archive_verified ) )
918
  return true;
919
 
920
+ if ( ! file_exists( $this->get_archive_filepath() ) )
921
+ $this->error( $this->get_archive_method(), __( 'The backup file was not created', 'hmbkp' ) );
922
 
923
  // Verify using the zip command if possible
924
+ if ( $this->get_zip_command_path() && $this->get_archive_method() === 'zip' ) {
925
 
926
+ $verify = shell_exec( escapeshellarg( $this->get_zip_command_path() ) . ' -T ' . escapeshellarg( $this->get_archive_filepath() ) . ' 2> /dev/null' );
927
 
928
  if ( strpos( $verify, 'OK' ) === false )
929
+ $this->error( $this->get_archive_method(), $verify );
930
 
931
  }
932
 
933
  // If there are errors delete the backup file.
934
+ if ( $this->get_errors( $this->get_archive_method() ) && file_exists( $this->get_archive_filepath() ) )
935
+ unlink( $this->get_archive_filepath() );
936
 
937
+ if ( $this->get_errors( $this->get_archive_method() ) )
938
  return false;
939
 
940
+ if ( $this->get_unreadable_files() )
941
+ $this->warning( $this->get_archive_method(), __( 'The following files are unreadable and couldn\'t be backed up: ', 'hmbkp' ) . implode( ', ', $this->get_unreadable_files() ) );
942
+
943
  return $this->archive_verified = true;
944
 
945
  }
946
 
947
  /**
948
+ * Return an array of all files in the filesystem
 
949
  *
950
  * @access public
951
  * @return array
952
  */
953
+ public function get_files() {
954
 
955
  if ( ! empty( $this->files ) )
956
  return $this->files;
957
 
958
  $this->files = array();
959
 
960
+ if ( defined( 'RecursiveDirectoryIterator::FOLLOW_SYMLINKS' ) )
961
+ $this->files = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $this->get_root(), RecursiveDirectoryIterator::FOLLOW_SYMLINKS ), RecursiveIteratorIterator::SELF_FIRST, RecursiveIteratorIterator::CATCH_GET_CHILD );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
962
 
963
+ else
964
+ $this->files = $this->get_files_fallback( $this->get_root() );
 
 
 
 
965
 
966
  return $this->files;
967
 
974
  * Used if RecursiveDirectoryIterator::FOLLOW_SYMLINKS isn't available
975
  *
976
  * @access private
977
+ * @param string $dir
978
  * @param array $files. (default: array())
979
  * @return array
980
  */
981
+ private function get_files_fallback( $dir, $files = array() ) {
982
 
983
  $handle = opendir( $dir );
984
 
987
  while ( $file = readdir( $handle ) ) :
988
 
989
  // Ignore current dir and containing dir and any unreadable files or directories
990
+ if ( $file === '.' || $file === '..' )
991
  continue;
992
 
993
  $filepath = $this->conform_dir( trailingslashit( $dir ) . $file );
994
+ $file = str_ireplace( trailingslashit( $this->get_root() ), '', $filepath );
995
 
996
+ $files[] = new SplFileInfo( $filepath );
 
 
 
 
 
 
 
 
 
997
 
998
  if ( is_dir( $filepath ) )
999
+ $files = $this->get_files_fallback( $filepath, $files );
1000
 
1001
  endwhile;
1002
 
1004
 
1005
  }
1006
 
1007
+ /**
1008
+ * Returns an array of files that will be included in the backup.
1009
+ *
1010
+ * @access public
1011
+ * @return array
1012
+ */
1013
+ public function get_included_files() {
1014
+
1015
+ if ( ! empty( $this->included_files ) )
1016
+ return $this->included_files;
1017
+
1018
+ $this->included_files = array();
1019
+
1020
+ $excludes = $this->exclude_string( 'regex' );
1021
+
1022
+ foreach ( $this->get_files() as $file ) {
1023
+
1024
+ if ( $file === '.' || $file === '..' || ! $file->isReadable() )
1025
+ continue;
1026
+
1027
+ // Excludes
1028
+ if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) ) )
1029
+ continue;
1030
+
1031
+ $this->included_files[] = $file;
1032
+
1033
+ }
1034
+
1035
+ return $this->included_files;
1036
+
1037
+ }
1038
+
1039
+ /**
1040
+ * Returns an array of files that match the exclude rules.
1041
+ *
1042
+ * @access public
1043
+ * @return array
1044
+ */
1045
+ public function get_excluded_files() {
1046
+
1047
+ if ( ! empty( $this->excluded_files ) )
1048
+ return $this->excluded_files;
1049
+
1050
+ $this->excluded_files = array();
1051
+
1052
+ $excludes = $this->exclude_string( 'regex' );
1053
+
1054
+ foreach ( $this->get_files() as $file ) {
1055
+
1056
+ if ( $file === '.' || $file === '..' || ! $file->isReadable() )
1057
+ continue;
1058
+
1059
+ // Excludes
1060
+ if ( $excludes && preg_match( '(' . $excludes . ')', str_ireplace( trailingslashit( $this->get_root() ), '', $this->conform_dir( $file->getPathname() ) ) ) )
1061
+ $this->excluded_files[] = $file;
1062
+
1063
+ }
1064
+
1065
+ return $this->excluded_files;
1066
+
1067
+ }
1068
+
1069
+ /**
1070
+ * Returns an array of unreadable files.
1071
+ *
1072
+ * @access public
1073
+ * @return array
1074
+ */
1075
+ public function get_unreadable_files() {
1076
+
1077
+ if ( ! empty( $this->unreadable_files ) )
1078
+ return $this->unreadable_files;
1079
+
1080
+ $this->unreadable_files = array();
1081
+
1082
+ foreach ( $this->get_files() as $file ) {
1083
+
1084
+ if ( $file === '.' || $file === '..' )
1085
+ continue;
1086
+
1087
+ if ( ! $file->isReadable() )
1088
+ $this->unreadable_files[] = $file;
1089
+
1090
+ }
1091
+
1092
+ return $this->unreadable_files;
1093
+
1094
+ }
1095
+
1096
  private function load_pclzip() {
1097
 
1098
  // Load PclZip
1099
  if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
1100
+ define( 'PCLZIP_TEMPORARY_DIR', trailingslashit( $this->get_path() ) );
1101
 
1102
  require_once( ABSPATH . 'wp-admin/includes/class-pclzip.php' );
1103
 
1104
  }
1105
 
1106
  /**
1107
+ * Get an array of exclude rules
1108
+ *
1109
+ * The backup path is automatically excluded
1110
  *
1111
  * @access public
1112
+ * @return array
1113
  */
1114
+ public function get_excludes() {
 
 
 
1115
 
1116
+ $excludes = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1117
 
1118
+ if ( isset( $this->excludes ) )
1119
+ $excludes = $this->excludes;
1120
 
1121
+ // If path() is inside root(), exclude it
1122
+ if ( strpos( $this->get_path(), $this->get_root() ) !== false )
1123
+ array_unshift( $excludes, trailingslashit( $this->get_path() ) );
 
1124
 
1125
+ return array_unique( $excludes );
1126
 
1127
  }
1128
 
1129
  /**
1130
+ * Set the excludes, expects and array
1131
  *
1132
  * @access public
1133
+ * @param Array $excludes
1134
+ * @param Bool $append
1135
  */
1136
+ public function set_excludes( $excludes, $append = false ) {
1137
 
1138
+ if ( is_string( $excludes ) )
1139
+ $excludes = explode( ',', $excludes );
 
 
 
 
 
 
1140
 
1141
+ if ( $append )
1142
+ $excludes = array_merge( $this->excludes, $excludes );
1143
 
1144
+ $this->excludes = array_filter( array_unique( array_map( 'trim', $excludes ) ) );
 
 
 
 
 
1145
 
1146
  }
1147
 
1155
  * @param string $context. (default: 'zip')
1156
  * @return string
1157
  */
1158
+ protected function exclude_string( $context = 'zip' ) {
1159
 
1160
  // Return a comma separated list by default
1161
  $separator = ', ';
1162
  $wildcard = '';
1163
 
1164
  // The zip command
1165
+ if ( $context === 'zip' ) {
1166
  $wildcard = '*';
1167
  $separator = ' -x ';
1168
 
1169
  // The PclZip fallback library
1170
+ } elseif ( $context === 'regex' ) {
1171
  $wildcard = '([\s\S]*?)';
1172
  $separator = '|';
1173
 
1174
  }
1175
 
1176
+ $excludes = $this->get_excludes();
 
 
 
 
 
1177
 
1178
  foreach( $excludes as $key => &$rule ) {
1179
 
1192
  $fragment = true;
1193
 
1194
  // Strip $this->root and conform
1195
+ $rule = str_ireplace( $this->get_root(), '', untrailingslashit( $this->conform_dir( $rule ) ) );
1196
 
1197
  // Strip the preceeding slash
1198
  if ( in_array( substr( $rule, 0, 1 ), array( '\\', '/' ) ) )
1199
  $rule = substr( $rule, 1 );
1200
 
1201
  // Escape string for regex
1202
+ if ( $context === 'regex' )
1203
  $rule = str_replace( '.', '\.', $rule );
1204
 
1205
  // Convert any existing wildcards
1206
+ if ( $wildcard !== '*' && strpos( $rule, '*' ) !== false )
1207
  $rule = str_replace( '*', $wildcard, $rule );
1208
 
1209
  // Wrap directory fragments and files in wildcards for zip
1210
+ if ( $context === 'zip' && ( $fragment || $file ) )
1211
  $rule = $wildcard . $rule . $wildcard;
1212
 
1213
  // Add a wildcard to the end of absolute url for zips
1214
+ if ( $context === 'zip' && $absolute )
1215
  $rule .= $wildcard;
1216
 
1217
  // Add and end carrot to files for pclzip but only if it doesn't end in a wildcard
1218
+ if ( $file && $context === 'regex' )
1219
  $rule .= '$';
1220
 
1221
  // Add a start carrot to absolute urls for pclzip
1222
+ if ( $absolute && $context === 'regex' )
1223
  $rule = '^' . $rule;
1224
 
1225
  }
1226
 
1227
  // Escape shell args for zip command
1228
+ if ( $context === 'zip' )
1229
  $excludes = array_map( 'escapeshellarg', array_unique( $excludes ) );
1230
 
1231
  return implode( $separator, $excludes );
1233
  }
1234
 
1235
  /**
1236
+ * Add backquotes to tables and db-names in SQL queries. Taken from phpMyAdmin.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1237
  *
1238
  * @access private
1239
  * @param mixed $a_name
1240
  */
1241
  private function sql_backquote( $a_name ) {
1242
 
1243
+ if ( ! empty( $a_name ) && $a_name !== '*' ) {
1244
 
1245
  if ( is_array( $a_name ) ) {
1246
 
1339
  $field_set[$j] = $this->sql_backquote( mysql_field_name( $result, $j ) );
1340
  $type = mysql_field_type( $result, $j );
1341
 
1342
+ if ( $type === 'tinyint' || $type === 'smallint' || $type === 'mediumint' || $type === 'int' || $type === 'bigint' || $type === 'timestamp')
1343
  $field_num[$j] = true;
1344
 
1345
  else
1364
  if ( ! isset($row[$j] ) ) {
1365
  $values[] = 'NULL';
1366
 
1367
+ } elseif ( $row[$j] === '0' || $row[$j] !== '' ) {
1368
 
1369
  // a number
1370
  if ( $field_num[$j] )
1383
  $sql_file .= " \n" . $entries . implode( ', ', $values ) . ") ;";
1384
 
1385
  // write the rows in batches of 100
1386
+ if ( $batch_write === 100 ) {
1387
  $batch_write = 0;
1388
  $this->write_sql( $sql_file );
1389
  $sql_file = '';
1437
  */
1438
  private function write_sql( $sql ) {
1439
 
1440
+ $sqlname = $this->get_database_dump_filepath();
1441
 
1442
  // Actually write the sql file
1443
  if ( is_writable( $sqlname ) || ! file_exists( $sqlname ) ) {
1444
 
1445
+ if ( ! $handle = @fopen( $sqlname, 'a' ) )
1446
  return;
1447
 
1448
  if ( ! fwrite( $handle, $sql ) )
1460
  * Get the errors
1461
  *
1462
  * @access public
 
1463
  */
1464
+ public function get_errors( $context = null ) {
1465
 
1466
  if ( ! empty( $context ) )
1467
  return isset( $this->errors[$context] ) ? $this->errors[$context] : array();
1470
 
1471
  }
1472
 
 
1473
  /**
1474
  * Add an error to the errors stack
1475
  *
1476
  * @access private
1477
  * @param string $context
1478
  * @param mixed $error
 
1479
  */
1480
  private function error( $context, $error ) {
1481
 
1491
  *
1492
  * @access private
1493
  * @param string $context. (default: null)
 
1494
  */
1495
  private function errors_to_warnings( $context = null ) {
1496
 
1497
+ $errors = empty( $context ) ? $this->get_errors() : array( $context => $this->get_errors( $context ) );
1498
 
1499
  if ( empty( $errors ) )
1500
  return;
1515
  * Get the warnings
1516
  *
1517
  * @access public
 
1518
  */
1519
+ public function get_warnings( $context = null ) {
1520
 
1521
  if ( ! empty( $context ) )
1522
  return isset( $this->warnings[$context] ) ? $this->warnings[$context] : array();
1525
 
1526
  }
1527
 
 
1528
  /**
1529
  * Add an warning to the warnings stack
1530
  *
1531
  * @access private
1532
  * @param string $context
1533
  * @param mixed $warning
 
1534
  */
1535
  private function warning( $context, $warning ) {
1536
 
1541
 
1542
  }
1543
 
 
1544
  /**
1545
  * Custom error handler for catching errors
1546
  *
1549
  * @param string $message
1550
  * @param string $file
1551
  * @param string $line
 
1552
  */
1553
  public function error_handler( $type ) {
1554
 
1555
+ if ( ( defined( 'E_DEPRECATED' ) && $type === E_DEPRECATED ) || ( defined( 'E_STRICT' ) && $type === E_STRICT ) || error_reporting() === 0 )
1556
  return false;
1557
 
1558
  $args = func_get_args();
languages/hmbkp-de_DE.mo CHANGED
Binary file
languages/hmbkp-de_DE.po CHANGED
@@ -2,8 +2,8 @@ msgid ""
2
  msgstr ""
3
  "Project-Id-Version: BackUpWordPress\n"
4
  "Report-Msgid-Bugs-To: \n"
5
- "POT-Creation-Date: 2012-08-14 14:32+0100\n"
6
- "PO-Revision-Date: 2012-08-14 14:54+0100\n"
7
  "Last-Translator: Flo Edelmann <florian-edelmann@online.de>\n"
8
  "Language-Team: Flo Edelmann <florian-edelmann@online.de>\n"
9
  "Language: \n"
@@ -18,522 +18,737 @@ msgstr ""
18
  "X-Poedit-SourceCharset: utf-8\n"
19
  "X-Poedit-SearchPath-0: .\n"
20
 
21
- #: admin.settings.php:3
22
- #: admin.page.php:11
23
- msgid "Settings"
24
- msgstr "Einstellungen"
25
 
26
- #: admin.settings.php:5
27
  #, php-format
28
- msgid "You can define %1$s in your %2$s to control some settings. A full list of %3$s can be found in the %4$s. Defined settings will not be editable below."
29
- msgstr "Du kannst %1$s in deinem %2$s definieren, um einige Einstellungen vorzunehmen. Eine komplette Liste der %3$s kannst du im %4$s finden. Definierte Einstellungen sind unten nicht veränderbar."
30
-
31
- #: admin.settings.php:5
32
- #: admin.constants.php:3
33
- #: admin.menus.php:76
34
- msgid "Constants"
35
- msgstr "Konstanten"
36
-
37
- #: admin.settings.php:5
38
- msgid "help panel"
39
- msgstr "Hilfe-Panel"
40
-
41
- #: admin.settings.php:16
42
- msgid "Automatic Backups"
43
- msgstr "Automatische Backups"
44
-
45
- #: admin.settings.php:22
46
- msgid "Backup my site automatically."
47
- msgstr "Sichere meine Seite automatisch."
48
-
49
- #: admin.settings.php:27
50
- msgid "No automatic backups."
51
- msgstr "Keine automatischen Backups."
52
-
53
- #: admin.settings.php:36
54
- msgid "Frequency of backups"
55
- msgstr "Häufigkeit der Backups"
56
-
57
- #: admin.settings.php:40
58
- msgid "Automatic backups will occur"
59
- msgstr "Automatische Backups werden ausgeführt:"
60
-
61
- #: admin.settings.php:43
62
- msgid "Daily"
63
- msgstr "Täglich"
64
-
65
- #: admin.settings.php:44
66
- msgid "Weekly"
67
- msgstr "Wöchentlich"
68
-
69
- #: admin.settings.php:45
70
- msgid "Fortnightly"
71
- msgstr "Vierzehntägig"
72
 
73
- #: admin.settings.php:46
74
- msgid "Monthly"
75
- msgstr "Monatlich"
 
76
 
77
- #: admin.settings.php:55
78
- msgid "What to Backup"
79
- msgstr "Zu sichernde Daten"
80
 
81
- #: admin.settings.php:59
82
- msgid "Backup my"
83
- msgstr "Sichere meine"
84
-
85
- #: admin.settings.php:62
86
- msgid "database &amp; files"
87
- msgstr "Datenbank &amp; Dateien"
88
-
89
- #: admin.settings.php:63
90
- msgid "database only"
91
- msgstr "Datenbank"
92
-
93
- #: admin.settings.php:64
94
- msgid "files only"
95
- msgstr "Dateien"
96
 
97
- #: admin.settings.php:72
98
- msgid "Number of backups"
99
- msgstr "Anzahl der Backups"
 
 
 
 
 
 
100
 
101
- #: admin.settings.php:73
102
- #, php-format
103
- msgid "The last %s backups will be stored on the server."
104
- msgstr "Die letzten %s Backups werden auf dem Server gespeichert bleiben."
 
 
 
 
 
105
 
106
- #: admin.settings.php:77
107
- msgid "Email backups"
108
- msgstr "Backup-E-Mail"
 
 
 
 
 
 
109
 
110
- #: admin.settings.php:78
111
- msgid "A copy of the backup file will be emailed to this address. Disabled if left blank."
112
- msgstr "Eine Kopie der Backup-Datei wird per E-Mail an diese Adresse gesendet. Leerlassen zum deaktivieren."
113
 
114
- #: admin.settings.php:82
115
- msgid "Excludes"
116
- msgstr "Ausnahmen"
117
 
118
- #: admin.settings.php:85
119
- msgid "A comma separated list of file and directory paths that you do <strong>not</strong> want to backup."
120
- msgstr "Eine kommagetrennte Liste von Datei- und Verzeichnispfaden, die du <strong>nicht</strong> sichern möchtest."
121
-
122
- #: admin.settings.php:86
123
- #: admin.constants.php:8
124
- #: admin.constants.php:11
125
- #: admin.constants.php:14
126
- #: admin.constants.php:17
127
- #: admin.constants.php:20
128
- #: admin.constants.php:23
129
- #: admin.constants.php:26
130
- #: admin.constants.php:29
131
- #: admin.constants.php:32
132
- #: admin.constants.php:35
133
- #: admin.constants.php:38
134
- #: admin.constants.php:41
135
- msgid "e.g."
136
- msgstr "z.B."
137
 
138
- #: admin.settings.php:94
139
- msgid "Save Changes"
140
- msgstr "Änderungen speichern"
141
 
142
- #: admin.backups-table.php:12
143
  #, php-format
144
- msgid "1 backup completed"
145
- msgid_plural "%d backups completed"
146
- msgstr[0] "1 Backup fertiggestellt"
147
- msgstr[1] "%d Backups fertiggestellt"
148
-
149
- #: admin.backups-table.php:13
150
- msgid "Size"
151
- msgstr "Größe"
152
-
153
- #: admin.backups-table.php:14
154
- msgid "Actions"
155
- msgstr "Aktionen"
156
 
157
- #: admin.backups-table.php:20
158
  #, php-format
159
- msgid "Only the most recent backup will be saved"
160
- msgid_plural "The %d most recent backups will be saved"
161
- msgstr[0] "Nur das neueste Backup wird gespeichert"
162
- msgstr[1] "Die %d neuesten Backups werden gespeichert"
163
 
164
- #: admin.backups-table.php:21
165
  #, php-format
166
- msgid "Total %s"
167
- msgstr "Insgesamt %s"
168
-
169
- #: admin.page.php:7
170
- #: admin.menus.php:10
171
- msgid "Manage Backups"
172
- msgstr "Backups verwalten"
173
 
174
- #: admin.page.php:23
175
- msgid "You need to fix the issues detailed above before BackUpWordPress can start."
176
- msgstr "Du musst die Probleme, die oben beschrieben werden, beheben, bevor BackUpWordPress starten kann."
177
-
178
- #: admin.page.php:29
179
  #, php-format
180
- msgid "If you need help getting things working you are more than welcome to email us at %s and we'll do what we can to help."
181
- msgstr "Wenn du Hilfe brauchst, sende uns ruhig eine E-Mail an %s (am besten auf Englisch) und wir werden sehen, was wir tun können."
182
 
183
- #: admin.backup-button.php:3
184
- msgid "cancel"
185
- msgstr "abbrechen"
186
 
187
- #: admin.backup-button.php:7
188
- msgid "Back Up Now"
189
- msgstr "Jetzt sichern"
190
 
191
- #: admin.constants.php:3
192
  #, php-format
193
  msgid "You can %1$s any of the following %2$s in your %3$s to control advanced settings. %4$s. Defined %5$s will be highlighted."
194
  msgstr "Du kannst jede der folgenden %2$s in deinem %3$s %1$sn, um erweiterte Einstellungen vorzunehmen. %4$s. Definierte %5$s werden hervorgehoben."
195
 
196
- #: admin.constants.php:3
 
 
 
 
197
  msgid "The Codex can help"
198
  msgstr "Der Codex kann helfen"
199
 
200
- #: admin.constants.php:8
201
  #, php-format
202
  msgid "The path to folder you would like to store your backup files in, defaults to %s."
203
  msgstr "Der Pfad zum Verzeichnis, in dem du die Backups speichern möchtest. Standard: %s"
204
 
205
- #: admin.constants.php:11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  #, php-format
207
  msgid "The path to your %1$s executable. Will be used for the %2$s part of the back up if available."
208
  msgstr "Der Pfad zur ausführbaren %1$s-Datei. Wird für den %2$s-Teil des Backups genutzt, wenn verfügbar."
209
 
210
- #: admin.constants.php:11
211
- #: admin.constants.php:14
212
- #: admin.constants.php:23
213
- #: admin.constants.php:26
214
- #: admin.status.php:14
215
- #: admin.status.php:18
216
  msgid "database"
217
  msgstr "Datenbank"
218
 
219
- #: admin.constants.php:14
220
  #, php-format
221
  msgid "The path to your %1$s executable. Will be used to zip up your %2$s and %3$s if available."
222
  msgstr "Der Pfad zur ausführbaren %1$s-Datei. Wird genutzt, um deine %2$s und %3$s als ZIP-Archiv zu komprimieren, wenn verfügbar."
223
 
224
- #: admin.constants.php:14
225
- #: admin.constants.php:23
226
- #: admin.constants.php:26
227
- #: admin.status.php:14
228
- #: admin.status.php:22
229
  msgid "files"
230
  msgstr "Dateien"
231
 
232
- #: admin.constants.php:17
233
  #, php-format
234
  msgid "Completely disables the automatic back up. You can still back up using the \"Back Up Now\" button. Defaults to %s."
235
  msgstr "Deaktiviert die automatischen Backups vollständig. Du kannst trotzdem Backups erstellen, indem du den \"Jetzt sichern\"-Button verwendest. Standard: %s"
236
 
237
- #: admin.constants.php:20
238
  #, php-format
239
  msgid "Number of backups to keep, older backups will be deleted automatically when a new backup is completed. Defaults to %s."
240
  msgstr "Anzahl der zu behaltenden Backups. Ältere Backups werden automatisch gelöscht, sobald ein neues Backup fertiggestellt ist. Standard: %s"
241
 
242
- #: admin.constants.php:23
243
- #: admin.constants.php:26
244
  #, php-format
245
  msgid "Backup %1$s only, your %2$s won't be backed up. Defaults to %3$s."
246
  msgstr "Nur die %1$s sichern, deine %2$s werden nicht gesichert. Standard: %3$s"
247
 
248
- #: admin.constants.php:29
249
  #, php-format
250
  msgid "The time that the daily back up should run. Defaults to %s."
251
  msgstr "Die Zeit, zu der das tägliche Backup laufen soll. Standard: %s"
252
 
253
- #: admin.constants.php:32
254
  #, php-format
255
  msgid "Attempt to email a copy of your backups. Value should be email address to send backups to. Defaults to %s."
256
  msgstr "Versuche, eine Kopie des Backups per E-Mail zu senden. Der Wert sollte eine E-Mail-Adresse sein. Standard: %s"
257
 
258
- #: admin.constants.php:35
259
  msgid "Comma separated list of files or directories to exclude, the backups directory is automatically excluded."
260
  msgstr "Kommagetrennte Liste von Dateien oder Verzeichnissen, die ausgeschlossen werden sollen (das Backup-Verzeichnis ist automatisch ausgeschlossen)."
261
 
262
- #: admin.constants.php:38
263
  #, php-format
264
  msgid "The capability to use when calling %1$s. Defaults to %2$s."
265
  msgstr "Die Rolle, die beim Aufrufen von %1$s benutzt wird. Standard: %2$s"
266
 
267
- #: admin.constants.php:41
268
  #, php-format
269
  msgid "The root directory that is backed up. Defaults to %s."
270
  msgstr "Das Wurzelverzeichnis, das gesichert wird. Standard: %s"
271
 
272
- #: admin.actions.php:70
273
- msgid "You have entered an invalid number of backups."
274
- msgstr "Du hast eine ungültige Anzahl von Backups eingegeben."
 
 
 
 
275
 
276
- #: admin.actions.php:79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
277
  #, php-format
278
- msgid "%s is an invalid email address."
279
- msgstr "%s ist eine ungültige E-Mail-Adresse."
280
 
281
- #: admin.actions.php:249
282
- #: functions/interface.functions.php:89
283
- #: functions/interface.functions.php:99
284
- #: functions/interface.functions.php:110
285
- #: functions/interface.functions.php:120
286
- #: functions/interface.functions.php:130
287
- #: functions/interface.functions.php:140
288
- #: functions/interface.functions.php:150
289
- msgid "BackUpWordPress has detected a problem."
290
- msgstr "BackUpWordPress hat ein Problem entdeckt."
291
 
292
- #: admin.actions.php:249
293
  #, php-format
294
- msgid "%1$s is returning a %2$s response which could mean cron jobs aren't getting fired properly. BackUpWordPress relies on wp-cron to run scheduled back ups. See the %3$s for more details."
295
- msgstr "%1$s gibt eine %2$s-Antwort zurück. Das könnte bedeuten, dass deine Cron-Jobs nicht richtig aufgerufen werden. BackUpWordPress benutzt wp-cron, um geplante Backups auszuführen. Sieh dir das %3$s an für mehr Details."
296
 
297
- #: admin.menus.php:10
298
- #: admin.menus.php:34
299
- msgid "Backups"
300
- msgstr "Backups"
301
 
302
- #: admin.menus.php:65
303
- msgid "You are not using the latest stable version of BackUpWordPress"
304
- msgstr "Du benutzt nicht die neueste stabile BackUpWordPress-Version"
 
305
 
306
- #: admin.menus.php:65
307
  #, php-format
308
- msgid "The information below is for version %1$s. View the <code>readme.txt</code> file for help specific to version %2$s."
309
- msgstr "Diese Informationen sind für Version %1$s. Sieh dir die <code>readme.txt</code>-Datei für Hilfe speziell für Version %2$s an."
310
 
311
- #: admin.menus.php:75
312
- msgid "FAQ"
313
- msgstr "FAQ"
314
 
315
- #: admin.menus.php:79
316
- msgid "For more information:"
317
- msgstr "Für mehr Informationen:"
 
318
 
319
- #: admin.menus.php:81
320
- msgid "Support Forums"
321
- msgstr "Support-Foren"
 
322
 
323
- #: admin.menus.php:82
324
- msgid "Help with translation"
325
- msgstr "Beim Übersetzen helfen"
 
326
 
327
- #: plugin.php:47
328
- msgid "BackUpWordPress requires PHP version 5.2.4 or greater."
329
- msgstr "BackUpWordPress benötigt PHP Version 5.2.4 oder höher."
 
 
 
 
 
330
 
331
- #: plugin.php:58
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
332
  #, php-format
333
- msgid "BackUpWordPress requires WordPress version %s."
334
- msgstr "BackUpWordPress benötigt WordPress Version %s."
 
 
 
 
 
 
 
 
335
 
336
- #: admin.status.php:9
337
  #, php-format
338
- msgid "Automatic backups are %s."
339
- msgstr "Automatische Backups sind %s."
340
 
341
- #: admin.status.php:9
342
- msgid "disabled"
343
- msgstr "deaktiviert"
344
 
345
- #: admin.status.php:14
346
- msgid "&amp;"
347
- msgstr "&amp;"
348
 
349
- #: admin.status.php:32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
350
  #, php-format
351
- msgid "Your %1$s will be automatically backed up %2$s. The next backup will occur at %3$s on %4$s and be saved to %5$s."
352
- msgid_plural "Your %1$s will be automatically backed up %2$s. The next backup will occur at %3$s on %4$s and be saved to %5$s."
353
- msgstr[0] "Deine %1$s wird automatisch %2$s gesichert. Das nächste Backup findet am %3$s um %4$s statt und wird nach %5$s gespeichert."
354
- msgstr[1] "Deine %1$s werden automatisch %2$s gesichert. Das nächste Backup findet am %3$s um %4$s statt und wird nach %5$s gespeichert."
355
 
356
- #: admin.status.php:39
357
  #, php-format
358
- msgid "It's currently %s"
359
- msgstr "Es ist jetzt %s"
 
 
 
 
 
 
 
 
360
 
361
- #: admin.status.php:47
362
  #, php-format
363
- msgid "Your site is %s. Backups will be compressed and should be smaller than this."
364
- msgstr "Deine Seite ist %s groß. Die Backups werden komprimiert und sollten kleiner sein."
365
 
366
- #: admin.status.php:47
367
- msgid "Calculating Size..."
368
- msgstr "Größe berechnen..."
369
 
370
- #: admin.status.php:50
371
  #, php-format
372
- msgid "A copy of each backup will be emailed to %s."
373
- msgstr "Eine Kopie jedes Backups wird an %s gesendet."
 
 
374
 
375
- #: admin.status.php:54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  #, php-format
377
- msgid "The following paths will be excluded from your backups %s."
378
- msgstr "Die folgenden Pfade werden von deinen Backups ausgeschlossen sein: %s"
379
 
380
- #: hm-backup/hm-backup.php:532
381
- msgid "The backup file was not created"
382
- msgstr "Die Backup-Datei wurde nicht angelegt"
383
 
384
- #: hm-backup/hm-backup.php:603
385
- msgid "The following files are unreadable and couldn't be backed up: "
386
- msgstr "Die folgenden Dateien sind nicht lesbar und konnten nicht gesichert werden:"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
387
 
388
- #: functions/interface.functions.php:25
 
 
 
 
 
389
  msgid "Download"
390
  msgstr "Download"
391
 
392
- #: functions/interface.functions.php:26
 
393
  msgid "Delete"
394
  msgstr "Löschen"
395
 
396
- #: functions/interface.functions.php:48
397
- msgid "Settings saved."
398
- msgstr "Einstellungen gespeichert."
399
-
400
- #: functions/interface.functions.php:67
401
- #: functions/interface.functions.php:79
402
  msgid "BackUpWordPress is almost ready."
403
  msgstr "BackUpWordPress ist fast fertig."
404
 
405
- #: functions/interface.functions.php:67
406
  #, php-format
407
  msgid "The backups directory can't be created because your %1$s directory isn't writable, run %2$s or %3$s or create the folder yourself."
408
  msgstr "Das Backup-Verzeichnis kann nicht erstellt werden, weil dein %1$s-Verzeichnis nicht schreibbar ist. Führe %2$s oder %3$s aus oder erstelle das Verzeichnis selbst."
409
 
410
- #: functions/interface.functions.php:79
411
  #, php-format
412
  msgid "Your backups directory isn't writable, run %1$s or %2$s or set the permissions yourself."
413
  msgstr "Dein Backup-Verzeichnis ist nicht schreibbar. Führe %1$s oder %2$s aus oder setze die Berechtigungen selbst."
414
 
415
- #: functions/interface.functions.php:89
416
  #, php-format
417
  msgid "%1$s is running in %2$s. Please contact your host and ask them to disable %3$s."
418
  msgstr "%1$s läuft im %2$s. Bitte kontaktiere deinen Administrator und bitte ihn, den %3$s zu deaktivieren."
419
 
420
- #: functions/interface.functions.php:89
421
  msgid "http://php.net/manual/en/features.safe-mode.php"
422
  msgstr "http://php.net/manual/de/features.safe-mode.php"
423
 
424
- #: functions/interface.functions.php:89
425
  msgid "Safe Mode"
426
  msgstr "Safe Mode"
427
 
428
- #: functions/interface.functions.php:99
429
- #, php-format
430
- msgid "You have both %1$s and %2$s defined so there isn't anything to back up."
431
- msgstr "Du hast sowohl %1$s, als auch %2$s definiert. Deswegen gibt es nichts zu sichern."
432
-
433
- #: functions/interface.functions.php:110
434
- #, php-format
435
- msgid "The following email address is not valid: %s."
436
- msgid_plural "The following email addresses are not valid: %s."
437
- msgstr[0] "Die folgende E-Mail-Adresse ist ungültig: %s"
438
- msgstr[1] "Die folgenden E-Mail-Adressen sind ungültig: %s"
439
-
440
- #: functions/interface.functions.php:120
441
- msgid "The last backup email failed to send. It's likely that the file is too large."
442
- msgstr "Das letzte Backup-E-Mail konnte nicht gesendet werden. Wahrscheinlich ist die Datei zu groß."
443
-
444
- #: functions/interface.functions.php:130
445
  #, php-format
446
  msgid "Your custom backups directory %1$s doesn't exist and can't be created, your backups will be saved to %2$s instead."
447
  msgstr "Dein angepasstes Backup-Verzeichnis %1$s existiert nicht und kann nicht erstellt werden, neue Backups werden stattdessen nach %2$s gespeichert."
448
 
449
- #: functions/interface.functions.php:140
450
  #, php-format
451
  msgid "Your custom backups directory %1$s isn't writable, new backups will be saved to %2$s instead."
452
  msgstr "Dein angepasstes Backup-Verzeichnis %1$s ist nicht schreibbar, neue Backups werden stattdessen nach %2$s gespeichert."
453
 
454
- #: functions/interface.functions.php:150
455
- #, php-format
456
- msgid "You have defined a custom exclude list but the following paths don't exist %s, are you sure you entered them correctly?"
457
- msgstr "Du hast eine Ausnahmen-Liste definiert, aber die folgenden Pfade existieren nicht: %s. Bist du sicher, dass du sie korrekt eingegeben hast?"
458
-
459
- #: functions/interface.functions.php:160
460
  msgid "BackUpWordPress detected issues with your last backup."
461
  msgstr "BackUpWordPress hat Probleme bei deinem letzten Backup bemerkt."
462
 
463
- #: functions/backup.actions.php:12
464
- msgid "Dumping database"
465
- msgstr "Datenbank wird gedump"
466
 
467
- #: functions/backup.actions.php:22
468
- msgid "Creating zip archive"
469
- msgstr "ZIP-Archiv wird erstellt"
470
 
471
- #: functions/backup.functions.php:19
472
- msgid "Removing old backups"
473
- msgstr "Alte Backups werden gelöscht"
474
 
475
- #: functions/backup.functions.php:147
476
- #: functions/backup.functions.php:157
477
- #, php-format
478
- msgid "Backup of %s"
479
- msgstr "Backup von %s"
480
 
481
- #: functions/backup.functions.php:148
482
- #, php-format
483
- msgid ""
484
- "BackUpWordPress has completed a backup of your site %1$s.\\n"
485
- "\\n"
486
- "The backup file should be attached to this email.\\n"
487
- "\\n"
488
- "You can also download the backup file by clicking the link below:\\n"
489
- "\\n"
490
- "%2$s\\n"
491
- "\\n"
492
- "Kind Regards\\n"
493
- "\\n"
494
- " The Happy BackUpWordPress Backup Emailing Robot"
495
- msgstr ""
496
- "BackUpWordPress hat ein Backup deiner Seite %1$s fertiggestellt.\n"
497
- "\n"
498
- "Die Backup-Datei sollte an diese E-Mail angehängt sein.\n"
499
- "\n"
500
- "Du kannst es auch herunterladen, indem du den folgenden Link anklickst:\n"
501
- "\n"
502
- "%2$s\n"
503
- "\n"
504
- "Liebe Grüße\n"
505
- "\n"
506
- " Der glückliche BackUpWordPress-Backup-E-Mail-Roboter"
507
 
508
- #: functions/backup.functions.php:158
509
- #, php-format
510
- msgid ""
511
- "BackUpWordPress has completed a backup of your site %1$s.\\n"
512
- "\\n"
513
- "Unfortunately the backup file was too large to attach to this email.\\n"
514
- "\\n"
515
- "You can download the backup file by clicking the link below:\\n"
516
- "\\n"
517
- "%2$s\\n"
518
- "\\n"
519
- "Kind Regards\\n"
520
- "\\n"
521
- " The Happy BackUpWordPress Backup Emailing Robot"
522
- msgstr ""
523
- "BackUpWordPress hat ein Backup deiner Seite %1$s fertiggestellt.\n"
524
- "\n"
525
- "Leider war die Backup-Datei zu groß, um sie an dieses E-Mail anzuhängen.\n"
526
- "\n"
527
- "Du kannst es aber herunterladen, indem du den folgenden Link anklickst:\n"
528
- "\n"
529
- "%2$s\n"
530
- "\n"
531
- "Liebe Grüße\n"
532
- "\n"
533
- " Der glückliche BackUpWordPress-Backup-E-Mail-Roboter"
534
 
535
- #: functions/core.functions.php:339
536
- #, php-format
537
- msgid "This %s file ensures that other people cannot download your backup files."
538
- msgstr "Diese %s-Datei garantiert, dass andere Leute nicht deine Backup-Dateien herunterladen können."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
539
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  msgstr ""
3
  "Project-Id-Version: BackUpWordPress\n"
4
  "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: 2012-08-22 15:49+0100\n"
6
+ "PO-Revision-Date: 2012-08-22 15:49+0100\n"
7
  "Last-Translator: Flo Edelmann <florian-edelmann@online.de>\n"
8
  "Language-Team: Flo Edelmann <florian-edelmann@online.de>\n"
9
  "Language: \n"
18
  "X-Poedit-SourceCharset: utf-8\n"
19
  "X-Poedit-SearchPath-0: .\n"
20
 
21
+ #: plugin.php:52
22
+ msgid "BackUpWordPress requires PHP version 5.2.4 or greater."
23
+ msgstr "BackUpWordPress benötigt PHP Version 5.2.4 oder höher."
 
24
 
25
+ #: plugin.php:63
26
  #, php-format
27
+ msgid "BackUpWordPress requires WordPress version %s or greater."
28
+ msgstr "BackUpWordPress benötigt WordPress Version %s oder größer."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
+ #: plugin.php:95
31
+ #: admin/schedule-form.php:52
32
+ msgid "Update"
33
+ msgstr "Update"
34
 
35
+ #: plugin.php:96
36
+ msgid "Cancel"
37
+ msgstr "Abbrechen"
38
 
39
+ #: plugin.php:97
40
+ msgid ""
41
+ "Are you sure you want to delete this schedule? All of it's backups will also be deleted.\n"
42
+ "\n"
43
+ "'Cancel' to go back, 'OK' to delete.\n"
44
+ msgstr ""
45
+ "Bist du sicher, dass du diesen Plan löschen möchtest? Alle enthaltenen Backups werden ebenfalls gelöscht.\n"
46
+ "\n"
47
+ "Drücke auf 'Abbrechen' zum Zurückgehen, 'OK' zum Löschen.\n"
 
 
 
 
 
 
48
 
49
+ #: plugin.php:98
50
+ msgid ""
51
+ "Are you sure you want to delete this backup?\n"
52
+ "\n"
53
+ "'Cancel' to go back, 'OK' to delete.\n"
54
+ msgstr ""
55
+ "Bist du sicher, dass du dieses Backup löschen möchtest?\n"
56
+ "\n"
57
+ "Drücke auf 'Abbrechen' zum Zurückgehen, 'OK' zum Löschen.\n"
58
 
59
+ #: plugin.php:99
60
+ msgid ""
61
+ "Are you sure you want to remove this exclude rule?\n"
62
+ "\n"
63
+ "'Cancel' to go back, 'OK' to delete.\n"
64
+ msgstr ""
65
+ "Bist du sicher, dass du diese Ausnahmeregel entfernen möchtest?\n"
66
+ "\n"
67
+ "Drücke auf 'Abbrechen' zum Zurückgehen, 'OK' zum Löschen.\n"
68
 
69
+ #: plugin.php:100
70
+ msgid ""
71
+ "Reducing the number of backups that are stored on this server will cause some of your existing backups to be deleted, are you sure that's what you want?\n"
72
+ "\n"
73
+ "'Cancel' to go back, 'OK' to delete.\n"
74
+ msgstr ""
75
+ "Wenn du die Anzahl der Backups, die auf diesem Server gespeichert werden, reduzierst, werden einige deiner existierenden Backups gelöscht. Bist du sicher, dass du das willst?\n"
76
+ "\n"
77
+ "Drücke auf 'Abbrechen' zum Zurückgehen, 'OK' zum Löschen.\n"
78
 
79
+ #: classes/schedule.php:460
80
+ msgid "Backup started"
81
+ msgstr "Backup gestartet"
82
 
83
+ #: classes/schedule.php:511
84
+ msgid "Creating zip archive"
85
+ msgstr "ZIP-Archiv wird erstellt"
86
 
87
+ #: classes/schedule.php:517
88
+ msgid "Dumping database"
89
+ msgstr "Datenbank wird gedump"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ #: classes/email.php:19
92
+ msgid "Email notification"
93
+ msgstr "E-Mail-Benachrichtigung"
94
 
95
+ #: classes/email.php:50
96
  #, php-format
97
+ msgid "Send an email notification to %s"
98
+ msgstr "Sende E-Mail-Benachrichtigungen an %s"
 
 
 
 
 
 
 
 
 
 
99
 
100
+ #: classes/email.php:72
101
  #, php-format
102
+ msgid "%s isn't a valid email"
103
+ msgstr "%s ist keine gültige E-Mail-Adresse"
 
 
104
 
105
+ #: classes/email.php:127
106
  #, php-format
107
+ msgid "Backup of %s Failed"
108
+ msgstr "Backup von %s fehlgeschlagen"
 
 
 
 
 
109
 
110
+ #: classes/email.php:137
 
 
 
 
111
  #, php-format
112
+ msgid "Backup of %s"
113
+ msgstr "Backup von %s"
114
 
115
+ #: hm-backup/hm-backup.php:532
116
+ msgid "The backup file was not created"
117
+ msgstr "Die Backup-Datei wurde nicht angelegt"
118
 
119
+ #: hm-backup/hm-backup.php:603
120
+ msgid "The following files are unreadable and couldn't be backed up: "
121
+ msgstr "Die folgenden Dateien sind nicht lesbar und konnten nicht gesichert werden:"
122
 
123
+ #: admin/constants.php:3
124
  #, php-format
125
  msgid "You can %1$s any of the following %2$s in your %3$s to control advanced settings. %4$s. Defined %5$s will be highlighted."
126
  msgstr "Du kannst jede der folgenden %2$s in deinem %3$s %1$sn, um erweiterte Einstellungen vorzunehmen. %4$s. Definierte %5$s werden hervorgehoben."
127
 
128
+ #: admin/constants.php:3
129
+ msgid "Constants"
130
+ msgstr "Konstanten"
131
+
132
+ #: admin/constants.php:3
133
  msgid "The Codex can help"
134
  msgstr "Der Codex kann helfen"
135
 
136
+ #: admin/constants.php:8
137
  #, php-format
138
  msgid "The path to folder you would like to store your backup files in, defaults to %s."
139
  msgstr "Der Pfad zum Verzeichnis, in dem du die Backups speichern möchtest. Standard: %s"
140
 
141
+ #: admin/constants.php:8
142
+ #: admin/constants.php:11
143
+ #: admin/constants.php:14
144
+ #: admin/constants.php:17
145
+ #: admin/constants.php:20
146
+ #: admin/constants.php:23
147
+ #: admin/constants.php:26
148
+ #: admin/constants.php:29
149
+ #: admin/constants.php:32
150
+ #: admin/constants.php:35
151
+ #: admin/constants.php:38
152
+ #: admin/constants.php:41
153
+ msgid "e.g."
154
+ msgstr "z.B."
155
+
156
+ #: admin/constants.php:11
157
  #, php-format
158
  msgid "The path to your %1$s executable. Will be used for the %2$s part of the back up if available."
159
  msgstr "Der Pfad zur ausführbaren %1$s-Datei. Wird für den %2$s-Teil des Backups genutzt, wenn verfügbar."
160
 
161
+ #: admin/constants.php:11
162
+ #: admin/constants.php:14
163
+ #: admin/constants.php:23
164
+ #: admin/constants.php:26
 
 
165
  msgid "database"
166
  msgstr "Datenbank"
167
 
168
+ #: admin/constants.php:14
169
  #, php-format
170
  msgid "The path to your %1$s executable. Will be used to zip up your %2$s and %3$s if available."
171
  msgstr "Der Pfad zur ausführbaren %1$s-Datei. Wird genutzt, um deine %2$s und %3$s als ZIP-Archiv zu komprimieren, wenn verfügbar."
172
 
173
+ #: admin/constants.php:14
174
+ #: admin/constants.php:23
175
+ #: admin/constants.php:26
 
 
176
  msgid "files"
177
  msgstr "Dateien"
178
 
179
+ #: admin/constants.php:17
180
  #, php-format
181
  msgid "Completely disables the automatic back up. You can still back up using the \"Back Up Now\" button. Defaults to %s."
182
  msgstr "Deaktiviert die automatischen Backups vollständig. Du kannst trotzdem Backups erstellen, indem du den \"Jetzt sichern\"-Button verwendest. Standard: %s"
183
 
184
+ #: admin/constants.php:20
185
  #, php-format
186
  msgid "Number of backups to keep, older backups will be deleted automatically when a new backup is completed. Defaults to %s."
187
  msgstr "Anzahl der zu behaltenden Backups. Ältere Backups werden automatisch gelöscht, sobald ein neues Backup fertiggestellt ist. Standard: %s"
188
 
189
+ #: admin/constants.php:23
190
+ #: admin/constants.php:26
191
  #, php-format
192
  msgid "Backup %1$s only, your %2$s won't be backed up. Defaults to %3$s."
193
  msgstr "Nur die %1$s sichern, deine %2$s werden nicht gesichert. Standard: %3$s"
194
 
195
+ #: admin/constants.php:29
196
  #, php-format
197
  msgid "The time that the daily back up should run. Defaults to %s."
198
  msgstr "Die Zeit, zu der das tägliche Backup laufen soll. Standard: %s"
199
 
200
+ #: admin/constants.php:32
201
  #, php-format
202
  msgid "Attempt to email a copy of your backups. Value should be email address to send backups to. Defaults to %s."
203
  msgstr "Versuche, eine Kopie des Backups per E-Mail zu senden. Der Wert sollte eine E-Mail-Adresse sein. Standard: %s"
204
 
205
+ #: admin/constants.php:35
206
  msgid "Comma separated list of files or directories to exclude, the backups directory is automatically excluded."
207
  msgstr "Kommagetrennte Liste von Dateien oder Verzeichnissen, die ausgeschlossen werden sollen (das Backup-Verzeichnis ist automatisch ausgeschlossen)."
208
 
209
+ #: admin/constants.php:38
210
  #, php-format
211
  msgid "The capability to use when calling %1$s. Defaults to %2$s."
212
  msgstr "Die Rolle, die beim Aufrufen von %1$s benutzt wird. Standard: %2$s"
213
 
214
+ #: admin/constants.php:41
215
  #, php-format
216
  msgid "The root directory that is backed up. Defaults to %s."
217
  msgstr "Das Wurzelverzeichnis, das gesichert wird. Standard: %s"
218
 
219
+ #: admin/schedule-form.php:7
220
+ msgid "Schedule Settings"
221
+ msgstr "Plan-Einstellungen"
222
+
223
+ #: admin/schedule-form.php:11
224
+ msgid "Backup"
225
+ msgstr "Backup"
226
 
227
+ #: admin/schedule-form.php:14
228
+ msgid "Both Database &amp; files"
229
+ msgstr "Datenbank &amp; Dateien"
230
+
231
+ #: admin/schedule-form.php:15
232
+ msgid "Files only"
233
+ msgstr "Dateien"
234
+
235
+ #: admin/schedule-form.php:16
236
+ msgid "Database only"
237
+ msgstr "Datenbank"
238
+
239
+ #: admin/schedule-form.php:23
240
+ msgid "Schedule"
241
+ msgstr "Plan"
242
+
243
+ #: admin/schedule-form.php:39
244
+ msgid "Number of backups to store on this server"
245
+ msgstr "Anzahl der Backups, die auf dem Server gespeichert bleiben"
246
+
247
+ #: admin/schedule-form.php:43
248
+ msgid "The number of previous backups to store on the server. past this limit the oldest backups will be deleted automatically."
249
+ msgstr "Die Anzahl der vorherigen Backups, die auf dem Server gespeichert bleiben sollen. Über diesem Limit werden die ältesten Backups automatisch gelöscht."
250
+
251
+ #: admin/schedule.php:16
252
+ msgid "hourly on the hour"
253
+ msgstr ""
254
+
255
+ #: admin/schedule.php:16
256
  #, php-format
257
+ msgid "hourly at %s minutes past the hour"
258
+ msgstr ""
259
 
260
+ #: admin/schedule.php:22
261
+ #, php-format
262
+ msgid "daily at %s"
263
+ msgstr ""
 
 
 
 
 
 
264
 
265
+ #: admin/schedule.php:34
266
  #, php-format
267
+ msgid "every 12 hours at %s &amp; %s"
268
+ msgstr ""
269
 
270
+ #: admin/schedule.php:40
271
+ #, php-format
272
+ msgid "weekly on %s at %s"
273
+ msgstr ""
274
 
275
+ #: admin/schedule.php:46
276
+ #, php-format
277
+ msgid "fortnightly on %s at %s"
278
+ msgstr ""
279
 
280
+ #: admin/schedule.php:53
281
  #, php-format
282
+ msgid "on the %s of each month at %s"
283
+ msgstr ""
284
 
285
+ #: admin/schedule.php:59
286
+ msgid "server"
287
+ msgstr "Server"
288
 
289
+ #: admin/schedule.php:66
290
+ #, php-format
291
+ msgid "store the only the last backup %s"
292
+ msgstr ""
293
 
294
+ #: admin/schedule.php:72
295
+ #, php-format
296
+ msgid "don't store any backups %s"
297
+ msgstr ""
298
 
299
+ #: admin/schedule.php:78
300
+ #, php-format
301
+ msgid "store only the last %s backups %s"
302
+ msgstr ""
303
 
304
+ #: admin/schedule.php:87
305
+ #, php-format
306
+ msgid "Backup my %s %s %s, %s. %s"
307
+ msgstr ""
308
+
309
+ #: admin/schedule.php:87
310
+ msgid "Backups will be compressed and should be smaller than this."
311
+ msgstr "Die Backups werden komprimiert und sollten kleiner sein."
312
 
313
+ #: admin/schedule-form-excludes.php:7
314
+ msgid "Manage Exclude"
315
+ msgstr "Ausnahmen verwalten"
316
+
317
+ #: admin/schedule-form-excludes.php:13
318
+ msgid "New Exclude Rule"
319
+ msgstr "Neue Ausnahmeregel"
320
+
321
+ #: admin/schedule-form-excludes.php:17
322
+ msgid "Preview"
323
+ msgstr "Vorschau"
324
+
325
+ #: admin/schedule-form-excludes.php:27
326
+ msgid "Exclude Rules"
327
+ msgstr "Ausnahmeregeln"
328
+
329
+ #: admin/schedule-form-excludes.php:42
330
+ msgid "Remove"
331
+ msgstr "Entfernen"
332
+
333
+ #: admin/schedule-form-excludes.php:59
334
+ msgid "Excluded"
335
+ msgstr "Ausnehmen"
336
+
337
+ #: admin/schedule-form-excludes.php:60
338
+ msgid "Included"
339
+ msgstr "Einschließen"
340
+
341
+ #: admin/schedule-form-excludes.php:63
342
+ msgid "Unreadable"
343
+ msgstr "Nicht lesbar"
344
+
345
+ #: admin/schedule-form-excludes.php:86
346
+ msgid "Unreadable files can't be backed up"
347
+ msgstr "Nicht lesbare Dateien können nicht gesichert werden"
348
+
349
+ #: admin/schedule-form-excludes.php:92
350
  #, php-format
351
+ msgid "Your site is %s. Backups will be compressed and so will be smaller."
352
+ msgstr "Deine Seite ist %s groß. Die Backups werden komprimiert und sollten kleiner sein."
353
+
354
+ #: admin/schedule-form-excludes.php:98
355
+ msgid "Close"
356
+ msgstr "Schließen"
357
+
358
+ #: admin/actions.php:163
359
+ msgid "BackUpWordPress has detected a problem."
360
+ msgstr "BackUpWordPress hat ein Problem entdeckt."
361
 
362
+ #: admin/actions.php:163
363
  #, php-format
364
+ msgid "%1$s is returning a %2$s response which could mean cron jobs aren't getting fired properly. BackUpWordPress relies on wp-cron to run scheduled back ups. See the %3$s for more details."
365
+ msgstr "%1$s gibt eine %2$s-Antwort zurück. Das könnte bedeuten, dass deine Cron-Jobs nicht richtig aufgerufen werden. BackUpWordPress benutzt wp-cron, um geplante Backups auszuführen. Sieh dir das %3$s an für mehr Details."
366
 
367
+ #: admin/actions.php:232
368
+ msgid "Backup type cannot be empty"
369
+ msgstr "Backup-Typ kann nicht leer sein"
370
 
371
+ #: admin/actions.php:235
372
+ msgid "Invalid backup type"
373
+ msgstr "Ungültiger Backup-Typ"
374
 
375
+ #: admin/actions.php:245
376
+ msgid "Schedule cannot be empty"
377
+ msgstr "Aufgaben können nicht leer sein"
378
+
379
+ #: admin/actions.php:248
380
+ msgid "Invalid schedule"
381
+ msgstr "Ungültige Aufgaben"
382
+
383
+ #: admin/actions.php:258
384
+ msgid "Max backups must be more than 1"
385
+ msgstr "Maximale Anzahl der Backups muss größer als 1 sein"
386
+
387
+ #: admin/actions.php:261
388
+ msgid "Max backups must be a number"
389
+ msgstr "Maximale Anzahl der Backups muss eine Nummer sein"
390
+
391
+ #: admin/actions.php:334
392
  #, php-format
393
+ msgid "%s matches 1 file."
394
+ msgid_plural "%s matches %d files"
395
+ msgstr[0] "%s passt auf eine Datei."
396
+ msgstr[1] "%s passt auf %d Dateien."
397
 
398
+ #: admin/actions.php:338
399
  #, php-format
400
+ msgid "%s didn't match any files."
401
+ msgstr "%s passt auf keine Dateien."
402
+
403
+ #: admin/page.php:5
404
+ msgid "Manage Backups"
405
+ msgstr "Backups verwalten"
406
+
407
+ #: admin/page.php:13
408
+ msgid "You need to fix the issues detailed above before BackUpWordPress can start."
409
+ msgstr "Du musst die Probleme, die oben beschrieben werden, beheben, bevor BackUpWordPress starten kann."
410
 
411
+ #: admin/page.php:17
412
  #, php-format
413
+ msgid "If you need help getting things working you are more than welcome to email us at %s and we'll do what we can."
414
+ msgstr "Wenn du Hilfe brauchst, sende uns ruhig eine E-Mail an %s (am besten auf Englisch) und wir werden tun, was wir können."
415
 
416
+ #: admin/backups.php:13
417
+ msgid "add schedule"
418
+ msgstr "Aufgabe hinzufügen"
419
 
420
+ #: admin/backups.php:36
421
  #, php-format
422
+ msgid "1 backup completed"
423
+ msgid_plural "%d backups completed"
424
+ msgstr[0] "1 Backup fertiggestellt"
425
+ msgstr[1] "%d Backups fertiggestellt"
426
 
427
+ #: admin/backups.php:37
428
+ msgid "Size"
429
+ msgstr "Größe"
430
+
431
+ #: admin/backups.php:38
432
+ msgid "Type"
433
+ msgstr "Typ"
434
+
435
+ #: admin/backups.php:39
436
+ msgid "Actions"
437
+ msgstr "Aktionen"
438
+
439
+ #: admin/backups.php:62
440
+ msgid "This is where your backups will appear once you have one."
441
+ msgstr "Hier erscheinen deine Backups, sobald du welche hast."
442
+
443
+ #: admin/menu.php:10
444
+ #: admin/menu.php:34
445
+ msgid "Backups"
446
+ msgstr "Backups"
447
+
448
+ #: admin/menu.php:69
449
+ msgid "You are not using the latest stable version of BackUpWordPress"
450
+ msgstr "Du benutzt nicht die neueste stabile BackUpWordPress-Version"
451
+
452
+ #: admin/menu.php:69
453
  #, php-format
454
+ msgid "The information below is for version %1$s. View the %2$s file for help specific to version %3$s."
455
+ msgstr "Diese Informationen sind für Version %1$s. Sieh dir die %2$s-Datei für Hilfe speziell für Version %3$s an."
456
 
457
+ #: admin/menu.php:75
458
+ msgid "FAQ"
459
+ msgstr "FAQ"
460
 
461
+ #: admin/menu.php:79
462
+ msgid "For more information:"
463
+ msgstr "Für mehr Informationen:"
464
+
465
+ #: admin/menu.php:81
466
+ msgid "Support Forums"
467
+ msgstr "Support-Foren"
468
+
469
+ #: admin/menu.php:82
470
+ msgid "Help with translation"
471
+ msgstr "Beim Übersetzen helfen"
472
+
473
+ #: functions/core.php:192
474
+ msgid "BackUpWordPress has setup your default schedules."
475
+ msgstr "BackUpWordPress hat deine Standard-Pläne eingerichtet."
476
+
477
+ #: functions/core.php:192
478
+ msgid "By default BackUpWordPress performs a daily backup of your database and a weekly backup of your database &amp; files. You can modify these schedules below."
479
+ msgstr "Standardmäßig macht BackUpWordPress täglich ein Backup deiner Datenbank und wöchentlich eines deiner Datenbank und deiner Dateien. Du kannst diese Pläne hier bearbeiten."
480
 
481
+ #: functions/core.php:273
482
+ #, php-format
483
+ msgid "This %s file ensures that other people cannot download your backup files."
484
+ msgstr "Diese %s-Datei garantiert, dass andere Leute nicht deine Backup-Dateien herunterladen können."
485
+
486
+ #: functions/interface.php:27
487
  msgid "Download"
488
  msgstr "Download"
489
 
490
+ #: functions/interface.php:28
491
+ #: functions/interface.php:215
492
  msgid "Delete"
493
  msgstr "Löschen"
494
 
495
+ #: functions/interface.php:50
496
+ #: functions/interface.php:62
 
 
 
 
497
  msgid "BackUpWordPress is almost ready."
498
  msgstr "BackUpWordPress ist fast fertig."
499
 
500
+ #: functions/interface.php:50
501
  #, php-format
502
  msgid "The backups directory can't be created because your %1$s directory isn't writable, run %2$s or %3$s or create the folder yourself."
503
  msgstr "Das Backup-Verzeichnis kann nicht erstellt werden, weil dein %1$s-Verzeichnis nicht schreibbar ist. Führe %2$s oder %3$s aus oder erstelle das Verzeichnis selbst."
504
 
505
+ #: functions/interface.php:62
506
  #, php-format
507
  msgid "Your backups directory isn't writable, run %1$s or %2$s or set the permissions yourself."
508
  msgstr "Dein Backup-Verzeichnis ist nicht schreibbar. Führe %1$s oder %2$s aus oder setze die Berechtigungen selbst."
509
 
510
+ #: functions/interface.php:72
511
  #, php-format
512
  msgid "%1$s is running in %2$s. Please contact your host and ask them to disable %3$s."
513
  msgstr "%1$s läuft im %2$s. Bitte kontaktiere deinen Administrator und bitte ihn, den %3$s zu deaktivieren."
514
 
515
+ #: functions/interface.php:72
516
  msgid "http://php.net/manual/en/features.safe-mode.php"
517
  msgstr "http://php.net/manual/de/features.safe-mode.php"
518
 
519
+ #: functions/interface.php:72
520
  msgid "Safe Mode"
521
  msgstr "Safe Mode"
522
 
523
+ #: functions/interface.php:82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
524
  #, php-format
525
  msgid "Your custom backups directory %1$s doesn't exist and can't be created, your backups will be saved to %2$s instead."
526
  msgstr "Dein angepasstes Backup-Verzeichnis %1$s existiert nicht und kann nicht erstellt werden, neue Backups werden stattdessen nach %2$s gespeichert."
527
 
528
+ #: functions/interface.php:92
529
  #, php-format
530
  msgid "Your custom backups directory %1$s isn't writable, new backups will be saved to %2$s instead."
531
  msgstr "Dein angepasstes Backup-Verzeichnis %1$s ist nicht schreibbar, neue Backups werden stattdessen nach %2$s gespeichert."
532
 
533
+ #: functions/interface.php:102
 
 
 
 
 
534
  msgid "BackUpWordPress detected issues with your last backup."
535
  msgstr "BackUpWordPress hat Probleme bei deinem letzten Backup bemerkt."
536
 
537
+ #: functions/interface.php:182
538
+ msgid "Database and Files"
539
+ msgstr "Datenbank und Dateien"
540
 
541
+ #: functions/interface.php:185
542
+ msgid "Files"
543
+ msgstr "Dateien"
544
 
545
+ #: functions/interface.php:188
546
+ msgid "Database"
547
+ msgstr "Datenbank"
548
 
549
+ #: functions/interface.php:193
550
+ msgid "Unknown"
551
+ msgstr "Unbekannt"
 
 
552
 
553
+ #: functions/interface.php:201
554
+ msgid "cancel"
555
+ msgstr "abbrechen"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
556
 
557
+ #: functions/interface.php:207
558
+ msgid "Settings"
559
+ msgstr "Einstellungen"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
560
 
561
+ #: functions/interface.php:210
562
+ msgid "Excludes"
563
+ msgstr "Ausnahmen"
564
+
565
+ #: functions/interface.php:213
566
+ msgid "Run now"
567
+ msgstr "Jetzt ausführen"
568
+
569
+ #~ msgid ""
570
+ #~ "You can define %1$s in your %2$s to control some settings. A full list of "
571
+ #~ "%3$s can be found in the %4$s. Defined settings will not be editable "
572
+ #~ "below."
573
+ #~ msgstr ""
574
+ #~ "Du kannst %1$s in deinem %2$s definieren, um einige Einstellungen "
575
+ #~ "vorzunehmen. Eine komplette Liste der %3$s kannst du im %4$s finden. "
576
+ #~ "Definierte Einstellungen sind unten nicht veränderbar."
577
+
578
+ #~ msgid "help panel"
579
+ #~ msgstr "Hilfe-Panel"
580
+
581
+ #~ msgid "Automatic Backups"
582
+ #~ msgstr "Automatische Backups"
583
+
584
+ #~ msgid "Backup my site automatically."
585
+ #~ msgstr "Sichere meine Seite automatisch."
586
+
587
+ #~ msgid "No automatic backups."
588
+ #~ msgstr "Keine automatischen Backups."
589
+
590
+ #~ msgid "Frequency of backups"
591
+ #~ msgstr "Häufigkeit der Backups"
592
+
593
+ #~ msgid "Automatic backups will occur"
594
+ #~ msgstr "Automatische Backups werden ausgeführt:"
595
+
596
+ #~ msgid "Daily"
597
+ #~ msgstr "Täglich"
598
+
599
+ #~ msgid "Weekly"
600
+ #~ msgstr "Wöchentlich"
601
+
602
+ #~ msgid "Fortnightly"
603
+ #~ msgstr "Vierzehntägig"
604
+
605
+ #~ msgid "Monthly"
606
+ #~ msgstr "Monatlich"
607
+
608
+ #~ msgid "What to Backup"
609
+ #~ msgstr "Zu sichernde Daten"
610
+
611
+ #~ msgid "Backup my"
612
+ #~ msgstr "Sichere meine"
613
+
614
+ #~ msgid "Number of backups"
615
+ #~ msgstr "Anzahl der Backups"
616
+
617
+ #~ msgid "Email backups"
618
+ #~ msgstr "Backup-E-Mail"
619
+
620
+ #~ msgid ""
621
+ #~ "A copy of the backup file will be emailed to this address. Disabled if "
622
+ #~ "left blank."
623
+ #~ msgstr ""
624
+ #~ "Eine Kopie der Backup-Datei wird per E-Mail an diese Adresse gesendet. "
625
+ #~ "Leerlassen zum deaktivieren."
626
 
627
+ #~ msgid ""
628
+ #~ "A comma separated list of file and directory paths that you do "
629
+ #~ "<strong>not</strong> want to backup."
630
+ #~ msgstr ""
631
+ #~ "Eine kommagetrennte Liste von Datei- und Verzeichnispfaden, die du "
632
+ #~ "<strong>nicht</strong> sichern möchtest."
633
+
634
+ #~ msgid "Save Changes"
635
+ #~ msgstr "Änderungen speichern"
636
+
637
+ #~ msgid "Only the most recent backup will be saved"
638
+
639
+ #~ msgid_plural "The %d most recent backups will be saved"
640
+ #~ msgstr[0] "Nur das neueste Backup wird gespeichert"
641
+ #~ msgstr[1] "Die %d neuesten Backups werden gespeichert"
642
+
643
+ #~ msgid "Total %s"
644
+ #~ msgstr "Insgesamt %s"
645
+
646
+ #~ msgid "Back Up Now"
647
+ #~ msgstr "Jetzt sichern"
648
+
649
+ #~ msgid "You have entered an invalid number of backups."
650
+ #~ msgstr "Du hast eine ungültige Anzahl von Backups eingegeben."
651
+
652
+ #~ msgid "Automatic backups are %s."
653
+ #~ msgstr "Automatische Backups sind %s."
654
+
655
+ #~ msgid "disabled"
656
+ #~ msgstr "deaktiviert"
657
+
658
+ #~ msgid "&amp;"
659
+ #~ msgstr "&amp;"
660
+
661
+ #~ msgid ""
662
+ #~ "Your %1$s will be automatically backed up %2$s. The next backup will "
663
+ #~ "occur at %3$s on %4$s and be saved to %5$s."
664
+
665
+ #~ msgid_plural ""
666
+ #~ "Your %1$s will be automatically backed up %2$s. The next backup will "
667
+ #~ "occur at %3$s on %4$s and be saved to %5$s."
668
+ #~ msgstr[0] ""
669
+ #~ "Deine %1$s wird automatisch %2$s gesichert. Das nächste Backup findet am "
670
+ #~ "%4$s um %3$s statt und wird nach %5$s gespeichert."
671
+ #~ msgstr[1] ""
672
+ #~ "Deine %1$s werden automatisch %2$s gesichert. Das nächste Backup findet "
673
+ #~ "am %3$s um %4$s statt und wird nach %5$s gespeichert."
674
+
675
+ #~ msgid "It's currently %s"
676
+ #~ msgstr "Es ist jetzt %s"
677
+
678
+ #~ msgid "Calculating Size..."
679
+ #~ msgstr "Größe berechnen..."
680
+
681
+ #~ msgid "A copy of each backup will be emailed to %s."
682
+ #~ msgstr "Eine Kopie jedes Backups wird an %s gesendet."
683
+
684
+ #~ msgid "The following paths will be excluded from your backups %s."
685
+ #~ msgstr ""
686
+ #~ "Die folgenden Pfade werden von deinen Backups ausgeschlossen sein: %s"
687
+
688
+ #~ msgid "Settings saved."
689
+ #~ msgstr "Einstellungen gespeichert."
690
+
691
+ #~ msgid ""
692
+ #~ "You have both %1$s and %2$s defined so there isn't anything to back up."
693
+ #~ msgstr ""
694
+ #~ "Du hast sowohl %1$s, als auch %2$s definiert. Deswegen gibt es nichts zu "
695
+ #~ "sichern."
696
+
697
+ #~ msgid "The following email address is not valid: %s."
698
+
699
+ #~ msgid_plural "The following email addresses are not valid: %s."
700
+ #~ msgstr[0] "Die folgende E-Mail-Adresse ist ungültig: %s"
701
+ #~ msgstr[1] "Die folgenden E-Mail-Adressen sind ungültig: %s"
702
+
703
+ #~ msgid ""
704
+ #~ "The last backup email failed to send. It's likely that the file is too "
705
+ #~ "large."
706
+ #~ msgstr ""
707
+ #~ "Das letzte Backup-E-Mail konnte nicht gesendet werden. Wahrscheinlich ist "
708
+ #~ "die Datei zu groß."
709
+
710
+ #~ msgid ""
711
+ #~ "You have defined a custom exclude list but the following paths don't "
712
+ #~ "exist %s, are you sure you entered them correctly?"
713
+ #~ msgstr ""
714
+ #~ "Du hast eine Ausnahmen-Liste definiert, aber die folgenden Pfade "
715
+ #~ "existieren nicht: %s. Bist du sicher, dass du sie korrekt eingegeben hast?"
716
+
717
+ #~ msgid "Removing old backups"
718
+ #~ msgstr "Alte Backups werden gelöscht"
719
+
720
+ #~ msgid ""
721
+ #~ "BackUpWordPress has completed a backup of your site %1$s.\\n\\nThe backup "
722
+ #~ "file should be attached to this email.\\n\\nYou can also download the "
723
+ #~ "backup file by clicking the link below:\\n\\n%2$s\\n\\nKind Regards\\n\\n "
724
+ #~ "The Happy BackUpWordPress Backup Emailing Robot"
725
+ #~ msgstr ""
726
+ #~ "BackUpWordPress hat ein Backup deiner Seite %1$s fertiggestellt.\n"
727
+ #~ "\n"
728
+ #~ "Die Backup-Datei sollte an diese E-Mail angehängt sein.\n"
729
+ #~ "\n"
730
+ #~ "Du kannst es auch herunterladen, indem du den folgenden Link anklickst:\n"
731
+ #~ "\n"
732
+ #~ "%2$s\n"
733
+ #~ "\n"
734
+ #~ "Liebe Grüße\n"
735
+ #~ "\n"
736
+ #~ " Der glückliche BackUpWordPress-Backup-E-Mail-Roboter"
737
+
738
+ #~ msgid ""
739
+ #~ "BackUpWordPress has completed a backup of your site %1$s.\\n"
740
+ #~ "\\nUnfortunately the backup file was too large to attach to this email.\\n"
741
+ #~ "\\nYou can download the backup file by clicking the link below:\\n\\n%2$s"
742
+ #~ "\\n\\nKind Regards\\n\\n The Happy BackUpWordPress Backup Emailing Robot"
743
+ #~ msgstr ""
744
+ #~ "BackUpWordPress hat ein Backup deiner Seite %1$s fertiggestellt.\n"
745
+ #~ "\n"
746
+ #~ "Leider war die Backup-Datei zu groß, um sie an dieses E-Mail anzuhängen.\n"
747
+ #~ "\n"
748
+ #~ "Du kannst es aber herunterladen, indem du den folgenden Link anklickst:\n"
749
+ #~ "\n"
750
+ #~ "%2$s\n"
751
+ #~ "\n"
752
+ #~ "Liebe Grüße\n"
753
+ #~ "\n"
754
+ #~ " Der glückliche BackUpWordPress-Backup-E-Mail-Roboter"
plugin.php CHANGED
@@ -5,11 +5,11 @@ Plugin Name: BackUpWordPress
5
  Plugin URI: http://hmn.md/backupwordpress/
6
  Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools &rarr; Backups</strong>.
7
  Author: Human Made Limited
8
- Version: 1.6.9
9
  Author URI: http://hmn.md/
10
  */
11
 
12
- /* Copyright 2011 Human Made Limited (email : hello@humanmade.co.uk)
13
 
14
  This program is free software; you can redistribute it and/or modify
15
  it under the terms of the GNU General Public License as published by
@@ -27,13 +27,18 @@ Author URI: http://hmn.md/
27
  */
28
 
29
  define( 'HMBKP_PLUGIN_SLUG', 'backupwordpress' );
30
- define( 'HMBKP_PLUGIN_PATH', WP_PLUGIN_DIR . '/' . HMBKP_PLUGIN_SLUG );
31
- define( 'HMBKP_PLUGIN_URL', WP_PLUGIN_URL . '/' . HMBKP_PLUGIN_SLUG );
32
- define( 'HMBKP_REQUIRED_WP_VERSION', '3.1' );
 
 
 
 
33
 
34
  if ( ! defined( 'HMBKP_SECURE_KEY' ) )
35
  define( 'HMBKP_SECURE_KEY', md5( ABSPATH . time() ) );
36
 
 
37
  if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) )
38
  define( 'WP_MAX_MEMORY_LIMIT', '256M' );
39
 
@@ -41,7 +46,7 @@ if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) )
41
  if ( version_compare( phpversion(), '5.2.4', '<' ) ) {
42
 
43
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
44
- deactivate_plugins( HMBKP_PLUGIN_PATH . '/plugin.php' );
45
 
46
  if ( isset( $_GET['action'] ) && ( $_GET['action'] == 'activate' || $_GET['action'] == 'error_scrape' ) )
47
  die( __( 'BackUpWordPress requires PHP version 5.2.4 or greater.', 'hmbkp' ) );
@@ -49,13 +54,13 @@ if ( version_compare( phpversion(), '5.2.4', '<' ) ) {
49
  }
50
 
51
  // Don't activate on old versions of WordPress
52
- if ( version_compare( get_bloginfo('version'), HMBKP_REQUIRED_WP_VERSION, '<' ) ) {
53
 
54
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
55
- deactivate_plugins( HMBKP_PLUGIN_PATH . '/plugin.php' );
56
 
57
  if ( isset( $_GET['action'] ) && ( $_GET['action'] == 'activate' || $_GET['action'] == 'error_scrape' ) )
58
- die( sprintf( __( 'BackUpWordPress requires WordPress version %s.', 'hmbkp' ), HMBKP_REQUIRED_WP_VERSION ) );
59
 
60
  }
61
 
@@ -64,82 +69,79 @@ if ( version_compare( get_bloginfo('version'), HMBKP_REQUIRED_WP_VERSION, '<' )
64
  *
65
  * @return null
66
  */
67
- function hmbkp_actions() {
68
 
69
  $plugin_data = get_plugin_data( __FILE__ );
70
 
 
71
  define( 'HMBKP_VERSION', $plugin_data['Version'] );
72
 
 
73
  load_plugin_textdomain( 'hmbkp', false, HMBKP_PLUGIN_SLUG . '/languages/' );
74
 
75
  // Fire the update action
76
- if ( HMBKP_VERSION > get_option( 'hmbkp_plugin_version' ) )
77
  hmbkp_update();
78
 
79
  // Load admin css and js
80
  if ( isset( $_GET['page'] ) && $_GET['page'] == HMBKP_PLUGIN_SLUG ) {
81
- wp_enqueue_script( 'hmbkp', HMBKP_PLUGIN_URL . '/assets/hmbkp.js' );
82
- wp_enqueue_style( 'hmbkp', HMBKP_PLUGIN_URL . '/assets/hmbkp.css' );
83
- }
84
-
85
- // Handle any advanced option changes
86
- hmbkp_constant_changes();
87
-
88
- }
89
- add_action( 'admin_init', 'hmbkp_actions' );
90
-
91
- /**
92
- * Setup the HM_Backup class
93
- *
94
- * @return null
95
- */
96
- function hmbkp_setup_hm_backup() {
97
 
98
- $hm_backup = HM_Backup::get_instance();
 
99
 
100
- $hm_backup->path = hmbkp_path();
101
- $hm_backup->files_only = hmbkp_get_files_only();
102
- $hm_backup->database_only = hmbkp_get_database_only();
 
 
 
 
 
103
 
104
- if ( defined( 'HMBKP_MYSQLDUMP_PATH' ) )
105
- $hm_backup->mysqldump_command_path = HMBKP_MYSQLDUMP_PATH;
106
 
107
- if ( defined( 'HMBKP_ZIP_PATH' ) )
108
- $hm_backup->zip_command_path = HMBKP_ZIP_PATH;
109
 
110
- if ( defined( 'HMBKP_ROOT' ) )
111
- $hm_backup->root = HMBKP_ROOT;
112
 
113
- $hm_backup->excludes = hmbkp_valid_custom_excludes();
 
 
114
 
115
  }
116
- add_action( 'init', 'hmbkp_setup_hm_backup' );
117
 
118
  // Load the admin menu
119
- require_once( HMBKP_PLUGIN_PATH . '/admin.menus.php' );
120
- require_once( HMBKP_PLUGIN_PATH . '/admin.actions.php' );
121
 
122
  // Load hm-backup
123
  if ( ! class_exists( 'HM_Backup' ) )
124
  require_once( HMBKP_PLUGIN_PATH . '/hm-backup/hm-backup.php' );
125
 
 
 
 
 
126
  // Load the core functions
127
- require_once( HMBKP_PLUGIN_PATH . '/functions/backup.actions.php' );
128
- require_once( HMBKP_PLUGIN_PATH . '/functions/core.functions.php' );
129
- require_once( HMBKP_PLUGIN_PATH . '/functions/interface.functions.php' );
130
- require_once( HMBKP_PLUGIN_PATH . '/functions/backup.functions.php' );
 
 
 
 
131
 
132
  // Load the wp cli command
133
  if ( defined( 'WP_CLI' ) && WP_CLI )
134
- include( HMBKP_PLUGIN_PATH . '/functions/wp-cli.php' );
135
 
 
136
  if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
137
  define( 'PCLZIP_TEMPORARY_DIR', trailingslashit( hmbkp_path() ) );
138
 
139
- // Plugin activation and deactivation
140
  add_action( 'activate_' . HMBKP_PLUGIN_SLUG . '/plugin.php', 'hmbkp_activate' );
141
  add_action( 'deactivate_' . HMBKP_PLUGIN_SLUG . '/plugin.php', 'hmbkp_deactivate' );
142
-
143
- // Cron hook for backups
144
- add_action( 'hmbkp_schedule_backup_hook', 'hmbkp_do_backup' );
145
- add_action( 'hmbkp_schedule_single_backup_hook', 'hmbkp_do_backup' );
5
  Plugin URI: http://hmn.md/backupwordpress/
6
  Description: Simple automated backups of your WordPress powered website. Once activated you'll find me under <strong>Tools &rarr; Backups</strong>.
7
  Author: Human Made Limited
8
+ Version: 2.0.1
9
  Author URI: http://hmn.md/
10
  */
11
 
12
+ /* Copyright 2011 Human Made Limited (email : support@hmn.md)
13
 
14
  This program is free software; you can redistribute it and/or modify
15
  it under the terms of the GNU General Public License as published by
27
  */
28
 
29
  define( 'HMBKP_PLUGIN_SLUG', 'backupwordpress' );
30
+ define( 'HMBKP_PLUGIN_PATH', plugin_dir_path( __FILE__ ) );
31
+ define( 'HMBKP_PLUGIN_URL', plugins_url( HMBKP_PLUGIN_SLUG ) );
32
+
33
+ if ( ! defined( 'HMBKP_REQUIRED_WP_VERSION' ) )
34
+ define( 'HMBKP_REQUIRED_WP_VERSION', '3.3.2' );
35
+
36
+ define( 'HMBKP_ADMIN_URL', add_query_arg( 'page', HMBKP_PLUGIN_SLUG, admin_url( 'tools.php' ) ) );
37
 
38
  if ( ! defined( 'HMBKP_SECURE_KEY' ) )
39
  define( 'HMBKP_SECURE_KEY', md5( ABSPATH . time() ) );
40
 
41
+ // Max memory limit isn't defined in old versions of WordPress
42
  if ( ! defined( 'WP_MAX_MEMORY_LIMIT' ) )
43
  define( 'WP_MAX_MEMORY_LIMIT', '256M' );
44
 
46
  if ( version_compare( phpversion(), '5.2.4', '<' ) ) {
47
 
48
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
49
+ deactivate_plugins( __FILE__ );
50
 
51
  if ( isset( $_GET['action'] ) && ( $_GET['action'] == 'activate' || $_GET['action'] == 'error_scrape' ) )
52
  die( __( 'BackUpWordPress requires PHP version 5.2.4 or greater.', 'hmbkp' ) );
54
  }
55
 
56
  // Don't activate on old versions of WordPress
57
+ if ( version_compare( get_bloginfo( 'version' ), HMBKP_REQUIRED_WP_VERSION, '<' ) ) {
58
 
59
  require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
60
+ deactivate_plugins( __FILE__ );
61
 
62
  if ( isset( $_GET['action'] ) && ( $_GET['action'] == 'activate' || $_GET['action'] == 'error_scrape' ) )
63
+ die( sprintf( __( 'BackUpWordPress requires WordPress version %s or greater.', 'hmbkp' ), HMBKP_REQUIRED_WP_VERSION ) );
64
 
65
  }
66
 
69
  *
70
  * @return null
71
  */
72
+ function hmbkp_init() {
73
 
74
  $plugin_data = get_plugin_data( __FILE__ );
75
 
76
+ // define the plugin version
77
  define( 'HMBKP_VERSION', $plugin_data['Version'] );
78
 
79
+ // Load translations
80
  load_plugin_textdomain( 'hmbkp', false, HMBKP_PLUGIN_SLUG . '/languages/' );
81
 
82
  // Fire the update action
83
+ if ( HMBKP_VERSION != get_option( 'hmbkp_plugin_version' ) )
84
  hmbkp_update();
85
 
86
  // Load admin css and js
87
  if ( isset( $_GET['page'] ) && $_GET['page'] == HMBKP_PLUGIN_SLUG ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
+ wp_enqueue_script( 'hmbkp_fancybox', HMBKP_PLUGIN_URL . '/assets/fancyBox/source/jquery.fancybox.js', array( 'jquery' ), HMBKP_VERSION );
90
+ wp_enqueue_script( 'hmbkp', HMBKP_PLUGIN_URL . '/assets/hmbkp.js', array( 'jquery-ui-tabs', 'jquery-ui-widget', 'hmbkp_fancybox' ), HMBKP_VERSION );
91
 
92
+ wp_localize_script( 'hmbkp', 'objectL10n', array(
93
+ 'update' => __( 'Update', 'hmbkp' ),
94
+ 'cancel' => __( 'Cancel', 'hmbkp' ),
95
+ 'delete_schedule' => __( 'Are you sure you want to delete this schedule? All of it\'s backups will also be deleted.' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'hmbkp' ) . "\n",
96
+ 'delete_backup' => __( 'Are you sure you want to delete this backup?', 'hmbkp' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'hmbkp' ) . "\n",
97
+ 'remove_exclude_rule' => __( 'Are you sure you want to remove this exclude rule?', 'hmbkp' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'hmbkp' ) . "\n",
98
+ 'remove_old_backups' => __( 'Reducing the number of backups that are stored on this server will cause some of your existing backups to be deleted, are you sure that\'s what you want?', 'hmbkp' ) . "\n\n" . __( '\'Cancel\' to go back, \'OK\' to delete.', 'hmbkp' ) . "\n"
99
+ ) );
100
 
101
+ wp_enqueue_style( 'hmbkp_fancybox', HMBKP_PLUGIN_URL . '/assets/fancyBox/source/jquery.fancybox.css', false, HMBKP_VERSION );
102
+ wp_enqueue_style( 'hmbkp', HMBKP_PLUGIN_URL . '/assets/hmbkp.css', false, HMBKP_VERSION );
103
 
104
+ }
 
105
 
106
+ hmbkp_setup_default_schedules();
 
107
 
108
+ // Handle any advanced option changes
109
+ // TODO
110
+ hmbkp_constant_changes();
111
 
112
  }
113
+ add_action( 'admin_init', 'hmbkp_init' );
114
 
115
  // Load the admin menu
116
+ require_once( HMBKP_PLUGIN_PATH . '/admin/menu.php' );
117
+ require_once( HMBKP_PLUGIN_PATH . '/admin/actions.php' );
118
 
119
  // Load hm-backup
120
  if ( ! class_exists( 'HM_Backup' ) )
121
  require_once( HMBKP_PLUGIN_PATH . '/hm-backup/hm-backup.php' );
122
 
123
+ // Load the schedules
124
+ require_once( HMBKP_PLUGIN_PATH . '/classes/schedule.php' );
125
+ require_once( HMBKP_PLUGIN_PATH . '/classes/schedules.php' );
126
+
127
  // Load the core functions
128
+ require_once( HMBKP_PLUGIN_PATH . '/functions/core.php' );
129
+ require_once( HMBKP_PLUGIN_PATH . '/functions/interface.php' );
130
+
131
+ // Load Services
132
+ require_once( HMBKP_PLUGIN_PATH . '/classes/services.php' );
133
+
134
+ // Load the email service
135
+ require_once( HMBKP_PLUGIN_PATH . '/classes/email.php' );
136
 
137
  // Load the wp cli command
138
  if ( defined( 'WP_CLI' ) && WP_CLI )
139
+ include( HMBKP_PLUGIN_PATH . '/classes/wp-cli.php' );
140
 
141
+ // Set the tmp directory to the backup path
142
  if ( ! defined( 'PCLZIP_TEMPORARY_DIR' ) )
143
  define( 'PCLZIP_TEMPORARY_DIR', trailingslashit( hmbkp_path() ) );
144
 
145
+ // Hook in the activation and deactivation actions
146
  add_action( 'activate_' . HMBKP_PLUGIN_SLUG . '/plugin.php', 'hmbkp_activate' );
147
  add_action( 'deactivate_' . HMBKP_PLUGIN_SLUG . '/plugin.php', 'hmbkp_deactivate' );
 
 
 
 
readme.txt CHANGED
@@ -1,33 +1,35 @@
1
  === BackUpWordPress ===
2
- Contributors: humanmade, joehoyle, mattheu, tcrsavage, willmot
3
  Tags: back up, backup, backups, database, zip, db, files, archive, wp-cli, humanmade
4
- Requires at least: 3.1.4
5
- Tested up to: 3.4.1
6
- Stable tag: 1.6.9
7
 
8
  Simple automated back ups of your WordPress powered website.
9
 
10
  == Description ==
11
 
12
- BackUpWordPress will back up your entire site including your database and all your files once every day.
13
 
14
  = Features =
15
 
 
16
  * Super simple to use, no setup required.
17
  * Uses `zip` and `mysqldump` for faster back ups if they are available.
18
  * Works in low memory, "shared host" environments.
19
  * Option to have each backup file emailed to you.
20
  * Works on Linux & Windows Server.
21
  * Exclude files and folders from your back ups.
22
- * Control advanced settings by defining any of the optional `Constants`.
23
  * Good support should you need help.
24
- * (Partial) Spanish & Russian translations.
25
 
26
  = Help develop this plugin =
27
 
28
- The BackUpWordPress plugin is hosted github, if you want to help out with development or testing then head over to https://github.com/humanmade/backupwordpress/.
29
 
30
- We'd also love help translating the plugin into more languages, if you can help then please contact support@hmn.md or send us a pull request.
 
 
31
 
32
  == Installation ==
33
 
@@ -85,7 +87,7 @@ If you have tried all these then feel free to contact support.
85
 
86
  The script to be entered into the Heart Internet cPanel is: `/usr/bin/php5 /home/sites/yourdomain.com/public_html/wp-cron.php` (note the space between php5 and the location of the file). The file `wp-cron.php` `chmod` must be set to `711`.
87
 
88
- **Further Support & Feedbask**
89
 
90
  General support questions should be posted in the <a href="http://wordpress.org/tags/backupwordpress?forum_id=10">WordPress support forums, tagged with backupwordpress.</a>
91
 
@@ -95,10 +97,24 @@ You can also tweet <a href="http://twitter.com/humanmadeltd">@humanmadeltd</a> o
95
 
96
  == Screenshots ==
97
 
98
- 1. Simple Automated Backups
 
 
99
 
100
  == Changelog ==
101
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  #### 1.6.9
103
 
104
  * Updated and improved translations across the board - props @elektronikLexikon.
@@ -349,8 +365,8 @@ Fix some silly 1.0 bugs
349
 
350
  #### 1.0
351
 
352
- 1.0 represents a total rewrite & rethink of the BackUpWordPress plugin with a focus on making it "Just Work". The management and development of the plugin has been taken over by [humanmade](http://hmn.md) the chaps behind [WP Remote](https://wpremote.com)
353
 
354
  #### Previous
355
 
356
- Version 0.4.5 and previous were developed by [wpdprx](http://profiles.wordpress.org/users/wpdprx/)
1
  === BackUpWordPress ===
2
+ Contributors: humanmade, joehoyle, mattheu, tcrsavage, willmot, cuvelier
3
  Tags: back up, backup, backups, database, zip, db, files, archive, wp-cli, humanmade
4
+ Requires at least: 3.3.3
5
+ Tested up to: 3.4.2
6
+ Stable tag: 2.0.1
7
 
8
  Simple automated back ups of your WordPress powered website.
9
 
10
  == Description ==
11
 
12
+ BackUpWordPress will back up your entire site including your database and all your files on a schedule that suits you.
13
 
14
  = Features =
15
 
16
+ * Manage multiple schedules.
17
  * Super simple to use, no setup required.
18
  * Uses `zip` and `mysqldump` for faster back ups if they are available.
19
  * Works in low memory, "shared host" environments.
20
  * Option to have each backup file emailed to you.
21
  * Works on Linux & Windows Server.
22
  * Exclude files and folders from your back ups.
 
23
  * Good support should you need help.
24
+ * Translations for Spanish, German, Chinese, Romanian, Russian, Serbian, Lithuanian, Italian, Czech, Dutch, French, Basque.
25
 
26
  = Help develop this plugin =
27
 
28
+ The BackUpWordPress plugin is hosted GitHub, if you want to help out with development or testing then head over to https://github.com/humanmade/backupwordpress/.
29
 
30
+ = Translations =
31
+
32
+ We'd also love help translating the plugin into more languages, if you can help then please contact support@hmn.md or visit http://translate.hmn.md/.
33
 
34
  == Installation ==
35
 
87
 
88
  The script to be entered into the Heart Internet cPanel is: `/usr/bin/php5 /home/sites/yourdomain.com/public_html/wp-cron.php` (note the space between php5 and the location of the file). The file `wp-cron.php` `chmod` must be set to `711`.
89
 
90
+ **Further Support & Feedback**
91
 
92
  General support questions should be posted in the <a href="http://wordpress.org/tags/backupwordpress?forum_id=10">WordPress support forums, tagged with backupwordpress.</a>
93
 
97
 
98
  == Screenshots ==
99
 
100
+ 1. Manage multiple schedules.
101
+ 2. Choose your schedule, backup type, number of backups to keep and whether to recieve a notification email.
102
+ 3. Easily manage exclude rules and see exactly which files are included and excluded from your backup.
103
 
104
  == Changelog ==
105
 
106
+ #### 2.0.1
107
+
108
+ * Fix fatal error on PHP 5.2.
109
+
110
+ #### 2.0
111
+
112
+ * Ability to have multiple schedules with separate settings & excludes per schedule.
113
+ * Ability to manage exclude rules and see exactly which files are included and excluded.
114
+ * Fix an issue with sites with an `open_basedir` restriction.
115
+ * Backups should now be much more reliable in low memory environments.
116
+ * Lots of other minor improvements and bug fixes.
117
+
118
  #### 1.6.9
119
 
120
  * Updated and improved translations across the board - props @elektronikLexikon.
365
 
366
  #### 1.0
367
 
368
+ 1.0 represents a total rewrite & rethink of the BackUpWordPress plugin with a focus on making it "Just Work". The management and development of the plugin has been taken over by [Human Made Limited](http://hmn.md) the chaps behind [WP Remote](https://wpremote.com)
369
 
370
  #### Previous
371
 
372
+ Version 0.4.5 and previous were developed by [wpdprx](http://profiles.wordpress.org/users/wpdprx/)
screenshot-1.png DELETED
Binary file