コード例 #1
0
static int bsd_number( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length) {
  int nread;
  CHECK_LENGTH( 1);
  uint8_t opcode = buffer[0];

  CHECK_DECODE( decodeInteger( ctx, x, buffer, length, &BS_NUMBER_INTEGER));

  /* Only go on if integer decoding failed */
  switch( opcode) {

  case BS_N_NULL:
    decodeNull( ctx, x);
    break;

  case BS_N_FLOAT32:
    CHECK_LENGTH( 5);
    x->kind = BSD_DOUBLE;
    float f;
    memcpy( &f, buffer + 1, sizeof(float));
    ntoh( &f, sizeof(float), sendian.float_);
    x->content.d = f;
    break;

  case BS_N_FLOAT64:
    CHECK_LENGTH( 9);
    x->kind = BSD_DOUBLE;
    memcpy( &(x->content.d), buffer + 1, sizeof(double));
    ntoh( &(x->content.d), sizeof(double), sendian.double_);
    break;
  default: return bsd_error( x, BSD_EINVALID);
  }

  return nread;
}
コード例 #2
0
static int bsd_uis( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length) {
  int nread;
  CHECK_LENGTH( 1);
  uint8_t opcode = buffer[0];

  CHECK_DECODE( decodeString( ctx, x, buffer, length, &BS_UIS_STRING));
  x->kind = BSD_INT;
  if( 0x3b <= opcode && opcode <= 0xc6) {
    /* Tiny unsigned */
    x->content.i = opcode - 0x3b;
  } else if( 0xc7 <= opcode && opcode <= 0xe6) {
    /* Small unsigned */
    CHECK_LENGTH( 2);
    x->content.i = ((opcode - 0xc7) << 8) + buffer[1] + BS_UTI_MAX + 1;
  } else if( 0xe7 <= opcode && opcode <= 0xf6) {
    /* Medium unsigned */
    CHECK_LENGTH( 3);
    x->content.i = ((opcode - 0xe7) << 16) + (buffer[1] << 8) + buffer[2] + BS_USI_MAX + 1;
  } else if( 0xf7 <= opcode && opcode <= 0xfe) {
    /* Large unsigned */
    CHECK_LENGTH( 4);
    x->content.i = ((opcode - 0xf7) << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3] + BS_UMI_MAX + 1;
  } else if( 0xff == opcode) {
    /* XLarge unsigned */
    CHECK_LENGTH( 5);
    x->content.i = ((uint32_t)buffer[1] << 24) + ((uint32_t)buffer[2] << 16) + ((uint32_t)buffer[3] << 8) + (uint32_t)buffer[4];
  } else if( 0x00 == opcode) {
    decodeNull( ctx, x);
  } else {
    return bsd_error( x, BSD_EINVALID);
  }

  return nread;
}
コード例 #3
0
ファイル: file.c プロジェクト: 50wu/gpdb
/*
 * FUNCTION UTL_FILE.PUTF(file UTL_FILE.FILE_TYPE,
 *			format text,
 *			arg1 text,
 *			arg2 text,
 *			arg3 text,
 *			arg4 text,
 *			arg5 text)
 *	    RETURNS bool;
 *
 * Puts formated data to file. Allows %s like subst symbol.
 *
 * Exception:
 *  INVALID_FILEHANDLE, INVALID_OPERATION, WRITE_ERROR
 */
