in serializer/src/agenttypesystem.c [3080:3871]
AGENT_DATA_TYPES_RESULT CreateAgentDataType_From_String(const char* source, AGENT_DATA_TYPE_TYPE type, AGENT_DATA_TYPE* agentData)
{
AGENT_DATA_TYPES_RESULT result;
if ((source == NULL) ||
(agentData == NULL))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
switch (type)
{
default:
result = AGENT_DATA_TYPES_NOT_IMPLEMENTED;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
break;
case EDM_BOOLEAN_TYPE:
{
if (strcmp(source, "true") == 0)
{
agentData->type = EDM_BOOLEAN_TYPE;
agentData->value.edmBoolean.value = EDM_TRUE;
result = AGENT_DATA_TYPES_OK;
}
else if (strcmp(source, "false") == 0)
{
agentData->type = EDM_BOOLEAN_TYPE;
agentData->value.edmBoolean.value = EDM_FALSE;
result = AGENT_DATA_TYPES_OK;
}
else
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
break;
}
case EDM_NULL_TYPE:
{
if (strcmp(source, "null") == 0)
{
agentData->type = EDM_NULL_TYPE;
result = AGENT_DATA_TYPES_OK;
}
else
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
break;
}
case EDM_SBYTE_TYPE:
{
int sByteValue;
if ((sscanfd(source, &sByteValue) != 1) ||
(sByteValue < -128) ||
(sByteValue > 127))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
agentData->type = EDM_SBYTE_TYPE;
agentData->value.edmSbyte.value = (int8_t)sByteValue;
result = AGENT_DATA_TYPES_OK;
}
break;
}
case EDM_BYTE_TYPE:
{
int byteValue;
if ((sscanfd(source, &byteValue) != 1) ||
(byteValue < 0) ||
(byteValue > 255))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
agentData->type = EDM_BYTE_TYPE;
agentData->value.edmByte.value = (uint8_t)byteValue;
result = AGENT_DATA_TYPES_OK;
}
break;
}
case EDM_INT16_TYPE:
{
int int16Value;
if ((sscanfd(source, &int16Value) != 1) ||
(int16Value < -32768) ||
(int16Value > 32767))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
agentData->type = EDM_INT16_TYPE;
agentData->value.edmInt16.value = (int16_t)int16Value;
result = AGENT_DATA_TYPES_OK;
}
break;
}
case EDM_INT32_TYPE:
{
int32_t int32Value;
unsigned char isNegative;
uint32_t uint32Value;
const char* pos;
size_t strLength;
if (source[0] == '-')
{
isNegative = 1;
pos = &source[1];
}
else
{
isNegative = 0;
pos = &source[0];
}
strLength = strlen(source);
if ((sscanfu(pos, &uint32Value) != 1) ||
(strLength > 11) ||
((uint32Value > 2147483648UL) && isNegative) ||
((uint32Value > 2147483647UL) && (!isNegative)))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
if (isNegative)
{
if (uint32Value == 2147483648UL)
{
int32Value = -2147483647L - 1L;
}
else
{
int32Value = -(int32_t)uint32Value;
}
}
else
{
int32Value = uint32Value;
}
agentData->type = EDM_INT32_TYPE;
agentData->value.edmInt32.value = (int32_t)int32Value;
result = AGENT_DATA_TYPES_OK;
}
break;
}
case EDM_INT64_TYPE:
{
long long int64Value;
unsigned char isNegative;
unsigned long long ullValue;
const char* pos;
size_t strLength;
if (source[0] == '-')
{
isNegative = 1;
pos = &source[1];
}
else
{
isNegative = 0;
pos = &source[0];
}
strLength = strlen(source);
if ((sscanfllu(&pos, &ullValue) != 1) ||
(strLength > 20) ||
((ullValue > 9223372036854775808ULL) && isNegative) ||
((ullValue > 9223372036854775807ULL) && (!isNegative)))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
if (isNegative)
{
if (ullValue == 9223372036854775808ULL)
{
int64Value = -9223372036854775807LL - 1LL;
}
else
{
int64Value = -(long long)ullValue;
}
}
else
{
int64Value = ullValue;
}
agentData->type = EDM_INT64_TYPE;
agentData->value.edmInt64.value = (int64_t)int64Value;
result = AGENT_DATA_TYPES_OK;
}
break;
}
case EDM_DATE_TYPE:
{
int year;
int month;
int day;
size_t strLength = strlen(source);
if ((strLength < 2) ||
(source[0] != '"') ||
(source[strLength - 1] != '"'))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
size_t pos = 1;
int sign;
scanOptionalMinusSign(source, 2, &pos, &sign);
if ((scanAndReadNDigitsInt(source, &pos, &year, 4) != 0) ||
(source[pos++] != '-') ||
(scanAndReadNDigitsInt(source, &pos, &month, 2) != 0) ||
(source[pos++] != '-') ||
(scanAndReadNDigitsInt(source, &pos, &day, 2) != 0) ||
(Create_AGENT_DATA_TYPE_from_date(agentData, (int16_t)(sign*year), (uint8_t)month, (uint8_t)day) != AGENT_DATA_TYPES_OK))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
result = AGENT_DATA_TYPES_OK;
}
}
break;
}
case EDM_DATE_TIME_OFFSET_TYPE:
{
int year;
int month;
int day;
int hour;
int min;
int sec = 0;
int hourOffset;
int minOffset;
unsigned long long fractionalSeconds = 0;
size_t strLength = strlen(source);
agentData->value.edmDateTimeOffset.hasFractionalSecond = 0;
agentData->value.edmDateTimeOffset.hasTimeZone = 0;
/* The value of tm_isdst is positive if Daylight Saving Time is in effect, zero if Daylight
Saving Time is not in effect, and negative if the information is not available.*/
agentData->value.edmDateTimeOffset.dateTime.tm_isdst = -1;
if ((strLength < 2) ||
(source[0] != '"') ||
(source[strLength - 1] != '"'))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
size_t pos = 1;
int sign;
scanOptionalMinusSign(source, 2, &pos, &sign);
if ((scanAndReadNDigitsInt(source, &pos, &year, 4) != 0) ||
(source[pos++] != '-') ||
(scanAndReadNDigitsInt(source, &pos, &month, 2) != 0) ||
(source[pos++] != '-') ||
(scanAndReadNDigitsInt(source, &pos, &day, 2) != 0) ||
(source[pos++] != 'T') ||
(scanAndReadNDigitsInt(source, &pos, &hour, 2) != 0) ||
(source[pos++] != ':') ||
(scanAndReadNDigitsInt(source, &pos, &min, 2) != 0))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
const char* pos2;
year = year*sign;
if ((pos2 = strchr(source, ':')) == NULL)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
pos2 += 3;
if (*pos2 == ':')
{
if (sscanf2d(pos2, &sec) != 1)
{
pos2 = NULL;
}
else
{
pos2 += 3;
}
}
if ((pos2 != NULL) &&
(*pos2 == '.'))
{
if (sscanfdotllu(pos2, &fractionalSeconds) != 1)
{
pos2 = NULL;
}
else
{
pos2++;
agentData->value.edmDateTimeOffset.hasFractionalSecond = 1;
while ((*pos2 != '\0') &&
(IS_DIGIT(*pos2)))
{
pos2++;
}
if (*pos2 == '\0')
{
pos2 = NULL;
}
}
}
if (pos2 == NULL)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
hourOffset = 0;
minOffset = 0;
if (sscanf3d2d(pos2, &hourOffset, &minOffset) == 2)
{
agentData->value.edmDateTimeOffset.hasTimeZone = 1;
}
if ((strcmp(pos2, "Z\"") == 0) ||
agentData->value.edmDateTimeOffset.hasTimeZone)
{
if ((ValidateDate(year, month, day) != 0) ||
(hour < 0) ||
(hour > 23) ||
(min < 0) ||
(min > 59) ||
(sec < 0) ||
(sec > 59) ||
(fractionalSeconds > 999999999999) ||
(hourOffset < -23) ||
(hourOffset > 23) ||
(minOffset < 0) ||
(minOffset > 59))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
agentData->type = EDM_DATE_TIME_OFFSET_TYPE;
agentData->value.edmDateTimeOffset.dateTime.tm_year= year-1900;
agentData->value.edmDateTimeOffset.dateTime.tm_mon = month-1;
agentData->value.edmDateTimeOffset.dateTime.tm_mday = day;
agentData->value.edmDateTimeOffset.dateTime.tm_hour = hour;
agentData->value.edmDateTimeOffset.dateTime.tm_min = min;
agentData->value.edmDateTimeOffset.dateTime.tm_sec = sec;
/*fill in tm_wday and tm_yday*/
fill_tm_yday_and_tm_wday(&agentData->value.edmDateTimeOffset.dateTime);
agentData->value.edmDateTimeOffset.fractionalSecond = (uint64_t)fractionalSeconds;
agentData->value.edmDateTimeOffset.timeZoneHour = (int8_t)hourOffset;
agentData->value.edmDateTimeOffset.timeZoneMinute = (uint8_t)minOffset;
result = AGENT_DATA_TYPES_OK;
}
}
else
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
}
}
}
}
break;
}
case EDM_DOUBLE_TYPE:
{
if (strcmp(source, "\"NaN\"") == 0)
{
agentData->type = EDM_DOUBLE_TYPE;
#pragma warning(disable:26451) // warning C26451: overflow in constant arithmetic
agentData->value.edmDouble.value = NAN;
#pragma warning (default:26451)
result = AGENT_DATA_TYPES_OK;
}
else if (strcmp(source, "\"INF\"") == 0)
{
agentData->type = EDM_DOUBLE_TYPE;
agentData->value.edmDouble.value = INFINITY;
result = AGENT_DATA_TYPES_OK;
}
else if (strcmp(source, "\"-INF\"") == 0)
{
agentData->type = EDM_DOUBLE_TYPE;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4056) /* Known warning for INIFNITY */
#endif
agentData->value.edmDouble.value = -INFINITY;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
result = AGENT_DATA_TYPES_OK;
}
else if (sscanflf(source, &(agentData->value.edmDouble.value)) != 1)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else
{
agentData->type = EDM_DOUBLE_TYPE;
result = AGENT_DATA_TYPES_OK;
}
break;
}
case EDM_SINGLE_TYPE:
{
if (strcmp(source, "\"NaN\"") == 0)
{
agentData->type = EDM_SINGLE_TYPE;
agentData->value.edmSingle.value = NAN;
result = AGENT_DATA_TYPES_OK;
}
else if (strcmp(source, "\"INF\"") == 0)
{
agentData->type = EDM_SINGLE_TYPE;
agentData->value.edmSingle.value = INFINITY;
result = AGENT_DATA_TYPES_OK;
}
else if (strcmp(source, "\"-INF\"") == 0)
{
agentData->type = EDM_SINGLE_TYPE;
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable: 4056) /* Known warning for INIFNITY */
#endif
agentData->value.edmSingle.value = -INFINITY;
#ifdef _MSC_VER
#pragma warning(pop)
#endif
result = AGENT_DATA_TYPES_OK;
}
else if (sscanff(source, &agentData->value.edmSingle.value) != 1)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
agentData->type = EDM_SINGLE_TYPE;
result = AGENT_DATA_TYPES_OK;
}
break;
}
case EDM_DECIMAL_TYPE:
{
size_t strLength = strlen(source);
if ((strLength < 2) ||
(source[0] != '"') ||
(source[strLength - 1] != '"') ||
(ValidateDecimal(source + 1, strLength - 2) != 0))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
agentData->type = EDM_DECIMAL_TYPE;
agentData->value.edmDecimal.value = STRING_construct_n(source + 1, strLength-2);
if (agentData->value.edmDecimal.value == NULL)
{
result = AGENT_DATA_TYPES_ERROR;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
result = AGENT_DATA_TYPES_OK;
}
}
break;
}
case EDM_STRING_TYPE:
{
size_t strLength = strlen(source);
if ((strLength < 2) ||
(source[0] != '"') ||
(source[strLength - 1] != '"'))
{
result = AGENT_DATA_TYPES_INVALID_ARG;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
char* temp;
size_t malloc_size = safe_subtract_size_t(strLength, 1);
if (malloc_size == SIZE_MAX ||
(temp = (char*)malloc(malloc_size)) == NULL)
{
result = AGENT_DATA_TYPES_ERROR;
LogError("(result = %s), size:%zu", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result), malloc_size);
}
else if (memcpy(temp, source + 1, strLength - 2) == NULL)
{
free(temp);
result = AGENT_DATA_TYPES_ERROR;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
// Removes the "
temp[strLength - 2] = 0;
agentData->type = EDM_STRING_TYPE;
agentData->value.edmString.chars = temp;
agentData->value.edmString.length = strLength - 2;
result = AGENT_DATA_TYPES_OK;
}
}
break;
}
case EDM_STRING_NO_QUOTES_TYPE:
{
char* temp;
size_t strLength = strlen(source);
if (mallocAndStrcpy_s(&temp, source) != 0)
{
result = AGENT_DATA_TYPES_ERROR;
LogError("(result = %s)", MU_ENUM_TO_STRING(AGENT_DATA_TYPES_RESULT, result));
}
else
{
agentData->type = EDM_STRING_NO_QUOTES_TYPE;
agentData->value.edmStringNoQuotes.chars = temp;
agentData->value.edmStringNoQuotes.length = strLength;
result = AGENT_DATA_TYPES_OK;
}
break;
}
case EDM_GUID_TYPE:
{
if (strlen(source) != GUID_STRING_LENGTH)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else
{
if (source[0] != '"')
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 1, &(agentData->value.edmGuid.GUID[0])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 3, &(agentData->value.edmGuid.GUID[1])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 5, &(agentData->value.edmGuid.GUID[2])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 7, &(agentData->value.edmGuid.GUID[3])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (source[9] != '-')
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 10, &(agentData->value.edmGuid.GUID[4])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 12, &(agentData->value.edmGuid.GUID[5])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (source[14] != '-')
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 15, &(agentData->value.edmGuid.GUID[6])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 17, &(agentData->value.edmGuid.GUID[7])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (source[19] != '-')
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 20, &(agentData->value.edmGuid.GUID[8])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 22, &(agentData->value.edmGuid.GUID[9])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (source[24] != '-')
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 25, &(agentData->value.edmGuid.GUID[10])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 27, &(agentData->value.edmGuid.GUID[11])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 29, &(agentData->value.edmGuid.GUID[12])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 31, &(agentData->value.edmGuid.GUID[13])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 33, &(agentData->value.edmGuid.GUID[14])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (scanMandatory2CapitalHexDigits(source + 35, &(agentData->value.edmGuid.GUID[15])) != 0)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (source[37] != '"')
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else
{
agentData->type = EDM_GUID_TYPE;
result = AGENT_DATA_TYPES_OK;
}
}
break;
}
case EDM_BINARY_TYPE:
{
size_t sourceLength = strlen(source);
if (sourceLength < 2)
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (sourceLength == 2)
{
agentData->type = EDM_BINARY_TYPE;
agentData->value.edmBinary.data = NULL;
agentData->value.edmBinary.size = 0;
result = AGENT_DATA_TYPES_OK;
}
else
{
size_t sourcePosition = 0;
if (source[sourcePosition++] != '"') /*if it doesn't start with a quote then... */
{
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else
{
/*1. read groups of 4 base64 character and transfer those into groups of 3 "normal" characters.
2. read the end of the string and produce from that the ending characters*/
/*compute the amount of memory to allocate*/
agentData->value.edmBinary.size = (((sourceLength - 2) + 4) / 4) * 3; /*this is overallocation, shall be trimmed later*/
agentData->value.edmBinary.data = (unsigned char*)malloc(agentData->value.edmBinary.size); /*this is overallocation, shall be trimmed later*/
if (agentData->value.edmBinary.data == NULL)
{
result = AGENT_DATA_TYPES_ERROR;
}
else
{
size_t destinationPosition = 0;
size_t consumed;
/*read and store "solid" groups of 4 base64 chars*/
while (scan4base64char(source + sourcePosition, sourceLength - sourcePosition, agentData->value.edmBinary.data + destinationPosition, agentData->value.edmBinary.data + destinationPosition + 1, agentData->value.edmBinary.data + destinationPosition + 2) == 0)
{
sourcePosition += 4;
destinationPosition += 3;
}
if (scanbase64b16(source + sourcePosition, sourceLength - sourcePosition, &consumed, agentData->value.edmBinary.data + destinationPosition, agentData->value.edmBinary.data + destinationPosition + 1) == 0)
{
sourcePosition += consumed;
destinationPosition += 2;
}
else if (scanbase64b8(source + sourcePosition, sourceLength - sourcePosition, &consumed, agentData->value.edmBinary.data + destinationPosition) == 0)
{
sourcePosition += consumed;
destinationPosition += 1;
}
if (source[sourcePosition++] != '"') /*if it doesn't end with " then bail out*/
{
free(agentData->value.edmBinary.data);
agentData->value.edmBinary.data = NULL;
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else if (sourcePosition != sourceLength)
{
free(agentData->value.edmBinary.data);
agentData->value.edmBinary.data = NULL;
result = AGENT_DATA_TYPES_INVALID_ARG;
}
else
{
/*trim the result*/
void* temp = realloc(agentData->value.edmBinary.data, destinationPosition);
if (temp == NULL) /*this is extremely unlikely to happen, but whatever*/
{
free(agentData->value.edmBinary.data);
agentData->value.edmBinary.data = NULL;
result = AGENT_DATA_TYPES_ERROR;
}
else
{
agentData->type = EDM_BINARY_TYPE;
agentData->value.edmBinary.data = (unsigned char*)temp;
agentData->value.edmBinary.size = destinationPosition;
result = AGENT_DATA_TYPES_OK;
}
}
}
}
}
break;
}
}
}
return result;
}