ucx
UAP Common Extensions
Loading...
Searching...
No Matches
json.h
Go to the documentation of this file.
1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2024 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
35
36#ifndef UCX_JSON_H
37#define UCX_JSON_H
38
39#include "common.h"
40#include "allocator.h"
41#include "string.h"
42#include "buffer.h"
43#include "array_list.h"
44#include "map.h"
45
103
141
159
168
172typedef struct cx_json_s CxJson;
173
178
183
196typedef int64_t CxJsonInteger;
200typedef double CxJsonNumber;
205
252
275
334
383
388
418
423
431
440
460int cxJsonWrite(void* target, const CxJsonValue* value,
461 cx_write_func wfunc, const CxJsonWriter* settings);
462
463
476
489
498void cxJsonInit(CxJson *json, const CxAllocator *allocator);
499
508
518void cxJsonReset(CxJson *json);
519
539int cxJsonFilln(CxJson *json, const char *buf, size_t len);
540
541
551int cx_json_fill(CxJson *json, cxstring str) {
552 return cxJsonFilln(json, str.ptr, str.length);
553}
554
572#define cxJsonFill(json, str) cx_json_fill(json, cx_strcast(str))
573
574
585 cxstring str, CxJsonValue **value);
586
601#define cxJsonFromString(allocator, str, value) \
602 cx_json_from_string(allocator, cx_strcast(str), value)
603
617
628
641CxJsonValue* cxJsonCreateArr(const CxAllocator* allocator, size_t capacity);
642
653CxJsonValue* cxJsonCreateNumber(const CxAllocator* allocator, double num);
654
665CxJsonValue* cxJsonCreateInteger(const CxAllocator* allocator, int64_t num);
666
680
690#define cxJsonCreateString(allocator, str) cx_json_create_string(allocator, cx_strcast(str))
691
703
714int cxJsonArrAddNumbers(CxJsonValue* arr, const double* num, size_t count);
715
726int cxJsonArrAddIntegers(CxJsonValue* arr, const int64_t* num, size_t count);
727
741int cxJsonArrAddStrings(CxJsonValue* arr, const char* const* str, size_t count);
742
756int cxJsonArrAddCxStrings(CxJsonValue* arr, const cxstring* str, size_t count);
757
768int cxJsonArrAddLiterals(CxJsonValue* arr, const CxJsonLiteral* lit, size_t count);
769
783int cxJsonArrAddValues(CxJsonValue* arr, CxJsonValue* const* val, size_t count);
784
798
813#define cxJsonObjPut(obj, name, child) cx_json_obj_put(obj, cx_strcast(name), child)
814
828
838#define cxJsonObjPutObj(obj, name) cx_json_obj_put_obj(obj, cx_strcast(name))
839
854
865#define cxJsonObjPutArr(obj, name, capacity) cx_json_obj_put_arr(obj, cx_strcast(name), capacity)
866
881
892#define cxJsonObjPutNumber(obj, name, num) cx_json_obj_put_number(obj, cx_strcast(name), num)
893
908
919#define cxJsonObjPutInteger(obj, name, num) cx_json_obj_put_integer(obj, cx_strcast(name), num)
920
935
948#define cxJsonObjPutString(obj, name, str) cx_json_obj_put_string(obj, cx_strcast(name), cx_strcast(str))
949
964
975#define cxJsonObjPutLiteral(obj, name, lit) cx_json_obj_put_literal(obj, cx_strcast(name), lit)
976
1001
1010bool cxJsonIsObject(const CxJsonValue *value) {
1011 return value->type == CX_JSON_OBJECT;
1012}
1013
1022bool cxJsonIsArray(const CxJsonValue *value) {
1023 return value->type == CX_JSON_ARRAY;
1024}
1025
1034bool cxJsonIsString(const CxJsonValue *value) {
1035 return value->type == CX_JSON_STRING;
1036}
1037
1050bool cxJsonIsNumber(const CxJsonValue *value) {
1051 return value->type == CX_JSON_NUMBER || value->type == CX_JSON_INTEGER;
1052}
1053
1063bool cxJsonIsInteger(const CxJsonValue *value) {
1064 return value->type == CX_JSON_INTEGER;
1065}
1066
1080bool cxJsonIsLiteral(const CxJsonValue *value) {
1081 return value->type == CX_JSON_LITERAL;
1082}
1083
1094bool cxJsonIsBool(const CxJsonValue *value) {
1095 return cxJsonIsLiteral(value) && value->literal != CX_JSON_NULL;
1096}
1097
1111bool cxJsonIsTrue(const CxJsonValue *value) {
1112 return cxJsonIsLiteral(value) && value->literal == CX_JSON_TRUE;
1113}
1114
1128bool cxJsonIsFalse(const CxJsonValue *value) {
1129 return cxJsonIsLiteral(value) && value->literal == CX_JSON_FALSE;
1130}
1131
1141bool cxJsonIsNull(const CxJsonValue *value) {
1142 return cxJsonIsLiteral(value) && value->literal == CX_JSON_NULL;
1143}
1144
1155char *cxJsonAsString(const CxJsonValue *value);
1156
1168
1180
1191double cxJsonAsDouble(const CxJsonValue *value);
1192
1206int64_t cxJsonAsInteger(const CxJsonValue *value);
1207
1219bool cxJsonAsBool(const CxJsonValue *value) {
1220 return value->literal == CX_JSON_TRUE;
1221}
1222
1233size_t cxJsonArrSize(const CxJsonValue *value) {
1234 return value->array.size;
1235}
1236
1252CxJsonValue *cxJsonArrGet(const CxJsonValue *value, size_t index);
1253
1269
1283
1294size_t cxJsonObjSize(const CxJsonValue *value) {
1295 return cxCollectionSize(value->object);
1296}
1297
1312
1321
1336#define cxJsonObjGet(value, name) cx_json_obj_get(value, cx_strcast(name))
1337
1346
1360#define cxJsonObjRemove(value, name) cx_json_obj_remove(value, cx_strcast(name))
1361
1373int cxJsonCompare(const CxJsonValue *json, const CxJsonValue *other);
1374
1375
1391 const CxAllocator* allocator);
1392
1407 CxJsonValue* target, const CxJsonValue* source,
1408 const CxAllocator* allocator, void *data);
1409
1420#define cxJsonCloneFunc ((cx_clone_func) cx_json_clone_func)
1421
1422#endif /* UCX_JSON_H */
1423
Interface for custom allocators.
struct cx_allocator_s CxAllocator
High-Level type alias for the allocator type.
Definition allocator.h:80
Array list implementation.
#define CX_ARRAY(type, name)
Declares a typed array with size and capacity.
Definition array_list.h:54
Advanced buffer implementation.
struct cx_buffer_s CxBuffer
UCX buffer.
Definition buffer.h:143
#define cxCollectionSize(c)
Returns the number of elements currently stored.
Definition collection.h:126
Common definitions and feature checks.
#define CX_MALLOC
The attributed function always returns freshly allocated memory.
Definition common.h:156
#define CX_DEALLOC(...)
Not supported in clang.
Definition common.h:172
#define CX_INLINE
Declares a function to be inlined.
Definition common.h:311
size_t(* cx_write_func)(const void *, size_t, size_t, void *)
Function pointer compatible with fwrite-like functions.
Definition common.h:325
#define CX_NONNULL
All pointer arguments must be non-NULL.
Definition common.h:141
#define CX_NODISCARD
Warn about discarded return value.
Definition common.h:256
#define CX_RETURNS_NONNULL
The returned value is guaranteed to be non-NULL.
Definition common.h:151
#define CX_NONNULL_ARG(...)
The specified pointer arguments must be non-NULL.
Definition common.h:146
#define CX_EXTERN
Declares a function with external linkage.
Definition common.h:297
#define CX_ACCESS_R(...)
Specifies that the function will only read through the given pointer.
Definition common.h:230
#define CX_ACCESS_W(...)
Specifies that the function will only write through the given pointer.
Definition common.h:246
struct cx_iterator_s CxIterator
Iterator type.
Definition iterator.h:144
enum cx_json_status CxJsonStatus
Typedef for the JSON status enum.
Definition json.h:387
static int cx_json_fill(CxJson *json, cxstring str)
Internal function, do not use.
Definition json.h:551
int cxJsonFilln(CxJson *json, const char *buf, size_t len)
Fills the input buffer.
static bool cxJsonIsArray(const CxJsonValue *value)
Checks if the specified value is a JSON array.
Definition json.h:1022
double CxJsonNumber
Type alias for a number that is not an integer.
Definition json.h:200
CxJsonValue * cxJsonArrRemove(CxJsonValue *value, size_t index)
Removes an element from a JSON array.
CxJsonValue * cx_json_obj_put_number(CxJsonValue *obj, cxstring name, double num)
Creates a new JSON number and adds it to an object.
struct cx_json_token_s CxJsonToken
Type alias for the token struct.
Definition json.h:177
CxJsonWriter cxJsonWriterPretty(bool use_spaces)
Creates a default writer configuration for pretty output.
CxJsonValue * cx_json_obj_remove(CxJsonValue *value, cxstring name)
Internal function, do not use.
int cxJsonArrAddCxStrings(CxJsonValue *arr, const cxstring *str, size_t count)
Adds strings to a JSON array.
CxJsonValue * cxJsonCreateLiteral(const CxAllocator *allocator, CxJsonLiteral lit)
Creates a new JSON literal.
cxmutstr cxJsonToPrettyString(const CxAllocator *allocator, CxJsonValue *value)
Produces a pretty string representation of the specified JSON value.
void cxJsonReset(CxJson *json)
Destroys and re-initializes the JSON interface.
int cxJsonArrAddLiterals(CxJsonValue *arr, const CxJsonLiteral *lit, size_t count)
Adds literals to a JSON array.
static bool cxJsonIsFalse(const CxJsonValue *value)
Checks if the specified value is false.
Definition json.h:1128
CxJsonStatus cx_json_from_string(const CxAllocator *allocator, cxstring str, CxJsonValue **value)
Internal function - use cxJsonFromString() instead.
CxJsonValue * cxJsonCreateArr(const CxAllocator *allocator, size_t capacity)
Creates a new (empty) JSON array.
cxmutstr cxJsonAsCxMutStr(const CxJsonValue *value)
Obtains a mutable UCX string from the given JSON value.
CxJsonValue * cxJsonCreateObj(const CxAllocator *allocator)
Creates a new (empty) JSON object.
char * cxJsonAsString(const CxJsonValue *value)
Obtains a C string from the given JSON value.
int cxJsonArrAddValues(CxJsonValue *arr, CxJsonValue *const *val, size_t count)
Add arbitrary values to a JSON array.
CxJsonStatus cxJsonNext(CxJson *json, CxJsonValue **value)
Tries to obtain the next JSON value.
CxJsonValue * cxJsonClone(const CxJsonValue *value, const CxAllocator *allocator)
Creates a deep copy of the specified JSON value.
static size_t cxJsonArrSize(const CxJsonValue *value)
Returns the size of a JSON array.
Definition json.h:1233
cxstring cxJsonAsCxString(const CxJsonValue *value)
Obtains a UCX string from the given JSON value.
enum cx_json_literal CxJsonLiteral
Type alias for a JSON literal.
Definition json.h:204
int cx_json_obj_put(CxJsonValue *obj, cxstring name, CxJsonValue *child)
Adds or replaces a value within a JSON object.
int cxJsonArrAddStrings(CxJsonValue *arr, const char *const *str, size_t count)
Adds strings to a JSON array.
static bool cxJsonIsBool(const CxJsonValue *value)
Checks if the specified value is a Boolean literal.
Definition json.h:1094
static bool cxJsonIsTrue(const CxJsonValue *value)
Checks if the specified value is true.
Definition json.h:1111
int cxJsonArrAddNumbers(CxJsonValue *arr, const double *num, size_t count)
Adds number values to a JSON array.
CxJsonValue * cx_json_obj_put_string(CxJsonValue *obj, cxstring name, cxstring str)
Creates a new JSON string and adds it to an object.
cx_json_token_type
The type of the parsed token.
Definition json.h:49
@ CX_JSON_TOKEN_ERROR
The presumed token contains syntactical errors.
Definition json.h:57
@ CX_JSON_TOKEN_END_OBJECT
An "end of object" '}' token.
Definition json.h:73
@ CX_JSON_NO_TOKEN
No complete token parsed, yet.
Definition json.h:53
@ CX_JSON_TOKEN_END_ARRAY
An "end of array" ']' token.
Definition json.h:69
@ CX_JSON_TOKEN_STRING
A string token.
Definition json.h:85
@ CX_JSON_TOKEN_BEGIN_ARRAY
A "begin of array" '[' token.
Definition json.h:61
@ CX_JSON_TOKEN_NUMBER
A number token that cannot be represented as an integer.
Definition json.h:93
@ CX_JSON_TOKEN_SPACE
A white-space token.
Definition json.h:101
@ CX_JSON_TOKEN_LITERAL
A literal token.
Definition json.h:97
@ CX_JSON_TOKEN_NAME_SEPARATOR
A colon ':' token separating names and values.
Definition json.h:77
@ CX_JSON_TOKEN_VALUE_SEPARATOR
A comma ',' token separating object entries or array elements.
Definition json.h:81
@ CX_JSON_TOKEN_INTEGER
A number token that can be represented as an integer.
Definition json.h:89
@ CX_JSON_TOKEN_BEGIN_OBJECT
A "begin of object" '{' token.
Definition json.h:65
CxJsonValue * cx_json_obj_put_obj(CxJsonValue *obj, cxstring name)
Creates a new JSON object and adds it to an existing object.
CxJsonValue * cxJsonArrGet(const CxJsonValue *value, size_t index)
Returns an element from a JSON array.
CxJsonValue * cxJsonCreateNumber(const CxAllocator *allocator, double num)
Creates a new JSON number value.
CxJsonValue * cx_json_clone_func(CxJsonValue *target, const CxJsonValue *source, const CxAllocator *allocator, void *data)
A cx_clone_func compatible version of cxJsonClone().
static bool cxJsonIsLiteral(const CxJsonValue *value)
Checks if the specified value is a JSON literal.
Definition json.h:1080
int64_t cxJsonAsInteger(const CxJsonValue *value)
Obtains a 64-bit signed integer from the given JSON value.
CxJsonValue * cx_json_create_string(const CxAllocator *allocator, cxstring str)
Creates a new JSON string.
static bool cxJsonIsObject(const CxJsonValue *value)
Checks if the specified value is a JSON object.
Definition json.h:1010
CxJsonValue * cx_json_obj_get(const CxJsonValue *value, cxstring name)
Internal function, do not use.
void cxJsonInit(CxJson *json, const CxAllocator *allocator)
Initializes the JSON interface.
CxJsonValue * cx_json_obj_put_integer(CxJsonValue *obj, cxstring name, int64_t num)
Creates a new JSON number, based on an integer, and adds it to an object.
cx_json_value_type
The type of some JSON value.
Definition json.h:107
@ CX_JSON_LITERAL
A literal (true, false, null).
Definition json.h:139
@ CX_JSON_NUMBER
A number, not necessarily an integer.
Definition json.h:135
@ CX_JSON_NOTHING
Reserved.
Definition json.h:111
@ CX_JSON_ARRAY
A JSON array.
Definition json.h:123
@ CX_JSON_INTEGER
A number that contains an integer.
Definition json.h:131
@ CX_JSON_UNINITIALIZED
No meaningful data.
Definition json.h:115
@ CX_JSON_OBJECT
A JSON object.
Definition json.h:119
@ CX_JSON_STRING
A string.
Definition json.h:127
CxJsonValue * cx_json_obj_put_arr(CxJsonValue *obj, cxstring name, size_t capacity)
Creates a new JSON array and adds it to an object.
CxJsonWriter cxJsonWriterCompact(void)
Creates a default writer configuration for compact output.
int cxJsonArrAddIntegers(CxJsonValue *arr, const int64_t *num, size_t count)
Adds number values, of which all are integers, to a JSON array.
enum cx_json_token_type CxJsonTokenType
Type alias for the token type enum.
Definition json.h:163
static bool cxJsonIsString(const CxJsonValue *value)
Checks if the specified value is a string.
Definition json.h:1034
struct cx_json_writer_s CxJsonWriter
Typedef for the JSON writer.
Definition json.h:422
cx_json_status
Status codes for the JSON interface.
Definition json.h:338
@ CX_JSON_FORMAT_ERROR_NUMBER
A number value is incorrectly formatted.
Definition json.h:377
@ CX_JSON_NO_DATA
The input buffer does not contain more data.
Definition json.h:346
@ CX_JSON_BUFFER_ALLOC_FAILED
Allocating memory for the internal buffer failed.
Definition json.h:369
@ CX_JSON_OK
Not used as a status and never returned by any function.
Definition json.h:361
@ CX_JSON_INCOMPLETE_DATA
The input ends unexpectedly.
Definition json.h:352
@ CX_JSON_NO_ERROR
Everything is fine.
Definition json.h:342
@ CX_JSON_FORMAT_ERROR_UNEXPECTED_TOKEN
The tokenizer found something unexpected.
Definition json.h:381
@ CX_JSON_NULL_DATA
The input buffer has never been filled.
Definition json.h:365
@ CX_JSON_VALUE_ALLOC_FAILED
Allocating memory for a JSON value failed.
Definition json.h:373
int64_t CxJsonInteger
Type alias for a number that can be represented as a 64-bit signed integer.
Definition json.h:196
enum cx_json_value_type CxJsonValueType
Type alias for the value type enum.
Definition json.h:167
static bool cxJsonIsNull(const CxJsonValue *value)
Checks if the specified value is null.
Definition json.h:1141
static bool cxJsonAsBool(const CxJsonValue *value)
Obtains a Boolean value from the given JSON value.
Definition json.h:1219
static bool cxJsonIsNumber(const CxJsonValue *value)
Checks if the specified value is a JSON number.
Definition json.h:1050
struct cx_json_s CxJson
Type alias for the JSON parser interface.
Definition json.h:172
CxMap * CxJsonObject
Type alias for the map representing a JSON object.
Definition json.h:188
struct cx_json_value_s CxJsonValue
Type alias for the JSON value struct.
Definition json.h:182
struct cx_mutstr_s CxJsonString
Type alias for a JSON string.
Definition json.h:192
int cxJsonWrite(void *target, const CxJsonValue *value, cx_write_func wfunc, const CxJsonWriter *settings)
Writes a JSON value to a buffer or stream.
CxJsonValue * cxJsonCreateInteger(const CxAllocator *allocator, int64_t num)
Creates a new JSON number value based on an integer.
cx_json_literal
JSON literal types.
Definition json.h:145
@ CX_JSON_TRUE
The true literal.
Definition json.h:153
@ CX_JSON_NULL
The null literal.
Definition json.h:149
@ CX_JSON_FALSE
The false literal.
Definition json.h:157
int cxJsonCompare(const CxJsonValue *json, const CxJsonValue *other)
Performs a deep comparison of two JSON values.
void cxJsonDestroy(CxJson *json)
Destroys the JSON interface.
cxmutstr cxJsonToString(const CxAllocator *allocator, CxJsonValue *value)
Produces a compact string representation of the specified JSON value.
static bool cxJsonIsInteger(const CxJsonValue *value)
Checks if the specified value is an integer number.
Definition json.h:1063
void cxJsonValueFree(CxJsonValue *value)
Recursively deallocates the memory of a JSON value.
CxJsonValue * cx_json_obj_put_literal(CxJsonValue *obj, cxstring name, CxJsonLiteral lit)
Creates a new JSON literal and adds it to an object.
double cxJsonAsDouble(const CxJsonValue *value)
Obtains a double-precision floating-point value from the given JSON value.
CxIterator cxJsonArrIter(const CxJsonValue *value)
Returns an iterator over the JSON array elements.
CxMapIterator cxJsonObjIter(const CxJsonValue *value)
Returns a map iterator over the JSON object members.
static size_t cxJsonObjSize(const CxJsonValue *value)
Returns the size of a JSON object.
Definition json.h:1294
Interface for map implementations.
struct cx_map_iterator_s CxMapIterator
Type for a map iterator.
Definition map.h:56
struct cx_map_s CxMap
Type for the UCX map.
Definition map.h:50
Strings that know their length.
struct cx_string_s cxstring
An immutable string.
Definition string.h:92
struct cx_mutstr_s cxmutstr
A mutable string.
Definition string.h:74
The JSON parser interface.
Definition json.h:279
struct cx_json_s::@211321012275325254323372376226265040342224311061 states
State stack.
CxJsonTokenType uncompleted_tokentype
The expected type of the currently parsed, uncompleted token.
Definition json.h:312
cxmutstr uncompleted_content
Internal buffer for uncompleted tokens.
Definition json.h:307
struct cx_json_s::@034250237261234253310313252037012355004173136051 vbuf
Value buffer stack.
int states_internal[8]
Internally reserved memory for the state stack.
Definition json.h:327
const CxAllocator * allocator
The allocator used for produced JSON values.
Definition json.h:283
CxBuffer buffer
The input buffer.
Definition json.h:288
cxmutstr uncompleted_member_name
The name of a not yet completely parsed object member.
Definition json.h:302
CxJsonValue * vbuf_internal[8]
Internally reserved memory for the value buffer stack.
Definition json.h:332
CxJsonValue * parsed
A pointer to an intermediate state of the currently parsed value.
Definition json.h:295
Internally used structure for a parsed token.
Definition json.h:258
cxmutstr content
The token text, if any.
Definition json.h:273
CxJsonTokenType tokentype
The token type.
Definition json.h:262
bool allocated
True, if the content must be passed to cx_strfree().
Definition json.h:266
Structure for a JSON value.
Definition json.h:209
const CxAllocator * allocator
The allocator with which the value was allocated.
Definition json.h:215
CxJsonLiteral literal
The literal type if the type is CX_JSON_LITERAL.
Definition json.h:249
CxJsonNumber number
The number if the type is CX_JSON_NUMBER.
Definition json.h:245
CxJsonString string
The string data if the type is CX_JSON_STRING.
Definition json.h:237
struct cx_json_value_s::@153346254145105011216326335113366211200126141046::@121051301266371100101164311051325000355007032300 array
The array data if the type is CX_JSON_ARRAY.
CxJsonValueType type
The type of this value.
Definition json.h:221
CxJsonInteger integer
The integer if the type is CX_JSON_INTEGER.
Definition json.h:241
CxJsonObject object
The object data if the type is CX_JSON_OBJECT.
Definition json.h:233
The JSON writer settings.
Definition json.h:392
bool indent_space
Set true to use spaces instead of tab characters.
Definition json.h:407
bool escape_slash
Set true to enable escaping of the slash character (solidus).
Definition json.h:416
uint8_t indent
If indent_space is true, this is the number of spaces per tab.
Definition json.h:412
uint8_t frac_max_digits
The maximum number of fractional digits in a number value.
Definition json.h:402
bool pretty
Set true to enable pretty output.
Definition json.h:396
The UCX string structure.
Definition string.h:61