Completed
Branch FET/asset-manager (018c4e)
by
unknown
87:46 queued 74:14
created

EEH_Debug_Tools::printv()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 26
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 23
nc 8
nop 7
dl 0
loc 26
rs 8.5806
c 0
b 0
f 0
1
<?php use EventEspresso\core\services\Benchmark;
2
3
if (! defined('EVENT_ESPRESSO_VERSION')) {
4
    exit('No direct script access allowed');
5
}
6
7
8
9
/**
10
 * Class EEH_Debug_Tools
11
 *
12
 * @package               Event Espresso
13
 * @subpackage            core
14
 * @author                Brent Christensen, Michael Nelson
15
 * @since                 4.0
16
 */
17
class EEH_Debug_Tools
18
{
19
20
    /**
21
     *    instance of the EEH_Autoloader object
22
     *
23
     * @var    $_instance
24
     * @access    private
25
     */
26
    private static $_instance;
27
28
    /**
29
     * @var array
30
     */
31
    protected $_memory_usage_points = array();
32
33
34
35
    /**
36
     * @singleton method used to instantiate class object
37
     * @access    public
38
     * @return EEH_Debug_Tools
39
     */
40
    public static function instance()
41
    {
42
        // check if class object is instantiated, and instantiated properly
43
        if (! self::$_instance instanceof EEH_Debug_Tools) {
44
            self::$_instance = new self();
45
        }
46
        return self::$_instance;
47
    }
48
49
50
51
    /**
52
     * private class constructor
53
     */
54
    private function __construct()
55
    {
56
        // load Kint PHP debugging library
57
        if (! class_exists('Kint') && file_exists(EE_PLUGIN_DIR_PATH . 'tests' . DS . 'kint' . DS . 'Kint.class.php')) {
58
            // despite EE4 having a check for an existing copy of the Kint debugging class,
59
            // if another plugin was loaded AFTER EE4 and they did NOT perform a similar check,
60
            // then hilarity would ensue as PHP throws a "Cannot redeclare class Kint" error
61
            // so we've moved it to our test folder so that it is not included with production releases
62
            // plz use https://wordpress.org/plugins/kint-debugger/  if testing production versions of EE
63
            require_once(EE_PLUGIN_DIR_PATH . 'tests' . DS . 'kint' . DS . 'Kint.class.php');
64
        }
65
        // if ( ! defined('DOING_AJAX') || $_REQUEST['noheader'] !== 'true' || ! isset( $_REQUEST['noheader'], $_REQUEST['TB_iframe'] ) ) {
66
        //add_action( 'shutdown', array($this,'espresso_session_footer_dump') );
67
        // }
68
        $plugin = basename(EE_PLUGIN_DIR_PATH);
69
        add_action("activate_{$plugin}", array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
70
        add_action('activated_plugin', array('EEH_Debug_Tools', 'ee_plugin_activation_errors'));
71
        add_action('shutdown', array('EEH_Debug_Tools', 'show_db_name'));
72
    }
73
74
75
76
    /**
77
     *    show_db_name
78
     *
79
     * @return void
80
     */
81
    public static function show_db_name()
82
    {
83
        if (! defined('DOING_AJAX') && (defined('EE_ERROR_EMAILS') && EE_ERROR_EMAILS)) {
84
            echo '<p style="font-size:10px;font-weight:normal;color:#E76700;margin: 1em 2em; text-align: right;">DB_NAME: '
85
                 . DB_NAME
86
                 . '</p>';
87
        }
88
        if (EE_DEBUG) {
89
            Benchmark::displayResults();
90
        }
91
    }
92
93
94
95
    /**
96
     *    dump EE_Session object at bottom of page after everything else has happened
97
     *
98
     * @return void
99
     */
100
    public function espresso_session_footer_dump()
101
    {
102
        if (
103
            (defined('WP_DEBUG') && WP_DEBUG)
104
            && ! defined('DOING_AJAX')
105
            && class_exists('Kint')
106
            && function_exists('wp_get_current_user')
107
            && current_user_can('update_core')
108
            && class_exists('EE_Registry')
109
        ) {
110
            Kint::dump(EE_Registry::instance()->SSN->id());
111
            Kint::dump(EE_Registry::instance()->SSN);
112
            //			Kint::dump( EE_Registry::instance()->SSN->get_session_data('cart')->get_tickets() );
113
            $this->espresso_list_hooked_functions();
114
            Benchmark::displayResults();
115
        }
116
    }
117
118
119
120
    /**
121
     *    List All Hooked Functions
122
     *    to list all functions for a specific hook, add ee_list_hooks={hook-name} to URL
123
     *    http://wp.smashingmagazine.com/2009/08/18/10-useful-wordpress-hook-hacks/
124
     *
125
     * @param string $tag
126
     * @return void
127
     */
128
    public function espresso_list_hooked_functions($tag = '')
129
    {
130
        global $wp_filter;
131
        echo '<br/><br/><br/><h3>Hooked Functions</h3>';
132
        if ($tag) {
133
            $hook[$tag] = $wp_filter[$tag];
0 ignored issues
show
Coding Style Comprehensibility introduced by
$hook was never initialized. Although not strictly required by PHP, it is generally a good practice to add $hook = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
134
            if (! is_array($hook[$tag])) {
135
                trigger_error("Nothing found for '$tag' hook", E_USER_WARNING);
136
                return;
137
            }
138
            echo '<h5>For Tag: ' . $tag . '</h5>';
139
        } else {
140
            $hook = is_array($wp_filter) ? $wp_filter : array($wp_filter);
141
            ksort($hook);
142
        }
143
        foreach ($hook as $tag_name => $priorities) {
144
            echo "<br />&gt;&gt;&gt;&gt;&gt;\t<strong>$tag_name</strong><br />";
145
            ksort($priorities);
146
            foreach ($priorities as $priority => $function) {
147
                echo $priority;
148
                foreach ($function as $name => $properties) {
149
                    echo "\t$name<br />";
150
                }
151
            }
152
        }
153
    }
154
155
156
157
    /**
158
     *    registered_filter_callbacks
159
     *
160
     * @param string $hook_name
161
     * @return array
162
     */
163
    public static function registered_filter_callbacks($hook_name = '')
164
    {
165
        $filters = array();
166
        global $wp_filter;
167
        if (isset($wp_filter[$hook_name])) {
168
            $filters[$hook_name] = array();
169
            foreach ($wp_filter[$hook_name] as $priority => $callbacks) {
170
                $filters[$hook_name][$priority] = array();
171
                foreach ($callbacks as $callback) {
172
                    $filters[$hook_name][$priority][] = $callback['function'];
173
                }
174
            }
175
        }
176
        return $filters;
177
    }
178
179
180
181
    /**
182
     *    captures plugin activation errors for debugging
183
     *
184
     * @return void
185
     * @throws EE_Error
186
     */
187
    public static function ee_plugin_activation_errors()
188
    {
189
        if (WP_DEBUG) {
190
            $activation_errors = ob_get_contents();
191
            if (! empty($activation_errors)) {
192
                $activation_errors = date('Y-m-d H:i:s') . "\n" . $activation_errors;
193
            }
194
            espresso_load_required('EEH_File', EE_HELPERS . 'EEH_File.helper.php');
195
            if (class_exists('EEH_File')) {
196
                try {
197
                    EEH_File::ensure_file_exists_and_is_writable(
198
                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . 'espresso_plugin_activation_errors.html'
199
                    );
200
                    EEH_File::write_to_file(
201
                        EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . 'espresso_plugin_activation_errors.html',
202
                        $activation_errors
203
                    );
204
                } catch (EE_Error $e) {
205
                    EE_Error::add_error(
206
                        sprintf(
207
                            __(
208
                                'The Event Espresso activation errors file could not be setup because: %s',
209
                                'event_espresso'
210
                            ),
211
                            $e->getMessage()
212
                        ),
213
                        __FILE__, __FUNCTION__, __LINE__
214
                    );
215
                }
216
            } else {
217
                // old school attempt
218
                file_put_contents(
219
                    EVENT_ESPRESSO_UPLOAD_DIR . 'logs' . DS . 'espresso_plugin_activation_errors.html',
220
                    $activation_errors
221
                );
222
            }
223
            $activation_errors = get_option('ee_plugin_activation_errors', '') . $activation_errors;
224
            update_option('ee_plugin_activation_errors', $activation_errors);
225
        }
226
    }
227
228
229
230
    /**
231
     * This basically mimics the WordPress _doing_it_wrong() function except adds our own messaging etc.
232
     * Very useful for providing helpful messages to developers when the method of doing something has been deprecated,
233
     * or we want to make sure they use something the right way.
234
     *
235
     * @access public
236
     * @param string $function      The function that was called
237
     * @param string $message       A message explaining what has been done incorrectly
238
     * @param string $version       The version of Event Espresso where the error was added
239
     * @param string $applies_when  a version string for when you want the doing_it_wrong notice to begin appearing
240
     *                              for a deprecated function. This allows deprecation to occur during one version,
241
     *                              but not have any notices appear until a later version. This allows developers
242
     *                              extra time to update their code before notices appear.
243
     * @param int    $error_type
244
     * @uses   trigger_error()
245
     */
246
    public function doing_it_wrong(
247
        $function,
248
        $message,
249
        $version,
250
        $applies_when = '',
251
        $error_type = null
252
    ) {
253
        $applies_when = ! empty($applies_when) ? $applies_when : espresso_version();
254
        $error_type = $error_type !== null ? $error_type : E_USER_NOTICE;
255
        // because we swapped the parameter order around for the last two params,
256
        // let's verify that some third party isn't still passing an error type value for the third param
257
        if (is_int($applies_when)) {
258
            $error_type = $applies_when;
259
            $applies_when = espresso_version();
260
        }
261
        // if not displaying notices yet, then just leave
262
        if (version_compare(espresso_version(), $applies_when, '<')) {
263
            return;
264
        }
265
        do_action('AHEE__EEH_Debug_Tools__doing_it_wrong_run', $function, $message, $version);
266
        $version = $version === null
267
            ? ''
268
            : sprintf(
269
                __('(This message was added in version %s of Event Espresso)', 'event_espresso'),
270
                $version
271
            );
272
        $error_message = sprintf(
273
            esc_html__('%1$s was called %2$sincorrectly%3$s. %4$s %5$s', 'event_espresso'),
274
            $function,
275
            '<strong>',
276
            '</strong>',
277
            $message,
278
            $version
279
        );
280
        // don't trigger error if doing ajax,
281
        // instead we'll add a transient EE_Error notice that in theory should show on the next request.
282
        if (defined('DOING_AJAX') && DOING_AJAX) {
283
            $error_message .= ' ' . esc_html__(
284
                    'This is a doing_it_wrong message that was triggered during an ajax request.  The request params on this request were: ',
285
                    'event_espresso'
286
                );
287
            $error_message .= '<ul><li>';
288
            $error_message .= implode('</li><li>', EE_Registry::instance()->REQ->params());
289
            $error_message .= '</ul>';
290
            EE_Error::add_error($error_message, 'debug::doing_it_wrong', $function, '42');
291
            //now we set this on the transient so it shows up on the next request.
292
            EE_Error::get_notices(false, true);
293
        } else {
294
            trigger_error($error_message, $error_type);
295
        }
296
    }
297
298
299
300
301
    /**
302
     * Logger helpers
303
     */
304
    /**
305
     * debug
306
     *
307
     * @param string $class
308
     * @param string $func
309
     * @param string $line
310
     * @param array  $info
311
     * @param bool   $display_request
312
     * @param string $debug_index
313
     * @param string $debug_key
314
     * @throws EE_Error
315
     * @throws \EventEspresso\core\exceptions\InvalidSessionDataException
316
     */
317
    public static function log(
318
        $class = '',
319
        $func = '',
320
        $line = '',
321
        $info = array(),
322
        $display_request = false,
323
        $debug_index = '',
324
        $debug_key = 'EE_DEBUG_SPCO'
325
    ) {
326
        if (WP_DEBUG) {
327
            $debug_key = $debug_key . '_' . EE_Session::instance()->id();
328
            $debug_data = get_option($debug_key, array());
329
            $default_data = array(
330
                $class => $func . '() : ' . $line,
331
                'REQ'  => $display_request ? $_REQUEST : '',
332
            );
333
            // don't serialize objects
334
            $info = self::strip_objects($info);
335
            $index = ! empty($debug_index) ? $debug_index : 0;
336
            if (! isset($debug_data[$index])) {
337
                $debug_data[$index] = array();
338
            }
339
            $debug_data[$index][microtime()] = array_merge($default_data, $info);
340
            update_option($debug_key, $debug_data);
341
        }
342
    }
343
344
345
346
    /**
347
     * strip_objects
348
     *
349
     * @param array $info
350
     * @return array
351
     */
352
    public static function strip_objects($info = array())
353
    {
354
        foreach ($info as $key => $value) {
355
            if (is_array($value)) {
356
                $info[$key] = self::strip_objects($value);
357 View Code Duplication
            } else if (is_object($value)) {
358
                $object_class = get_class($value);
359
                $info[$object_class] = array();
360
                $info[$object_class]['ID'] = method_exists($value, 'ID') ? $value->ID() : spl_object_hash($value);
361
                if (method_exists($value, 'ID')) {
362
                    $info[$object_class]['ID'] = $value->ID();
363
                }
364
                if (method_exists($value, 'status')) {
365
                    $info[$object_class]['status'] = $value->status();
366
                } else if (method_exists($value, 'status_ID')) {
367
                    $info[$object_class]['status'] = $value->status_ID();
368
                }
369
                unset($info[$key]);
370
            }
371
        }
372
        return (array)$info;
373
    }
374
375
376
377
    /**
378
     * @param mixed      $var
379
     * @param string     $var_name
380
     * @param string     $file
381
     * @param int|string $line
382
     * @param int|string $heading_tag
383
     * @param bool       $die
384
     * @param string     $margin
385
     */
386
    public static function printv(
387
        $var,
388
        $var_name = '',
389
        $file = '',
390
        $line = '',
391
        $heading_tag = 5,
392
        $die = false,
393
        $margin = ''
394
    ) {
395
        $var_name = ! $var_name ? 'string' : $var_name;
396
        $var_name = ucwords(str_replace('$', '', $var_name));
397
        $is_method = method_exists($var_name, $var);
398
        $var_name = ucwords(str_replace('_', ' ', $var_name));
399
        $heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
400
        $result = EEH_Debug_Tools::headingSpacer($heading_tag);
401
        $result .= EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
402
        $result .= $is_method
403
            ? EEH_Debug_Tools::grey_span('::') . EEH_Debug_Tools::orange_span($var . '()')
404
            : EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span($var);
405
        $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
406
        $result .= EEH_Debug_Tools::headingX($heading_tag);
407
        if ($die) {
408
            die($result);
409
        }
410
        echo $result;
411
    }
412
413
414
    protected static function headingTag($heading_tag)
415
    {
416
        $heading_tag = absint($heading_tag);
417
        return $heading_tag > 0 && $heading_tag < 7 ? "h{$heading_tag}" : 'h5';
418
    }
419
420
421
    protected static function headingSpacer($heading_tag)
422
    {
423
        return EEH_Debug_Tools::plainOutput() && ($heading_tag === 'h1' || $heading_tag === 'h2')
424
            ? "\n"
425
            : '';
426
    }
427
428
429
    protected static function plainOutput()
430
    {
431
        return defined('EE_TESTS_DIR') || (defined('DOING_AJAX') && DOING_AJAX);
432
    }
433
434
435
    /**
436
     * @param string $var_name
437
     * @param string $heading_tag
438
     * @param string $margin
439
     * @param int    $line
440
     * @return string
441
     */
442
    protected static function heading($var_name = '', $heading_tag = 'h5', $margin = '', $line = 0)
443
    {
444
        if (EEH_Debug_Tools::plainOutput()) {
445
            $heading = '';
446
            if($heading_tag === 'h1' || $heading_tag === 'h2') {
447
                $heading .= "\n";
448
            }
449
            $heading .= "\n{$line}) {$var_name}";
450
            return $heading;
451
        }
452
        $margin = "25px 0 0 {$margin}";
453
        return '<' . $heading_tag . ' style="color:#2EA2CC; margin:' . $margin . ';"><b>' . $var_name . '</b>';
454
    }
455
456
457
458
    /**
459
     * @param string $heading_tag
460
     * @return string
461
     */
462
    protected static function headingX($heading_tag = 'h5')
463
    {
464
        if (EEH_Debug_Tools::plainOutput()) {
465
            return '';
466
        }
467
        return '</' . $heading_tag . '>';
468
    }
469
470
471
472
    /**
473
     * @param string $content
474
     * @return string
475
     */
476
    protected static function grey_span($content = '')
477
    {
478
        if (EEH_Debug_Tools::plainOutput()) {
479
            return $content;
480
        }
481
        return '<span style="color:#999">' . $content . '</span>';
482
    }
483
484
485
486
    /**
487
     * @param string $file
488
     * @param int    $line
489
     * @return string
490
     */
491
    protected static function file_and_line($file, $line, $heading_tag)
492
    {
493
        if ($file === '' || $line === '') {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of $line (integer) and '' (string) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
494
            return '';
495
        }
496
        $file = str_replace(EE_PLUGIN_DIR_PATH, '/', $file);
497
        if (EEH_Debug_Tools::plainOutput()) {
498
            if ($heading_tag === 'h1' || $heading_tag === 'h2') {
499
                return " ({$file})";
500
            }
501
            return '';
502
        }
503
        return '<br /><span style="font-size:9px;font-weight:normal;color:#666;line-height: 12px;">'
504
               . $file
505
               . '<br />line no: '
506
               . $line
507
               . '</span>';
508
    }
509
510
511
512
    /**
513
     * @param string $content
514
     * @return string
515
     */
516
    protected static function orange_span($content = '')
517
    {
518
        if (EEH_Debug_Tools::plainOutput()) {
519
            return $content;
520
        }
521
        return '<span style="color:#E76700">' . $content . '</span>';
522
    }
523
524
525
526
    /**
527
     * @param mixed $var
528
     * @return string
529
     */
530
    protected static function pre_span($var)
531
    {
532
        ob_start();
533
        var_dump($var);
534
        $var = ob_get_clean();
535
        if (EEH_Debug_Tools::plainOutput()) {
536
            return $var;
537
        }
538
        return '<pre style="color:#999; padding:1em; background: #fff">' . $var . '</pre>';
539
    }
540
541
542
543
    /**
544
     * @param mixed      $var
545
     * @param string     $var_name
546
     * @param string     $file
547
     * @param int|string $line
548
     * @param int|string $heading_tag
549
     * @param bool       $die
550
     */
551
    public static function printr(
552
        $var,
553
        $var_name = '',
554
        $file = '',
555
        $line = '',
556
        $heading_tag = 5,
557
        $die = false
558
    ) {
559
        // return;
560
        $file = str_replace(rtrim(ABSPATH, '\\/'), '', $file);
561
        $margin = is_admin() ? ' 180px' : '0';
562
        //$print_r = false;
563
        if (is_string($var)) {
564
            EEH_Debug_Tools::printv($var, $var_name, $file, $line, $heading_tag, $die, $margin);
565
            return;
566
        }
567
        if (is_object($var)) {
568
            $var_name = ! $var_name ? 'object' : $var_name;
569
            //$print_r = true;
570
        } else if (is_array($var)) {
571
            $var_name = ! $var_name ? 'array' : $var_name;
572
            //$print_r = true;
573
        } else if (is_numeric($var)) {
574
            $var_name = ! $var_name ? 'numeric' : $var_name;
575
        } else if ($var === null) {
576
            $var_name = ! $var_name ? 'null' : $var_name;
577
        }
578
        $var_name = ucwords(str_replace(array('$', '_'), array('', ' '), $var_name));
579
        $heading_tag = EEH_Debug_Tools::headingTag($heading_tag);
580
        $result = EEH_Debug_Tools::headingSpacer($heading_tag);
581
        $result .= EEH_Debug_Tools::heading($var_name, $heading_tag, $margin, $line);
582
        $result .= EEH_Debug_Tools::grey_span(' : ') . EEH_Debug_Tools::orange_span(
583
                EEH_Debug_Tools::pre_span($var)
584
            );
585
        $result .= EEH_Debug_Tools::file_and_line($file, $line, $heading_tag);
586
        $result .= EEH_Debug_Tools::headingX($heading_tag);
587
        if ($die) {
588
            die($result);
589
        }
590
        echo $result;
591
    }
592
593
594
595
    /******************** deprecated ********************/
596
597
598
599
    /**
600
     * @deprecated 4.9.39.rc.034
601
     */
602
    public function reset_times()
603
    {
604
        Benchmark::resetTimes();
605
    }
606
607
608
609
    /**
610
     * @deprecated 4.9.39.rc.034
611
     * @param null $timer_name
612
     */
613
    public function start_timer($timer_name = null)
614
    {
615
        Benchmark::startTimer($timer_name);
616
    }
617
618
619
620
    /**
621
     * @deprecated 4.9.39.rc.034
622
     * @param string $timer_name
623
     */
624
    public function stop_timer($timer_name = '')
625
    {
626
        Benchmark::stopTimer($timer_name);
627
    }
628
629
630
631
    /**
632
     * @deprecated 4.9.39.rc.034
633
     * @param string  $label      The label to show for this time eg "Start of calling Some_Class::some_function"
634
     * @param boolean $output_now whether to echo now, or wait until EEH_Debug_Tools::show_times() is called
635
     * @return void
636
     */
637
    public function measure_memory($label, $output_now = false)
638
    {
639
        Benchmark::measureMemory($label, $output_now);
640
    }
641
642
643
644
    /**
645
     * @deprecated 4.9.39.rc.034
646
     * @param int $size
647
     * @return string
648
     */
649
    public function convert($size)
650
    {
651
        return Benchmark::convert($size);
652
    }
653
654
655
656
    /**
657
     * @deprecated 4.9.39.rc.034
658
     * @param bool $output_now
659
     * @return string
660
     */
661
    public function show_times($output_now = true)
662
    {
663
        return Benchmark::displayResults($output_now);
664
    }
665
666
667
668
    /**
669
     * @deprecated 4.9.39.rc.034
670
     * @param string $timer_name
671
     * @param float  $total_time
672
     * @return string
673
     */
674
    public function format_time($timer_name, $total_time)
675
    {
676
        return Benchmark::formatTime($timer_name, $total_time);
677
    }
678
679
680
681
}
682
683
684
685
/**
686
 * borrowed from Kint Debugger
687
 * Plugin URI: http://upthemes.com/plugins/kint-debugger/
688
 */
689
if (class_exists('Kint') && ! function_exists('dump_wp_query')) {
690
    function dump_wp_query()
691
    {
692
        global $wp_query;
693
        d($wp_query);
694
    }
695
}
696
/**
697
 * borrowed from Kint Debugger
698
 * Plugin URI: http://upthemes.com/plugins/kint-debugger/
699
 */
700
if (class_exists('Kint') && ! function_exists('dump_wp')) {
701
    function dump_wp()
702
    {
703
        global $wp;
704
        d($wp);
705
    }
706
}
707
/**
708
 * borrowed from Kint Debugger
709
 * Plugin URI: http://upthemes.com/plugins/kint-debugger/
710
 */
711
if (class_exists('Kint') && ! function_exists('dump_post')) {
712
    function dump_post()
713
    {
714
        global $post;
715
        d($post);
716
    }
717
}
718