2021-03-05 18:31:16 +00:00
|
|
|
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
|
|
|
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
|
|
|
╞══════════════════════════════════════════════════════════════════════════════╡
|
|
|
|
│ Copyright 2021 Justine Alexandra Roberts Tunney │
|
|
|
|
│ │
|
|
|
|
│ Permission to use, copy, modify, and/or distribute this software for │
|
|
|
|
│ any purpose with or without fee is hereby granted, provided that the │
|
|
|
|
│ above copyright notice and this permission notice appear in all copies. │
|
|
|
|
│ │
|
|
|
|
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
|
|
|
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
|
|
|
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
|
|
|
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
|
|
|
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
|
|
|
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
|
|
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
|
|
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
|
|
|
#include "libc/assert.h"
|
|
|
|
#include "libc/fmt/conv.h"
|
2022-03-18 19:43:21 +00:00
|
|
|
#include "libc/fmt/divmod10.internal.h"
|
2022-04-21 20:44:59 +00:00
|
|
|
#include "libc/fmt/fmt.internal.h"
|
2021-03-05 18:31:16 +00:00
|
|
|
#include "libc/fmt/internal.h"
|
2021-10-14 00:27:13 +00:00
|
|
|
#include "libc/limits.h"
|
2022-10-10 05:38:28 +00:00
|
|
|
#include "libc/mem/reverse.internal.h"
|
2021-03-05 18:31:16 +00:00
|
|
|
|
|
|
|
#define BUFFER_SIZE 144
|
|
|
|
|
Import C++ Standard Template Library
You can now use the hardest fastest and most dangerous language there is
with Cosmopolitan. So far about 75% of LLVM libcxx has been added. A few
breaking changes needed to be made to help this go smoothly.
- Rename nothrow to dontthrow
- Rename nodiscard to dontdiscard
- Add some libm functions, e.g. lgamma, nan, etc.
- Change intmax_t from int128 to int64 like everything else
- Introduce %jjd formatting directive for int128_t
- Introduce strtoi128(), strtou128(), etc.
- Rename bsrmax() to bsr128()
Some of the templates that should be working currently are std::vector,
std::string, std::map, std::set, std::deque, etc.
2022-03-22 12:51:41 +00:00
|
|
|
uint128_t __udivmodti4(uint128_t, uint128_t, uint128_t *);
|
2021-03-05 18:31:16 +00:00
|
|
|
|
2021-04-24 20:58:34 +00:00
|
|
|
static int __fmt_ntoa_format(int out(const char *, void *, size_t), void *arg,
|
|
|
|
char *buf, unsigned len, bool negative,
|
|
|
|
unsigned log2base, unsigned prec, unsigned width,
|
2023-03-29 07:10:53 +00:00
|
|
|
unsigned char flags, const char *alphabet) {
|
Fix printf precision/field width being limited by internal buffer size (#799)
The C standard, when defining field width and precision, never gives
any limit on the values used for them (except, I believe, that they
fit within an int). In other words, if the user gives a field width of
32145 and a precision of 9218, the implementation has to handle these
values correctly. However, when such kinds of high numbers are used
with integer conversions, cosmopolitan is limited by an internal
buffer size of 144, which means precisions and field widths have to
fit within this, which violates the standard.
This means that for example, the following program:
#include <stdio.h>
#include <string.h>
int main()
{
char buf2[512] = {};
int i = snprintf(buf2, sizeof(buf2), "%.9999u", 10);
printf("%d %zu\n", i, strlen(buf2));
}
would, instead of printing "9999 511" (the correct output), instead
print "144 144" under cosmopolitan.
This patch fixes this.
2023-04-04 18:16:34 +00:00
|
|
|
unsigned i, prec_width_zeros;
|
|
|
|
char alternate_form_middle_char, sign_character;
|
|
|
|
unsigned actual_buf_len;
|
|
|
|
actual_buf_len = len;
|
|
|
|
prec_width_zeros = 0;
|
2021-03-05 18:31:16 +00:00
|
|
|
/* pad leading zeros */
|
Fix padding+minus flag on numbers for printf-family functions (#787)
The C standard states, for conversions using the d, i, b, B, o, u, x or X conversion specifiers:
> The precision specifies the minimum number of digits to appear; if
> the value being converted can be represented in fewer digits, it is
> expanded with leading zeros.
- C standard, 7.23.6.1. The fprintf function
However, cosmopolitan currently suppresses the addition of leading
zeros when the minus flag is set. This is not reflected by anything
within the C standard, meaning that behavior is incorrect.
This patch fixes this.
2023-03-25 18:39:25 +00:00
|
|
|
if (width && (flags & FLAGS_ZEROPAD) &&
|
|
|
|
(negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
|
|
|
|
width--;
|
|
|
|
}
|
Fix printf precision/field width being limited by internal buffer size (#799)
The C standard, when defining field width and precision, never gives
any limit on the values used for them (except, I believe, that they
fit within an int). In other words, if the user gives a field width of
32145 and a precision of 9218, the implementation has to handle these
values correctly. However, when such kinds of high numbers are used
with integer conversions, cosmopolitan is limited by an internal
buffer size of 144, which means precisions and field widths have to
fit within this, which violates the standard.
This means that for example, the following program:
#include <stdio.h>
#include <string.h>
int main()
{
char buf2[512] = {};
int i = snprintf(buf2, sizeof(buf2), "%.9999u", 10);
printf("%d %zu\n", i, strlen(buf2));
}
would, instead of printing "9999 511" (the correct output), instead
print "144 144" under cosmopolitan.
This patch fixes this.
2023-04-04 18:16:34 +00:00
|
|
|
if (len < prec) {
|
|
|
|
prec_width_zeros += (prec - len);
|
|
|
|
len = prec;
|
Fix padding+minus flag on numbers for printf-family functions (#787)
The C standard states, for conversions using the d, i, b, B, o, u, x or X conversion specifiers:
> The precision specifies the minimum number of digits to appear; if
> the value being converted can be represented in fewer digits, it is
> expanded with leading zeros.
- C standard, 7.23.6.1. The fprintf function
However, cosmopolitan currently suppresses the addition of leading
zeros when the minus flag is set. This is not reflected by anything
within the C standard, meaning that behavior is incorrect.
This patch fixes this.
2023-03-25 18:39:25 +00:00
|
|
|
}
|
Fix printf precision/field width being limited by internal buffer size (#799)
The C standard, when defining field width and precision, never gives
any limit on the values used for them (except, I believe, that they
fit within an int). In other words, if the user gives a field width of
32145 and a precision of 9218, the implementation has to handle these
values correctly. However, when such kinds of high numbers are used
with integer conversions, cosmopolitan is limited by an internal
buffer size of 144, which means precisions and field widths have to
fit within this, which violates the standard.
This means that for example, the following program:
#include <stdio.h>
#include <string.h>
int main()
{
char buf2[512] = {};
int i = snprintf(buf2, sizeof(buf2), "%.9999u", 10);
printf("%d %zu\n", i, strlen(buf2));
}
would, instead of printing "9999 511" (the correct output), instead
print "144 144" under cosmopolitan.
This patch fixes this.
2023-04-04 18:16:34 +00:00
|
|
|
if ((flags & FLAGS_ZEROPAD) && (len < width)) {
|
|
|
|
prec_width_zeros += (width - len);
|
|
|
|
len = width;
|
2021-03-05 18:31:16 +00:00
|
|
|
}
|
|
|
|
/* handle hash */
|
|
|
|
if (flags & FLAGS_HASH) {
|
Fix issues 774, 782 and 789 (printf precision bugs) (#790)
The C standard states that, within the context of a printf-family
function, when specifying the precision of a conversion specification:
> A negative precision argument is taken as if the precision were
> omitted.
- Quoth the C Standard, 7.23.6.1. The fprintf function
Cosmopolitan instead treated negative precision arguments as
though they had a value of 0, which was non-conforming. This
change fixes that. Another issue we found relates to:
> For o conversion, it increases the precision, if and only if
> necessary, to force the first digit of the result to be a zero (if
> the value and precision are both 0, a single 0 is printed).
- Quoth the C standard, 7.23.6.1.6. The fprintf function
When printing numbers in their alternative form, with a precision and
with a conversion specifier of o (octal), Cosmopolitan wasn't following
the standard in two ways:
1. When printing a value with a precision that results in 0-padding,
cosmopolitan would still add an extra 0 even though this should be
done "if and only if necessary"
2. When printing a value of 0 with a precision of 0, nothing is
printed, even though the standard specifically states that a single
0 is printed in this case
This change fixes those issues too. Furthermore, regression tests have
been introduced to ensure Cosmopolitan continues to be conformant
going forward.
Fixes #774
Fixes #782
Fixes #789
2023-03-29 08:11:48 +00:00
|
|
|
if ((!(flags & FLAGS_PRECISION) || log2base == 3) && len &&
|
Fix printf precision/field width being limited by internal buffer size (#799)
The C standard, when defining field width and precision, never gives
any limit on the values used for them (except, I believe, that they
fit within an int). In other words, if the user gives a field width of
32145 and a precision of 9218, the implementation has to handle these
values correctly. However, when such kinds of high numbers are used
with integer conversions, cosmopolitan is limited by an internal
buffer size of 144, which means precisions and field widths have to
fit within this, which violates the standard.
This means that for example, the following program:
#include <stdio.h>
#include <string.h>
int main()
{
char buf2[512] = {};
int i = snprintf(buf2, sizeof(buf2), "%.9999u", 10);
printf("%d %zu\n", i, strlen(buf2));
}
would, instead of printing "9999 511" (the correct output), instead
print "144 144" under cosmopolitan.
This patch fixes this.
2023-04-04 18:16:34 +00:00
|
|
|
((len >= prec) || (len >= width)) &&
|
|
|
|
(prec_width_zeros || buf[len - 1] == '0')) {
|
|
|
|
if (prec_width_zeros) {
|
|
|
|
--prec_width_zeros;
|
|
|
|
}
|
|
|
|
--len;
|
|
|
|
if (len < actual_buf_len) {
|
|
|
|
actual_buf_len = len;
|
|
|
|
}
|
|
|
|
if (len && (log2base == 4 || log2base == 1) &&
|
|
|
|
(prec_width_zeros || buf[len - 1] == '0')) {
|
|
|
|
if (prec_width_zeros) {
|
|
|
|
--prec_width_zeros;
|
|
|
|
}
|
|
|
|
--len;
|
|
|
|
if (len < actual_buf_len) {
|
|
|
|
actual_buf_len = len;
|
|
|
|
}
|
2021-03-05 18:31:16 +00:00
|
|
|
}
|
|
|
|
}
|
Fix printf precision/field width being limited by internal buffer size (#799)
The C standard, when defining field width and precision, never gives
any limit on the values used for them (except, I believe, that they
fit within an int). In other words, if the user gives a field width of
32145 and a precision of 9218, the implementation has to handle these
values correctly. However, when such kinds of high numbers are used
with integer conversions, cosmopolitan is limited by an internal
buffer size of 144, which means precisions and field widths have to
fit within this, which violates the standard.
This means that for example, the following program:
#include <stdio.h>
#include <string.h>
int main()
{
char buf2[512] = {};
int i = snprintf(buf2, sizeof(buf2), "%.9999u", 10);
printf("%d %zu\n", i, strlen(buf2));
}
would, instead of printing "9999 511" (the correct output), instead
print "144 144" under cosmopolitan.
This patch fixes this.
2023-04-04 18:16:34 +00:00
|
|
|
alternate_form_middle_char = '\0';
|
|
|
|
if ((log2base == 4 || log2base == 1)) {
|
|
|
|
++len;
|
|
|
|
alternate_form_middle_char =
|
|
|
|
alphabet[17]; // x, X or b (for the corresponding conversion
|
|
|
|
// specifiers)
|
2021-03-05 18:31:16 +00:00
|
|
|
}
|
Fix printf precision/field width being limited by internal buffer size (#799)
The C standard, when defining field width and precision, never gives
any limit on the values used for them (except, I believe, that they
fit within an int). In other words, if the user gives a field width of
32145 and a precision of 9218, the implementation has to handle these
values correctly. However, when such kinds of high numbers are used
with integer conversions, cosmopolitan is limited by an internal
buffer size of 144, which means precisions and field widths have to
fit within this, which violates the standard.
This means that for example, the following program:
#include <stdio.h>
#include <string.h>
int main()
{
char buf2[512] = {};
int i = snprintf(buf2, sizeof(buf2), "%.9999u", 10);
printf("%d %zu\n", i, strlen(buf2));
}
would, instead of printing "9999 511" (the correct output), instead
print "144 144" under cosmopolitan.
This patch fixes this.
2023-04-04 18:16:34 +00:00
|
|
|
++len;
|
2021-03-05 18:31:16 +00:00
|
|
|
}
|
Fix printf precision/field width being limited by internal buffer size (#799)
The C standard, when defining field width and precision, never gives
any limit on the values used for them (except, I believe, that they
fit within an int). In other words, if the user gives a field width of
32145 and a precision of 9218, the implementation has to handle these
values correctly. However, when such kinds of high numbers are used
with integer conversions, cosmopolitan is limited by an internal
buffer size of 144, which means precisions and field widths have to
fit within this, which violates the standard.
This means that for example, the following program:
#include <stdio.h>
#include <string.h>
int main()
{
char buf2[512] = {};
int i = snprintf(buf2, sizeof(buf2), "%.9999u", 10);
printf("%d %zu\n", i, strlen(buf2));
}
would, instead of printing "9999 511" (the correct output), instead
print "144 144" under cosmopolitan.
This patch fixes this.
2023-04-04 18:16:34 +00:00
|
|
|
sign_character = '\0';
|
|
|
|
if (negative) {
|
|
|
|
++len;
|
|
|
|
sign_character = '-';
|
|
|
|
} else if (flags & FLAGS_PLUS) {
|
|
|
|
++len;
|
|
|
|
sign_character = '+'; /* ignore the space if the '+' exists */
|
|
|
|
} else if (flags & FLAGS_SPACE) {
|
|
|
|
++len;
|
|
|
|
sign_character = ' ';
|
2021-03-05 18:31:16 +00:00
|
|
|
}
|
|
|
|
/* pad spaces up to given width */
|
|
|
|
if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
|
|
|
|
if (len < width) {
|
|
|
|
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
|
|
|
}
|
|
|
|
}
|
Fix printf precision/field width being limited by internal buffer size (#799)
The C standard, when defining field width and precision, never gives
any limit on the values used for them (except, I believe, that they
fit within an int). In other words, if the user gives a field width of
32145 and a precision of 9218, the implementation has to handle these
values correctly. However, when such kinds of high numbers are used
with integer conversions, cosmopolitan is limited by an internal
buffer size of 144, which means precisions and field widths have to
fit within this, which violates the standard.
This means that for example, the following program:
#include <stdio.h>
#include <string.h>
int main()
{
char buf2[512] = {};
int i = snprintf(buf2, sizeof(buf2), "%.9999u", 10);
printf("%d %zu\n", i, strlen(buf2));
}
would, instead of printing "9999 511" (the correct output), instead
print "144 144" under cosmopolitan.
This patch fixes this.
2023-04-04 18:16:34 +00:00
|
|
|
if (sign_character != '\0' && out(&sign_character, arg, 1) == -1) return -1;
|
|
|
|
if (flags & FLAGS_HASH) {
|
|
|
|
if (out("0", arg, 1) == -1) return -1;
|
|
|
|
if (alternate_form_middle_char != '\0' &&
|
|
|
|
out(&alternate_form_middle_char, arg, 1) == -1)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
for (i = 0; i < prec_width_zeros; ++i)
|
|
|
|
if (out("0", arg, 1) == -1) return -1;
|
|
|
|
reverse(buf, actual_buf_len);
|
|
|
|
if (out(buf, arg, actual_buf_len) == -1) return -1;
|
2021-03-05 18:31:16 +00:00
|
|
|
/* append pad spaces up to given width */
|
|
|
|
if (flags & FLAGS_LEFT) {
|
2021-04-24 20:58:34 +00:00
|
|
|
if (len < width) {
|
|
|
|
if (__fmt_pad(out, arg, width - len) == -1) return -1;
|
2021-03-05 18:31:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-04-24 20:58:34 +00:00
|
|
|
int __fmt_ntoa2(int out(const char *, void *, size_t), void *arg,
|
Import C++ Standard Template Library
You can now use the hardest fastest and most dangerous language there is
with Cosmopolitan. So far about 75% of LLVM libcxx has been added. A few
breaking changes needed to be made to help this go smoothly.
- Rename nothrow to dontthrow
- Rename nodiscard to dontdiscard
- Add some libm functions, e.g. lgamma, nan, etc.
- Change intmax_t from int128 to int64 like everything else
- Introduce %jjd formatting directive for int128_t
- Introduce strtoi128(), strtou128(), etc.
- Rename bsrmax() to bsr128()
Some of the templates that should be working currently are std::vector,
std::string, std::map, std::set, std::deque, etc.
2022-03-22 12:51:41 +00:00
|
|
|
uint128_t value, bool neg, unsigned log2base, unsigned prec,
|
2021-04-24 20:58:34 +00:00
|
|
|
unsigned width, unsigned flags, const char *alphabet) {
|
Import C++ Standard Template Library
You can now use the hardest fastest and most dangerous language there is
with Cosmopolitan. So far about 75% of LLVM libcxx has been added. A few
breaking changes needed to be made to help this go smoothly.
- Rename nothrow to dontthrow
- Rename nodiscard to dontdiscard
- Add some libm functions, e.g. lgamma, nan, etc.
- Change intmax_t from int128 to int64 like everything else
- Introduce %jjd formatting directive for int128_t
- Introduce strtoi128(), strtou128(), etc.
- Rename bsrmax() to bsr128()
Some of the templates that should be working currently are std::vector,
std::string, std::map, std::set, std::deque, etc.
2022-03-22 12:51:41 +00:00
|
|
|
uint128_t remainder;
|
2021-03-05 18:31:16 +00:00
|
|
|
unsigned len, count, digit;
|
|
|
|
char buf[BUFFER_SIZE];
|
|
|
|
len = 0;
|
Fix printf precision/field width being limited by internal buffer size (#799)
The C standard, when defining field width and precision, never gives
any limit on the values used for them (except, I believe, that they
fit within an int). In other words, if the user gives a field width of
32145 and a precision of 9218, the implementation has to handle these
values correctly. However, when such kinds of high numbers are used
with integer conversions, cosmopolitan is limited by an internal
buffer size of 144, which means precisions and field widths have to
fit within this, which violates the standard.
This means that for example, the following program:
#include <stdio.h>
#include <string.h>
int main()
{
char buf2[512] = {};
int i = snprintf(buf2, sizeof(buf2), "%.9999u", 10);
printf("%d %zu\n", i, strlen(buf2));
}
would, instead of printing "9999 511" (the correct output), instead
print "144 144" under cosmopolitan.
This patch fixes this.
2023-04-04 18:16:34 +00:00
|
|
|
/* we check for log2base != 3 because otherwise we'll print nothing for a
|
|
|
|
* value of 0 with precision 0 when # mandates that one be printed */
|
|
|
|
if (!value && log2base != 3) flags &= ~FLAGS_HASH;
|
2021-03-05 18:31:16 +00:00
|
|
|
if (value || !(flags & FLAGS_PRECISION)) {
|
|
|
|
count = 0;
|
|
|
|
do {
|
|
|
|
if (!log2base) {
|
2021-10-14 00:27:13 +00:00
|
|
|
if (value <= UINT64_MAX) {
|
2022-03-18 19:43:21 +00:00
|
|
|
value = DivMod10(value, &digit);
|
2021-10-14 00:27:13 +00:00
|
|
|
} else {
|
|
|
|
value = __udivmodti4(value, 10, &remainder);
|
|
|
|
digit = remainder;
|
|
|
|
}
|
2021-03-05 18:31:16 +00:00
|
|
|
} else {
|
|
|
|
digit = value;
|
|
|
|
digit &= (1u << log2base) - 1;
|
|
|
|
value >>= log2base;
|
|
|
|
}
|
|
|
|
if ((flags & FLAGS_GROUPING) && count == 3) {
|
|
|
|
buf[len++] = ',';
|
|
|
|
count = 1;
|
|
|
|
} else {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
buf[len++] = alphabet[digit];
|
|
|
|
} while (value);
|
2022-10-10 05:38:28 +00:00
|
|
|
_npassert(count <= BUFFER_SIZE);
|
2021-03-05 18:31:16 +00:00
|
|
|
}
|
|
|
|
return __fmt_ntoa_format(out, arg, buf, len, neg, log2base, prec, width,
|
2023-03-29 07:10:53 +00:00
|
|
|
flags, alphabet);
|
2021-03-05 18:31:16 +00:00
|
|
|
}
|
|
|
|
|
2023-05-10 14:32:15 +00:00
|
|
|
int __fmt_ntoa(int out(const char *, void *, size_t), void *arg,
|
|
|
|
uint128_t value, unsigned char signbit, unsigned long log2base,
|
2021-03-05 18:31:16 +00:00
|
|
|
unsigned long prec, unsigned long width, unsigned char flags,
|
|
|
|
const char *lang) {
|
|
|
|
bool neg;
|
2023-05-10 14:32:15 +00:00
|
|
|
uint128_t sign;
|
2021-03-05 18:31:16 +00:00
|
|
|
|
Fix padding+minus flag on numbers for printf-family functions (#787)
The C standard states, for conversions using the d, i, b, B, o, u, x or X conversion specifiers:
> The precision specifies the minimum number of digits to appear; if
> the value being converted can be represented in fewer digits, it is
> expanded with leading zeros.
- C standard, 7.23.6.1. The fprintf function
However, cosmopolitan currently suppresses the addition of leading
zeros when the minus flag is set. This is not reflected by anything
within the C standard, meaning that behavior is incorrect.
This patch fixes this.
2023-03-25 18:39:25 +00:00
|
|
|
/* ignore '0' flag when prec or minus flag is given */
|
|
|
|
if (flags & (FLAGS_PRECISION | FLAGS_LEFT)) {
|
2021-03-05 18:31:16 +00:00
|
|
|
flags &= ~FLAGS_ZEROPAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no plus / space flag for u, x, X, o, b */
|
|
|
|
if (!(flags & FLAGS_ISSIGNED)) {
|
|
|
|
flags &= ~(FLAGS_PLUS | FLAGS_SPACE);
|
|
|
|
}
|
|
|
|
|
|
|
|
neg = 0;
|
|
|
|
sign = 1;
|
|
|
|
sign <<= signbit;
|
|
|
|
value &= sign | (sign - 1);
|
|
|
|
if (flags & FLAGS_ISSIGNED) {
|
|
|
|
if (value != sign) {
|
|
|
|
if (value & sign) {
|
|
|
|
value = ~value + 1;
|
|
|
|
value &= sign | (sign - 1);
|
|
|
|
neg = 1;
|
|
|
|
}
|
|
|
|
value &= sign - 1;
|
|
|
|
} else {
|
|
|
|
neg = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return __fmt_ntoa2(out, arg, value, neg, log2base, prec, width, flags, lang);
|
|
|
|
}
|