Datum
utl_file_putf(PG_FUNCTION_ARGS)
{
	FILE   *f;
	char   *format;
	int		max_linesize = 0;
	int		encoding = 0;
	int		format_length;
	char   *fpt;
	int		cur_par = 0;
	int		cur_len = 0;

	CHECK_FILE_HANDLE();
	f = get_stream(PG_GETARG_INT32(0), &max_linesize, &encoding);

	NOT_NULL_ARG(1);
	format = encode_text(encoding, PG_GETARG_TEXT_P(1), &format_length);

	for (fpt = format; format_length > 0; fpt++, format_length--)
	{
		if (format_length == 1)
		{
			/* last char */
			CHECK_LENGTH(++cur_len);
			if (fputc(*fpt, f) == EOF)
				CHECK_ERRNO_PUT();
			continue;
		}
		/* ansi compatible string */
		if (fpt[0] == '\\' && fpt[1] == 'n')
		{
			CHECK_LENGTH(++cur_len);
			if (fputc('\n', f) == EOF)
				CHECK_ERRNO_PUT();
			fpt++; format_length--;
			continue;
		}
		if (fpt[0] == '%')
		{
			if (fpt[1] == '%')
			{
				CHECK_LENGTH(++cur_len);
				if (fputc('%', f) == EOF)
					CHECK_ERRNO_PUT();
			}
			else if (fpt[1] == 's' && ++cur_par <= 5 && !PG_ARGISNULL(cur_par + 1))
			{
				cur_len += do_write(fcinfo, cur_par + 1, f, max_linesize - cur_len, encoding);
			}
			fpt++; format_length--;
			continue;
		}
		CHECK_LENGTH(++cur_len);
		if (fputc(fpt[0], f) == EOF)
			CHECK_ERRNO_PUT();
	}

	PG_RETURN_BOOL(true);
}
コード例 #4
0
static int bsd_global( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length) {
  int nread;
  CHECK_LENGTH( 1);
  uint8_t opcode = buffer[0];


  CHECK_DECODE( decodeInteger( ctx, x, buffer, length, &BS_GLOBAL_INTEGER));
  CHECK_DECODE( decodeString( ctx, x, buffer, length, &BS_GLOBAL_STRING));
  CHECK_DECODE( decodeCollection( ctx, x, buffer, length, NULL, &BS_GLOBAL_LIST));
  CHECK_DECODE( decodeCollection( ctx, x, buffer, length, NULL, &BS_GLOBAL_MAP));
  CHECK_DECODE( decodeClass( ctx, x, buffer, length));
  if( 0x60 <= opcode && opcode <= 0x6f) { /* object (short form) */
    CHECK_ERROR( bsd_object( ctx, x, opcode - 0x60));
    return nread;
  }
  switch( opcode) {
  case BS_G_NULL: /* null */
    decodeNull( ctx, x);
    break;
  case 0x01: /* boolean true */
    x->kind = BSD_BOOL;
    x->content.boolean = 1;
    break;
  case 0x02: /* boolean false */
    x->kind = BSD_BOOL;
    x->content.boolean = 0;
    break;
  case 0x70: /* object (long form) */
    CHECK_SUBDECODE( bsd_uis( ctx, x, buffer + nread, length - nread), BSD_INT);
    CHECK_ERROR( bsd_object( ctx, x, x->content.i + 0x10));
    break;
  case BS_G_FLOAT32: /* float */
    CHECK_LENGTH( 5);
    x->kind = BSD_DOUBLE;
    float f;
    memcpy( &f, buffer + 1, sizeof(float));
    ntoh( &f, sizeof(float), sendian.float_);
    x->content.d = f;
    break;
  case BS_G_FLOAT64: /* double */
    CHECK_LENGTH( 9);
    x->kind = BSD_DOUBLE;
    memcpy( &(x->content.d), buffer + 1, sizeof(double));
    ntoh( &(x->content.d), sizeof(double), sendian.double_);
    break;
  default: return bsd_error( x, BSD_EINVALID);
  }

  return nread;
}
コード例 #5
0
static int decodeCollection( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length, union bsd_stackframecontent_t **f, const bs_coll_encoding_t *enc) {
  int nread = 0;
  uint8_t opcode = buffer[0];
  CHECK_LENGTH( 1);

  if( enc->empty_opcode == opcode) {
    /* empty container */
    x->kind = bsd_typeFromFrameKind( enc->fixed_kind);
    x->content.length = 0;
    CHECK_ERROR( openContainer( ctx, enc->fixed_kind, BS_CTXID_GLOBAL, 0, f));
  } else if( enc->small_untyped_opcode <= opcode && opcode <= enc->small_untyped_opcode + enc->small_limit - 1) {
    /* Small untyped container */
    x->kind = bsd_typeFromFrameKind( enc->fixed_kind);
    x->content.length = opcode - enc->small_untyped_opcode + 1;
    CHECK_ERROR( openContainer( ctx, enc->fixed_kind, BS_CTXID_GLOBAL, x->content.length, f));
  } else if( enc->long_untyped_opcode == opcode) {
    /* Long untyped container */
    CHECK_SUBDECODE( bsd_uis( ctx, x, buffer + 1, length + 1), BSD_INT);
    x->kind = bsd_typeFromFrameKind( enc->fixed_kind);
    x->content.length = x->content.i + enc->small_limit + 1;
    CHECK_ERROR( openContainer( ctx, enc->fixed_kind, BS_CTXID_GLOBAL, x->content.length, f));
  } else if( enc->variable_untyped_opcode == opcode) {
    /* Variable untyped container */
    x->kind = bsd_typeFromFrameKind( enc->variable_kind);
    CHECK_ERROR( openContainer( ctx, enc->variable_kind, BS_CTXID_GLOBAL, -1, f));
  } else if( enc->small_typed_opcode <= opcode && opcode <= enc->small_typed_opcode + enc->small_limit - 1) {
    /* Small typed container */
    CHECK_LENGTH( 2);
    x->kind = bsd_typeFromFrameKind( enc->fixed_kind);
    x->content.length = opcode - enc->small_typed_opcode + 1;
    CHECK_ERROR( openContainer( ctx, enc->fixed_kind, buffer[1], x->content.length, f));
  } else if( enc->long_typed_opcode == opcode) {
    /* Long typed container */
    CHECK_SUBDECODE( bsd_uis( ctx, x, buffer + 1, length + 1), BSD_INT);
    CHECK_LENGTH( nread + 1);
    x->kind = bsd_typeFromFrameKind( enc->fixed_kind);
    x->content.length = x->content.i + enc->small_limit + 1;
    CHECK_ERROR( openContainer( ctx, enc->fixed_kind, buffer[nread-1], x->content.length, f));
  } else if( enc->variable_typed_opcode == opcode) {
    /* Variable untyped container */
    CHECK_LENGTH( 2);
    x->kind = bsd_typeFromFrameKind( enc->variable_kind);
    CHECK_ERROR( openContainer( ctx, enc->variable_kind, buffer[1], -1, f));
  } else {
    return 0;
  }
  return nread;
}
コード例 #6
0
ファイル: ipv6.c プロジェクト: kwitaszczyk/freebsd
void
fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av, int cblen)
{
       uint8_t type;

       CHECK_LENGTH(cblen, F_INSN_SIZE(ipfw_insn_icmp6));

       bzero(cmd, sizeof(*cmd));
       while (*av) {
	   if (*av == ',')
	       av++;
	   type = strtoul(av, &av, 0);
	   if (*av != ',' && *av != '\0')
	       errx(EX_DATAERR, "invalid ICMP6 type");
	   /*
	    * XXX: shouldn't this be 0xFF?  I can't see any reason why
	    * we shouldn't be able to filter all possiable values
	    * regardless of the ability of the rest of the kernel to do
	    * anything useful with them.
	    */
	   if (type > ICMP6_MAXTYPE)
	       errx(EX_DATAERR, "ICMP6 type out of range");
	   cmd->d[type / 32] |= ( 1 << (type % 32));
       }
       cmd->o.opcode = O_ICMP6TYPE;
       cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);
}
コード例 #7
0
/**
 * Try to decode a number under given context.
 * This algorithm assume that all number kind are consecutive and in the same order.
 */
