mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 03:25:31 +00:00
glib_compat: make the API compatible with glib
This commit is contained in:
parent
7287f2a82f
commit
6b57da1fc2
|
@ -49,7 +49,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
This may be marginally better than what glib does in their direct_hash
|
This may be marginally better than what glib does in their direct_hash
|
||||||
but someone with some chops in this space should fix if it needs improving
|
but someone with some chops in this space should fix if it needs improving
|
||||||
*/
|
*/
|
||||||
guint g_direct_hash(const void *v)
|
guint g_direct_hash(gconstpointer v)
|
||||||
{
|
{
|
||||||
#ifdef __HAVE_64_BIT_PTRS
|
#ifdef __HAVE_64_BIT_PTRS
|
||||||
uint64_t hash = (uint64_t)v;
|
uint64_t hash = (uint64_t)v;
|
||||||
|
@ -67,7 +67,7 @@ guint g_direct_hash(const void *v)
|
||||||
djb2+ string hashing
|
djb2+ string hashing
|
||||||
see: http://www.cse.yorku.ca/~oz/hash.html
|
see: http://www.cse.yorku.ca/~oz/hash.html
|
||||||
*/
|
*/
|
||||||
guint g_str_hash(const void *v)
|
guint g_str_hash(gconstpointer v)
|
||||||
{
|
{
|
||||||
const char *s = (const char*)v;
|
const char *s = (const char*)v;
|
||||||
guint hash = 5381;
|
guint hash = 5381;
|
||||||
|
@ -78,7 +78,7 @@ guint g_str_hash(const void *v)
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
int g_str_equal(const void *v1, const void *v2)
|
gboolean g_str_equal(gconstpointer v1, gconstpointer v2)
|
||||||
{
|
{
|
||||||
return strcmp((const char*)v1, (const char*)v2) == 0;
|
return strcmp((const char*)v1, (const char*)v2) == 0;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ int g_str_equal(const void *v1, const void *v2)
|
||||||
Bob Jenkins integer hash algorithm
|
Bob Jenkins integer hash algorithm
|
||||||
see: http://burtleburtle.net/bob/hash/integer.html
|
see: http://burtleburtle.net/bob/hash/integer.html
|
||||||
*/
|
*/
|
||||||
guint g_int_hash(const void *v)
|
guint g_int_hash(gconstpointer v)
|
||||||
{
|
{
|
||||||
guint hash = *(const guint*)v;
|
guint hash = *(const guint*)v;
|
||||||
hash = (hash + 0x7ed55d16) + (hash << 12);
|
hash = (hash + 0x7ed55d16) + (hash << 12);
|
||||||
|
@ -99,7 +99,7 @@ guint g_int_hash(const void *v)
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
int g_int_equal(const void *v1, const void *v2)
|
gboolean g_int_equal(gconstpointer v1, gconstpointer v2)
|
||||||
{
|
{
|
||||||
return *(const int*)v1 == *(const int*)v2;
|
return *(const int*)v1 == *(const int*)v2;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ GList *g_list_first(GList *list)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
void g_list_foreach(GList *list, GFunc func, void* user_data)
|
void g_list_foreach(GList *list, GFunc func, gpointer user_data)
|
||||||
{
|
{
|
||||||
GList *lp;
|
GList *lp;
|
||||||
for (lp = list; lp; lp = lp->next) {
|
for (lp = list; lp; lp = lp->next) {
|
||||||
|
@ -135,7 +135,7 @@ void g_list_free(GList *list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GList *g_list_insert_sorted(GList *list, void* data, GCompareFunc compare)
|
GList *g_list_insert_sorted(GList *list, gpointer data, GCompareFunc compare)
|
||||||
{
|
{
|
||||||
GList *i;
|
GList *i;
|
||||||
GList *n = (GList*)g_malloc(sizeof(GList));
|
GList *n = (GList*)g_malloc(sizeof(GList));
|
||||||
|
@ -159,7 +159,7 @@ GList *g_list_insert_sorted(GList *list, void* data, GCompareFunc compare)
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
GList *g_list_prepend(GList *list, void* data)
|
GList *g_list_prepend(GList *list, gpointer data)
|
||||||
{
|
{
|
||||||
GList *n = (GList*)g_malloc(sizeof(GList));
|
GList *n = (GList*)g_malloc(sizeof(GList));
|
||||||
n->next = list;
|
n->next = list;
|
||||||
|
@ -227,7 +227,7 @@ GList *g_list_sort(GList *list, GCompareFunc compare)
|
||||||
|
|
||||||
/* Singly-linked list */
|
/* Singly-linked list */
|
||||||
|
|
||||||
GSList *g_slist_append(GSList *list, void* data)
|
GSList *g_slist_append(GSList *list, gpointer data)
|
||||||
{
|
{
|
||||||
GSList *head = list;
|
GSList *head = list;
|
||||||
if (list) {
|
if (list) {
|
||||||
|
@ -243,7 +243,7 @@ GSList *g_slist_append(GSList *list, void* data)
|
||||||
return head;
|
return head;
|
||||||
}
|
}
|
||||||
|
|
||||||
void g_slist_foreach(GSList *list, GFunc func, void* user_data)
|
void g_slist_foreach(GSList *list, GFunc func, gpointer user_data)
|
||||||
{
|
{
|
||||||
GSList *lp;
|
GSList *lp;
|
||||||
for (lp = list; lp; lp = lp->next) {
|
for (lp = list; lp; lp = lp->next) {
|
||||||
|
@ -260,7 +260,7 @@ void g_slist_free(GSList *list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GSList *g_slist_prepend(GSList *list, void* data)
|
GSList *g_slist_prepend(GSList *list, gpointer data)
|
||||||
{
|
{
|
||||||
GSList *head = (GSList*)g_malloc(sizeof(GSList));
|
GSList *head = (GSList*)g_malloc(sizeof(GSList));
|
||||||
head->next = list;
|
head->next = list;
|
||||||
|
@ -342,7 +342,7 @@ void g_hash_table_destroy(GHashTable *hash_table)
|
||||||
g_hash_table_unref(hash_table);
|
g_hash_table_unref(hash_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* g_hash_table_find(GHashTable *hash_table, GHRFunc predicate, void* user_data)
|
gpointer g_hash_table_find(GHashTable *hash_table, GHRFunc predicate, gpointer user_data)
|
||||||
{
|
{
|
||||||
if (hash_table == NULL) return NULL;
|
if (hash_table == NULL) return NULL;
|
||||||
int i;
|
int i;
|
||||||
|
@ -356,7 +356,7 @@ void* g_hash_table_find(GHashTable *hash_table, GHRFunc predicate, void* user_da
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, void* user_data)
|
void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, gpointer user_data)
|
||||||
{
|
{
|
||||||
if (hash_table == NULL) return;
|
if (hash_table == NULL) return;
|
||||||
int i;
|
int i;
|
||||||
|
@ -369,9 +369,9 @@ void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, void* user_data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int g_hash_table_insert(GHashTable *hash_table, void* key, void* value)
|
gboolean g_hash_table_insert(GHashTable *hash_table, gpointer key, gpointer value)
|
||||||
{
|
{
|
||||||
if (hash_table == NULL) return 1;
|
if (hash_table == NULL) return TRUE;
|
||||||
GSList *lp;
|
GSList *lp;
|
||||||
guint hash = (*hash_table->hash_func)(key);
|
guint hash = (*hash_table->hash_func)(key);
|
||||||
int bnum = hash % hash_table->size;
|
int bnum = hash % hash_table->size;
|
||||||
|
@ -381,7 +381,7 @@ int g_hash_table_insert(GHashTable *hash_table, void* key, void* value)
|
||||||
if (match) {
|
if (match) {
|
||||||
/* replace */
|
/* replace */
|
||||||
kv->value = value;
|
kv->value = value;
|
||||||
return 0;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* new key */
|
/* new key */
|
||||||
|
@ -391,10 +391,10 @@ int g_hash_table_insert(GHashTable *hash_table, void* key, void* value)
|
||||||
hash_table->buckets[bnum] = g_slist_prepend(hash_table->buckets[bnum], pair);
|
hash_table->buckets[bnum] = g_slist_prepend(hash_table->buckets[bnum], pair);
|
||||||
hash_table->num_entries++;
|
hash_table->num_entries++;
|
||||||
/* grow and rehash at num_entries / size == ??? */
|
/* grow and rehash at num_entries / size == ??? */
|
||||||
return 1;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* g_hash_table_lookup(GHashTable *hash_table, const void* key)
|
gpointer g_hash_table_lookup(GHashTable *hash_table, gconstpointer key)
|
||||||
{
|
{
|
||||||
if (hash_table == NULL) return NULL;
|
if (hash_table == NULL) return NULL;
|
||||||
GSList *lp;
|
GSList *lp;
|
||||||
|
@ -448,10 +448,10 @@ void g_hash_table_remove_all(GHashTable *hash_table)
|
||||||
hash_table->num_entries = 0;
|
hash_table->num_entries = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int g_hash_table_remove(GHashTable *hash_table, const void* key)
|
gboolean g_hash_table_remove(GHashTable *hash_table, gconstpointer key)
|
||||||
{
|
{
|
||||||
GSList *lp, *prev = NULL;
|
GSList *lp, *prev = NULL;
|
||||||
if (hash_table == NULL) return 0;
|
if (hash_table == NULL) return FALSE;
|
||||||
guint hash = (*hash_table->hash_func)(key);
|
guint hash = (*hash_table->hash_func)(key);
|
||||||
int bnum = hash % hash_table->size;
|
int bnum = hash % hash_table->size;
|
||||||
for (lp = hash_table->buckets[bnum]; lp; lp = lp->next) {
|
for (lp = hash_table->buckets[bnum]; lp; lp = lp->next) {
|
||||||
|
@ -468,11 +468,11 @@ int g_hash_table_remove(GHashTable *hash_table, const void* key)
|
||||||
prev->next = lp->next;
|
prev->next = lp->next;
|
||||||
}
|
}
|
||||||
free(lp);
|
free(lp);
|
||||||
return 1;
|
return TRUE;
|
||||||
}
|
}
|
||||||
prev = lp;
|
prev = lp;
|
||||||
}
|
}
|
||||||
return 0;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void g_hash_table_unref(GHashTable *hash_table)
|
void g_hash_table_unref(GHashTable *hash_table)
|
||||||
|
@ -501,12 +501,12 @@ guint g_hash_table_size(GHashTable *hash_table)
|
||||||
|
|
||||||
/* general g_XXX substitutes */
|
/* general g_XXX substitutes */
|
||||||
|
|
||||||
void g_free(void *ptr)
|
void g_free(gpointer ptr)
|
||||||
{
|
{
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *g_malloc(size_t size)
|
gpointer g_malloc(size_t size)
|
||||||
{
|
{
|
||||||
if (size == 0) return NULL;
|
if (size == 0) return NULL;
|
||||||
void *res = malloc(size);
|
void *res = malloc(size);
|
||||||
|
@ -514,7 +514,7 @@ void *g_malloc(size_t size)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *g_malloc0(size_t size)
|
gpointer g_malloc0(size_t size)
|
||||||
{
|
{
|
||||||
if (size == 0) return NULL;
|
if (size == 0) return NULL;
|
||||||
void *res = calloc(size, 1);
|
void *res = calloc(size, 1);
|
||||||
|
@ -522,14 +522,14 @@ void *g_malloc0(size_t size)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *g_try_malloc0(size_t size)
|
gpointer g_try_malloc0(size_t size)
|
||||||
{
|
{
|
||||||
if (size == 0) return NULL;
|
if (size == 0) return NULL;
|
||||||
void *res = calloc(size, 1);
|
void *res = calloc(size, 1);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *g_realloc(void *ptr, size_t size)
|
gpointer g_realloc(gpointer ptr, size_t size)
|
||||||
{
|
{
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
free(ptr);
|
free(ptr);
|
||||||
|
@ -581,7 +581,7 @@ void g_strfreev(char **str_array)
|
||||||
free(str_array);
|
free(str_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *g_memdup(const void *mem, size_t byte_size)
|
gpointer g_memdup(gconstpointer mem, size_t byte_size)
|
||||||
{
|
{
|
||||||
if (mem) {
|
if (mem) {
|
||||||
void *res = g_malloc(byte_size);
|
void *res = g_malloc(byte_size);
|
||||||
|
@ -591,21 +591,21 @@ void *g_memdup(const void *mem, size_t byte_size)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *g_new_(size_t sz, size_t n_structs)
|
gpointer g_new_(size_t sz, size_t n_structs)
|
||||||
{
|
{
|
||||||
size_t need = sz * n_structs;
|
size_t need = sz * n_structs;
|
||||||
if ((need / sz) != n_structs) return NULL;
|
if ((need / sz) != n_structs) return NULL;
|
||||||
return g_malloc(need);
|
return g_malloc(need);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *g_new0_(size_t sz, size_t n_structs)
|
gpointer g_new0_(size_t sz, size_t n_structs)
|
||||||
{
|
{
|
||||||
size_t need = sz * n_structs;
|
size_t need = sz * n_structs;
|
||||||
if ((need / sz) != n_structs) return NULL;
|
if ((need / sz) != n_structs) return NULL;
|
||||||
return g_malloc0(need);
|
return g_malloc0(need);
|
||||||
}
|
}
|
||||||
|
|
||||||
void *g_renew_(size_t sz, void *mem, size_t n_structs)
|
gpointer g_renew_(size_t sz, gpointer mem, size_t n_structs)
|
||||||
{
|
{
|
||||||
size_t need = sz * n_structs;
|
size_t need = sz * n_structs;
|
||||||
if ((need / sz) != n_structs) return NULL;
|
if ((need / sz) != n_structs) return NULL;
|
||||||
|
|
|
@ -44,78 +44,79 @@ typedef unsigned int guint;
|
||||||
typedef char gchar;
|
typedef char gchar;
|
||||||
typedef int gboolean;
|
typedef int gboolean;
|
||||||
|
|
||||||
typedef void (*GFunc)(void* data, void* user_data);
|
typedef void (*GFunc)(gpointer data, gpointer user_data);
|
||||||
typedef gint (*GCompareFunc)(const void *v1, const void *v2);
|
typedef gint (*GCompareFunc)(gconstpointer v1, gconstpointer v2);
|
||||||
typedef void (*GDestroyNotify)(void *data);
|
typedef void (*GDestroyNotify)(gpointer data);
|
||||||
|
|
||||||
guint g_direct_hash(const void *v);
|
guint g_direct_hash(gconstpointer v);
|
||||||
guint g_str_hash(const void *v);
|
guint g_str_hash(gconstpointer v);
|
||||||
int g_str_equal(const void *v1, const void *v2);
|
gboolean g_str_equal(gconstpointer v1, gconstpointer v2);
|
||||||
guint g_int_hash(const void *v);
|
guint g_int_hash(gconstpointer v);
|
||||||
int g_int_equal(const void *v1, const void *v2);
|
|
||||||
|
gboolean g_int_equal(gconstpointer v1, gconstpointer v2);
|
||||||
|
|
||||||
typedef struct _GList {
|
typedef struct _GList {
|
||||||
void *data;
|
gpointer data;
|
||||||
struct _GList *next;
|
struct _GList *next;
|
||||||
struct _GList *prev;
|
struct _GList *prev;
|
||||||
} GList;
|
} GList;
|
||||||
|
|
||||||
GList *g_list_first(GList *list);
|
GList *g_list_first(GList *list);
|
||||||
void g_list_foreach(GList *list, GFunc func, void* user_data);
|
void g_list_foreach(GList *list, GFunc func, gpointer user_data);
|
||||||
void g_list_free(GList *list);
|
void g_list_free(GList *list);
|
||||||
GList *g_list_insert_sorted(GList *list, void* data, GCompareFunc compare);
|
GList *g_list_insert_sorted(GList *list, gpointer data, GCompareFunc compare);
|
||||||
#define g_list_next(list) (list->next)
|
#define g_list_next(list) (list->next)
|
||||||
GList *g_list_prepend(GList *list, void* data);
|
GList *g_list_prepend(GList *list, gpointer data);
|
||||||
GList *g_list_remove_link(GList *list, GList *llink);
|
GList *g_list_remove_link(GList *list, GList *llink);
|
||||||
GList *g_list_sort(GList *list, GCompareFunc compare);
|
GList *g_list_sort(GList *list, GCompareFunc compare);
|
||||||
|
|
||||||
typedef struct _GSList {
|
typedef struct _GSList {
|
||||||
void *data;
|
gpointer data;
|
||||||
struct _GSList *next;
|
struct _GSList *next;
|
||||||
} GSList;
|
} GSList;
|
||||||
|
|
||||||
GSList *g_slist_append(GSList *list, void* data);
|
GSList *g_slist_append(GSList *list, gpointer data);
|
||||||
void g_slist_foreach(GSList *list, GFunc func, void* user_data);
|
void g_slist_foreach(GSList *list, GFunc func, gpointer user_data);
|
||||||
void g_slist_free(GSList *list);
|
void g_slist_free(GSList *list);
|
||||||
GSList *g_slist_prepend(GSList *list, void* data);
|
GSList *g_slist_prepend(GSList *list, gpointer data);
|
||||||
GSList *g_slist_sort(GSList *list, GCompareFunc compare);
|
GSList *g_slist_sort(GSList *list, GCompareFunc compare);
|
||||||
|
|
||||||
typedef guint (*GHashFunc)(const void *key);
|
typedef guint (*GHashFunc)(gconstpointer key);
|
||||||
typedef int (*GEqualFunc)(const void *a, const void *b);
|
typedef gboolean (*GEqualFunc)(gconstpointer a, gconstpointer b);
|
||||||
typedef void (*GHFunc)(void* key, void* value, void* user_data);
|
typedef void (*GHFunc)(gpointer key, gpointer value, gpointer user_data);
|
||||||
typedef int (*GHRFunc)(void* key, void* value, void* user_data);
|
typedef gboolean (*GHRFunc)(gpointer key, gpointer value, gpointer user_data);
|
||||||
|
|
||||||
typedef struct _GHashTable GHashTable;
|
typedef struct _GHashTable GHashTable;
|
||||||
|
|
||||||
void g_hash_table_destroy(GHashTable *hash_table);
|
void g_hash_table_destroy(GHashTable *hash_table);
|
||||||
void* g_hash_table_find(GHashTable *hash_table, GHRFunc predicate, void* user_data);
|
gpointer g_hash_table_find(GHashTable *hash_table, GHRFunc predicate, gpointer user_data);
|
||||||
void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, void* user_data);
|
void g_hash_table_foreach(GHashTable *hash_table, GHFunc func, gpointer user_data);
|
||||||
int g_hash_table_insert(GHashTable *hash_table, void* key, void* value);
|
gboolean g_hash_table_insert(GHashTable *hash_table, gpointer key, gpointer value);
|
||||||
void* g_hash_table_lookup(GHashTable *hash_table, const void* key);
|
gpointer g_hash_table_lookup(GHashTable *hash_table, gconstpointer key);
|
||||||
GHashTable *g_hash_table_new(GHashFunc hash_func, GEqualFunc key_equal_func);
|
GHashTable *g_hash_table_new(GHashFunc hash_func, GEqualFunc key_equal_func);
|
||||||
GHashTable *g_hash_table_new_full(GHashFunc hash_func, GEqualFunc key_equal_func,
|
GHashTable *g_hash_table_new_full(GHashFunc hash_func, GEqualFunc key_equal_func,
|
||||||
GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func);
|
GDestroyNotify key_destroy_func, GDestroyNotify value_destroy_func);
|
||||||
void g_hash_table_remove_all(GHashTable *hash_table);
|
void g_hash_table_remove_all(GHashTable *hash_table);
|
||||||
int g_hash_table_remove(GHashTable *hash_table, const void* key);
|
gboolean g_hash_table_remove(GHashTable *hash_table, gconstpointer key);
|
||||||
void g_hash_table_unref(GHashTable *hash_table);
|
void g_hash_table_unref(GHashTable *hash_table);
|
||||||
GHashTable *g_hash_table_ref(GHashTable *hash_table);
|
GHashTable *g_hash_table_ref(GHashTable *hash_table);
|
||||||
guint g_hash_table_size(GHashTable *hash_table);
|
guint g_hash_table_size(GHashTable *hash_table);
|
||||||
|
|
||||||
/* replacement for g_malloc dependency */
|
/* replacement for g_malloc dependency */
|
||||||
void g_free(void *ptr);
|
void g_free(gpointer ptr);
|
||||||
void *g_malloc(size_t size);
|
gpointer g_malloc(size_t size);
|
||||||
void *g_malloc0(size_t size);
|
gpointer g_malloc0(size_t size);
|
||||||
void *g_try_malloc0(size_t size);
|
gpointer g_try_malloc0(size_t size);
|
||||||
void *g_realloc(void *ptr, size_t size);
|
gpointer g_realloc(gpointer ptr, size_t size);
|
||||||
char *g_strdup(const char *str);
|
char *g_strdup(const char *str);
|
||||||
char *g_strdup_printf(const char *format, ...);
|
char *g_strdup_printf(const char *format, ...);
|
||||||
char *g_strdup_vprintf(const char *format, va_list ap);
|
char *g_strdup_vprintf(const char *format, va_list ap);
|
||||||
char *g_strndup(const char *str, size_t n);
|
char *g_strndup(const char *str, size_t n);
|
||||||
void g_strfreev(char **v);
|
void g_strfreev(char **v);
|
||||||
void *g_memdup(const void *mem, size_t byte_size);
|
gpointer g_memdup(gconstpointer mem, size_t byte_size);
|
||||||
void *g_new_(size_t sz, size_t n_structs);
|
gpointer g_new_(size_t sz, size_t n_structs);
|
||||||
void *g_new0_(size_t sz, size_t n_structs);
|
gpointer g_new0_(size_t sz, size_t n_structs);
|
||||||
void *g_renew_(size_t sz, void *mem, size_t n_structs);
|
gpointer g_renew_(size_t sz, gpointer mem, size_t n_structs);
|
||||||
char *g_strconcat(const char *string1, ...);
|
char *g_strconcat(const char *string1, ...);
|
||||||
|
|
||||||
char **g_strsplit(const char *string, const char *delimiter, int max_tokens);
|
char **g_strsplit(const char *string, const char *delimiter, int max_tokens);
|
||||||
|
|
Loading…
Reference in a new issue