00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 #include <string.h>
00125
00126 #include <sys/types.h>
00127 #include <sys/stat.h>
00128 #include <unistd.h>
00129 #include <fcntl.h>
00130
00131 #include <grass/config.h>
00132
00133 #include "G.h"
00134 #include <grass/glocale.h>
00135
00136 static int _zeros_r_nulls = 1;
00137
00138 static int put_raster_data(int, const void *, int, int, int, int,
00139 RASTER_MAP_TYPE);
00140 static int put_data(int, const CELL *, int, int, int, int);
00141 static int check_open(const char *, int, int);
00142 static int adjust(int, int *, int *);
00143 static void write_error(int, int);
00144 static int same(const unsigned char *, const unsigned char *, int);
00145 static int seek_random(int, int, int);
00146 static void set_file_pointer(int, int);
00147 static int put_fp_data(int, const void *, int, int, int, RASTER_MAP_TYPE);
00148 static int put_null_data(int, const char *, int);
00149 static int convert_and_write_if(int, const CELL *);
00150 static int convert_and_write_id(int, const CELL *);
00151 static int convert_and_write_df(int, const DCELL *);
00152 static int convert_and_write_fd(int, const FCELL *);
00153 static int put_raster_row(int fd, const void *buf, RASTER_MAP_TYPE data_type,
00154 int zeros_r_nulls);
00155
00156
00157
00158
00159
00160
00161
00162 int G_zeros_r_nulls(int zeros_r_nulls)
00163 {
00164 if (zeros_r_nulls >= 0)
00165 _zeros_r_nulls = zeros_r_nulls > 0;
00166
00167 return _zeros_r_nulls;
00168 }
00169
00170 int G_put_map_row_random(int fd, const CELL * buf, int row, int col, int n)
00171 {
00172 struct fileinfo *fcb = &G__.fileinfo[fd];
00173
00174 if (!check_open("G_put_map_row_random", fd, 1))
00175 return -1;
00176
00177 buf += adjust(fd, &col, &n);
00178 switch (put_data(fd, buf, row, col, n, _zeros_r_nulls)) {
00179 case -1:
00180 return -1;
00181 case 0:
00182 return 1;
00183 }
00184
00185
00186 if (fcb->want_histogram)
00187 G_update_cell_stats(buf, n, &fcb->statf);
00188
00189 G_row_update_range(buf, n, &fcb->range);
00190
00191 return 1;
00192 }
00193
00194 int G__put_null_value_row(int fd, const char *buf)
00195 {
00196 struct fileinfo *fcb = &G__.fileinfo[fd];
00197
00198 switch (put_null_data(fd, buf, fcb->null_cur_row)) {
00199 case -1:
00200 return -1;
00201 case 0:
00202 return 1;
00203 }
00204
00205 fcb->null_cur_row++;
00206
00207 return 1;
00208 }
00209
00210 int G_put_map_row(int fd, const CELL * buf)
00211 {
00212 struct fileinfo *fcb = &G__.fileinfo[fd];
00213
00214 if (fcb->map_type != CELL_TYPE) {
00215 G_fatal_error(_("G_put_map_row: %s is not integer! Use G_put_[f/d]_raster_row()!"),
00216 fcb->name);
00217 return -1;
00218 }
00219
00220 return put_raster_row(fd, buf, CELL_TYPE, _zeros_r_nulls);
00221 }
00222
00223 int G_put_raster_row(int fd, const void *buf, RASTER_MAP_TYPE data_type)
00224 {
00225 return put_raster_row(fd, buf, data_type, 0);
00226 }
00227
00228 int G_put_c_raster_row(int fd, const CELL * buf)
00229 {
00230 return G_put_raster_row(fd, buf, CELL_TYPE);
00231 }
00232
00233 int G_put_f_raster_row(int fd, const FCELL * buf)
00234 {
00235 return G_put_raster_row(fd, buf, FCELL_TYPE);
00236 }
00237
00238 int G_put_d_raster_row(int fd, const DCELL * buf)
00239 {
00240 return G_put_raster_row(fd, buf, DCELL_TYPE);
00241 }
00242
00243
00244
00245 static int check_open(const char *me, int fd, int random)
00246 {
00247 struct fileinfo *fcb = &G__.fileinfo[fd];
00248
00249 switch (fcb->open_mode) {
00250 case OPEN_OLD:
00251 G_warning(_("%s: map [%s] not open for write - request ignored"), me,
00252 fcb->name);
00253 break;
00254 case OPEN_NEW_COMPRESSED:
00255 case OPEN_NEW_UNCOMPRESSED:
00256 if (!random)
00257 return 1;
00258
00259 G_warning(_("%s: map [%s] not open for random write - request ignored"),
00260 me, fcb->name);
00261 break;
00262 case OPEN_NEW_RANDOM:
00263 if (random)
00264 return 1;
00265
00266 G_warning(_("%s: map [%s] not open for sequential write - request ignored"),
00267 me, fcb->name);
00268 break;
00269 default:
00270 G_warning(_("%s: unopened file descriptor - request ignored"), me);
00271 break;
00272 }
00273
00274 return 0;
00275 }
00276
00277
00278
00279
00280
00281
00282
00283
00284 static int adjust(int fd, int *col, int *n)
00285 {
00286 struct fileinfo *fcb = &G__.fileinfo[fd];
00287 int adj = 0;
00288 int last = *col + *n;
00289
00290 if (*col < 0) {
00291 adj = -(*col);
00292 *col = 0;
00293 }
00294
00295 if (last > fcb->cellhd.cols)
00296 last = fcb->cellhd.cols;
00297
00298 *n = last - *col;
00299
00300 return adj;
00301 }
00302
00303 static void write_error(int fd, int row)
00304 {
00305 struct fileinfo *fcb = &G__.fileinfo[fd];
00306
00307 if (fcb->io_error)
00308 return;
00309
00310 G_warning(_("map [%s] - unable to write row %d"), fcb->name, row);
00311
00312 fcb->io_error = 1;
00313
00314 return;
00315 }
00316
00317
00318
00319 int G__write_data(int fd, int row, int n)
00320 {
00321 struct fileinfo *fcb = &G__.fileinfo[fd];
00322 ssize_t nwrite = fcb->nbytes * n;
00323
00324 if (write(fd, G__.work_buf, nwrite) != nwrite) {
00325 write_error(fd, row);
00326 return -1;
00327 }
00328
00329 return 0;
00330 }
00331
00332 int G__write_data_compressed(int fd, int row, int n)
00333 {
00334 struct fileinfo *fcb = &G__.fileinfo[fd];
00335 int nwrite = fcb->nbytes * n;
00336
00337 if (G_zlib_write(fd, G__.work_buf, nwrite) < 0) {
00338 write_error(fd, row);
00339 return -1;
00340 }
00341
00342 return 0;
00343 }
00344
00345
00346
00347 static int seek_random(int fd, int row, int col)
00348 {
00349 struct fileinfo *fcb = &G__.fileinfo[fd];
00350 off_t offset = ((off_t) fcb->cellhd.cols * row + col) * fcb->nbytes;
00351
00352 if (lseek(fd, offset, SEEK_SET) < 0) {
00353 write_error(fd, row);
00354 return -1;
00355 }
00356
00357 return 0;
00358 }
00359
00360
00361
00362 static void set_file_pointer(int fd, int row)
00363 {
00364 struct fileinfo *fcb = &G__.fileinfo[fd];
00365
00366 fcb->row_ptr[row] = lseek(fd, 0L, SEEK_CUR);
00367 }
00368
00369
00370
00371
00372
00373
00374
00375 static int convert_float(XDR * xdrs, const FCELL * rast, int row, int col,
00376 int n, int random)
00377 {
00378 int i;
00379
00380 for (i = 0; i < n; i++) {
00381 FCELL f;
00382
00383
00384 if (G_is_f_null_value(&rast[i])) {
00385 f = 0.;
00386 if (!random)
00387 G__.null_buf[col + i] = 1;
00388 }
00389 else
00390 f = rast[i];
00391
00392 if (!xdr_float(xdrs, &f)) {
00393 G_warning(_("xdr_float failed for index %d of row %d"), i, row);
00394 return -1;
00395 }
00396 }
00397
00398 return 0;
00399 }
00400
00401 static int convert_double(XDR * xdrs, const DCELL * rast, int row, int col,
00402 int n, int random)
00403 {
00404 int i;
00405
00406 for (i = 0; i < n; i++) {
00407 DCELL d;
00408
00409
00410 if (G_is_d_null_value(&rast[i])) {
00411 d = 0.;
00412 if (!random)
00413 G__.null_buf[col + i] = 1;
00414 }
00415 else
00416 d = rast[i];
00417
00418 if (!xdr_double(xdrs, &d)) {
00419 G_warning(_("xdr_double failed for index %d of row %d"), i, row);
00420 return -1;
00421 }
00422 }
00423
00424 return 0;
00425 }
00426
00427
00428
00429
00430
00431 static int put_fp_data(int fd, const void *rast, int row, int col, int n,
00432 RASTER_MAP_TYPE data_type)
00433 {
00434 struct fileinfo *fcb = &G__.fileinfo[fd];
00435 int random = (fcb->open_mode == OPEN_NEW_RANDOM);
00436 int compressed = (fcb->open_mode == OPEN_NEW_COMPRESSED);
00437 XDR *xdrs = &fcb->xdrstream;
00438
00439 if (row < 0 || row >= fcb->cellhd.rows)
00440 return 0;
00441
00442 if (n <= 0)
00443 return 0;
00444
00445 if (random) {
00446 if (seek_random(fd, row, col) == -1)
00447 return -1;
00448 }
00449 else if (compressed)
00450 set_file_pointer(fd, row);
00451
00452 xdrmem_create(xdrs, (caddr_t) G__.work_buf,
00453 (u_int) (fcb->nbytes * fcb->cellhd.cols), XDR_ENCODE);
00454 xdr_setpos(xdrs, 0);
00455
00456 if (data_type == FCELL_TYPE) {
00457 if (convert_float(xdrs, rast, row, col, n, random) < 0)
00458 return -1;
00459 }
00460 else {
00461 if (convert_double(xdrs, rast, row, col, n, random) < 0)
00462 return -1;
00463 }
00464
00465 xdr_destroy(&fcb->xdrstream);
00466
00467 if (compressed) {
00468 if (G__write_data_compressed(fd, row, n) == -1)
00469 return -1;
00470 }
00471 else if (G__write_data(fd, row, n) == -1)
00472 return -1;
00473
00474 return 1;
00475 }
00476
00477
00478
00479
00480
00481
00482
00483 static void convert_int(unsigned char *wk, const CELL * rast, int col, int n,
00484 int random, int len, int zeros_r_nulls)
00485 {
00486 int i;
00487
00488
00489
00490 for (i = 0; i < n; i++) {
00491 CELL v = rast[i];
00492 int neg;
00493 int k;
00494
00495
00496 if (G_is_c_null_value(&v)) {
00497 v = 0;
00498 if (!random)
00499 G__.null_buf[col + i] = 1;
00500 }
00501 else if (!random && zeros_r_nulls && !v)
00502 G__.null_buf[col + i] = 1;
00503
00504
00505 if (v < 0) {
00506 neg = 1;
00507 v = -v;
00508 }
00509 else
00510 neg = 0;
00511
00512
00513 for (k = len - 1; k >= 0; k--) {
00514 wk[k] = v & 0xff;
00515 v >>= 8;
00516 }
00517
00518
00519 if (neg)
00520 wk[0] |= 0x80;
00521
00522 wk += len;
00523 }
00524 }
00525
00526 static int count_bytes(const unsigned char *wk, int n, int len)
00527 {
00528 int i, j;
00529
00530 for (i = 0; i < len - 1; i++)
00531 for (j = 0; j < n; j++)
00532 if (wk[j * len + i] != 0)
00533 return len - i;
00534
00535 return 1;
00536 }
00537
00538 static void trim_bytes(unsigned char *wk, int n, int slen, int trim)
00539 {
00540 unsigned char *wk2 = wk;
00541 int i, j;
00542
00543 for (i = 0; i < n; i++) {
00544 for (j = 0; j < trim; j++)
00545 wk++;
00546 for (; j < slen; j++)
00547 *wk2++ = *wk++;
00548 }
00549 }
00550
00551 static int same(const unsigned char *x, const unsigned char *y, int n)
00552 {
00553 return (memcmp(x, y, n) == 0);
00554 }
00555
00556 static int count_run(const unsigned char *src, int n, int nbytes)
00557 {
00558 const unsigned char *cur = src + nbytes;
00559 int i;
00560
00561 for (i = 1; i < n; i++) {
00562 if (i == 255 || !same(cur, src, nbytes))
00563 return i;
00564
00565 cur += nbytes;
00566 }
00567
00568 return n;
00569 }
00570
00571 static int rle_compress(unsigned char *dst, unsigned char *src, int n,
00572 int nbytes)
00573 {
00574 int nwrite = 0;
00575 int total = nbytes * n;
00576
00577 while (n > 0) {
00578 int count;
00579
00580 nwrite += nbytes + 1;
00581 if (nwrite >= total)
00582 return 0;
00583
00584 count = count_run(src, n, nbytes);
00585
00586 *dst++ = count;
00587 memcpy(dst, src, nbytes);
00588 dst += nbytes;
00589
00590 src += count * nbytes;
00591 n -= count;
00592 }
00593
00594 return nwrite;
00595 }
00596
00597 static int zlib_compress(unsigned char *dst, unsigned char *src, int n,
00598 int nbytes)
00599 {
00600 int total = nbytes * n;
00601 int nwrite = G_zlib_compress(G__.work_buf + 1, total,
00602 G__.compressed_buf + 1,
00603 G__.compressed_buf_size - 1);
00604
00605 return (nwrite >= total) ? 0 : nwrite;
00606 }
00607
00608
00609
00610 static int put_data(int fd, const CELL * cell, int row, int col, int n,
00611 int zeros_r_nulls)
00612 {
00613 struct fileinfo *fcb = &G__.fileinfo[fd];
00614 int random = (fcb->open_mode == OPEN_NEW_RANDOM);
00615 int compressed = fcb->cellhd.compressed;
00616 int len = compressed ? sizeof(CELL) : fcb->nbytes;
00617 unsigned char *wk = G__.work_buf;
00618 ssize_t nwrite;
00619
00620 if (row < 0 || row >= fcb->cellhd.rows)
00621 return 0;
00622
00623 if (n <= 0)
00624 return 0;
00625
00626 if (random) {
00627 if (seek_random(fd, row, col) == -1)
00628 return -1;
00629 }
00630 else if (compressed)
00631 set_file_pointer(fd, row);
00632
00633 if (compressed)
00634 wk++;
00635
00636 convert_int(wk, cell, col, n, random, len, zeros_r_nulls);
00637
00638 if (compressed) {
00639 unsigned char *wk = G__.work_buf + 1;
00640 int nbytes = count_bytes(wk, n, len);
00641
00642 if (fcb->nbytes < nbytes)
00643 fcb->nbytes = nbytes;
00644
00645
00646 if (nbytes < len)
00647 trim_bytes(wk, n, len, len - nbytes);
00648
00649 G__.compressed_buf[0] = G__.work_buf[0] = nbytes;
00650
00651
00652 nwrite = compressed == 1
00653 ? rle_compress(G__.compressed_buf + 1, G__.work_buf + 1, n,
00654 nbytes)
00655 : zlib_compress(G__.compressed_buf + 1, G__.work_buf + 1, n,
00656 nbytes);
00657
00658 if (nwrite > 0) {
00659 nwrite++;
00660
00661 if (write(fd, G__.compressed_buf, nwrite) != nwrite) {
00662 write_error(fd, row);
00663 return -1;
00664 }
00665 }
00666 else {
00667 nwrite = nbytes * n + 1;
00668 if (write(fd, G__.work_buf, nwrite) != nwrite) {
00669 write_error(fd, row);
00670 return -1;
00671 }
00672 }
00673 }
00674 else {
00675 nwrite = fcb->nbytes * n;
00676
00677 if (write(fd, G__.work_buf, nwrite) != nwrite) {
00678 write_error(fd, row);
00679 return -1;
00680 }
00681 }
00682
00683 return 1;
00684 }
00685
00686
00687
00688
00689
00690
00691
00692 static int put_raster_data(int fd, const void *rast, int row, int col, int n,
00693 int zeros_r_nulls, RASTER_MAP_TYPE map_type)
00694 {
00695 return (map_type == CELL_TYPE)
00696 ? put_data(fd, rast, row, col, n, zeros_r_nulls)
00697 : put_fp_data(fd, rast, row, col, n, map_type);
00698 }
00699
00700
00701
00702
00703
00704
00705
00706 static int put_null_data(int fd, const char *flags, int row)
00707 {
00708 struct fileinfo *fcb = &G__.fileinfo[fd];
00709 int null_fd, i;
00710
00711 if (fcb->min_null_row + NULL_ROWS_INMEM <= row) {
00712
00713
00714
00715
00716 if (fcb->min_null_row >= 0) {
00717 null_fd = G__open_null_write(fd);
00718 if (null_fd < 0)
00719 return -1;
00720
00721 for (i = 0; i < NULL_ROWS_INMEM; i++) {
00722
00723 if (i + fcb->min_null_row >= fcb->cellhd.rows)
00724 break;
00725
00726 if (G__write_null_bits(null_fd, fcb->NULL_ROWS[i],
00727 i + fcb->min_null_row,
00728 fcb->cellhd.cols, fd) < 0)
00729 return -1;
00730
00731 }
00732 if (null_fd >= 0)
00733 close(null_fd);
00734 }
00735
00736
00737 fcb->min_null_row = fcb->min_null_row + NULL_ROWS_INMEM;
00738
00739 }
00740
00741
00742 G__convert_01_flags(flags, fcb->NULL_ROWS[row - fcb->min_null_row],
00743 fcb->cellhd.cols);
00744
00745 return 1;
00746 }
00747
00748 int G__open_null_write(int fd)
00749 {
00750 struct fileinfo *fcb = &G__.fileinfo[fd];
00751 int null_fd;
00752
00753 if (access(fcb->null_temp_name, 0) != 0) {
00754 G_warning(_("unable to find a temporary null file %s"),
00755 fcb->null_temp_name);
00756 return -1;
00757 }
00758
00759 null_fd = open(fcb->null_temp_name, O_WRONLY);
00760 if (null_fd < 0)
00761 return -1;
00762
00763 return null_fd;
00764 }
00765
00766 int G__write_null_bits(int null_fd, const unsigned char *flags, int row,
00767 int cols, int fd)
00768 {
00769 off_t offset;
00770 size_t size;
00771
00772 size = G__null_bitstream_size(cols);
00773 offset = (off_t) size *row;
00774
00775 if (lseek(null_fd, offset, SEEK_SET) < 0) {
00776 G_warning(_("error writing null row %d"), row);
00777 return -1;
00778 }
00779
00780 if (write(null_fd, flags, size) != size) {
00781 G_warning(_("error writing null row %d"), row);
00782 return -1;
00783 }
00784
00785 return 1;
00786 }
00787
00788
00789
00790
00791
00792
00793
00794 static int convert_and_write_if(int fd, const CELL * buf)
00795 {
00796 struct fileinfo *fcb = &G__.fileinfo[fd];
00797 FCELL *p = (FCELL *) fcb->data;
00798 int i;
00799
00800 for (i = 0; i < fcb->cellhd.cols; i++)
00801 if (G_is_c_null_value(&buf[i]))
00802 G_set_f_null_value(&p[i], 1);
00803 else
00804 p[i] = (FCELL) buf[i];
00805
00806 return G_put_f_raster_row(fd, p);
00807 }
00808
00809 static int convert_and_write_df(int fd, const DCELL * buf)
00810 {
00811 struct fileinfo *fcb = &G__.fileinfo[fd];
00812 FCELL *p = (FCELL *) fcb->data;
00813 int i;
00814
00815 for (i = 0; i < fcb->cellhd.cols; i++)
00816 if (G_is_d_null_value(&buf[i]))
00817 G_set_f_null_value(&p[i], 1);
00818 else
00819 p[i] = (FCELL) buf[i];
00820
00821 return G_put_f_raster_row(fd, p);
00822 }
00823
00824 static int convert_and_write_id(int fd, const CELL * buf)
00825 {
00826 struct fileinfo *fcb = &G__.fileinfo[fd];
00827 DCELL *p = (DCELL *) fcb->data;
00828 int i;
00829
00830 for (i = 0; i < fcb->cellhd.cols; i++)
00831 if (G_is_c_null_value(&buf[i]))
00832 G_set_d_null_value(&p[i], 1);
00833 else
00834 p[i] = (DCELL) buf[i];
00835
00836 return G_put_d_raster_row(fd, p);
00837 }
00838
00839 static int convert_and_write_fd(int fd, const FCELL * buf)
00840 {
00841 struct fileinfo *fcb = &G__.fileinfo[fd];
00842 DCELL *p = (DCELL *) fcb->data;
00843 int i;
00844
00845 for (i = 0; i < fcb->cellhd.cols; i++)
00846 if (G_is_f_null_value(&buf[i]))
00847 G_set_d_null_value(&p[i], 1);
00848 else
00849 p[i] = (DCELL) buf[i];
00850
00851 return G_put_d_raster_row(fd, p);
00852 }
00853
00854 static int convert_and_write_fi(int fd, const FCELL * buf)
00855 {
00856 struct fileinfo *fcb = &G__.fileinfo[fd];
00857 CELL *p = (CELL *) fcb->data;
00858 int i;
00859
00860 for (i = 0; i < fcb->cellhd.cols; i++)
00861 if (G_is_f_null_value(&buf[i]))
00862 G_set_c_null_value(&p[i], 1);
00863 else
00864 p[i] = (CELL) buf[i];
00865
00866 return G_put_c_raster_row(fd, p);
00867 }
00868
00869 static int convert_and_write_di(int fd, const DCELL * buf)
00870 {
00871 struct fileinfo *fcb = &G__.fileinfo[fd];
00872 CELL *p = (CELL *) fcb->data;
00873 int i;
00874
00875 for (i = 0; i < fcb->cellhd.cols; i++)
00876 if (G_is_d_null_value(&buf[i]))
00877 G_set_c_null_value(&p[i], 1);
00878 else
00879 p[i] = (CELL) buf[i];
00880
00881 return G_put_c_raster_row(fd, p);
00882 }
00883
00884
00885
00886 static int put_raster_row(int fd, const void *buf, RASTER_MAP_TYPE data_type,
00887 int zeros_r_nulls)
00888 {
00889 struct fileinfo *fcb = &G__.fileinfo[fd];
00890
00891 static int (*convert_and_write_FtypeOtype[3][3]) () = {
00892 {
00893 NULL, convert_and_write_if, convert_and_write_id}, {
00894 convert_and_write_fi, NULL, convert_and_write_fd}, {
00895 convert_and_write_di, convert_and_write_df, NULL}
00896 };
00897
00898 if (!check_open("put_raster_row", fd, 0))
00899 return -1;
00900
00901 if (fcb->map_type != data_type)
00902 return convert_and_write_FtypeOtype[data_type][fcb->map_type] (fd,
00903 buf);
00904
00905 G_zero(G__.null_buf, fcb->cellhd.cols * sizeof(char));
00906
00907 switch (put_raster_data
00908 (fd, buf, fcb->cur_row, 0, fcb->cellhd.cols, zeros_r_nulls,
00909 data_type)) {
00910 case -1:
00911 return -1;
00912 case 0:
00913 return 1;
00914 }
00915
00916
00917 if (data_type == CELL_TYPE) {
00918 if (fcb->want_histogram)
00919 G_update_cell_stats(buf, fcb->cellhd.cols, &fcb->statf);
00920 G__row_update_range(buf, fcb->cellhd.cols, &fcb->range,
00921 zeros_r_nulls);
00922 }
00923 else
00924 G_row_update_fp_range(buf, fcb->cellhd.cols, &fcb->fp_range,
00925 data_type);
00926
00927 fcb->cur_row++;
00928
00929
00930 return G__put_null_value_row(fd, G__.null_buf);
00931 }