static int decodeInteger( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length,
    const bs_integer_encoding_t *enc) {
  int nread = 0;
  uint8_t opcode = buffer[0];
  CHECK_LENGTH( 1);

  x->kind = BSD_INT;
  if( (enc->tiny_zero_opcode + enc->tiny_min) <= opcode && opcode <= (enc->tiny_zero_opcode + enc->tiny_max)) {
    /* tiny number */
    x->content.i = opcode - enc->tiny_zero_opcode;
  } else if( enc->small_pos_opcode <= opcode && opcode < enc->small_neg_opcode) {
    /* small positive number */
    CHECK_LENGTH( 2);
    x->content.i = ((opcode - enc->small_pos_opcode) << 8) + buffer[1] + enc->tiny_max + 1;
  } else if( enc->small_neg_opcode <= opcode && opcode < enc->medium_pos_opcode) {
    /* small negative number */
    CHECK_LENGTH( 2);
    x->content.i = -(((opcode - enc->small_neg_opcode) << 8) + buffer[1]) + enc->tiny_min - 1;
  } else if( enc->medium_pos_opcode <= opcode && opcode < enc->medium_neg_opcode) {
    /* medium positive number */
    CHECK_LENGTH( 3);
    x->content.i = ((opcode - enc->medium_pos_opcode) << 16) + (buffer[1] << 8) + buffer[2] + enc->small_max + 1;
  } else if( enc->medium_neg_opcode <= opcode && opcode < enc->large_pos_opcode) {
    /* medium negative number */
    CHECK_LENGTH( 3);
    x->content.i = -(((opcode - enc->medium_neg_opcode) << 16) + (buffer[1] << 8) + buffer[2]) + enc->small_min - 1;
  } else if( enc->large_pos_opcode <= opcode && opcode < enc->large_neg_opcode) {
    /* large positive opcode */
    CHECK_LENGTH( 4);
    x->content.i = ((opcode - enc->large_pos_opcode) << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3] + enc->medium_max + 1;
  } else if( enc->large_neg_opcode <= opcode && opcode <= enc->last_large_neg_opcode) {
    /* large negative opcode */
    CHECK_LENGTH( 4);
    x->content.i = -(((opcode - enc->large_neg_opcode) << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3]) + enc->medium_min - 1;
  } else if( enc->int32_opcode == opcode) {
    /* big endian 32 bits integer */
    CHECK_LENGTH( 5);
    int32_t val;
    memcpy( &val, buffer + 1, sizeof(int32_t));
    ntoh( &val, sizeof(int32_t), sendian.int32_);
    x->content.i = val;
  } else if( enc->int64_opcode == opcode) {
    /* big endian 64 bits integer */
    CHECK_LENGTH( 9);
    memcpy( &(x->content.i), buffer + 1, sizeof(int64_t));
    ntoh( &(x->content.i), sizeof(int64_t), sendian.int64_);
  } else {
    return 0;
  }

  return nread;
}
コード例 #8
0
static int bsd_chunked( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length) {
  int nread;
  CHECK_LENGTH( 2);
  size_t chunksize = (buffer[0] << 8) + buffer[1];

  if( 0 == chunksize) {
    x->kind = BSD_CLOSE;
    x->content.cont_type = BSD_CHUNKED_STRING;
    ctx->stacksize--;
  } else {
    CHECK_LENGTH( chunksize + 2);
    x->kind = BSD_CHUNK;
    x->content.chunk.data = (const char *) buffer + 2;
    x->content.chunk.length = chunksize;
  }

  return nread;
}
コード例 #9
0
static int bsd_int32( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length) {
  int nread;
  union { uint32_t u; int32_t i; } val;

  CHECK_LENGTH( 4);
  val.u = ((uint32_t)buffer[0] << 24) + ((uint32_t)buffer[1] << 16) + ((uint32_t)buffer[2] << 8) + (uint32_t)buffer[3];
  x->kind = BSD_INT;
  x->content.i = val.i;

  // check for escape sequence
  if( 0x80000000U == val.u) {
    CHECK_LENGTH( 5);
    switch( buffer[4]) {
    case 0x00: decodeNull( ctx, x); break;
    case 0x01: break;
    default: return bsd_error( x, BSD_EINVALID);
    }
  }

  return nread;
}
コード例 #10
0
static int decodeString( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length, const bs_string_encoding_t *enc) {
  int nread = 0;
  uint8_t opcode = buffer[0];
  CHECK_LENGTH( 1);

  x->kind = BSD_STRING;
  if( enc->small_opcode <= opcode && opcode < enc->medium_opcode) {
    /* Small string */
    size_t len = opcode - enc->small_opcode;
    CHECK_LENGTH( len + 1);
    bsd_string( x, len, (const char *) buffer + 1);
  } else if( enc->medium_opcode <= opcode && opcode < enc->large_opcode) {
    /* Medium string */
    CHECK_LENGTH( 2);
    size_t len = ((opcode - enc->medium_opcode) << 8) + buffer[1] + enc->small_limit + 1;
    CHECK_LENGTH( len + 2);
    bsd_string( x, len, (const char *) buffer + 2);
  } else if( enc->large_opcode == opcode) {
    /* Large string */
    CHECK_LENGTH( 3);
    size_t len = ((buffer[1]) << 8) + buffer[2] + enc->medium_limit + 1;
    CHECK_LENGTH( len + 3);
    bsd_string( x, len, (const char *) buffer + 3);
  } else if( enc->chunked_opcode == opcode) {
    CHECK_ERROR( openContainer( ctx, BS_FCHUNKED, BS_CTXID_CHUNKED, -1, NULL));
    x->kind = BSD_CHUNKED_STRING;
  }
  else {
    return 0;
  }
  return nread;
}
コード例 #11
0
ファイル: unicode.c プロジェクト: ryo/netbsd-src
size_t
utf16_to_utf8(char *dst, size_t dst_len,
	      const uint16_t *src, size_t src_len,
	      int flags, int *errp)
{
	uint8_t spos, dpos;
	int error;

#define CHECK_LENGTH(l)	(dpos > dst_len-(l) ? dst=NULL : NULL)
#define ADD_BYTE(b)	(dst ? dst[dpos] = (b) : 0, dpos++)

	error = 0;
	dpos = 0;
	for (spos = 0; spos < src_len; spos++) {
		if (src[spos] < 0x80) {
			CHECK_LENGTH(1);
			ADD_BYTE(src[spos]);
		} else if (src[spos] < 0x800) {
			CHECK_LENGTH(2);
			ADD_BYTE(0xc0 | (src[spos]>>6));
			ADD_BYTE(0x80 | (src[spos] & 0x3f));
		} else if ((src[spos] & 0xdc00) == 0xd800) {
コード例 #12
0
static int bsd_double( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length) {
  int nread;
  union { uint64_t u; double d; } val;

  CHECK_LENGTH( 8);
  memcpy( &val.d, buffer, sizeof(double));
  ntoh( &val.d, sizeof(double), sendian.float_);
  x->content.d = val.d;
  x->kind = BSD_DOUBLE;

  // check for escape sequence
  if( 0xFFFFFFFFFFFFFFFFULL == val.u) {
    CHECK_LENGTH( 9);
    switch( buffer[8]) {
    case 0x00: decodeNull( ctx, x); break;
    case 0x01: break;
    default: return bsd_error( x, BSD_EINVALID);
    }
  }

  return nread;
}
コード例 #13
0
static int bsd_float( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length) {
  int nread;
  union { uint32_t u; float f; } val;

  CHECK_LENGTH( 4);
  memcpy( &val.f, buffer, sizeof(float));
  ntoh( &val.f, sizeof(float), sendian.float_);
  x->content.d = val.f;
  x->kind = BSD_DOUBLE;

  // check for escape sequence
  if( 0xFFFFFFFFU == val.u) {
    CHECK_LENGTH( 5);
    switch( buffer[4]) {
    case 0x00: decodeNull( ctx, x); break;
    case 0x01: break;
    default: return bsd_error( x, BSD_EINVALID);
    }
  }

  return nread;
}
コード例 #14
0
static int bsd_listmap( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length) {
  int nread;
  CHECK_LENGTH( 1);
  uint8_t opcode = buffer[0];

  CHECK_DECODE( decodeCollection( ctx, x, buffer, length, NULL, &BS_LISTMAP_LIST));
  CHECK_DECODE( decodeCollection( ctx, x, buffer, length, NULL, &BS_LISTMAP_MAP));
  if( 0x00 == opcode) {
    decodeNull( ctx, x);
  } else {
    return bsd_error( x, BSD_EINVALID);
  }

  return nread;
}
コード例 #15
0
ファイル: file.c プロジェクト: 50wu/gpdb
/* fwrite(encode(args[n], encoding), f) */
static int
do_write(PG_FUNCTION_ARGS, int n, FILE *f, int max_linesize, int encoding)
{
	text	   *arg = PG_GETARG_TEXT_P(n);
	char	   *str;
	int			len;

	str = encode_text(encoding, arg, &len);
	CHECK_LENGTH(len);

	if (fwrite(str, 1, len, f) != len)
		CHECK_ERRNO_PUT();

	if (VARDATA(arg) != str)
		pfree(str);
	PG_FREE_IF_COPY(arg, n);

	return len;
}
コード例 #16
0
static int decodeClass( bsd_ctx_t *ctx, bsd_data_t *x, const uint8_t *buffer, int length) {
  int nread, i, named, fieldnread;
  size_t nfields, blocksize, namesize;
  bs_classid_t classid;
  const char *name;
  const uint8_t *fieldbuffer;
  void *endofclass;
  bs_class_t *classdef;

  CHECK_LENGTH( 1);
  switch( buffer[0]) {
  case 0x71: named = 1; break;
  case 0x72: named = 0; name = NULL; namesize = 0; break;
  default: return 0;
  }

  // decoding is done in two passes: 1st to compute the size and allocate right amount of memory,
  // second one to make the actual data copy.
  blocksize = sizeof( bs_class_t);

  CHECK_SUBDECODE( bsd_uis( ctx, x, buffer + nread, length - nread ), BSD_INT);
  classid = x->content.i;
  if( named) {
    CHECK_SUBDECODE( bsd_uis( ctx, x, buffer + nread, length - nread ), BSD_STRING);
    name = x->content.string.data;
    namesize = x->content.string.length + 1; // add null terminator
  }
  CHECK_SUBDECODE( bsd_uis( ctx, x, buffer + nread, length - nread), BSD_INT);
  nfields = x->content.i;

  // allocate class structure
  blocksize = sizeof( bs_class_t) + namesize + nfields * sizeof( struct bs_field_t);

  // 1st pass
  fieldbuffer = buffer;
  fieldnread = nread;
  for( i=0; i<nfields; i++) {
    if( named) {
      CHECK_SUBDECODE( bsd_uis( ctx, x, buffer + nread, length - nread ), BSD_STRING);
      blocksize += x->content.length + 1;
    }
    CHECK_LENGTH( nread + 1);
  }

  // memory allocation
  classdef = BS_MEM_ALLOC( blocksize);
  if( NULL == classdef) return bsd_error( x, BSD_EMEMORY);
  classdef->classid = classid;
  classdef->nfields = nfields;
  classdef->mode = BS_CLASS_MANAGED;
  endofclass = ((void *)classdef) + sizeof( bs_class_t);
  classdef->classname = NULL;
  if( named) {
    memcpy( endofclass, name, namesize-1);
    ((char *)endofclass)[namesize-1] = '\0';
    classdef->classname = endofclass;
    endofclass += namesize;
  }
  classdef->fields = endofclass;
  endofclass += nfields * sizeof( struct bs_field_t);

  // 2nd pass (no possible parsing errors since processing is the same as 1st pass)
  buffer = fieldbuffer;
  nread = fieldnread;
  for( i=0; i<classdef->nfields; i++) {
    if( named) {
      CHECK_SUBDECODE( bsd_uis( ctx, x, buffer + nread, length - nread ), BSD_STRING);
      memcpy( endofclass, x->content.string.data, x->content.string.length);
      ((char *)endofclass)[x->content.string.length] = '\0';
      classdef->fields[i].name = endofclass;
      endofclass += x->content.string.length + 1;
    } else {
      classdef->fields[i].name = NULL;
    }
    CHECK_LENGTH( nread + 1);
    classdef->fields[i].ctxid = buffer[nread - 1];
  }

  bsd_addClass( ctx, classdef);
  x->kind = BSD_CLASSDEF;
  x->content.classdef = classdef;
  return nread;
}