root/ext/bcmath/bcmath.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ZEND_GET_MODULE
  2. PHP_GSHUTDOWN_FUNCTION
  3. PHP_MINIT_FUNCTION
  4. PHP_MSHUTDOWN_FUNCTION
  5. PHP_MINFO_FUNCTION
  6. php_str2num
  7. PHP_FUNCTION
  8. PHP_FUNCTION
  9. PHP_FUNCTION
  10. PHP_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Author: Andi Gutmans <andi@zend.com>                                 |
  16    +----------------------------------------------------------------------+
  17 */
  18 
  19 /* $Id$ */
  20 
  21 #ifdef HAVE_CONFIG_H
  22 #include "config.h"
  23 #endif
  24 
  25 #include "php.h"
  26 
  27 #if HAVE_BCMATH
  28 
  29 #include "php_ini.h"
  30 #include "ext/standard/info.h"
  31 #include "php_bcmath.h"
  32 #include "libbcmath/src/bcmath.h"
  33 
  34 ZEND_DECLARE_MODULE_GLOBALS(bcmath)
  35 static PHP_GINIT_FUNCTION(bcmath);
  36 static PHP_GSHUTDOWN_FUNCTION(bcmath);
  37 
  38 /* {{{ arginfo */
  39 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcadd, 0, 0, 2)
  40         ZEND_ARG_INFO(0, left_operand)
  41         ZEND_ARG_INFO(0, right_operand)
  42         ZEND_ARG_INFO(0, scale)
  43 ZEND_END_ARG_INFO()
  44 
  45 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsub, 0, 0, 2)
  46         ZEND_ARG_INFO(0, left_operand)
  47         ZEND_ARG_INFO(0, right_operand)
  48         ZEND_ARG_INFO(0, scale)
  49 ZEND_END_ARG_INFO()
  50 
  51 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcmul, 0, 0, 2)
  52         ZEND_ARG_INFO(0, left_operand)
  53         ZEND_ARG_INFO(0, right_operand)
  54         ZEND_ARG_INFO(0, scale)
  55 ZEND_END_ARG_INFO()
  56 
  57 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcdiv, 0, 0, 2)
  58         ZEND_ARG_INFO(0, left_operand)
  59         ZEND_ARG_INFO(0, right_operand)
  60         ZEND_ARG_INFO(0, scale)
  61 ZEND_END_ARG_INFO()
  62 
  63 ZEND_BEGIN_ARG_INFO(arginfo_bcmod, 0)
  64         ZEND_ARG_INFO(0, left_operand)
  65         ZEND_ARG_INFO(0, right_operand)
  66 ZEND_END_ARG_INFO()
  67 
  68 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpowmod, 0, 0, 3)
  69         ZEND_ARG_INFO(0, x)
  70         ZEND_ARG_INFO(0, y)
  71         ZEND_ARG_INFO(0, mod)
  72         ZEND_ARG_INFO(0, scale)
  73 ZEND_END_ARG_INFO()
  74 
  75 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcpow, 0, 0, 2)
  76         ZEND_ARG_INFO(0, x)
  77         ZEND_ARG_INFO(0, y)
  78         ZEND_ARG_INFO(0, scale)
  79 ZEND_END_ARG_INFO()
  80 
  81 ZEND_BEGIN_ARG_INFO_EX(arginfo_bcsqrt, 0, 0, 1)
  82         ZEND_ARG_INFO(0, operand)
  83         ZEND_ARG_INFO(0, scale)
  84 ZEND_END_ARG_INFO()
  85 
  86 ZEND_BEGIN_ARG_INFO_EX(arginfo_bccomp, 0, 0, 2)
  87         ZEND_ARG_INFO(0, left_operand)
  88         ZEND_ARG_INFO(0, right_operand)
  89         ZEND_ARG_INFO(0, scale)
  90 ZEND_END_ARG_INFO()
  91 
  92 ZEND_BEGIN_ARG_INFO(arginfo_bcscale, 0)
  93         ZEND_ARG_INFO(0, scale)
  94 ZEND_END_ARG_INFO()
  95 
  96 /* }}} */
  97 
  98 const zend_function_entry bcmath_functions[] = {
  99         PHP_FE(bcadd,                                                                   arginfo_bcadd)
 100         PHP_FE(bcsub,                                                                   arginfo_bcsub)
 101         PHP_FE(bcmul,                                                                   arginfo_bcmul)
 102         PHP_FE(bcdiv,                                                                   arginfo_bcdiv)
 103         PHP_FE(bcmod,                                                                   arginfo_bcmod)
 104         PHP_FE(bcpow,                                                                   arginfo_bcpow)
 105         PHP_FE(bcsqrt,                                                                  arginfo_bcsqrt)
 106         PHP_FE(bcscale,                                                                 arginfo_bcscale)
 107         PHP_FE(bccomp,                                                                  arginfo_bccomp)
 108         PHP_FE(bcpowmod,                                                                arginfo_bcpowmod)
 109         PHP_FE_END
 110 };
 111 
 112 zend_module_entry bcmath_module_entry = {
 113         STANDARD_MODULE_HEADER,
 114         "bcmath",
 115         bcmath_functions,
 116         PHP_MINIT(bcmath),
 117         PHP_MSHUTDOWN(bcmath),
 118         NULL,
 119         NULL,
 120         PHP_MINFO(bcmath),
 121         NO_VERSION_YET,
 122         PHP_MODULE_GLOBALS(bcmath),
 123         PHP_GINIT(bcmath),
 124     PHP_GSHUTDOWN(bcmath),
 125         NULL,
 126         STANDARD_MODULE_PROPERTIES_EX
 127 };
 128 
 129 #ifdef COMPILE_DL_BCMATH
 130 ZEND_GET_MODULE(bcmath)
 131 #endif
 132 
 133 /* {{{ PHP_INI */
 134 PHP_INI_BEGIN()
 135         STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
 136 PHP_INI_END()
 137 /* }}} */
 138 
 139 /* {{{ PHP_GINIT_FUNCTION
 140  */
 141 static PHP_GINIT_FUNCTION(bcmath)
 142 {
 143         bcmath_globals->bc_precision = 0;
 144         bc_init_numbers(TSRMLS_C);
 145 }
 146 /* }}} */
 147 
 148 /* {{{ PHP_GSHUTDOWN_FUNCTION
 149  */
 150 static PHP_GSHUTDOWN_FUNCTION(bcmath)
 151 {
 152         _bc_free_num_ex(&bcmath_globals->_zero_, 1);
 153         _bc_free_num_ex(&bcmath_globals->_one_, 1);
 154         _bc_free_num_ex(&bcmath_globals->_two_, 1);
 155 }
 156 /* }}} */
 157 
 158 /* {{{ PHP_MINIT_FUNCTION
 159  */
 160 PHP_MINIT_FUNCTION(bcmath)
 161 {
 162         REGISTER_INI_ENTRIES();
 163 
 164         return SUCCESS;
 165 }
 166 /* }}} */
 167 
 168 /* {{{ PHP_MSHUTDOWN_FUNCTION
 169  */
 170 PHP_MSHUTDOWN_FUNCTION(bcmath)
 171 {
 172         UNREGISTER_INI_ENTRIES();
 173 
 174         return SUCCESS;
 175 }
 176 /* }}} */
 177 
 178 /* {{{ PHP_MINFO_FUNCTION
 179  */
 180 PHP_MINFO_FUNCTION(bcmath)
 181 {
 182         php_info_print_table_start();
 183         php_info_print_table_row(2, "BCMath support", "enabled");
 184         php_info_print_table_end();
 185         DISPLAY_INI_ENTRIES();
 186 }
 187 /* }}} */
 188 
 189 /* {{{ php_str2num
 190    Convert to bc_num detecting scale */
 191 static void php_str2num(bc_num *num, char *str TSRMLS_DC)
 192 {
 193         char *p;
 194 
 195         if (!(p = strchr(str, '.'))) {
 196                 bc_str2num(num, str, 0 TSRMLS_CC);
 197                 return;
 198         }
 199 
 200         bc_str2num(num, str, strlen(p+1) TSRMLS_CC);
 201 }
 202 /* }}} */
 203 
 204 /* {{{ proto string bcadd(string left_operand, string right_operand [, int scale])
 205    Returns the sum of two arbitrary precision numbers */
 206 PHP_FUNCTION(bcadd)
 207 {
 208         char *left, *right;
 209         long scale_param = 0;
 210         bc_num first, second, result;
 211         int left_len, right_len;
 212         int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
 213 
 214         if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 215                 return;
 216         }
 217         
 218         if (argc == 3) {
 219                 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
 220         }
 221 
 222         bc_init_num(&first TSRMLS_CC);
 223         bc_init_num(&second TSRMLS_CC);
 224         bc_init_num(&result TSRMLS_CC);
 225         php_str2num(&first, left TSRMLS_CC);
 226         php_str2num(&second, right TSRMLS_CC);
 227         bc_add (first, second, &result, scale);
 228         
 229         if (result->n_scale > scale) {
 230                 result->n_scale = scale;
 231         }
 232         
 233         Z_STRVAL_P(return_value) = bc_num2str(result);
 234         Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
 235         Z_TYPE_P(return_value) = IS_STRING;
 236         bc_free_num(&first);
 237         bc_free_num(&second);
 238         bc_free_num(&result);
 239         return;
 240 }
 241 /* }}} */
 242 
 243 /* {{{ proto string bcsub(string left_operand, string right_operand [, int scale])
 244    Returns the difference between two arbitrary precision numbers */
 245 PHP_FUNCTION(bcsub)
 246 {
 247         char *left, *right;
 248         int left_len, right_len;
 249         long scale_param = 0;
 250         bc_num first, second, result;
 251         int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
 252 
 253         if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 254                 return;
 255         }
 256         
 257         if (argc == 3) {
 258                 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
 259         }
 260 
 261         bc_init_num(&first TSRMLS_CC);
 262         bc_init_num(&second TSRMLS_CC);
 263         bc_init_num(&result TSRMLS_CC);
 264         php_str2num(&first, left TSRMLS_CC);
 265         php_str2num(&second, right TSRMLS_CC);
 266         bc_sub (first, second, &result, scale);
 267 
 268         if (result->n_scale > scale) {
 269                 result->n_scale = scale;
 270         }
 271 
 272         Z_STRVAL_P(return_value) = bc_num2str(result);
 273         Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
 274         Z_TYPE_P(return_value) = IS_STRING;
 275         bc_free_num(&first);
 276         bc_free_num(&second);
 277         bc_free_num(&result);
 278         return;
 279 }
 280 /* }}} */
 281 
 282 /* {{{ proto string bcmul(string left_operand, string right_operand [, int scale])
 283    Returns the multiplication of two arbitrary precision numbers */
 284 PHP_FUNCTION(bcmul)
 285 {
 286         char *left, *right;
 287         int left_len, right_len;
 288         long scale_param = 0;
 289         bc_num first, second, result;
 290         int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
 291 
 292         if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 293                 return;
 294         }
 295         
 296         if (argc == 3) {
 297                 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
 298         }
 299         
 300         bc_init_num(&first TSRMLS_CC);
 301         bc_init_num(&second TSRMLS_CC);
 302         bc_init_num(&result TSRMLS_CC);
 303         php_str2num(&first, left TSRMLS_CC);
 304         php_str2num(&second, right TSRMLS_CC);
 305         bc_multiply (first, second, &result, scale TSRMLS_CC);
 306 
 307         if (result->n_scale > scale) {
 308                 result->n_scale = scale;
 309         }
 310 
 311         Z_STRVAL_P(return_value) = bc_num2str(result);
 312         Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
 313         Z_TYPE_P(return_value) = IS_STRING;
 314         bc_free_num(&first);
 315         bc_free_num(&second);
 316         bc_free_num(&result);
 317         return;
 318 }
 319 /* }}} */
 320 
 321 /* {{{ proto string bcdiv(string left_operand, string right_operand [, int scale])
 322    Returns the quotient of two arbitrary precision numbers (division) */
 323 PHP_FUNCTION(bcdiv)
 324 {
 325         char *left, *right;
 326         int left_len, right_len;
 327         long scale_param = 0;
 328         bc_num first, second, result;
 329         int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
 330 
 331         if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 332                 return;
 333         }
 334         
 335         if (argc == 3) {
 336                 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
 337         }
 338         
 339         bc_init_num(&first TSRMLS_CC);
 340         bc_init_num(&second TSRMLS_CC);
 341         bc_init_num(&result TSRMLS_CC);
 342         php_str2num(&first, left TSRMLS_CC);
 343         php_str2num(&second, right TSRMLS_CC);
 344 
 345         switch (bc_divide(first, second, &result, scale TSRMLS_CC)) {
 346                 case 0: /* OK */
 347                         if (result->n_scale > scale) {
 348                                 result->n_scale = scale;
 349                         }
 350                         Z_STRVAL_P(return_value) = bc_num2str(result);
 351                         Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
 352                         Z_TYPE_P(return_value) = IS_STRING;
 353                         break;
 354                 case -1: /* division by zero */
 355                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
 356                         break;
 357         }
 358 
 359         bc_free_num(&first);
 360         bc_free_num(&second);
 361         bc_free_num(&result);
 362         return;
 363 }
 364 /* }}} */
 365 
 366 /* {{{ proto string bcmod(string left_operand, string right_operand)
 367    Returns the modulus of the two arbitrary precision operands */
 368 PHP_FUNCTION(bcmod)
 369 {
 370         char *left, *right;
 371         int left_len, right_len;
 372         bc_num first, second, result;
 373 
 374         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &left, &left_len, &right, &right_len) == FAILURE) {
 375                 return;
 376         }
 377         
 378         bc_init_num(&first TSRMLS_CC);
 379         bc_init_num(&second TSRMLS_CC);
 380         bc_init_num(&result TSRMLS_CC);
 381         bc_str2num(&first, left, 0 TSRMLS_CC);
 382         bc_str2num(&second, right, 0 TSRMLS_CC);
 383         
 384         switch (bc_modulo(first, second, &result, 0 TSRMLS_CC)) {
 385                 case 0:
 386                         Z_STRVAL_P(return_value) = bc_num2str(result);
 387                         Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
 388                         Z_TYPE_P(return_value) = IS_STRING;
 389                         break;
 390                 case -1:
 391                         php_error_docref(NULL TSRMLS_CC, E_WARNING, "Division by zero");
 392                         break;
 393         }
 394         
 395         bc_free_num(&first);
 396         bc_free_num(&second);
 397         bc_free_num(&result);
 398         return;
 399 }
 400 /* }}} */
 401 
 402 /* {{{ proto string bcpowmod(string x, string y, string mod [, int scale])
 403    Returns the value of an arbitrary precision number raised to the power of another reduced by a modulous */
 404 PHP_FUNCTION(bcpowmod)
 405 {
 406         char *left, *right, *modulous;
 407         int left_len, right_len, modulous_len;
 408         bc_num first, second, mod, result;
 409         long scale = BCG(bc_precision);
 410         int scale_int;
 411 
 412         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|l", &left, &left_len, &right, &right_len, &modulous, &modulous_len, &scale) == FAILURE) {
 413                 return;
 414         }
 415 
 416         bc_init_num(&first TSRMLS_CC);
 417         bc_init_num(&second TSRMLS_CC);
 418         bc_init_num(&mod TSRMLS_CC);
 419         bc_init_num(&result TSRMLS_CC);
 420         php_str2num(&first, left TSRMLS_CC);
 421         php_str2num(&second, right TSRMLS_CC);
 422         php_str2num(&mod, modulous TSRMLS_CC);
 423 
 424         scale_int = (int) ((int)scale < 0) ? 0 : scale;
 425 
 426         if (bc_raisemod(first, second, mod, &result, scale_int TSRMLS_CC) != -1) {
 427                 if (result->n_scale > scale) {
 428                         result->n_scale = scale;
 429                 }
 430                 Z_STRVAL_P(return_value) = bc_num2str(result);
 431                 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
 432                 Z_TYPE_P(return_value) = IS_STRING;
 433         } else {
 434                 RETVAL_FALSE;
 435         }
 436         
 437         bc_free_num(&first);
 438         bc_free_num(&second);
 439         bc_free_num(&mod);
 440         bc_free_num(&result);
 441         return;
 442 }
 443 /* }}} */
 444 
 445 /* {{{ proto string bcpow(string x, string y [, int scale])
 446    Returns the value of an arbitrary precision number raised to the power of another */
 447 PHP_FUNCTION(bcpow)
 448 {
 449         char *left, *right;
 450         int left_len, right_len;
 451         long scale_param = 0;
 452         bc_num first, second, result;
 453         int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
 454 
 455         if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 456                 return;
 457         }
 458         
 459         if (argc == 3) {
 460                 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
 461         }
 462 
 463         bc_init_num(&first TSRMLS_CC);
 464         bc_init_num(&second TSRMLS_CC);
 465         bc_init_num(&result TSRMLS_CC);
 466         php_str2num(&first, left TSRMLS_CC);
 467         php_str2num(&second, right TSRMLS_CC);
 468         bc_raise (first, second, &result, scale TSRMLS_CC);
 469 
 470         if (result->n_scale > scale) {
 471                 result->n_scale = scale;
 472         }
 473 
 474         Z_STRVAL_P(return_value) = bc_num2str(result);
 475         Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
 476         Z_TYPE_P(return_value) = IS_STRING;
 477         bc_free_num(&first);
 478         bc_free_num(&second);
 479         bc_free_num(&result);
 480         return;
 481 }
 482 /* }}} */
 483 
 484 /* {{{ proto string bcsqrt(string operand [, int scale])
 485    Returns the square root of an arbitray precision number */
 486 PHP_FUNCTION(bcsqrt)
 487 {
 488         char *left;
 489         int left_len;
 490         long scale_param = 0;
 491         bc_num result;
 492         int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
 493 
 494         if (zend_parse_parameters(argc TSRMLS_CC, "s|l", &left, &left_len, &scale_param) == FAILURE) {
 495                 return;
 496         }
 497         
 498         if (argc == 2) {
 499                 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
 500         }
 501 
 502         bc_init_num(&result TSRMLS_CC);
 503         php_str2num(&result, left TSRMLS_CC);
 504         
 505         if (bc_sqrt (&result, scale TSRMLS_CC) != 0) {
 506                 if (result->n_scale > scale) {
 507                         result->n_scale = scale;
 508                 }
 509                 Z_STRVAL_P(return_value) = bc_num2str(result);
 510                 Z_STRLEN_P(return_value) = strlen(Z_STRVAL_P(return_value));
 511                 Z_TYPE_P(return_value) = IS_STRING;
 512         } else {
 513                 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Square root of negative number");
 514         }
 515 
 516         bc_free_num(&result);
 517         return;
 518 }
 519 /* }}} */
 520 
 521 /* {{{ proto int bccomp(string left_operand, string right_operand [, int scale])
 522    Compares two arbitrary precision numbers */
 523 PHP_FUNCTION(bccomp)
 524 {
 525         char *left, *right;
 526         int left_len, right_len;
 527         long scale_param = 0;
 528         bc_num first, second;
 529         int scale = BCG(bc_precision), argc = ZEND_NUM_ARGS();
 530 
 531         if (zend_parse_parameters(argc TSRMLS_CC, "ss|l", &left, &left_len, &right, &right_len, &scale_param) == FAILURE) {
 532                 return;
 533         }
 534         
 535         if (argc == 3) {
 536                 scale = (int) ((int)scale_param < 0) ? 0 : scale_param;
 537         }
 538 
 539         bc_init_num(&first TSRMLS_CC);
 540         bc_init_num(&second TSRMLS_CC);
 541 
 542         bc_str2num(&first, left, scale TSRMLS_CC);
 543         bc_str2num(&second, right, scale TSRMLS_CC);
 544         Z_LVAL_P(return_value) = bc_compare(first, second);
 545         Z_TYPE_P(return_value) = IS_LONG;
 546 
 547         bc_free_num(&first);
 548         bc_free_num(&second);
 549         return;
 550 }
 551 /* }}} */
 552 
 553 /* {{{ proto bool bcscale(int scale)
 554    Sets default scale parameter for all bc math functions */
 555 PHP_FUNCTION(bcscale)
 556 {
 557         long new_scale;
 558         
 559         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &new_scale) == FAILURE) {
 560                 return;
 561         }
 562 
 563         BCG(bc_precision) = ((int)new_scale < 0) ? 0 : new_scale;
 564 
 565         RETURN_TRUE;
 566 }
 567 /* }}} */
 568 
 569 
 570 #endif
 571 
 572 /*
 573  * Local variables:
 574  * tab-width: 4
 575  * c-basic-offset: 4
 576  * End:
 577  * vim600: sw=4 ts=4 fdm=marker
 578  * vim<600: sw=4 ts=4
 579  */

/* [<][>][^][v][top][bottom][index][help] */