FossilOrigin-Name: 967fd6da6e3933a0d828690f71772025331bfa874d9b397755bf529d13f6140c
This commit is contained in:
nekobit 2022-11-01 02:45:54 +00:00
parent dfb0a2e230
commit 949876fc7f
11 changed files with 252 additions and 214 deletions

View file

@ -29,33 +29,35 @@
#include <mastodont_announcement.h>
#include <mastodont_chats.h>
//! Initializes libcurl
/// Initializes libcurl
void mstdnt_global_curl_init();
//! Cleans up libcurl
/// Cleans up libcurl
void mstdnt_global_curl_cleanup();
/*!
/**
* Initializes a mstdnt struct
*
* \param data Pointer to struct to fill in
* \return Value of curl_easy_init(); either Zero or non-zero
* @param data Pointer to struct to fill in
* @return Value of curl_easy_init(); either Zero or non-zero
*/
int mstdnt_init(mastodont_t* data);
/*!
/**
* Cleans up the mstdnt struct
*
* \param data Pointer to the mstdnt data
* @param data Pointer to the mstdnt data
*/
void mstdnt_cleanup(mastodont_t* data);
/*!
/**
* Cleans up a storage struct.
*
* This contains information such as JSON information and errors.
*
* \param storage The storage block to cleanup
* @param storage The storage block to cleanup
*/
void mstdnt_storage_cleanup(struct mstdnt_storage* storage);
void mstdnt_request_cb_cleanup(mstdnt_request_cb_t* data);
#endif /* MASTODONT_H */

View file

@ -25,9 +25,13 @@ struct mstdnt_fetch_data
char* response;
size_t size;
struct mstdnt_storage storage;
// Callback from user
mstdnt_request_cb_t callback;
void* callback_args;
int (*json_cb)(cJSON*, void*);
void* json_args;
};
struct mstdnt_fd
@ -69,6 +73,8 @@ int mstdnt_fetch_curl_async(mastodont_t* mstdnt,
struct mstdnt_args* args,
mstdnt_request_cb_t cb_request,
void* cb_args,
int (*json_cb)(cJSON*, void*),
void* json_args,
char* url,
CURLoption request_t,
char* request_t_custom);

View file

@ -31,7 +31,7 @@ struct mstdnt_request_args
CURLoption request_type;
char* request_type_custom;
void* args;
int (*callback)(cJSON*, void*);
int (*callback)(cJSON*, void**);
};
/**

View file

@ -29,7 +29,6 @@
#include "mastodont_pleroma.h"
#include "mastodont_account.h"
#include "mastodont_visibility_types.h"
/* Status: Complete, not implemented */
struct mstdnt_status
{
@ -114,13 +113,13 @@ void mstdnt_cleanup_status(struct mstdnt_status* status);
int mstdnt_status_json(struct mstdnt_status* status, cJSON* js);
int mstdnt_status_emoji_react(mastodont_t* api,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
char* emoji,
struct mstdnt_storage* storage,
struct mstdnt_status* status);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
char* emoji,
struct mstdnt_storage* storage,
struct mstdnt_status* status);
// Generated function
int mstdnt_statuses_json(struct mstdnt_status* statuses[],
@ -137,33 +136,33 @@ int mstdnt_status_context_json(struct mstdnt_status* statuses_before[],
cJSON* js);
int mstdnt_get_account_statuses(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_account_statuses_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_account_statuses_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size);
int mstdnt_get_status(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* status);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* status);
int mstdnt_get_status_context(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses_before[],
struct mstdnt_status* statuses_after[],
size_t* size_before,
size_t* size_after);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses_before[],
struct mstdnt_status* statuses_after[],
size_t* size_before,
size_t* size_after);
int mstdnt_status_favourited_by(mastodont_t* data,
struct mstdnt_args* args,
@ -210,30 +209,47 @@ MSTDNT_STATUS_ACTION_DECL(unbookmark);
MSTDNT_STATUS_ACTION_DECL(delete);
int mstdnt_mute_conversation(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* status);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* status);
int mstdnt_unmute_conversation(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* status);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* status);
struct mstdnt_statuses
{
struct mstdnt_status* statuses;
size_t len;
};
/* Callbacks */
struct mstdnt_status_context
{
struct mstdnt_statuses before;
struct mstdnt_statuses after;
};
// DEPRECATED
struct _mstdnt_statuses_cb_args
{
struct mstdnt_status** statuses;
size_t* size;
};
// DEPRECATED
struct _mstdnt_status_context_result_cb_args
{
struct mstdnt_status** statuses_before;
struct mstdnt_status** statuses_after;
size_t* size_before;
@ -256,25 +272,25 @@ struct mstdnt_favourites_args
};
int mstdnt_get_bookmarks(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_bookmarks_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_bookmarks_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size);
int mstdnt_get_favourites(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_favourites_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_favourites_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size);
int mstdnt_statuses_json_callback(cJSON* json, void* _args);
int mstdnt_status_json_callback(cJSON* json, void* status);
int mstdnt_status_context_json_callback(cJSON* json, void* _args);
int mstdnt_statuses_json_callback(cJSON* json, void** _args);
int mstdnt_status_json_callback(cJSON* json, void** status);
int mstdnt_status_context_json_callback(cJSON* json, void** _args);
#endif /* MASTODONT_STATUS */

