PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-a.7
Jetpack – WP Security, Backup, Speed, & Growth v16.3-a.7
16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 All 506 releases
jetpack / modules / likes / jetpack-likes-settings.php

jetpack-likes-settings.php in Jetpack – WP Security, Backup, Speed, & Growth 16.3-a.7, at modules/likes/jetpack-likes-settings.php

685 lines 20.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
3 use Automattic\Jetpack\Status\Host;
4 use Automattic\Jetpack\Sync\Settings;
5
6 /**
7 * Jetpack likes settings class.
8 */
9 class Jetpack_Likes_Settings {
10
11 /**
12 * Determines whether the module runs in the Jetpack plugin, as opposed to WP.com Simple site environment
13 *
14 * @var bool
15 */
16 public $in_jetpack = true;
17
18 /**
19 * Constructor function.
20 */
21 public function __construct() {
22 $this->in_jetpack = ! ( new Host() )->is_wpcom_simple();
23 }
24
25 /**
26 * Replaces the "Sharing" title for the post screen metabox with "Likes and Shares"
27 */
28 public function add_likes_to_sharing_meta_box_title() {
29 return __( 'Likes and Shares', 'jetpack' );
30 }
31
32 /**
33 * Adds a metabox to the post screen if the sharing one doesn't currently exist.
34 */
35 public function add_meta_box() {
36 if (
37 /**
38 * Allow disabling of the Likes metabox on the post editor screen.
39 *
40 * @module likes
41 *
42 * @since 2.2.0
43 *
44 * @param bool false Should the Likes metabox be disabled? Default to false.
45 */
46 apply_filters( 'post_flair_disable', false )
47 ) {
48 return;
49 }
50
51 $post_types = get_post_types( array( 'public' => true ) );
52 /**
53 * Filters the Likes metabox title.
54 *
55 * @module likes
56 *
57 * @since 2.2.0
58 *
59 * @param string Likes metabox title. Default to "Likes".
60 */
61 $title = apply_filters( 'likes_meta_box_title', __( 'Likes', 'jetpack' ) );
62 foreach ( $post_types as $post_type ) {
63 add_meta_box( 'likes_meta', $title, array( $this, 'meta_box_content' ), $post_type, 'side', 'default', array( '__back_compat_meta_box' => true ) );
64 }
65 }
66
67 /**
68 * Shows the likes option in the post screen metabox.
69 *
70 * @param object $post - the post object.
71 */
72 public function meta_box_content( $post ) {
73 $post_id = ! empty( $post->ID ) ? (int) $post->ID : get_the_ID();
74 $checked = true;
75 $disabled = ! $this->is_enabled_sitewide();
76 $switched_status = get_post_meta( $post_id, 'switch_like_status', true );
77
78 if ( $disabled && empty( $switched_status ) || ! $disabled && $switched_status === '0' ) {
79 $checked = false;
80 }
81
82 /**
83 * Fires before the Likes meta box content in the post editor.
84 *
85 * @module likes
86 *
87 * @since 2.2.0
88 *
89 * @param WP_Post|array|null $post Post data.
90 */
91 do_action( 'start_likes_meta_box_content', $post );
92 ?>
93
94 <p>
95 <label for="wpl_enable_post_likes">
96 <input type="checkbox" name="wpl_enable_post_likes" id="wpl_enable_post_likes" value="1" <?php checked( $checked ); ?>>
97 <?php esc_html_e( 'Show likes.', 'jetpack' ); ?>
98 </label>
99 <input type="hidden" name="wpl_like_status_hidden" value="1" />
100 <?php wp_nonce_field( 'likes-and-shares', '_likesharenonce' ); ?>
101 </p>
102 <?php
103 /**
104 * Fires after the Likes meta box content in the post editor.
105 *
106 * @module likes
107 *
108 * @since 2.2.0
109 *
110 * @param WP_Post|array|null $post Post data.
111 */
112 do_action( 'end_likes_meta_box_content', $post );
113 }
114
115 /**
116 * Returns the current state of the "WordPress.com Likes are" option.
117 *
118 * @return boolean true if enabled sitewide, false if not
119 */
120 public function is_enabled_sitewide() {
121 /**
122 * Filters whether Likes are enabled by default on all posts.
123 * true if enabled sitewide, false if not.
124 *
125 * @module likes
126 *
127 * @since 2.2.0
128 *
129 * @param bool $option Are Likes enabled sitewide.
130 */
131 return (bool) apply_filters( 'wpl_is_enabled_sitewide', ! Jetpack_Options::get_option_and_ensure_autoload( 'disabled_likes', 0 ) );
132 }
133
134 /**
135 * Handle meta box saving.
136 *
137 * @param int $post_id - the post ID.
138 */
139 public function meta_box_save( $post_id ) {
140 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
141 return $post_id;
142 }
143
144 if ( empty( $_POST['wpl_like_status_hidden'] ) ) {
145 return $post_id;
146 }
147
148 if ( ! isset( $_POST['_likesharenonce'] ) || ! wp_verify_nonce( $_POST['_likesharenonce'], 'likes-and-shares' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- WordPress core doesn't unslash or verify nonces either.
149 return $post_id;
150 }
151
152 // Record sharing disable. Only needs to be done for WPCOM.
153 if ( ! $this->in_jetpack ) {
154 if ( isset( $_POST['post_type'] ) && in_array( $_POST['post_type'], get_post_types( array( 'public' => true ) ), true ) ) {
155 if ( ! isset( $_POST['wpl_enable_post_sharing'] ) ) {
156 update_post_meta( $post_id, 'sharing_disabled', 1 );
157 } else {
158 delete_post_meta( $post_id, 'sharing_disabled' );
159 }
160 }
161 }
162
163 if ( 'post' === $_POST['post_type'] ) {
164 if ( ! current_user_can( 'edit_post', $post_id ) ) {
165 return $post_id;
166 }
167 }
168
169 // Record a change in like status for this post - only if it contradicts the
170 // site like setting. If it doesn't contradict, then we delete the new individual status.
171 if ( ! $this->is_enabled_sitewide() && ! empty( $_POST['wpl_enable_post_likes'] ) ) {
172 // Likes turned on for individual posts. User wants to add the button to a single post.
173 update_post_meta( $post_id, 'switch_like_status', 1 );
174 } elseif ( $this->is_enabled_sitewide() && empty( $_POST['wpl_enable_post_likes'] ) ) {
175 // Likes turned on for all posts. User wants to remove the button from a single post.
176 update_post_meta( $post_id, 'switch_like_status', 0 );
177 } elseif (
178 ( ! $this->is_enabled_sitewide() && empty( $_POST['wpl_enable_post_likes'] ) ) ||
179 ( $this->is_enabled_sitewide() && ! empty( $_POST['wpl_enable_post_likes'] ) )
180 ) {
181 // User wants to update the likes button status for an individual post, but the new status
182 // is the same as if they're asking for the default behavior according to the current Likes setting.
183 // So we delete the meta.
184 delete_post_meta( $post_id, 'switch_like_status' );
185 }
186
187 return $post_id;
188 }
189
190 /**
191 * WordPress.com: Metabox option for sharing (sharedaddy will handle this on the JP blog).
192 *
193 * @param object $post - the post object.
194 */
195 public function sharing_meta_box_content( $post ) {
196 $post_id = ! empty( $post->ID ) ? (int) $post->ID : get_the_ID();
197 $disabled = get_post_meta( $post_id, 'sharing_disabled', true );
198 ?>
199 <p>
200 <label for="wpl_enable_post_sharing">
201 <input type="checkbox" name="wpl_enable_post_sharing" id="wpl_enable_post_sharing" value="1" <?php checked( ! $disabled ); ?>>
202 <?php esc_html_e( 'Show sharing buttons.', 'jetpack' ); ?>
203 </label>
204 <input type="hidden" name="wpl_sharing_status_hidden" value="1" />
205 </p>
206 <?php
207 }
208
209 /**
210 * Should we register the Settings > Sharing screen ourselves?
211 *
212 * @deprecated 16.3 Settings > Sharing is registered by Automattic\Jetpack\Sharing_Likes\Settings\Settings_Page.
213 *
214 * @param bool $sharedaddy_active Whether the Sharing (sharedaddy) module is active.
215 * @return bool
216 */
217 public function needs_own_sharing_menu( $sharedaddy_active ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
218 _deprecated_function( __METHOD__, 'jetpack-16.3' );
219 return false;
220 }
221
222 /**
223 * Adds the 'sharing' menu to the settings menu.
224 *
225 * @deprecated 16.3 Use Automattic\Jetpack\Sharing_Likes\Settings\Settings_Page::register_menu() instead.
226 *
227 * @return void
228 */
229 public function sharing_menu() {
230 _deprecated_function( __METHOD__, 'jetpack-16.3', 'Automattic\Jetpack\Sharing_Likes\Settings\Settings_Page::register_menu' );
231 }
232
233 /**
234 * Provides a sharing page with the sharing_global_options hook so we can display the setting.
235 *
236 * @deprecated 16.3 Use Automattic\Jetpack\Sharing_Likes\Settings\Settings_Page::render() instead.
237 *
238 * @return void
239 */
240 public function sharing_page() {
241 _deprecated_function( __METHOD__, 'jetpack-16.3', 'Automattic\Jetpack\Sharing_Likes\Settings\Settings_Page::render' );
242 }
243
244 /**
245 * Returns the settings have been saved message.
246 *
247 * @deprecated 16.3 Use Automattic\Jetpack\Sharing_Likes\Settings\Settings_Page::render() instead.
248 *
249 * @return void
250 */
251 public function updated_message() {
252 _deprecated_function( __METHOD__, 'jetpack-16.3', 'Automattic\Jetpack\Sharing_Likes\Settings\Settings_Page::render' );
253 }
254
255 /**
256 * Returns the Likes options block, so it can be inserted into different sharing page contexts.
257 *
258 * @deprecated 16.3 Use Automattic\Jetpack\Sharing_Likes\Settings\Likes_Section::render() instead.
259 *
260 * @return void
261 */
262 public function sharing_block() {
263 _deprecated_function( __METHOD__, 'jetpack-16.3', 'Automattic\Jetpack\Sharing_Likes\Settings\Likes_Section::render' );
264 }
265
266 /**
267 * Are likes enabled for this post?
268 *
269 * @param int $post_id - the post ID.
270 * @return bool
271 */
272 public function is_post_likeable( $post_id = 0 ) {
273 $post = get_post( $post_id );
274 if ( ! $post || is_wp_error( $post ) ) {
275 return false;
276 }
277
278 if ( ! empty( $post->post_password ) ) {
279 return false;
280 }
281
282 $sitewide_likes_enabled = (bool) $this->is_enabled_sitewide();
283 $post_likes_switched = get_post_meta( $post->ID, 'switch_like_status', true );
284
285 /*
286 * On WPCOM, headstart was inserting bad data for post_likes_switched.
287 * it was wrapping the boolean value in an array. The array is always truthy regardless of its contents.
288 * There was another bug where truthy values were ignored if the global like setting was false.
289 * So in effect, the values for headstart never had an inpact.
290 * Delete the $post_likes_switched flag in this case in order to keep the behaviour as it was.
291 */
292 if ( is_array( $post_likes_switched ) ) {
293 $post_likes_switched = null;
294 }
295
296 /*
297 * on WPCOM, we need to look at post edit date so we don't break old posts
298 * if post edit date predates this code, stick with the former (buggy) behavior
299 * see: p7DVsv-64H-p2
300 */
301 $last_modified_time = strtotime( $post->post_modified_gmt );
302
303 $behavior_was_changed_at = strtotime( '2019-02-22 00:40:42' );
304
305 if ( $this->in_jetpack || $last_modified_time > $behavior_was_changed_at ) {
306 /*
307 * the new and improved behavior on Jetpack and recent WPCOM posts:
308 * $post_likes_switched is empty to follow site setting,
309 * 0 if we want likes disabled, 1 if we want likes enabled.
310 */
311 return $post_likes_switched || ( $sitewide_likes_enabled && $post_likes_switched !== '0' );
312 }
313
314 // implicit else (old behavior): $post_likes_switched simply inverts the global setting.
315 return ( (bool) $post_likes_switched ) xor $sitewide_likes_enabled;
316 }
317
318 /**
319 * Is the like button itself visible (as opposed to the reblog button)
320 *
321 * If called from within The Loop or if called with a $post_id set, then the post will be checked.
322 * Otherwise the sitewide setting will be used.
323 *
324 * @param int $post_id The ID of the post being rendered. Defaults to the current post if called from within The Loop.
325 * @return bool
326 */
327 public function is_likes_button_visible( $post_id = 0 ) {
328 if ( in_the_loop() || $post_id ) {
329 // If in The Loop, is_post_likeable will check the current post.
330 return $this->is_post_likeable( $post_id );
331 } else {
332 // Otherwise, check and see if likes are enabled sitewide.
333 return $this->is_enabled_sitewide();
334 }
335 }
336
337 /**
338 * Are likes visible in this context?
339 *
340 * Some of this code was taken and modified from sharing_display() to ensure
341 * similar logic and filters apply here, too.
342 */
343 public function is_likes_visible() {
344 if ( Settings::is_syncing() ) {
345 return false;
346 }
347
348 return $this->is_likes_button_visible() && $this->is_likes_module_enabled();
349 }
350
351 /**
352 * Apply filters to determine if the likes module itself is enabled
353 *
354 * @return bool
355 */
356 public function is_likes_module_enabled() {
357 global $wp_current_filter; // Used to apply 'sharing_show' filter.
358
359 $post = get_post();
360 $enabled = true;
361
362 // Never show on feeds or previews.
363 if ( is_feed() || is_preview() ) {
364 $enabled = false;
365 // Not a feed or preview, so what is it?
366 } else {
367 if ( post_password_required() ) {
368 $enabled = false;
369 }
370
371 if ( in_array( 'get_the_excerpt', (array) $wp_current_filter, true ) ) {
372 $enabled = false;
373 }
374 // Sharing Setting Overrides ****************************************
375 // Single post including custom post types.
376 if ( is_single() ) {
377 if ( ! $this->is_single_post_enabled( ( $post instanceof WP_Post ) ? $post->post_type : 'post' ) ) {
378 $enabled = false;
379 }
380
381 // Single page.
382 } elseif ( is_page() && ! is_front_page() ) {
383 if ( ! $this->is_single_page_enabled() ) {
384 $enabled = false;
385 }
386
387 // Attachment.
388 } elseif ( is_attachment() ) {
389 if ( ! $this->is_attachment_enabled() ) {
390 $enabled = false;
391 }
392
393 // All other loops.
394 } elseif ( ! $this->is_index_enabled() ) {
395 $enabled = false;
396 }
397 }
398
399 if ( $post instanceof WP_Post ) {
400 // Check that the post is a public, published post.
401 if ( 'attachment' === $post->post_type ) {
402 $post_status = get_post_status( $post->post_parent );
403 } else {
404 $post_status = $post->post_status;
405 }
406 if ( 'publish' !== $post_status ) {
407 $enabled = false;
408 }
409 }
410
411 // Run through the sharing filters.
412 /** This filter is documented in modules/sharedaddy/sharing-service.php */
413 $enabled = apply_filters( 'sharing_show', $enabled, $post );
414
415 /**
416 * Filters whether the Likes should be visible or not.
417 * Allows overwriting the options set in Settings > Sharing.
418 *
419 * @module likes
420 *
421 * @since 2.2.0
422 *
423 * @param bool $enabled Should the Likes be visible?
424 */
425 return (bool) apply_filters( 'wpl_is_likes_visible', $enabled );
426 }
427
428 /**
429 * Are Post Likes enabled on single posts?
430 *
431 * @param string $post_type custom post type identifier.
432 * @return bool
433 */
434 public function is_single_post_enabled( $post_type = 'post' ) {
435 $options = $this->get_options();
436
437 /**
438 * Filters whether Likes should be enabled on single posts.
439 *
440 * The dynamic part of the filter, {$post_type}, allows you to specific the post type where Likes should be enabled.
441 *
442 * @module likes
443 *
444 * @since 2.2.0
445 *
446 * @param bool $enabled Are Post Likes enabled on single posts?
447 */
448 $post_likes_enabled = apply_filters(
449 "wpl_is_single_{$post_type}_disabled",
450 in_array( $post_type, $options['show'], true )
451 );
452
453 return (bool) $post_likes_enabled;
454 }
455
456 /**
457 * Get the 'disabled_likes' option from the DB of the current blog.
458 *
459 * @return array
460 */
461 public function get_options() {
462 $setting = array();
463 $setting['disabled'] = get_option( 'disabled_likes' );
464 $sharing = get_option( 'sharing-options', array() );
465
466 if ( ! is_array( $sharing ) ) {
467 $sharing = array();
468 }
469 if ( ! isset( $sharing['global'] ) || ! is_array( $sharing['global'] ) ) {
470 $sharing['global'] = array();
471 }
472
473 // Default visibility settings
474 if ( ! isset( $sharing['global']['show'] ) ) {
475 $public_commentable_cpts = array_filter(
476 get_post_types(
477 array(
478 'public' => true,
479 '_builtin' => false,
480 )
481 ),
482 function ( $post_type ) {
483 return post_type_supports( $post_type, 'comments' );
484 }
485 );
486 $public_commentable_cpts = array_values( $public_commentable_cpts );
487
488 /**
489 * Filters the default post types that show Likes when no sharing settings have been saved.
490 *
491 * Only applies when the site has never explicitly configured Likes visibility.
492 * Once a site owner saves sharing settings, those are used instead.
493 *
494 * @since 16.2
495 *
496 * @param string[] $post_types Array of post type slugs that will show Likes by default.
497 */
498 $sharing['global']['show'] = apply_filters(
499 'jetpack_likes_default_post_types',
500 array_merge( array( 'post', 'page' ), $public_commentable_cpts )
501 );
502
503 // Scalar check
504 } elseif ( is_scalar( $sharing['global']['show'] ) ) {
505 switch ( $sharing['global']['show'] ) {
506 case 'posts':
507 $sharing['global']['show'] = array( 'post', 'page' );
508 break;
509 case 'index':
510 $sharing['global']['show'] = array( 'index' );
511 break;
512 case 'posts-index':
513 $sharing['global']['show'] = array( 'post', 'page', 'index' );
514 break;
515 }
516 }
517
518 // Ensure it's always an array (even if not previously empty or scalar).
519 $show = $sharing['global']['show'] ?? array();
520 $setting['show'] = ! empty( $show ) ? (array) $show : array();
521
522 /**
523 * Filters where the Likes are displayed.
524 *
525 * @module likes
526 *
527 * @since 2.2.0
528 *
529 * @param array $setting Array of Likes display settings.
530 */
531 return apply_filters( 'wpl_get_options', $setting );
532 }
533
534 /**
535 * Are Post Likes enabled on archive/front/search pages?
536 *
537 * @return bool
538 */
539 public function is_index_enabled() {
540 $options = $this->get_options();
541 /**
542 * Filters whether Likes should be enabled on archive/front/search pages.
543 *
544 * @module likes
545 *
546 * @since 2.2.0
547 *
548 * @param bool $enabled Are Post Likes enabled on archive/front/search pages?
549 */
550 return (bool) apply_filters( 'wpl_is_index_disabled', in_array( 'index', $options['show'], true ) );
551 }
552
553 /**
554 * Are Post Likes enabled on single pages?
555 *
556 * @return bool
557 */
558 public function is_single_page_enabled() {
559 $options = $this->get_options();
560 /**
561 * Filters whether Likes should be enabled on single pages.
562 *
563 * @module likes
564 *
565 * @since 2.2.0
566 *
567 * @param bool $enabled Are Post Likes enabled on single pages?
568 */
569 return (bool) apply_filters( 'wpl_is_single_page_disabled', in_array( 'page', $options['show'], true ) );
570 }
571
572 /**
573 * Are Media Likes enabled on single pages?
574 *
575 * @return bool
576 */
577 public function is_attachment_enabled() {
578 $options = $this->get_options();
579 /**
580 * Filters whether Likes should be enabled on attachment pages.
581 *
582 * @module likes
583 *
584 * @since 2.2.0
585 *
586 * @param bool $enabled Are Post Likes enabled on attachment pages?
587 */
588 return (bool) apply_filters( 'wpl_is_attachment_disabled', in_array( 'attachment', $options['show'], true ) );
589 }
590
591 /**
592 * The actual options block to be inserted into the sharing page.
593 *
594 * @deprecated 16.3 Use Automattic\Jetpack\Sharing_Likes\Settings\Likes_Section::render() instead.
595 *
596 * @return void
597 */
598 public function admin_settings_init() {
599 _deprecated_function( __METHOD__, 'jetpack-16.3', 'Automattic\Jetpack\Sharing_Likes\Settings\Likes_Section::render' );
600 }
601
602 /**
603 * Returns the current state of the "WordPress.com Reblogs are" option.
604 *
605 * @return bool true if enabled sitewide, false if not
606 */
607 public function reblogs_enabled_sitewide() {
608 /**
609 * Filters whether Reblogs are enabled by default on all posts.
610 * true if enabled sitewide, false if not.
611 *
612 * @module likes
613 *
614 * @since 3.0.0
615 *
616 * @param bool $option Are Reblogs enabled sitewide.
617 */
618 return (bool) apply_filters( 'wpl_reblogging_enabled_sitewide', ! get_option( 'disabled_reblogs' ) );
619 }
620
621 /**
622 * Used for WPCOM ONLY. Comment likes are in their own module in Jetpack.
623 * Returns if comment likes are enabled. Defaults to 'off'
624 *
625 * @return boolean true if we should show comment likes, false if not
626 */
627 public function is_comments_enabled() {
628 /**
629 * Filters whether Comment Likes are enabled.
630 * true if enabled, false if not.
631 *
632 * @module comment-likes
633 *
634 * @since 2.2.0
635 *
636 * @param bool $option Are Comment Likes enabled sitewide.
637 */
638 return (bool) apply_filters( 'jetpack_comment_likes_enabled', get_option( 'jetpack_comment_likes_enabled', false ) );
639 }
640
641 /**
642 * Saves the setting in the database.
643 *
644 * @deprecated 16.3 Use Automattic\Jetpack\Sharing_Likes\Settings\Post_Handler::maybe_handle() instead.
645 *
646 * @return void
647 */
648 public function admin_settings_callback() {
649 _deprecated_function( __METHOD__, 'jetpack-16.3', 'Automattic\Jetpack\Sharing_Likes\Settings\Post_Handler::maybe_handle' );
650 }
651
652 /**
653 * Adds the admin update hook so we can save settings even if Sharedaddy is not enabled.
654 *
655 * @deprecated 16.3 Use Automattic\Jetpack\Sharing_Likes\Settings\Post_Handler::maybe_handle() instead.
656 *
657 * @return void
658 */
659 public function process_update_requests_if_sharedaddy_not_loaded() {
660 _deprecated_function( __METHOD__, 'jetpack-16.3', 'Automattic\Jetpack\Sharing_Likes\Settings\Post_Handler::maybe_handle' );
661 }
662
663 /**
664 * If sharedaddy is not loaded, we don't have the "Show buttons on" yet, so we need to add that since it affects likes too.
665 *
666 * @deprecated 16.3 Use Automattic\Jetpack\Sharing_Likes\Settings\Placement_Section::render() instead.
667 *
668 * @return void
669 */
670 public function admin_settings_showbuttonon_init() {
671 _deprecated_function( __METHOD__, 'jetpack-16.3', 'Automattic\Jetpack\Sharing_Likes\Settings\Placement_Section::render' );
672 }
673
674 /**
675 * If sharedaddy is not loaded, we still need to save the the settings of the "Show buttons on" option.
676 *
677 * @deprecated 16.3 Use Automattic\Jetpack\Sharing_Likes\Settings\Post_Handler::maybe_handle() instead.
678 *
679 * @return void
680 */
681 public function admin_settings_showbuttonon_callback() {
682 _deprecated_function( __METHOD__, 'jetpack-16.3', 'Automattic\Jetpack\Sharing_Likes\Settings\Post_Handler::maybe_handle' );
683 }
684 }
685