Passed
Pull Request — master (#406)
by Brian
04:17
created

getpaid_admin_subscription_metabox_display_amount()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 39
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 22
c 0
b 0
f 0
dl 0
loc 39
rs 9.568
cc 4
nc 6
nop 1
1
<?php
2
/**
3
 * Contains functions that display the subscriptions admin page.
4
 */
5
6
defined( 'ABSPATH' ) || exit;
7
8
/**
9
 * Render the Subscriptions page
10
 *
11
 * @access      public
12
 * @since       1.0.0
13
 * @return      void
14
 */
15
function wpinv_subscriptions_page() {
16
17
	?>
18
19
	<div class="wrap">
20
		<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
21
		<div class="bsui">
22
23
			<?php
24
25
				// Verify user permissions.
26
				if ( ! wpinv_current_user_can_manage_invoicing() ) {
27
28
					echo aui()->alert(
29
						array(
30
							'type'    => 'danger',
31
							'content' => __( 'You are not permitted to view this page.', 'invoicing' ),
32
						)
33
					);
34
35
				} else if ( ! empty( $_GET['id'] ) && is_numeric( $_GET['id'] ) ) {
36
37
					// Display a single subscription.
38
					wpinv_recurring_subscription_details();
39
				} else {
40
41
					// Display a list of available subscriptions.
42
					getpaid_print_subscriptions_list();
43
				}
44
45
			?>
46
47
		</div>
48
	</div>
49
50
	<?php
51
}
52
53
/**
54
 * Render the Subscriptions table
55
 *
56
 * @access      public
57
 * @since       1.0.19
58
 * @return      void
59
 */
60
function getpaid_print_subscriptions_list() {
61
62
	$subscribers_table = new WPInv_Subscriptions_List_Table();
63
	$subscribers_table->prepare_items();
64
65
	?>
66
	<form id="subscribers-filter" class="bsui" method="get">
67
		<input type="hidden" name="page" value="wpinv-subscriptions" />
68
		<?php $subscribers_table->views(); ?>
69
		<?php $subscribers_table->display(); ?>
70
	</form>
71
	<?php
72
}
73
74
/**
75
 * Render a single subscription.
76
 *
77
 * @access      public
78
 * @since       1.0.0
79
 * @return      void
80
 */
81
function wpinv_recurring_subscription_details() {
82
83
	// Fetch the subscription.
84
	$sub = new WPInv_Subscription( (int) $_GET['id'] );
85
	if ( ! $sub->get_id() ) {
86
87
		echo aui()->alert(
88
			array(
89
				'type'    => 'danger',
90
				'content' => __( 'Subscription not found.', 'invoicing' ),
91
			)
92
		);
93
94
		return;
95
	}
96
97
	// Use metaboxes to display the subscription details.
98
	add_meta_box( 'getpaid_admin_subscription_details_metabox', __( 'Subscription Details', 'invoicing' ), 'getpaid_admin_subscription_details_metabox', get_current_screen(), 'normal' );
0 ignored issues
show
Bug introduced by
Are you sure the usage of get_current_screen() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
99
	add_meta_box( 'getpaid_admin_subscription_update_metabox', __( 'Change Status', 'invoicing' ), 'getpaid_admin_subscription_update_metabox', get_current_screen(), 'side' );
0 ignored issues
show
Bug introduced by
Are you sure the usage of get_current_screen() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
100
	add_meta_box( 'getpaid_admin_subscription_invoice_details_metabox', __( 'Invoices', 'invoicing' ), 'getpaid_admin_subscription_invoice_details_metabox', get_current_screen(), 'advanced' );
0 ignored issues
show
Bug introduced by
Are you sure the usage of get_current_screen() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
101
	do_action( 'getpaid_admin_single_subscription_register_metabox', $sub );
102
103
	?>
104
105
		<form method="post" action="<?php echo admin_url( 'admin.php?page=wpinv-subscriptions&id=' . absint( $sub->get_id() ) ); ?>">
106
107
			<?php wp_nonce_field( 'getpaid-nonce', 'getpaid-nonce' ); ?>
108
			<?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>
109
			<?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
110
			<input type="hidden" name="getpaid-admin-action" value="update_single_subscription" />
111
			<input type="hidden" name="subscription_id" value="<?php echo (int) $sub->get_id() ;?>" />
112
113
			<div id="poststuff">
114
				<div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>">
0 ignored issues
show
Bug introduced by
Are you sure the usage of get_current_screen() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
115
116
					<div id="postbox-container-1" class="postbox-container">
117
						<?php do_meta_boxes( get_current_screen(), 'side', $sub ); ?>
0 ignored issues
show
Bug introduced by
Are you sure the usage of get_current_screen() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
118
					</div>
119
120
					<div id="postbox-container-2" class="postbox-container">
121
						<?php do_meta_boxes( get_current_screen(), 'normal', $sub ); ?>
0 ignored issues
show
Bug introduced by
Are you sure the usage of get_current_screen() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
122
						<?php do_meta_boxes( get_current_screen(), 'advanced', $sub ); ?>
0 ignored issues
show
Bug introduced by
Are you sure the usage of get_current_screen() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
123
					</div>
124
125
				</div>
126
			</div>
127
128
		</form>
129
130
		<script>jQuery(document).ready(function(){ postboxes.add_postbox_toggles('getpaid_page_wpinv-subscriptions'); });</script>
131
132
	<?php
133
134
}
135
136
/**
137
 * Displays the subscription details metabox.
138
 *
139
 * @param WPInv_Subscription $sub
140
 */
141
function getpaid_admin_subscription_details_metabox( $sub ) {
142
143
	// Prepare subscription detail columns.
144
	$fields = apply_filters(
145
		'getpaid_subscription_admin_page_fields',
146
		array(
147
			'subscription'   => __( 'Subscription', 'invoicing' ),
148
			'customer'       => __( 'Customer', 'invoicing' ),
149
			'amount'         => __( 'Amount', 'invoicing' ),
150
			'start_date'     => __( 'Start Date', 'invoicing' ),
151
			'renews_on'      => __( 'Next Payment', 'invoicing' ),
152
			'renewals'       => __( 'Renewals', 'invoicing' ),
153
			'item'           => __( 'Item', 'invoicing' ),
154
			'gateway'        => __( 'Payment Method', 'invoicing' ),
155
			'profile_id'     => __( 'Profile ID', 'invoicing' ),
156
			'status'         => __( 'Status', 'invoicing' ),
157
		)
158
	);
159
160
	if ( ! $sub->is_active() && isset( $fields['renews_on'] ) ) {
161
		unset( $fields['renews_on'] );
162
	}
163
164
	?>
165
166
		<table class="table table-borderless" style="font-size: 14px;">
167
			<tbody>
168
169
				<?php foreach ( $fields as $key => $label ) : ?>
170
171
					<tr class="getpaid-subscription-meta-<?php echo sanitize_html_class( $key ); ?>">
172
173
						<th class="w-25" style="font-weight: 500;">
174
							<?php echo sanitize_text_field( $label ); ?>
175
						</th>
176
177
						<td class="w-75 text-muted">
178
							<?php do_action( 'getpaid_subscription_admin_display_' . sanitize_text_field( $key ), $sub ); ?>
179
						</td>
180
181
					</tr>
182
183
				<?php endforeach; ?>
184
185
			</tbody>
186
		</table>
187
188
	<?php
189
}
190
191
/**
192
 * Displays the subscription customer.
193
 *
194
 * @param WPInv_Subscription $subscription
195
 */
196
function getpaid_admin_subscription_metabox_display_customer( $subscription ) {
197
198
	$username = __( '(Missing User)', 'invoicing' );
199
200
	$user = get_userdata( $subscription->get_customer_id() );
201
	if ( $user ) {
202
203
		$username = sprintf(
204
			'<a href="user-edit.php?user_id=%s">%s</a>',
205
			absint( $user->ID ),
206
			! empty( $user->display_name ) ? sanitize_text_field( $user->display_name ) : sanitize_email( $user->user_email )
207
		);
208
209
	}
210
211
	echo  $username;
212
}
213
add_action( 'getpaid_subscription_admin_display_customer', 'getpaid_admin_subscription_metabox_display_customer' );
214
215
/**
216
 * Displays the subscription amount.
217
 *
218
 * @param WPInv_Subscription $subscription
219
 */
220
function getpaid_admin_subscription_metabox_display_amount( $subscription ) {
221
222
	$initial   = wpinv_price( wpinv_format_amount( wpinv_sanitize_amount( $subscription->get_initial_amount() ) ), $subscription->get_parent_payment()->get_currency() );
223
	$recurring = wpinv_price( wpinv_format_amount( wpinv_sanitize_amount( $subscription->get_recurring_amount() ) ), $subscription->get_parent_payment()->get_currency() );
224
	$period    = 1 == $subscription->get_frequency() ? getpaid_get_subscription_period_label( $subscription->get_period() ) : WPInv_Subscriptions::wpinv_get_pretty_subscription_frequency( $subscription->get_period(),$subscription->get_frequency() );
225
226
	if ( $subscription->has_trial_period() ) {
227
228
		// translators: $1: is the initial amount, $2: is the trial period, $3: is the recurring amount, $4: is the recurring period
229
		$amount = sprintf(
230
			_x( '%1$s trial for %2$s(s) then %3$s / %4$s', 'Subscription amount on admin table. (e.g.: $10 trial for 1 month then $120 / year)', 'invoicing' ),
231
			$initial,
232
			sanitize_text_field( $subscription->get_trial_period() ),
233
			$recurring,
234
			sanitize_text_field( strtolower( $period ) )
235
		);
236
237
	} else if ( $initial != $recurring ) {
238
239
		// translators: $1: is the initial amount, $2: is the recurring amount, $3: is the recurring perio
240
		$amount = sprintf(
241
			_x( 'Initial payment of %1$s then %2$s / %3$s', 'Subscription amount on admin table. (e.g.:Initial payment of $100 then $120 / year)', 'invoicing' ),
242
			$initial,
243
			$recurring,
244
			sanitize_text_field( strtolower( $period ) )
245
		);
246
247
	} else {
248
249
		// translators: $1: is the recurring amount, $2: is the recurring period
250
		$amount = sprintf(
251
			_x( '%1$s / %2$s', 'Subscription amount on admin table. (e.g.: $120 / year)', 'invoicing' ),
252
			$initial,
253
			sanitize_text_field( strtolower( $period ) )
254
		);
255
256
	}
257
258
	echo "<span>$amount</span>";
259
}
260
add_action( 'getpaid_subscription_admin_display_amount', 'getpaid_admin_subscription_metabox_display_amount' );
261
262
/**
263
 * Displays the subscription id.
264
 *
265
 * @param WPInv_Subscription $subscription
266
 */
267
function getpaid_admin_subscription_metabox_display_id( $subscription ) {
268
	echo  '#' . absint( $subscription->get_id() );
269
}
270
add_action( 'getpaid_subscription_admin_display_subscription', 'getpaid_admin_subscription_metabox_display_id' );
271
272
/**
273
 * Displays the subscription renewal date.
274
 *
275
 * @param WPInv_Subscription $subscription
276
 */
277
function getpaid_admin_subscription_metabox_display_start_date( $subscription ) {
278
279
	$created = $subscription->get_date_created();
280
	if ( empty( $created ) || '0000-00-00 00:00:00' == $created ) {
281
		echo "&mdash;";
282
	} else {
283
		echo date_i18n( /** @scrutinizer ignore-type */get_option( 'date_format' ), strtotime( $created ) );
284
	}
285
286
}
287
add_action( 'getpaid_subscription_admin_display_start_date', 'getpaid_admin_subscription_metabox_display_start_date' );
288
289
/**
290
 * Displays the subscription renewal date.
291
 *
292
 * @param WPInv_Subscription $subscription
293
 */
294
function getpaid_admin_subscription_metabox_display_renews_on( $subscription ) {
295
296
	$expiration = $subscription->get_expiration();
297
	if ( empty( $expiration ) || '0000-00-00 00:00:00' == $expiration ) {
298
		echo "&mdash;";
299
	} else {
300
		echo date_i18n( /** @scrutinizer ignore-type */get_option( 'date_format' ), strtotime( $expiration ) );
301
	}
302
303
}
304
add_action( 'getpaid_subscription_admin_display_renews_on', 'getpaid_admin_subscription_metabox_display_renews_on' );
305
306
/**
307
 * Displays the subscription renewal count.
308
 *
309
 * @param WPInv_Subscription $subscription
310
 */
311
function getpaid_admin_subscription_metabox_display_renewals( $subscription ) {
312
	$max_bills = $subscription->get_bill_times();
313
	echo $subscription->get_times_billed() . ' / ' . ( empty( $max_bills ) ? "&infin;" : $max_bills );
314
}
315
add_action( 'getpaid_subscription_admin_display_renewals', 'getpaid_admin_subscription_metabox_display_renewals' );
316
317
/**
318
 * Displays the subscription item.
319
 *
320
 * @param WPInv_Subscription $subscription
321
 */
322
function getpaid_admin_subscription_metabox_display_item( $subscription ) {
323
324
	$item = get_post( $subscription->get_product_id() );
325
326
	if ( ! empty( $item ) ) {
327
		$link = get_edit_post_link( $item );
328
		$link = esc_url( $link );
329
		$name = esc_html( get_the_title( $item ) );
330
		echo "<a href='$link'>$name</a>";
331
	} else {
332
		echo sprintf( __( 'Item #%s', 'invoicing' ), $subscription->get_product_id() );
333
	}
334
335
}
336
add_action( 'getpaid_subscription_admin_display_item', 'getpaid_admin_subscription_metabox_display_item' );
337
338
/**
339
 * Displays the subscription gateway.
340
 *
341
 * @param WPInv_Subscription $subscription
342
 */
343
function getpaid_admin_subscription_metabox_display_gateway( $subscription ) {
344
345
	$gateway = $subscription->get_gateway();
346
347
	if ( ! empty( $gateway ) ) {
348
		echo sanitize_text_field( wpinv_get_gateway_admin_label( $gateway ) );
349
	} else {
350
		echo "&mdash;";
351
	}
352
353
}
354
add_action( 'getpaid_subscription_admin_display_gateway', 'getpaid_admin_subscription_metabox_display_gateway' );
355
356
/**
357
 * Displays the subscription status.
358
 *
359
 * @param WPInv_Subscription $subscription
360
 */
361
function getpaid_admin_subscription_metabox_display_status( $subscription ) {
362
	echo $subscription->get_status_label_html();
363
}
364
add_action( 'getpaid_subscription_admin_display_status', 'getpaid_admin_subscription_metabox_display_status' );
365
366
/**
367
 * Displays the subscription profile id.
368
 *
369
 * @param WPInv_Subscription $subscription
370
 */
371
function getpaid_admin_subscription_metabox_display_profile_id( $subscription ) {
372
373
	$profile_id = $subscription->get_profile_id();
374
375
	if ( ! empty( $profile_id ) ) {
376
		$profile_id = sanitize_text_field( $profile_id );
377
		echo apply_filters( 'getpaid_subscription_profile_id_display', $profile_id, $subscription );
378
	} else {
379
		echo "&mdash;";
380
	}
381
382
}
383
add_action( 'getpaid_subscription_admin_display_profile_id', 'getpaid_admin_subscription_metabox_display_profile_id' );
384
385
/**
386
 * Displays the subscriptions update metabox.
387
 * 
388
 * @param WPInv_Subscription $subscription
389
 */
390
function getpaid_admin_subscription_update_metabox( $subscription ) {
391
392
	?>
393
	<div class="mt-3">
394
395
		<?php
396
			echo aui()->select(
397
				array(
398
					'options'          => getpaid_get_subscription_statuses(),
399
					'name'             => 'subscription_status',
400
					'id'               => 'subscription_status_update_select',
401
					'required'         => true,
402
					'no_wrap'          => false,
403
					'label'            => __( 'Subscription Status', 'invoicing' ),
404
					'help_text'        => __( 'Updating the status will trigger related actions and hooks', 'invoicing' ),
405
					'select2'          => true,
406
					'value'            => $subscription->get_status( 'edit' ),
407
				)
408
			);
409
		?>
410
411
		<div class="mt-2 px-3 py-2 bg-light border-top" style="margin: -12px;">
412
	
413
		<?php
414
			submit_button( __( 'Update', 'invoicing' ), 'primary', 'submit', false );
415
416
			$url    = esc_url( wp_nonce_url( add_query_arg( 'getpaid-admin-action', 'subscription_manual_renew' ), 'getpaid-nonce', 'getpaid-nonce' ) );
417
			$anchor = __( 'Renew Subscription', 'invoicing' );
418
			$title  = esc_attr__( 'Are you sure you want to extend the subscription and generate a new invoice that will be automatically marked as paid?', 'invoicing' );
419
420
			if ( $subscription->is_active() ) {
421
				echo "<a href='$url' class='float-right text-muted' onclick='return confirm(\"$title\")'>$anchor</a>";
422
			}
423
424
	echo '</div></div>';
425
}
426
427
/**
428
 * Displays the subscriptions invoices metabox.
429
 * 
430
 * @param WPInv_Subscription $subscription
431
 */
432
function getpaid_admin_subscription_invoice_details_metabox( $subscription ) {
433
434
	$columns = apply_filters(
435
		'getpaid_subscription_related_invoices_columns',
436
		array(
437
438
			'invoice'      => __( 'Invoice', 'invoicing' ),
439
			'relationship' => __( 'Relationship', 'invoicing' ),
440
			'date'         => __( 'Date', 'invoicing' ),
441
			'status'       => __( 'Status', 'invoicing' ),
442
			'total'        => __( 'Total', 'invoicing' ),
443
		)
444
	);
445
446
	// Prepare the invoices.
447
	$payments = $subscription->get_child_payments();
448
	$parent   = $subscription->get_parent_invoice();
449
450
	if ( $parent->get_id() ) {
451
		$payments = array_merge( array( $parent ), $payments );
452
	}
453
	
454
	?>
455
		<div class="m-0" style="overflow: auto;">
456
457
			<table class="w-100 bg-white">
458
459
				<thead>
460
					<tr>
461
						<?php
462
							foreach ( $columns as $key => $label ) {
463
								$key   = esc_attr( $key );
464
								$label = sanitize_text_field( $label );
465
466
								echo "<th class='subscription-invoice-field-$key bg-light p-2 text-left color-dark'>$label</th>";
467
							}
468
						?>
469
					</tr>
470
				</thead>
471
472
				<tbody>
473
474
					<?php
475
476
						foreach( $payments as $payment ) :
477
478
							// Ensure that we have an invoice.
479
							if ( ! is_a( $payment, 'WPInv_Invoice' ) ) {
480
								$payment = new WPInv_Invoice( $payment );
481
							}
482
483
							// Abort if the invoice is invalid.
484
							if ( ! $payment->get_id() ) {
485
								continue;
486
							}
487
488
							echo '<tr>';
489
490
								foreach ( array_keys( $columns ) as $key ) {
491
									
492
									echo '<td class="p-2 text-left">';
493
494
										switch( $key ) {
495
496
											case 'total':
497
												echo '<strong>' . wpinv_price( wpinv_format_amount( wpinv_sanitize_amount( $payment->get_total ) ), $payment->get_currency() ) . '</strong>';
0 ignored issues
show
Bug Best Practice introduced by
The property get_total does not exist on WPInv_Invoice. Since you implemented __get, consider adding a @property annotation.
Loading history...
498
												break;
499
500
											case 'relationship':
501
												echo $payment->is_renewal() ? __( 'Renewal Invoice', 'invoicing' ) : __( 'Initial Invoice', 'invoicing' );
502
												break;
503
504
											case 'date':
505
												echo date_i18n( /** @scrutinizer ignore-type */get_option( 'date_format' ), strtotime( $payment->get_date_created() ) );
506
												break;
507
508
											case 'status':
509
												echo $payment->get_status_label_html();
510
												break;
511
512
											case 'invoice':
513
												$link    = esc_url( get_edit_post_link( $payment->get_id() ) );
514
												$invoice = sanitize_text_field( $payment->get_number() );
515
												echo "<a href='$link'>$invoice</a>";
516
												break;
517
										}
518
519
									echo '</td>';
520
								
521
								}
522
523
							echo '</tr>';
524
525
						endforeach;
526
					?>
527
528
				</tbody>
529
530
			</table>
531
532
		</div>
533
534
	<?php
535
}
536
537
/**
538
 * Handles subscription deletion
539
 *
540
 * @access      public
541
 * @since       1.0.0
542
 * @return      void
543
 */
544
function wpinv_recurring_process_subscription_deletion() {
545
546
	if( empty( $_POST['sub_id'] ) ) {
547
		return;
548
	}
549
550
	if( empty( $_POST['wpinv_delete_subscription'] ) ) {
551
		return;
552
	}
553
554
	if( ! current_user_can( 'manage_invoicing') ) {
555
		return;
556
	}
557
558
	if( ! wp_verify_nonce( $_POST['wpinv-recurring-update-nonce'], 'wpinv-recurring-update' ) ) {
559
		wp_die( __( 'Nonce verification failed', 'invoicing' ), __( 'Error', 'invoicing' ), array( 'response' => 403 ) );
560
	}
561
562
	$subscription = new WPInv_Subscription( absint( $_POST['sub_id'] ) );
563
564
	delete_post_meta( $subscription->parent_payment_id, '_wpinv_subscription_payment' );
0 ignored issues
show
Bug Best Practice introduced by
The property parent_payment_id does not exist on WPInv_Subscription. Since you implemented __get, consider adding a @property annotation.
Loading history...
565
566
	$subscription->delete();
567
568
	wp_redirect( admin_url( 'admin.php?page=wpinv-subscriptions&wpinv-message=deleted' ) );
569
	exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
570
571
}
572
add_action( 'admin_init', 'wpinv_recurring_process_subscription_deletion', 2 );
573