View file

@ -41,50 +41,35 @@ struct mstdnt_timeline_args
};
int mstdnt_timeline_home(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args);
int mstdnt_timeline_list(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* list_id,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* list_id,
struct mstdnt_timeline_args* args);
int mstdnt_timeline_public(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* statuses_size);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args);
int mstdnt_timeline_direct(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* statuses_size);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args);
int mstdnt_timeline_tag(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* hashtag,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size);
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* hashtag,
struct mstdnt_timeline_args* args);
#endif /* MASTODONT_TIMELINE_H */

View file

@ -28,11 +28,17 @@ typedef int8_t mstdnt_bool;
#define MSTDNT_FALSE 1
#define MSTDNT_BOOL_UNSET 0
struct mstdnt_storage;
// Only god knows
typedef struct mstdnt_request_cb_data {
} mstdnt_request_cb_data_t;
struct mstdnt_storage* storage;
void* data;
void (*data_free_cb)(void*);
} mstdnt_request_cb_data;
typedef void (*mstdnt_request_cb_t)(void* data, void* args);
#define MSTDNT_CB_DATA(_data) (_data->data)
#define MSTDNT_FLAG_NO_URI_SANITIZE (1<<0)
#define MSTDNT_FLAG_SSL_UNVERIFIED (1<<1)
#define MSTDNT_FLAG_SYNC (1<<2)

View file

@ -18,6 +18,7 @@
#include <pthread.h>
#include <mastodont_hooks.h>
#include <mastodont_fetch.h>
#include <mastodont_json_helper.h>
/* For use with libcurl */
size_t mstdnt_curl_write_callback(char* ptr, size_t _size, size_t nmemb, void* _content)
@ -51,6 +52,8 @@ int mstdnt_fetch_curl_async(mastodont_t* mstdnt,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
int (*json_cb)(cJSON*, void*),
void* json_args,
char* _url,
CURLoption request_t,
char* request_t_custom)
@ -84,6 +87,8 @@ int mstdnt_fetch_curl_async(mastodont_t* mstdnt,
}
results->callback = cb_request;
results->callback_args = cb_args;
results->json_cb = json_cb;
results->json_args = json_args;
// Set options
curl_easy_setopt(curl, CURLOPT_URL, url);
@ -108,7 +113,6 @@ int mstdnt_fetch_curl_async(mastodont_t* mstdnt,
// Add curl handle to multi, then run
res = curl_multi_add_handle(mstdnt->curl, curl);
// No docs on this?
int running;
res = curl_multi_perform(mstdnt->curl, &running);
if (res != CURLM_OK)
@ -145,6 +149,9 @@ int mstdnt_await(mastodont_t* mstdnt,
res = curl_multi_poll(mstdnt->curl, fds, nfds, 0, NULL);
struct mstdnt_fetch_data* data;
cJSON* root;
struct mstdnt_storage storage = { 0 };
struct mstdnt_fetch_data results = { 0 };
// Check if our socket is done
do
@ -155,9 +162,26 @@ int mstdnt_await(mastodont_t* mstdnt,
{
// Get easy info
curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &data);
data->callback(NULL, data->callback_args);
mstdnt_fetch_data_cleanup(data);
/* Zero out */
memset(&(data->storage), 0, sizeof(struct mstdnt_storage));
data->storage.needs_cleanup = 0;
// Get json
if (_mstdnt_json_init(&root, &results, &storage))
{
res = 1;
goto cleanup_res;
}
void** json_cb_res;
if (data->json_cb)
res = data->json_cb(storage.root, data->json_args);
data->callback(NULL, data->callback_args);
cleanup_res:
// Cleanup
mstdnt_fetch_data_cleanup(data);
curl_multi_remove_handle(mstdnt->curl, msg->easy_handle);
curl_easy_cleanup(msg->easy_handle);
}

View file

@ -33,3 +33,8 @@ void mstdnt_storage_cleanup(struct mstdnt_storage* storage)
storage->needs_cleanup = 0;
}
}
void mstdnt_request_cb_cleanup(mstdnt_request_cb_t* data)
{
}

View file

@ -144,9 +144,6 @@ int mstdnt_request(mastodont_t* data,
// Create cURL single handle, we will run this later and then block
CURL* curl = curl_easy_init();
/* Zero out */
memset(storage, 0, sizeof(struct mstdnt_storage));
storage->needs_cleanup = 0;
if (args->params_post &&
(args->request_type == CURLOPT_POST ||
@ -175,6 +172,8 @@ int mstdnt_request(mastodont_t* data,
m_args,
cb_request,
cb_args,
args->callback,
args->args,
url_query,
args->request_type,
args->request_type_custom);

View file

@ -13,6 +13,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <features.h>
#include <string.h>
#include <stdlib.h>
#include <mastodont_hooks.h>
@ -131,29 +132,32 @@ int mstdnt_status_json(struct mstdnt_status* status, cJSON* js)
return 0;
}
int mstdnt_status_json_callback(cJSON* json, void* status)
int mstdnt_status_json_callback(cJSON* json, void** _args)
{
return mstdnt_status_json((struct mstdnt_status*)status, json->child);
struct mstdnt_status* status = malloc(sizeof(struct mstdnt_status));
*_args = status;
return mstdnt_status_json(status, json->child);
}
// GENERATE mstdnt_statuses_json
GENERATE_JSON_ARRAY_FUNC(mstdnt_statuses_json, struct mstdnt_status, mstdnt_status_json)
int mstdnt_statuses_json_callback(cJSON* json, void* _args)
int mstdnt_statuses_json_callback(cJSON* json, void** _args)
{
struct _mstdnt_statuses_cb_args* args = _args;
return mstdnt_statuses_json(args->statuses, args->size, json);
struct mstdnt_statuses* statuses = malloc(sizeof(struct mstdnt_statuses));
*_args = statuses;
return mstdnt_statuses_json(&(statuses->statuses), &(statuses->size), json);
}
int mstdnt_get_account_statuses(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_account_statuses_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size)
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_account_statuses_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size)
{
char url[MSTDNT_URLSIZE];
struct _mstdnt_statuses_cb_args req_cb_args = { statuses, size };
@ -391,26 +395,27 @@ int mstdnt_status_context_json(struct mstdnt_status* statuses_before[],
return 0;
}
int mstdnt_status_context_json_callback(cJSON* json, void* _args)
int mstdnt_status_context_json_callback(cJSON* json, void** _args)
{
struct _mstdnt_status_context_result_cb_args* args = _args;
return mstdnt_status_context_json(args->statuses_before,
args->statuses_after,
args->size_before,
args->size_after,
struct mstdnt_status_context* ctx = malloc(sizeof(struct mstdnt_status_context));
*_args = ctx;
return mstdnt_status_context_json(&(ctx->before.statuses),
&(ctx->after.statuses),
&(ctx->before.len),
&(ctx->after.len),
json);
}
int mstdnt_get_status_context(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses_before[],
struct mstdnt_status* statuses_after[],
size_t* size_before,
size_t* size_after)
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* id,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses_before[],
struct mstdnt_status* statuses_after[],
size_t* size_before,
size_t* size_after)
{
struct _mstdnt_status_context_result_cb_args args = {
statuses_before,

View file

@ -21,16 +21,12 @@
#include <mastodont_request.h>
int mstdnt_timeline_list(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* list_id,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size)
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* list_id,
struct mstdnt_timeline_args* args)
{
struct _mstdnt_statuses_cb_args req_cb_args = { statuses, size };
char url[MSTDNT_URLSIZE];
snprintf(url, MSTDNT_URLSIZE, "api/v1/timelines/list/%s", list_id);
@ -48,30 +44,28 @@ void* cb_args,
};
struct mstdnt_request_args req_args = {
storage,
url,
params, _mstdnt_arr_len(params),
NULL, 0,
CURLOPT_HTTPGET,
NULL,
&req_cb_args,
mstdnt_statuses_json_callback,
.storage = storage,
.url = url,
.params_query = params,
.params_query_len = _mstdnt_arr_len(params),
.params_post = NULL,
.params_post_len = 0,
.request_type = CURLOPT_HTTPGET,
.request_type_custom = NULL,
.args = NULL,
.callback = mstdnt_statuses_json_callback,
};
return mstdnt_request(data, m_args, cb_request, cb_args, &req_args);
}
int mstdnt_timeline_tag(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* hashtag,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size)
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
char* hashtag,
struct mstdnt_timeline_args* args)
{
struct _mstdnt_statuses_cb_args req_cb_args = { statuses, size };
char url[MSTDNT_URLSIZE];
snprintf(url, MSTDNT_URLSIZE, "api/v1/timelines/tag/%s", hashtag);
@ -92,14 +86,16 @@ void* cb_args,
};
struct mstdnt_request_args req_args = {
storage,
url,
params, _mstdnt_arr_len(params),
NULL, 0,
CURLOPT_HTTPGET,
NULL,
&req_cb_args,
mstdnt_statuses_json_callback,
.storage = storage,
.url = url,
.params_query = params,
.params_query_len = _mstdnt_arr_len(params),
.params_post = NULL,
.params_post_len = 0,
.request_type = CURLOPT_HTTPGET,
.request_type_custom = NULL,
.args = NULL,
.callback = mstdnt_statuses_json_callback,
};
return mstdnt_request(data, m_args, cb_request, cb_args, &req_args);
@ -120,15 +116,14 @@ static const char* reply_visibility_str(enum mstdnt_reply_visibility vis)
}
int mstdnt_timeline_public(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size)
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size)
{
struct _mstdnt_statuses_cb_args req_cb_args = { statuses, size };
struct _mstdnt_query_param params[] = {
{ _MSTDNT_QUERY_BOOL, "local", { .b = args->local } },
{ _MSTDNT_QUERY_STRING, "instance", { .s = args->instance } },
@ -142,16 +137,18 @@ void* cb_args,
{ _MSTDNT_QUERY_INT, "offset", { .i = args->offset } },
{ _MSTDNT_QUERY_INT, "limit", { .i = args->limit } },
};
struct mstdnt_request_args req_args = {
storage,
"api/v1/timelines/public",
params, _mstdnt_arr_len(params),
NULL, 0,
CURLOPT_HTTPGET,
NULL,
&req_cb_args,
mstdnt_statuses_json_callback,
.storage = storage,
.url = "api/v1/timelines/public",
.params_query = params,
.params_query_len = _mstdnt_arr_len(params),
.params_post = NULL,
.params_post_len = 0,
.request_type = CURLOPT_HTTPGET,
.request_type_custom = NULL,
.args = NULL,
.callback = mstdnt_statuses_json_callback,
};
return mstdnt_request(data, m_args, cb_request, cb_args, &req_args);
@ -159,16 +156,14 @@ void* cb_args,
int mstdnt_timeline_direct(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size)
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size)
{
struct _mstdnt_statuses_cb_args req_cb_args = { statuses, size };
struct _mstdnt_query_param params[] = {
{ _MSTDNT_QUERY_STRING, "max_id", { .s = args->max_id } },
{ _MSTDNT_QUERY_STRING, "since_id", { .s = args->since_id } },
@ -185,7 +180,7 @@ void* cb_args,
NULL, 0,
CURLOPT_HTTPGET,
NULL,
&req_cb_args,
NULL,
mstdnt_statuses_json_callback,
};
@ -194,16 +189,11 @@ void* cb_args,
int mstdnt_timeline_home(mastodont_t* data,
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args,
struct mstdnt_storage* storage,
struct mstdnt_status* statuses[],
size_t* size)
struct mstdnt_args* m_args,
mstdnt_request_cb_t cb_request,
void* cb_args,
struct mstdnt_timeline_args* args)
{
struct _mstdnt_statuses_cb_args req_cb_args = { statuses, size };
struct _mstdnt_query_param params[] = {
{ _MSTDNT_QUERY_BOOL, "local", { .b = args->local } },
{ _MSTDNT_QUERY_BOOL, "remote", { .b = args->remote } },
@ -225,7 +215,7 @@ void* cb_args,
NULL, 0,
CURLOPT_HTTPGET,
NULL,
&req_cb_args,
NULL,
mstdnt_statuses_json_callback,
};