* [RFC v3 obexd 03/10] fuse: Add obexhlp_connect/disconnect functions with helpers
From: Michał Poczwardowski @ 2012-12-01 23:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Michał Poczwardowski
In-Reply-To: <1354403695-18985-1-git-send-email-dmp0x7c5@gmail.com>
---
fuse/helpers.c | 268 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
fuse/helpers.h | 4 +
fuse/obexfuse.c | 40 ++++++++
3 files changed, 312 insertions(+), 0 deletions(-)
diff --git a/fuse/helpers.c b/fuse/helpers.c
index 2dc309a..82797d9 100644
--- a/fuse/helpers.c
+++ b/fuse/helpers.c
@@ -43,6 +43,9 @@
#define OBEX_FTP_LS "x-obex/folder-listing"
+static GCond *obexhlp_cond;
+static GMutex *obexhlp_mutex;
+
struct obexhlp_request {
gchar *name;
gboolean complete;
@@ -52,3 +55,268 @@ struct obexhlp_location {
gchar *dir;
gchar *file;
};
+
+static volatile sig_atomic_t __sdp_io_finished = 0;
+
+/* adopted from client/bluetooth.c - search_callback() */
+static void search_callback(uint8_t type, uint16_t status,
+ uint8_t *rsp, size_t size, void *user_data)
+{
+ struct obexhlp_session *session = user_data;
+ unsigned int scanned, bytesleft = size;
+ int seqlen = 0;
+ uint8_t dataType;
+ uint16_t port = 0;
+
+ if (status || type != SDP_SVC_SEARCH_ATTR_RSP)
+ goto done;
+
+ scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
+ if (!scanned || !seqlen)
+ goto done;
+
+ rsp += scanned;
+ bytesleft -= scanned;
+ do {
+ sdp_record_t *rec;
+ sdp_list_t *protos;
+ sdp_data_t *data;
+ int recsize, ch = -1;
+
+ recsize = 0;
+ rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
+ if (!rec)
+ break;
+
+ if (!recsize) {
+ sdp_record_free(rec);
+ break;
+ }
+
+ if (!sdp_get_access_protos(rec, &protos)) {
+ port = sdp_get_proto_port(protos, RFCOMM_UUID);
+ sdp_list_foreach(protos,
+ (sdp_list_func_t) sdp_list_free, NULL);
+ sdp_list_free(protos, NULL);
+ protos = NULL;
+ goto done;
+ }
+
+ data = sdp_data_get(rec, 0x0200);
+ /* PSM must be odd and lsb of upper byte must be 0 */
+ if (data != NULL && (data->val.uint16 & 0x0101) == 0x0001)
+ ch = data->val.uint16;
+
+ sdp_record_free(rec);
+
+ if (ch > 0) {
+ port = ch;
+ break;
+ }
+
+ scanned += recsize;
+ rsp += recsize;
+ bytesleft -= recsize;
+ } while (scanned < size && bytesleft > 0);
+
+done:
+ session->channel = port;
+ __sdp_io_finished = 1;
+}
+
+static uint16_t get_ftp_channel(struct obexhlp_session* session,
+ bdaddr_t *src, bdaddr_t *dst)
+{
+ sdp_list_t *search, *attrid;
+ uint32_t range = 0x0000ffff;
+ sdp_session_t *sdp;
+ uuid_t uuid;
+
+ sdp = sdp_connect(src, dst, SDP_RETRY_IF_BUSY);
+ if (sdp == NULL)
+ return 0;
+
+ /* FTP_SDP_UUID "00001106-0000-1000-8000-00805f9b34fb" */
+ uint8_t uuid_int[] = {0, 0, 0x11, 0x06, 0, 0, 0x10, 0, 0x80,
+ 0, 0, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
+ sdp_uuid128_create(&uuid, uuid_int);
+
+ if (sdp_set_notify(sdp, search_callback, session) < 0)
+ goto done;
+
+ search = sdp_list_append(NULL, &uuid);
+ attrid = sdp_list_append(NULL, &range);
+
+ if (sdp_service_search_attr_async(sdp,
+ search, SDP_ATTR_REQ_RANGE, attrid) < 0) {
+ sdp_list_free(attrid, NULL);
+ sdp_list_free(search, NULL);
+ goto done;
+ }
+
+ sdp_list_free(attrid, NULL);
+ sdp_list_free(search, NULL);
+
+ while (!__sdp_io_finished)
+ sdp_process(sdp);
+
+done:
+ return session->channel;
+}
+
+/* taken from client/bluetooth.c - bluetooth_getpacketopt */
+static int get_packet_opt(GIOChannel *io, int *tx_mtu, int *rx_mtu)
+{
+ int sk = g_io_channel_unix_get_fd(io);
+ int type;
+ int omtu = -1;
+ int imtu = -1;
+ socklen_t len = sizeof(int);
+
+ if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
+ return -errno;
+
+ if (type != SOCK_SEQPACKET)
+ return -EINVAL;
+
+ if (!bt_io_get(io, NULL, BT_IO_OPT_OMTU, &omtu,
+ BT_IO_OPT_IMTU, &imtu,
+ BT_IO_OPT_INVALID))
+ return -EINVAL;
+
+ if (tx_mtu)
+ *tx_mtu = omtu;
+
+ if (rx_mtu)
+ *rx_mtu = imtu;
+
+ return 0;
+}
+
+static void obex_callback(GObex *obex, GError *err, GObexPacket *rsp,
+ gpointer user_data)
+{
+ if (err != NULL) {
+ g_print("OBEX Connect failed: %s\n", err->message);
+ g_error_free(err);
+ } else {
+ g_print("OBEX Connect succeeded\n");
+ }
+}
+
+static void bt_io_callback(GIOChannel *io, GError *err, gpointer user_data)
+{
+ struct obexhlp_session *session = user_data;
+ GObexTransportType type;
+ int tx_mtu = -1;
+ int rx_mtu = -1;
+
+ if (err != NULL) {
+ g_printerr("%s\n", err->message);
+ g_error_free(err);
+ return;
+ }
+
+ g_print("Bluetooth socket connected\n");
+
+ g_io_channel_set_close_on_unref(io, FALSE);
+
+ if (get_packet_opt(io, &tx_mtu, &rx_mtu) == 0) {
+ type = G_OBEX_TRANSPORT_PACKET;
+ g_print("PACKET transport tx:%d rx:%d\n", tx_mtu, rx_mtu);
+ } else {
+ type = G_OBEX_TRANSPORT_STREAM;
+ g_print("STREAM transport\n");
+ }
+
+ session->obex = g_obex_new(io, type, tx_mtu, rx_mtu);
+ if (session->obex == NULL) {
+ g_print("ERROR: obex is NULL");
+ raise(SIGTERM);
+ }
+
+ g_io_channel_set_close_on_unref(io, TRUE);
+
+ g_obex_connect(session->obex, obex_callback, session, &err,
+ G_OBEX_HDR_TARGET, OBEX_FTP_UUID,
+ OBEX_FTP_UUID_LEN, G_OBEX_HDR_INVALID);
+
+ if (err != NULL) {
+ g_print("ERROR: %s\n", err->message);
+ g_obex_unref(session->obex);
+ raise(SIGTERM);
+ }
+}
+
+struct obexhlp_session* obexhlp_connect(const char *srcstr,
+ const char *dststr)
+{
+ struct obexhlp_session *session;
+ uint16_t channel;
+ bdaddr_t src, dst;
+
+ session = g_try_malloc0(sizeof(struct obexhlp_session));
+ if (session == NULL)
+ return NULL;
+
+ if (srcstr == NULL)
+ bacpy(&src, BDADDR_ANY);
+ else
+ str2ba(srcstr, &src);
+
+ str2ba(dststr, &dst);
+ channel = get_ftp_channel(session, &src, &dst);
+
+ if (channel == 0)
+ return NULL;
+
+ if (channel > 31)
+ session->io = bt_io_connect(bt_io_callback, session,
+ NULL, &session->err,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_PSM, channel,
+ BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
+ BT_IO_OPT_OMTU, BT_TX_MTU,
+ BT_IO_OPT_IMTU, BT_RX_MTU,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_INVALID);
+ else
+ session->io = bt_io_connect(bt_io_callback, session,
+ NULL, &session->err,
+ BT_IO_OPT_SOURCE_BDADDR, &src,
+ BT_IO_OPT_DEST_BDADDR, &dst,
+ BT_IO_OPT_CHANNEL, channel,
+ BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+ BT_IO_OPT_INVALID);
+
+ if (session->err != NULL)
+ return NULL;
+
+ session->file_stat = g_hash_table_new_full( g_str_hash, g_str_equal,
+ g_free, g_free);
+ session->setpath = g_strdup("/");
+
+ obexhlp_mutex = g_mutex_new();
+ obexhlp_cond = g_cond_new();
+
+ return session;
+}
+
+void obexhlp_disconnect(struct obexhlp_session* session)
+{
+ if (session == NULL)
+ return;
+
+ g_obex_unref(session->obex);
+ g_free(session->io);
+
+ g_hash_table_remove_all(session->file_stat);
+ g_list_free_full(session->lsfiles, g_free);
+ g_free(session->setpath);
+
+ g_mutex_free(obexhlp_mutex);
+ g_cond_free(obexhlp_cond);
+
+ g_free(session);
+}
diff --git a/fuse/helpers.h b/fuse/helpers.h
index abbdd70..3ef924e 100644
--- a/fuse/helpers.h
+++ b/fuse/helpers.h
@@ -47,3 +47,7 @@ struct obexhlp_session {
int status;
GError *err;
};
+
+struct obexhlp_session* obexhlp_connect(const char *srcstr,
+ const char *dstsrc);
+void obexhlp_disconnect(struct obexhlp_session* session);
diff --git a/fuse/obexfuse.c b/fuse/obexfuse.c
index fe4f4da..d6a87f3 100644
--- a/fuse/obexfuse.c
+++ b/fuse/obexfuse.c
@@ -33,6 +33,10 @@
#include "helpers.h"
+struct obexhlp_session* session = NULL;
+static GMainLoop *main_loop;
+static GThread *main_gthread;
+
struct options {
char* dststr;
char* srcstr;
@@ -60,7 +64,34 @@ static struct fuse_opt obexfuse_opts[] =
FUSE_OPT_END
};
+gpointer main_loop_func(gpointer user_data)
+{
+ main_loop = g_main_loop_new(NULL, FALSE);
+ g_main_loop_run(main_loop);
+
+ return 0;
+}
+
+void* obexfuse_init(struct fuse_conn_info *conn)
+{
+ main_gthread = g_thread_create(main_loop_func, NULL, TRUE, NULL);
+
+ conn->async_read = 0;
+ conn->want &= ~FUSE_CAP_ASYNC_READ;
+
+ return 0;
+}
+
+void obexfuse_destroy()
+{
+ obexhlp_disconnect(session);
+ g_main_loop_quit(main_loop);
+ g_thread_join(main_gthread);
+}
+
static struct fuse_operations obexfuse_oper = {
+ .init = obexfuse_init,
+ .destroy = obexfuse_destroy,
};
static int obexfuse_opt_proc(void *data, const char *arg, int key,
@@ -111,6 +142,15 @@ int main(int argc, char *argv[])
g_thread_init(NULL);
+ session = obexhlp_connect(options.srcstr, options.dststr);
+ if (session == NULL || session->io == NULL) {
+ g_printerr("Connection to %s failed\n", options.dststr);
+ obexhlp_disconnect(session);
+ return -EHOSTUNREACH;
+ } else {
+ g_print("Connected\nMounting %s\n", options.dststr);
+ }
+
fuse_opt_add_arg(&args, "-s"); /* force single threaded mode */
retfuse = fuse_main(args.argc, args.argv, &obexfuse_oper, NULL);
--
1.7.8.6
^ permalink raw reply related
* [RFC v3 obexd 04/10] fuse: Add request helpers and setpath operation
From: Michał Poczwardowski @ 2012-12-01 23:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Michał Poczwardowski
In-Reply-To: <1354403695-18985-1-git-send-email-dmp0x7c5@gmail.com>
---
fuse/helpers.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 108 insertions(+), 0 deletions(-)
diff --git a/fuse/helpers.c b/fuse/helpers.c
index 82797d9..d3e70ff 100644
--- a/fuse/helpers.c
+++ b/fuse/helpers.c
@@ -320,3 +320,111 @@ void obexhlp_disconnect(struct obexhlp_session* session)
g_free(session);
}
+
+void request_new(struct obexhlp_session *session,
+ gchar *name)
+{
+ g_print("REQUEST %s\n", name);
+
+ if (session->request != NULL)
+ g_error("Another request (%s) active!\n",
+ session->request->name);
+
+ session->status = 0;
+ session->request = g_malloc0(sizeof(struct obexhlp_request));
+ session->request->name = name;
+
+ /*
+ * suspend/resume operations recreates g_io_add_watch(),
+ * it fixes obex->io freeze during transfer
+ */
+ g_obex_suspend(session->obex);
+ g_obex_resume(session->obex);
+}
+
+void request_wait_free(struct obexhlp_session *session)
+{
+ g_print("WAIT for %s\n", session->request->name);
+
+ g_obex_suspend(session->obex);
+ g_obex_resume(session->obex);
+
+ if (session->err != NULL) {
+ g_print("ERROR: %s (%d)\n", session->err->message,
+ session->err->code);
+ g_error_free(session->err);
+ raise(SIGTERM);
+ return;
+ }
+
+ g_mutex_lock(obexhlp_mutex);
+
+ while (session->request->complete != TRUE)
+ g_cond_wait(obexhlp_cond, obexhlp_mutex);
+
+ g_mutex_unlock(obexhlp_mutex);
+
+ g_free(session->request->name);
+ g_free(session->request);
+ session->request = NULL;
+}
+
+static void complete_func(GObex *obex, GError *err,
+ gpointer user_data)
+{
+ struct obexhlp_session *session = user_data;
+
+ if (err != NULL) {
+ g_print("ERROR: %s\n", err->message);
+ session->status = -ECANCELED;
+ g_error_free(err);
+ } else {
+ g_print("COMPLETE %s\n", session->request->name);
+ }
+
+ g_mutex_lock(obexhlp_mutex);
+ session->request->complete = TRUE;
+ g_cond_signal(obexhlp_cond);
+ g_mutex_unlock(obexhlp_mutex);
+}
+
+static void response_func(GObex *obex, GError *err, GObexPacket *rsp,
+ gpointer user_data)
+{
+ complete_func(obex, err, user_data);
+}
+
+void obexhlp_setpath(struct obexhlp_session *session, const char *path)
+{
+ guint i = 0, split = 0;
+ gchar **path_v;
+ gsize len;
+
+ g_print("obexhlp_setpath(%s)\n", path);
+
+ if (g_str_has_prefix(path, session->setpath)) {
+ split = strlen(session->setpath);
+ } else {
+ request_new(session, g_strdup_printf("setpath root"));
+ g_obex_setpath(session->obex, "", response_func,
+ session, &session->err);
+ request_wait_free(session);
+ }
+
+ path_v = g_strsplit(path+split, "/", -1);
+ len = g_strv_length(path_v);
+
+ for (i = 0; i < len; i++)
+ if (path_v[i][0] != '\0') {
+ request_new(session,
+ g_strdup_printf("setpath %s", path_v[i]));
+ g_obex_setpath(session->obex, path_v[i],
+ response_func, session, &session->err);
+ request_wait_free(session);
+ }
+
+ g_free(session->setpath);
+ session->setpath = g_strdup(path);
+
+ g_strfreev(path_v);
+}
--
1.7.8.6
^ permalink raw reply related
* [RFC v3 obexd 05/10] fuse: Add readdir operation
From: Michał Poczwardowski @ 2012-12-01 23:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Michał Poczwardowski
In-Reply-To: <1354403695-18985-1-git-send-email-dmp0x7c5@gmail.com>
---
fuse/helpers.c | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
fuse/helpers.h | 2 +
fuse/obexfuse.c | 23 ++++++++++
3 files changed, 153 insertions(+), 0 deletions(-)
diff --git a/fuse/helpers.c b/fuse/helpers.c
index d3e70ff..42a0e21 100644
--- a/fuse/helpers.c
+++ b/fuse/helpers.c
@@ -428,3 +428,131 @@ void obexhlp_setpath(struct obexhlp_session *session, const char *path)
g_strfreev(path_v);
}
+
+static void listfolder_xml_element(GMarkupParseContext *ctxt,
+ const gchar *element, const gchar **names,
+ const gchar **values, gpointer user_data,
+ GError **gerr)
+{
+ gchar *key, *pathname, *name = NULL;
+ struct obexhlp_session *session = user_data;
+ struct stat *stbuf;
+ gint i = 0;
+
+ stbuf = g_malloc0(sizeof(struct stat));
+
+ if ((strcasecmp("file", element) == 0)) {
+ stbuf->st_mode = S_IFREG;
+ } else if ((strcasecmp("folder", element)) == 0) {
+ stbuf->st_mode = S_IFDIR;
+ stbuf->st_mtime = time(NULL);
+ } else {
+ g_free(stbuf);
+ return;
+ }
+
+ for (key = (gchar *) names[i]; key; key = (gchar *) names[++i]) {
+ if (g_str_equal("name", key) == TRUE) {
+ session->lsfiles = g_list_append(session->lsfiles,
+ g_strdup(values[i]));
+ name = g_strdup(values[i]);
+
+ } else if (g_str_equal("size", key) == TRUE) {
+ guint64 size;
+ size = g_ascii_strtoll(values[i], NULL, 10);
+ stbuf->st_size = size;
+
+ } else if (g_str_equal("created", key) == TRUE) {
+ GTimeVal time;
+ GDateTime *datetime;
+ g_time_val_from_iso8601(values[i], &time);
+ datetime = g_date_time_new_from_timeval_utc(&time);
+ stbuf->st_mtime = g_date_time_to_unix(datetime);
+ }
+ }
+
+ if (g_str_equal("/", session->setpath) == TRUE)
+ pathname = g_strdup_printf("/%s", name);
+ else
+ pathname = g_strdup_printf("%s/%s", session->setpath, name);
+
+ g_hash_table_replace(session->file_stat, pathname, stbuf);
+ g_free(name);
+}
+
+static const GMarkupParser parser = {
+ listfolder_xml_element,
+ NULL, NULL, NULL, NULL
+};
+
+static void complete_listfolder_func(GObex *obex, GError *err,
+ gpointer user_data)
+{
+ GMarkupParseContext *ctxt;
+ struct obexhlp_session *session = user_data;
+ struct obexhlp_buffer *buffer = session->buffer;
+
+ if (err == NULL) {
+ ctxt = g_markup_parse_context_new(&parser, 0, session, NULL);
+ g_markup_parse_context_parse(ctxt, buffer->data, buffer->size,
+ NULL);
+ g_markup_parse_context_free(ctxt);
+ }
+
+ complete_func(obex, err, user_data);
+}
+
+static gboolean async_get_consumer(const void *buf, gsize len,
+ gpointer user_data)
+{
+ struct obexhlp_session *session = user_data;
+ struct obexhlp_buffer *buffer = session->buffer;
+
+ if (buffer->size == 0)
+ buffer->data = g_malloc0(sizeof(char) * len);
+ else
+ buffer->data = g_realloc(buffer->data, buffer->size + len);
+
+ memcpy(buffer->data + buffer->size, buf, len);
+ buffer->size += len;
+
+ g_obex_suspend(session->obex);
+ g_obex_resume(session->obex);
+
+ return TRUE;
+}
+
+GList *obexhlp_listfolder(struct obexhlp_session* session,
+ const char *path)
+{
+ struct obexhlp_buffer *buffer;
+ GObexPacket *req;
+ guint reqpkt;
+
+ obexhlp_setpath(session, path);
+
+ g_print("obexhlp_listfolder(%s)\n", path);
+
+ if (session->lsfiles != NULL) {
+ g_list_free_full(session->lsfiles, g_free);
+ session->lsfiles = NULL;
+ }
+
+ session->lsfiles = g_list_alloc();
+ buffer = g_malloc0(sizeof(struct obexhlp_buffer));
+ session->buffer = buffer;
+
+ request_new(session, g_strdup_printf("listfolder %s", path));
+ req = g_obex_packet_new(G_OBEX_OP_GET, TRUE, G_OBEX_HDR_INVALID);
+ g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, OBEX_FTP_LS,
+ strlen(OBEX_FTP_LS) + 1);
+ reqpkt = g_obex_get_req_pkt(session->obex, req,
+ async_get_consumer,
+ complete_listfolder_func,
+ session, &session->err);
+ request_wait_free(session);
+ g_free(buffer->data);
+ g_free(buffer);
+
+ return session->lsfiles;
+}
diff --git a/fuse/helpers.h b/fuse/helpers.h
index 3ef924e..832f856 100644
--- a/fuse/helpers.h
+++ b/fuse/helpers.h
@@ -51,3 +51,5 @@ struct obexhlp_session {
struct obexhlp_session* obexhlp_connect(const char *srcstr,
const char *dstsrc);
void obexhlp_disconnect(struct obexhlp_session* session);
+
+GList *obexhlp_listfolder(struct obexhlp_session* session, const char *path);
diff --git a/fuse/obexfuse.c b/fuse/obexfuse.c
index d6a87f3..0560031 100644
--- a/fuse/obexfuse.c
+++ b/fuse/obexfuse.c
@@ -89,7 +89,30 @@ void obexfuse_destroy()
g_thread_join(main_gthread);
}
+static int obexfuse_readdir(const char *path, void *buf,
+ fuse_fill_dir_t filler, off_t offset,
+ struct fuse_file_info *fi)
+{
+ int len, i;
+ gchar *string;
+ GList *files;
+
+ filler(buf, ".", NULL, 0);
+ filler(buf, "..", NULL, 0);
+
+ files = obexhlp_listfolder(session, path);
+ len = g_list_length(files);
+
+ for (i = 1; i < len; i++) { /* element for i==0 is NULL */
+ string = g_list_nth_data(files, i);
+ filler(buf, string, NULL, 0);
+ }
+
+ return session->status;
+}
+
static struct fuse_operations obexfuse_oper = {
+ .readdir = obexfuse_readdir,
.init = obexfuse_init,
.destroy = obexfuse_destroy,
};
--
1.7.8.6
^ permalink raw reply related
* [RFC v3 obexd 06/10] fuse: Add getattr operation
From: Michał Poczwardowski @ 2012-12-01 23:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Michał Poczwardowski
In-Reply-To: <1354403695-18985-1-git-send-email-dmp0x7c5@gmail.com>
---
fuse/helpers.c | 6 ++++++
fuse/helpers.h | 2 ++
fuse/obexfuse.c | 34 ++++++++++++++++++++++++++++++++++
3 files changed, 42 insertions(+), 0 deletions(-)
diff --git a/fuse/helpers.c b/fuse/helpers.c
index 42a0e21..4e4747d 100644
--- a/fuse/helpers.c
+++ b/fuse/helpers.c
@@ -556,3 +556,9 @@ GList *obexhlp_listfolder(struct obexhlp_session* session,
return session->lsfiles;
}
+
+struct stat *obexhlp_getattr(struct obexhlp_session* session,
+ const char *path)
+{
+ return g_hash_table_lookup(session->file_stat, path);
+}
diff --git a/fuse/helpers.h b/fuse/helpers.h
index 832f856..0435317 100644
--- a/fuse/helpers.h
+++ b/fuse/helpers.h
@@ -53,3 +53,5 @@ struct obexhlp_session* obexhlp_connect(const char *srcstr,
void obexhlp_disconnect(struct obexhlp_session* session);
GList *obexhlp_listfolder(struct obexhlp_session* session, const char *path);
+struct stat *obexhlp_getattr(struct obexhlp_session* session,
+ const char *path);
diff --git a/fuse/obexfuse.c b/fuse/obexfuse.c
index 0560031..5270293 100644
--- a/fuse/obexfuse.c
+++ b/fuse/obexfuse.c
@@ -111,8 +111,42 @@ static int obexfuse_readdir(const char *path, void *buf,
return session->status;
}
+static int obexfuse_getattr(const char *path, struct stat *stbuf)
+{
+ int res = 0;
+ struct stat *stfile;
+
+ memset(stbuf, 0, sizeof(struct stat));
+
+ if (strcmp(path, "/") == 0) {
+ stbuf->st_mode = S_IFDIR | 0755;
+ stbuf->st_nlink = 2;
+ } else {
+ stfile = obexhlp_getattr(session, path);
+
+ if (stfile == NULL)
+ return -ENOENT;
+
+ if (stfile->st_mode == S_IFREG)
+ stbuf->st_mode = stfile->st_mode | 0666;
+ else /* S_IFDIR */
+ stbuf->st_mode = stfile->st_mode | 0755;
+
+ stbuf->st_nlink = 1;
+ stbuf->st_size = stfile->st_size;
+ stbuf->st_mtime = stbuf->st_atime = stbuf->st_ctime =
+ stfile->st_mtime;
+ stbuf->st_blksize = 512;
+ stbuf->st_blocks = (stbuf->st_size + stbuf->st_blksize)
+ / stbuf->st_blksize;
+ }
+
+ return res;
+}
+
static struct fuse_operations obexfuse_oper = {
.readdir = obexfuse_readdir,
+ .getattr = obexfuse_getattr,
.init = obexfuse_init,
.destroy = obexfuse_destroy,
};
--
1.7.8.6
^ permalink raw reply related
* [RFC v3 obexd 07/10] fuse: Add open and read operations plus location helpers
From: Michał Poczwardowski @ 2012-12-01 23:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Michał Poczwardowski
In-Reply-To: <1354403695-18985-1-git-send-email-dmp0x7c5@gmail.com>
---
fuse/helpers.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
fuse/helpers.h | 2 +
fuse/obexfuse.c | 32 ++++++++++++++++++++++++++++
3 files changed, 96 insertions(+), 0 deletions(-)
diff --git a/fuse/helpers.c b/fuse/helpers.c
index 4e4747d..72b0b3e 100644
--- a/fuse/helpers.c
+++ b/fuse/helpers.c
@@ -562,3 +562,65 @@ struct stat *obexhlp_getattr(struct obexhlp_session* session,
{
return g_hash_table_lookup(session->file_stat, path);
}
+
+static struct obexhlp_location *get_location(const char *path)
+{
+ struct obexhlp_location *location;
+ gchar **directories;
+ guint i, len, fid = 0;
+
+ location = g_malloc0(sizeof(*location));
+ directories = g_strsplit(path, "/", -1);
+ len = g_strv_length(directories);
+
+ for (i = 0; i < len; i++)
+ if (directories[i][0] != '\0') /* protect multi slashes */
+ fid = i; /* last nonempty is a file */
+
+ location->file = g_strdup(directories[fid]);
+ directories[fid][0] = '\0'; /* remove file */
+ location->dir = g_strjoinv("/", directories);
+
+ g_strfreev(directories);
+
+ return location;
+}
+
+void free_location(struct obexhlp_location *location)
+{
+ g_free(location->file);
+ g_free(location->dir);
+ g_free(location);
+}
+
+struct obexhlp_buffer *obexhlp_get(struct obexhlp_session* session,
+ const char *path)
+{
+ struct obexhlp_location *l;
+ struct obexhlp_buffer *buffer;
+ struct stat *stfile;
+ l = get_location(path);
+
+ g_print("obexhlp_get(%s%s)\n", l->dir, l->file);
+
+ stfile = obexhlp_getattr(session, path);
+ if (stfile == NULL)
+ return NULL;
+
+ buffer = g_malloc0(sizeof(*buffer));
+
+ if (stfile->st_size == 0)
+ return buffer;
+
+ obexhlp_setpath(session, l->dir);
+ request_new(session, g_strdup_printf("get %s", path));
+ session->buffer = buffer;
+ g_obex_get_req(session->obex, async_get_consumer,
+ complete_func, session, &session->err,
+ G_OBEX_HDR_NAME, l->file,
+ G_OBEX_HDR_INVALID);
+ free_location(l);
+ request_wait_free(session);
+
+ return buffer;
+}
diff --git a/fuse/helpers.h b/fuse/helpers.h
index 0435317..9080590 100644
--- a/fuse/helpers.h
+++ b/fuse/helpers.h
@@ -55,3 +55,5 @@ void obexhlp_disconnect(struct obexhlp_session* session);
GList *obexhlp_listfolder(struct obexhlp_session* session, const char *path);
struct stat *obexhlp_getattr(struct obexhlp_session* session,
const char *path);
+struct obexhlp_buffer *obexhlp_get(struct obexhlp_session* session,
+ const char *path);
diff --git a/fuse/obexfuse.c b/fuse/obexfuse.c
index 5270293..e185250 100644
--- a/fuse/obexfuse.c
+++ b/fuse/obexfuse.c
@@ -144,9 +144,41 @@ static int obexfuse_getattr(const char *path, struct stat *stbuf)
return res;
}
+static int obexfuse_open(const char *path, struct fuse_file_info *fi)
+{
+ struct obexhlp_buffer *file_buffer;
+
+ file_buffer = obexhlp_get(session, path);
+
+ if (file_buffer == NULL)
+ return -ENOENT;
+
+ fi->fh = (uint64_t)file_buffer;
+
+ return session->status;
+}
+
+static int obexfuse_read(const char *path, char *buf, size_t size,
+ off_t offset, struct fuse_file_info *fi)
+{
+ gsize asize;
+ struct obexhlp_buffer *file_buffer = (struct obexhlp_buffer*)fi->fh;
+
+ asize = file_buffer->size - offset;
+
+ if (asize > size)
+ asize = size;
+
+ memcpy(buf, file_buffer->data + offset, asize);
+
+ return asize;
+}
+
static struct fuse_operations obexfuse_oper = {
.readdir = obexfuse_readdir,
.getattr = obexfuse_getattr,
+ .open = obexfuse_open,
+ .read = obexfuse_read,
.init = obexfuse_init,
.destroy = obexfuse_destroy,
};
--
1.7.8.6
^ permalink raw reply related
* [RFC v3 obexd 08/10] fuse: Add write and touch operations
From: Michał Poczwardowski @ 2012-12-01 23:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Michał Poczwardowski
In-Reply-To: <1354403695-18985-1-git-send-email-dmp0x7c5@gmail.com>
---
fuse/helpers.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
fuse/helpers.h | 4 ++
fuse/obexfuse.c | 61 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/fuse/helpers.c b/fuse/helpers.c
index 72b0b3e..b4bd7e5 100644
--- a/fuse/helpers.c
+++ b/fuse/helpers.c
@@ -56,6 +56,8 @@ struct obexhlp_location {
gchar *file;
};
+void obexhlp_touch_real(struct obexhlp_session* session, gchar *path);
+
static volatile sig_atomic_t __sdp_io_finished = 0;
/* adopted from client/bluetooth.c - search_callback() */
@@ -326,6 +328,12 @@ void request_new(struct obexhlp_session *session,
{
g_print("REQUEST %s\n", name);
+ if (session->vtouch == TRUE) {
+ session->vtouch = FALSE;
+ obexhlp_touch_real(session, session->vtouch_path);
+ g_free(session->vtouch_path);
+ }
+
if (session->request != NULL)
g_error("Another request (%s) active!\n",
session->request->name);
@@ -624,3 +632,79 @@ struct obexhlp_buffer *obexhlp_get(struct obexhlp_session* session,
return buffer;
}
+
+static gssize async_put_producer(void *buf, gsize len, gpointer user_data)
+{
+ gssize size;
+ struct obexhlp_session *session = user_data;
+ struct obexhlp_buffer *buffer = session->buffer;
+
+ size = buffer->size - buffer->tmpsize;
+
+ if (size > len)
+ size = len;
+
+ g_obex_suspend(session->obex);
+ g_obex_resume(session->obex);
+
+ if (size == 0)
+ return 0;
+
+ memcpy(buf, buffer->data + buffer->tmpsize, size);
+ buffer->tmpsize += size;
+
+ return size;
+}
+
+void obexhlp_put(struct obexhlp_session* session,
+ struct obexhlp_buffer *buffer,
+ const char *path)
+{
+ struct obexhlp_location *l;
+ l = get_location(path);
+
+ g_print("obexhlp_put(%s%s)\n", l->dir, l->file);
+
+ obexhlp_setpath(session, l->dir);
+ buffer->tmpsize = 0;
+ session->buffer = buffer;
+ request_new(session, g_strdup_printf("put %s", path));
+ g_obex_put_req(session->obex, async_put_producer,
+ complete_func, session, &session->err,
+ G_OBEX_HDR_NAME, l->file,
+ G_OBEX_HDR_INVALID);
+ free_location(l);
+ request_wait_free(session);
+}
+
+/* virtual file creation */
+void obexhlp_touch(struct obexhlp_session* session, const char *path)
+{
+ struct stat *stbuf;
+
+ g_print("obexhlp_touch(%s)\n", path);
+
+ stbuf = g_malloc0(sizeof(struct stat));
+ stbuf->st_mode = S_IFREG;
+ g_hash_table_replace(session->file_stat, g_strdup(path), stbuf);
+
+ session->vtouch = TRUE;
+ session->vtouch_path = g_strdup(path);
+}
+
+void obexhlp_touch_real(struct obexhlp_session* session, gchar *path)
+{
+ struct obexhlp_buffer *buffer, *tmpbuf;
+
+ g_print("obexhlp_touch_real(%s)\n", path);
+
+ tmpbuf = session->buffer; /* save buffer state */
+
+ buffer = g_malloc0(sizeof(struct obexhlp_buffer));
+ session->rtouch = TRUE;
+ obexhlp_put(session, buffer, path);
+ session->rtouch = FALSE;
+ g_free(buffer);
+
+ session->buffer = tmpbuf;
+}
diff --git a/fuse/helpers.h b/fuse/helpers.h
index 9080590..4372fdf 100644
--- a/fuse/helpers.h
+++ b/fuse/helpers.h
@@ -57,3 +57,7 @@ struct stat *obexhlp_getattr(struct obexhlp_session* session,
const char *path);
struct obexhlp_buffer *obexhlp_get(struct obexhlp_session* session,
const char *path);
+void obexhlp_put(struct obexhlp_session* session,
+ struct obexhlp_buffer *buffer,
+ const char *path);
+void obexhlp_touch(struct obexhlp_session* session, const char *path);
diff --git a/fuse/obexfuse.c b/fuse/obexfuse.c
index e185250..4a9f297 100644
--- a/fuse/obexfuse.c
+++ b/fuse/obexfuse.c
@@ -174,11 +174,72 @@ static int obexfuse_read(const char *path, char *buf, size_t size,
return asize;
}
+static int obexfuse_write(const char *path, const char *buf, size_t size,
+ off_t offset, struct fuse_file_info *fi)
+{
+ gsize nsize;
+ struct obexhlp_buffer *file_buffer = (struct obexhlp_buffer*)fi->fh;
+
+ if (file_buffer->size < offset + size) {
+ nsize = offset + size;
+ file_buffer->data = g_realloc(file_buffer->data, nsize);
+ file_buffer->size = nsize;
+ } else {
+ nsize = file_buffer->size;
+ }
+
+ file_buffer->edited = TRUE;
+ memcpy(file_buffer->data + offset, buf, size);
+
+ return size;
+}
+
+static int obexfuse_truncate(const char *path, off_t offset)
+{
+ /*
+ * Allow to change the size of a file.
+ */
+ return 0;
+}
+
+static int obexfuse_release(const char *path, struct fuse_file_info *fi)
+{
+ struct obexhlp_buffer *file_buffer = (struct obexhlp_buffer*)fi->fh;
+
+ if (file_buffer->edited == TRUE)
+ obexhlp_put(session, file_buffer, path); /* send to device */
+
+ g_free(file_buffer->data);
+ g_free(file_buffer);
+
+ return session->status;
+}
+
+static int obexfuse_utimens(const char *path, const struct timespec tv[2])
+{
+ /*
+ * Important for mknod (touch) operation
+ */
+ return 0;
+}
+
+static int obexfuse_mknod(const char *path, mode_t mode, dev_t dev)
+{
+ obexhlp_touch(session, path);
+
+ return 0;
+}
+
static struct fuse_operations obexfuse_oper = {
.readdir = obexfuse_readdir,
.getattr = obexfuse_getattr,
.open = obexfuse_open,
.read = obexfuse_read,
+ .write = obexfuse_write,
+ .truncate = obexfuse_truncate,
+ .release = obexfuse_release,
+ .utimens = obexfuse_utimens,
+ .mknod = obexfuse_mknod,
.init = obexfuse_init,
.destroy = obexfuse_destroy,
};
--
1.7.8.6
^ permalink raw reply related
* [RFC v3 obexd 09/10] fuse: Add unlink/rmdir operation
From: Michał Poczwardowski @ 2012-12-01 23:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Michał Poczwardowski
In-Reply-To: <1354403695-18985-1-git-send-email-dmp0x7c5@gmail.com>
---
fuse/helpers.c | 28 ++++++++++++++++++++++++++++
fuse/helpers.h | 1 +
fuse/obexfuse.c | 9 +++++++++
3 files changed, 38 insertions(+), 0 deletions(-)
diff --git a/fuse/helpers.c b/fuse/helpers.c
index b4bd7e5..a523cc3 100644
--- a/fuse/helpers.c
+++ b/fuse/helpers.c
@@ -665,6 +665,16 @@ void obexhlp_put(struct obexhlp_session* session,
g_print("obexhlp_put(%s%s)\n", l->dir, l->file);
+ if (g_strcmp0(path, session->vtouch_path) == 0 &&
+ session->vtouch == TRUE) {
+ session->vtouch = FALSE;
+ g_free(session->vtouch_path);
+ } else {
+ /* delete existing file */
+ if (session->rtouch == FALSE)
+ obexhlp_delete(session, path);
+ }
+
obexhlp_setpath(session, l->dir);
buffer->tmpsize = 0;
session->buffer = buffer;
@@ -708,3 +718,21 @@ void obexhlp_touch_real(struct obexhlp_session* session, gchar *path)
session->buffer = tmpbuf;
}
+
+void obexhlp_delete(struct obexhlp_session* session, const char *path)
+{
+ struct obexhlp_location *l;
+ l = get_location(path);
+
+ g_print("obexhlp_delete(%s)\n", l->file);
+
+ obexhlp_setpath(session, l->dir);
+ request_new(session, g_strdup_printf("delete %s", path));
+ g_obex_delete(session->obex, l->file, response_func, session,
+ &session->err);
+
+ g_hash_table_remove(session->file_stat, path);
+
+ free_location(l);
+ request_wait_free(session);
+}
diff --git a/fuse/helpers.h b/fuse/helpers.h
index 4372fdf..362e322 100644
--- a/fuse/helpers.h
+++ b/fuse/helpers.h
@@ -61,3 +61,4 @@ void obexhlp_put(struct obexhlp_session* session,
struct obexhlp_buffer *buffer,
const char *path);
void obexhlp_touch(struct obexhlp_session* session, const char *path);
+void obexhlp_delete(struct obexhlp_session* session, const char *path);
diff --git a/fuse/obexfuse.c b/fuse/obexfuse.c
index 4a9f297..065b6a6 100644
--- a/fuse/obexfuse.c
+++ b/fuse/obexfuse.c
@@ -230,6 +230,13 @@ static int obexfuse_mknod(const char *path, mode_t mode, dev_t dev)
return 0;
}
+static int obexfuse_unlink(const char *path)
+{
+ obexhlp_delete(session, path);
+
+ return session->status;
+}
+
static struct fuse_operations obexfuse_oper = {
.readdir = obexfuse_readdir,
.getattr = obexfuse_getattr,
@@ -240,6 +247,8 @@ static struct fuse_operations obexfuse_oper = {
.release = obexfuse_release,
.utimens = obexfuse_utimens,
.mknod = obexfuse_mknod,
+ .unlink = obexfuse_unlink,
+ .rmdir = obexfuse_unlink,
.init = obexfuse_init,
.destroy = obexfuse_destroy,
};
--
1.7.8.6
^ permalink raw reply related
* [RFC v3 obexd 10/10] fuse: Add rename operation
From: Michał Poczwardowski @ 2012-12-01 23:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Michał Poczwardowski
In-Reply-To: <1354403695-18985-1-git-send-email-dmp0x7c5@gmail.com>
---
fuse/helpers.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
fuse/helpers.h | 3 +++
fuse/obexfuse.c | 16 ++++++++++++++++
3 files changed, 65 insertions(+), 0 deletions(-)
diff --git a/fuse/helpers.c b/fuse/helpers.c
index a523cc3..e45591d 100644
--- a/fuse/helpers.c
+++ b/fuse/helpers.c
@@ -736,3 +736,49 @@ void obexhlp_delete(struct obexhlp_session* session, const char *path)
free_location(l);
request_wait_free(session);
}
+
+void obexhlp_mkdir(struct obexhlp_session* session, const char *path)
+{
+ struct obexhlp_location *l;
+ struct stat *stbuf;
+
+ g_print("obexhlp_mkdir(%s)\n", path);
+
+ l = get_location(path);
+ obexhlp_setpath(session, l->dir);
+
+ request_new(session, g_strdup_printf("mkdir %s", path));
+ /* g_obex_mkdir also sets path, to new folder */
+ g_obex_mkdir(session->obex, l->file, response_func, session,
+ &session->err);
+ g_free(session->setpath);
+ session->setpath = g_strdup(path);
+
+ stbuf = g_malloc0(sizeof(struct stat));
+ stbuf->st_mode = S_IFDIR;
+ stbuf->st_mtime = time(NULL);
+ g_hash_table_replace(session->file_stat, g_strdup(path), stbuf);
+
+ free_location(l);
+ request_wait_free(session);
+}
+
+void obexhlp_move(struct obexhlp_session* session, const char *oldpath,
+ const char* newpath)
+{
+ struct obexhlp_location *l_from, *l_to;
+
+ l_to = get_location(newpath);
+ l_from = get_location(oldpath);
+ obexhlp_setpath(session, l_from->dir);
+
+ g_print("obexhlp_move(%s to %s)\n", l_from->file, l_to->file);
+
+ request_new(session, g_strdup_printf("move %s:%s",
+ oldpath, newpath));
+ g_obex_move(session->obex, l_from->file, l_to->file, response_func,
+ session, &session->err);
+ free_location(l_to);
+ free_location(l_from);
+ request_wait_free(session);
+}
diff --git a/fuse/helpers.h b/fuse/helpers.h
index 362e322..5ace3ea 100644
--- a/fuse/helpers.h
+++ b/fuse/helpers.h
@@ -62,3 +62,6 @@ void obexhlp_put(struct obexhlp_session* session,
const char *path);
void obexhlp_touch(struct obexhlp_session* session, const char *path);
void obexhlp_delete(struct obexhlp_session* session, const char *path);
+void obexhlp_mkdir(struct obexhlp_session* session, const char *path);
+void obexhlp_move(struct obexhlp_session* session, const char *oldpath,
+ const char* newpath);
diff --git a/fuse/obexfuse.c b/fuse/obexfuse.c
index 065b6a6..a08f720 100644
--- a/fuse/obexfuse.c
+++ b/fuse/obexfuse.c
@@ -237,6 +237,20 @@ static int obexfuse_unlink(const char *path)
return session->status;
}
+static int obexfuse_mkdir(const char *path, mode_t mode)
+{
+ obexhlp_mkdir(session, path);
+
+ return session->status;
+}
+
+static int obexfuse_rename(const char *from, const char *to)
+{
+ obexhlp_move(session, from, to);
+
+ return session->status;
+}
+
static struct fuse_operations obexfuse_oper = {
.readdir = obexfuse_readdir,
.getattr = obexfuse_getattr,
@@ -249,6 +263,8 @@ static struct fuse_operations obexfuse_oper = {
.mknod = obexfuse_mknod,
.unlink = obexfuse_unlink,
.rmdir = obexfuse_unlink,
+ .mkdir = obexfuse_mkdir,
+ .rename = obexfuse_rename,
.init = obexfuse_init,
.destroy = obexfuse_destroy,
};
--
1.7.8.6
^ permalink raw reply related
* Oops: sysfs duplicate filename on device reconnect
From: Matthew Gabeler-Lee @ 2012-12-03 6:33 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 685 bytes --]
I'm having what appears to be the same error as reported by Jebb
Stewart ("Problem pairing wiimote device via bluetooth", 2012-10-10),
but with a Logitech DiNovo Mini keyboard/mouse device, and the dongle
that comes with it.
In my case, the problem is possibly more severe than Jebb's, as the
Logitech device goes into a power saving mode after only a few seconds
of not typing, producing a bluetooth disconnect, and then reconnects
as soon as you touch it again. Therefore, in normal usage, it is
disconnects and reconnects a lot.
The sysfs error I see is, AFAICT, identical to Jebb's. I'm running a
vanilla 3.6.8 kernel.
An example of the error as it occurs for me is attached.
[-- Attachment #2: bthiderror.log --]
[-- Type: application/octet-stream, Size: 17452 bytes --]
Dec 3 00:37:01 cheetah kernel: Bluetooth: HIDP (Human Interface Emulation) ver 1.2
Dec 3 00:38:41 cheetah kernel: hid-generic 0005:046D:B30C.0005: unknown main item tag 0x0
Dec 3 00:38:41 cheetah kernel: input: Logitech diNovo Mini as /devices/pci0000:00/0000:00:1d.0/usb8/8-2/8-2.1/8-2.1:1.0/bluetooth/hci0/hci0:11/input14
Dec 3 00:38:41 cheetah kernel: hid-generic 0005:046D:B30C.0005: input,hidraw1: BLUETOOTH HID v0.44 Mouse [Logitech diNovo Mini] on 00:1F:20:08:FD:0F
Dec 3 00:39:11 cheetah kernel: ------------[ cut here ]------------
Dec 3 00:39:11 cheetah kernel: WARNING: at fs/sysfs/dir.c:536 sysfs_add_one+0xc3/0xf0()
Dec 3 00:39:11 cheetah kernel: Hardware name: MS-7666
Dec 3 00:39:11 cheetah kernel: sysfs: cannot create duplicate filename '/devices/pci0000:00/0000:00:1d.0/usb8/8-2/8-2.1/8-2.1:1.0/bluetooth/hci0/hci0:11'
Dec 3 00:39:11 cheetah kernel: Modules linked in: hidp tcp_diag cpufreq_ondemand cpufreq_userspace cpufreq_stats cpufreq_conservative cpufreq_powersave rfcomm bnep ppdev autofs4 tun binfmt_misc nfsd auth_rpcgss nfs_acl nfs lockd fscache sunrpc xt_NOTRACK iptable_raw xt_set ip_set_hash_net ip_set ip6table_mangle xt_hl nf_conntrack_ipv6 nf_defrag_ipv6 xt_hashlimit xt_multiport xt_LOG xt_tcpudp iptable_mangle xt_mark xt_state ip6table_filter ip6_tables iptable_filter nf_nat_h323 nf_nat_pptp nf_nat_ftp nf_nat_sip nf_nat_irc iptable_nat ip_tables nf_nat_proto_dccp nf_nat_proto_gre nf_nat_proto_udplite nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_conntrack_sip nf_conntrack_h323 nf_conntrack_proto_dccp nf_conntrack_netlink nfnetlink xt_conntrack x_tables nf_conntrack_proto_udplite nf_conntrack_irc nf_conntrack_pptp nf_conntrack_proto_gre nf_conntrack_ftp nf_conntrack ipv6 btusb bluetooth rfkill dm_crypt hid_generic quota_v2 quota_tree fuse inet_diag pl2303 usbserial usb_storage uas nvidia(PO) coretemp kvm_intel kvm crc3
Dec 3 00:39:11 cheetah kernel: c_intel ghash_clmulni_intel aesni_intel aes_x86_64 snd_hda_codec_realtek aes_generic ablk_helper cryptd acpi_cpufreq uhci_hcd mperf snd_hda_intel snd_hda_codec iTCO_wdt iTCO_vendor_support gpio_ich freq_table snd_pcm snd_page_alloc snd_timer firewire_ohci i2c_i801 microcode lpc_ich processor sg r8169 firewire_core snd serio_raw button ehci_hcd wmi soundcore xhci_hcd crc_itu_t mfd_core mii
Dec 3 00:39:11 cheetah kernel: Pid: 7, comm: kworker/u:0H Tainted: P O 3.6.8 #1
Dec 3 00:39:11 cheetah kernel: Call Trace:
Dec 3 00:39:11 cheetah kernel: [<ffffffff81035419>] ? warn_slowpath_common+0x79/0xc0
Dec 3 00:39:11 cheetah kernel: [<ffffffff81035515>] ? warn_slowpath_fmt+0x45/0x50
Dec 3 00:39:11 cheetah kernel: [<ffffffff81151a73>] ? sysfs_add_one+0xc3/0xf0
Dec 3 00:39:11 cheetah kernel: [<ffffffff81151c82>] ? create_dir+0x72/0xd0
Dec 3 00:39:11 cheetah kernel: [<ffffffff81151fe3>] ? sysfs_create_dir+0x83/0xe0
Dec 3 00:39:11 cheetah kernel: [<ffffffff81229f10>] ? kobject_add_internal+0x90/0x210
Dec 3 00:39:11 cheetah kernel: [<ffffffff8122a65e>] ? kobject_add+0x6e/0xc0
Dec 3 00:39:11 cheetah kernel: [<ffffffff810e2ac8>] ? kmem_cache_alloc+0xd8/0xe0
Dec 3 00:39:11 cheetah kernel: [<ffffffff812d5bd1>] ? device_add+0x101/0x690
Dec 3 00:39:11 cheetah kernel: [<ffffffff812d45f2>] ? dev_set_name+0x42/0x50
Dec 3 00:39:11 cheetah kernel: [<ffffffffa01c408d>] ? hci_conn_add_sysfs+0x3d/0x80 [bluetooth]
Dec 3 00:39:11 cheetah kernel: [<ffffffffa01b9102>] ? hci_event_packet+0x102/0x27b0 [bluetooth]
Dec 3 00:39:11 cheetah kernel: [<ffffffffa01b05bb>] ? hci_rx_work+0x27b/0x330 [bluetooth]
Dec 3 00:39:11 cheetah kernel: [<ffffffff81042213>] ? lock_timer_base.isra.33+0x33/0x70
Dec 3 00:39:11 cheetah kernel: [<ffffffff81041e68>] ? internal_add_timer+0x18/0x50
Dec 3 00:39:11 cheetah kernel: [<ffffffff81042453>] ? mod_timer+0x103/0x1c0
Dec 3 00:39:11 cheetah kernel: [<ffffffff8104ce86>] ? process_one_work+0x126/0x450
Dec 3 00:39:11 cheetah kernel: [<ffffffff8104aede>] ? cwq_activate_delayed_work+0x2e/0x50
Dec 3 00:39:11 cheetah kernel: [<ffffffffa01b0340>] ? hci_send_frame+0x90/0x90 [bluetooth]
Dec 3 00:39:11 cheetah kernel: [<ffffffff8104d57d>] ? worker_thread+0x15d/0x440
Dec 3 00:39:11 cheetah kernel: [<ffffffff8104d420>] ? rescuer_thread+0x230/0x230
Dec 3 00:39:11 cheetah kernel: [<ffffffff81052245>] ? kthread+0x85/0x90
Dec 3 00:39:11 cheetah kernel: [<ffffffff814642f4>] ? kernel_thread_helper+0x4/0x10
Dec 3 00:39:11 cheetah kernel: [<ffffffff810521c0>] ? kthread_freezable_should_stop+0x60/0x60
Dec 3 00:39:11 cheetah kernel: [<ffffffff814642f0>] ? gs_change+0xb/0xb
Dec 3 00:39:11 cheetah kernel: ---[ end trace 0dcb8b510e7dd429 ]---
Dec 3 00:39:11 cheetah kernel: ------------[ cut here ]------------
Dec 3 00:39:11 cheetah kernel: WARNING: at lib/kobject.c:196 kobject_add_internal+0x1f4/0x210()
Dec 3 00:39:11 cheetah kernel: Hardware name: MS-7666
Dec 3 00:39:11 cheetah kernel: kobject_add_internal failed for hci0:11 with -EEXIST, don't try to register things with the same name in the same directory.
Dec 3 00:39:11 cheetah kernel: Modules linked in: hidp tcp_diag cpufreq_ondemand cpufreq_userspace cpufreq_stats cpufreq_conservative cpufreq_powersave rfcomm bnep ppdev autofs4 tun binfmt_misc nfsd auth_rpcgss nfs_acl nfs lockd fscache sunrpc xt_NOTRACK iptable_raw xt_set ip_set_hash_net ip_set ip6table_mangle xt_hl nf_conntrack_ipv6 nf_defrag_ipv6 xt_hashlimit xt_multiport xt_LOG xt_tcpudp iptable_mangle xt_mark xt_state ip6table_filter ip6_tables iptable_filter nf_nat_h323 nf_nat_pptp nf_nat_ftp nf_nat_sip nf_nat_irc iptable_nat ip_tables nf_nat_proto_dccp nf_nat_proto_gre nf_nat_proto_udplite nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_conntrack_sip nf_conntrack_h323 nf_conntrack_proto_dccp nf_conntrack_netlink nfnetlink xt_conntrack x_tables nf_conntrack_proto_udplite nf_conntrack_irc nf_conntrack_pptp nf_conntrack_proto_gre nf_conntrack_ftp nf_conntrack ipv6 btusb bluetooth rfkill dm_crypt hid_generic quota_v2 quota_tree fuse inet_diag pl2303 usbserial usb_storage uas nvidia(PO) coretemp kvm_intel kvm crc3
Dec 3 00:39:11 cheetah kernel: c_intel ghash_clmulni_intel aesni_intel aes_x86_64 snd_hda_codec_realtek aes_generic ablk_helper cryptd acpi_cpufreq uhci_hcd mperf snd_hda_intel snd_hda_codec iTCO_wdt iTCO_vendor_support gpio_ich freq_table snd_pcm snd_page_alloc snd_timer firewire_ohci i2c_i801 microcode lpc_ich processor sg r8169 firewire_core snd serio_raw button ehci_hcd wmi soundcore xhci_hcd crc_itu_t mfd_core mii
Dec 3 00:39:11 cheetah kernel: Pid: 7, comm: kworker/u:0H Tainted: P W O 3.6.8 #1
Dec 3 00:39:11 cheetah kernel: Call Trace:
Dec 3 00:39:11 cheetah kernel: [<ffffffff81035419>] ? warn_slowpath_common+0x79/0xc0
Dec 3 00:39:11 cheetah kernel: [<ffffffff81035515>] ? warn_slowpath_fmt+0x45/0x50
Dec 3 00:39:11 cheetah kernel: [<ffffffff81151fe3>] ? sysfs_create_dir+0x83/0xe0
Dec 3 00:39:11 cheetah kernel: [<ffffffff8122a074>] ? kobject_add_internal+0x1f4/0x210
Dec 3 00:39:11 cheetah kernel: [<ffffffff8122a65e>] ? kobject_add+0x6e/0xc0
Dec 3 00:39:11 cheetah kernel: [<ffffffff810e2ac8>] ? kmem_cache_alloc+0xd8/0xe0
Dec 3 00:39:11 cheetah kernel: [<ffffffff812d5bd1>] ? device_add+0x101/0x690
Dec 3 00:39:11 cheetah kernel: [<ffffffff812d45f2>] ? dev_set_name+0x42/0x50
Dec 3 00:39:11 cheetah kernel: [<ffffffffa01c408d>] ? hci_conn_add_sysfs+0x3d/0x80 [bluetooth]
Dec 3 00:39:11 cheetah kernel: [<ffffffffa01b9102>] ? hci_event_packet+0x102/0x27b0 [bluetooth]
Dec 3 00:39:11 cheetah kernel: [<ffffffffa01b05bb>] ? hci_rx_work+0x27b/0x330 [bluetooth]
Dec 3 00:39:11 cheetah kernel: [<ffffffff81042213>] ? lock_timer_base.isra.33+0x33/0x70
Dec 3 00:39:11 cheetah kernel: [<ffffffff81041e68>] ? internal_add_timer+0x18/0x50
Dec 3 00:39:11 cheetah kernel: [<ffffffff81042453>] ? mod_timer+0x103/0x1c0
Dec 3 00:39:11 cheetah kernel: [<ffffffff8104ce86>] ? process_one_work+0x126/0x450
Dec 3 00:39:11 cheetah kernel: [<ffffffff8104aede>] ? cwq_activate_delayed_work+0x2e/0x50
Dec 3 00:39:11 cheetah kernel: [<ffffffffa01b0340>] ? hci_send_frame+0x90/0x90 [bluetooth]
Dec 3 00:39:11 cheetah kernel: [<ffffffff8104d57d>] ? worker_thread+0x15d/0x440
Dec 3 00:39:11 cheetah kernel: [<ffffffff8104d420>] ? rescuer_thread+0x230/0x230
Dec 3 00:39:11 cheetah kernel: [<ffffffff81052245>] ? kthread+0x85/0x90
Dec 3 00:39:11 cheetah kernel: [<ffffffff814642f4>] ? kernel_thread_helper+0x4/0x10
Dec 3 00:39:11 cheetah kernel: [<ffffffff810521c0>] ? kthread_freezable_should_stop+0x60/0x60
Dec 3 00:39:11 cheetah kernel: [<ffffffff814642f0>] ? gs_change+0xb/0xb
Dec 3 00:39:11 cheetah kernel: ---[ end trace 0dcb8b510e7dd42a ]---
Dec 3 00:39:11 cheetah kernel: Bluetooth: Failed to register connection device
Dec 3 00:39:14 cheetah kernel: power_supply hid-00:1F:20:05:16:2D-battery: driver failed to report `capacity' property: -5
Dec 3 00:39:19 cheetah kernel: power_supply hid-00:1F:20:05:16:2D-battery: driver failed to report `capacity' property: -5
Dec 3 00:39:20 cheetah kernel: ------------[ cut here ]------------
Dec 3 00:39:20 cheetah kernel: WARNING: at lib/kobject.c:200 kobject_add_internal+0xf3/0x210()
Dec 3 00:39:20 cheetah kernel: Hardware name: MS-7666
Dec 3 00:39:20 cheetah kernel: kobject_add_internal failed for 0005:046D:B30C.0006 (error: -2 parent: hci0:11)
Dec 3 00:39:20 cheetah kernel: Modules linked in: hidp tcp_diag cpufreq_ondemand cpufreq_userspace cpufreq_stats cpufreq_conservative cpufreq_powersave rfcomm bnep ppdev autofs4 tun binfmt_misc nfsd auth_rpcgss nfs_acl nfs lockd fscache sunrpc xt_NOTRACK iptable_raw xt_set ip_set_hash_net ip_set ip6table_mangle xt_hl nf_conntrack_ipv6 nf_defrag_ipv6 xt_hashlimit xt_multiport xt_LOG xt_tcpudp iptable_mangle xt_mark xt_state ip6table_filter ip6_tables iptable_filter nf_nat_h323 nf_nat_pptp nf_nat_ftp nf_nat_sip nf_nat_irc iptable_nat ip_tables nf_nat_proto_dccp nf_nat_proto_gre nf_nat_proto_udplite nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_conntrack_sip nf_conntrack_h323 nf_conntrack_proto_dccp nf_conntrack_netlink nfnetlink xt_conntrack x_tables nf_conntrack_proto_udplite nf_conntrack_irc nf_conntrack_pptp nf_conntrack_proto_gre nf_conntrack_ftp nf_conntrack ipv6 btusb bluetooth rfkill dm_crypt hid_generic quota_v2 quota_tree fuse inet_diag pl2303 usbserial usb_storage uas nvidia(PO) coretemp kvm_intel kvm crc3
Dec 3 00:39:20 cheetah kernel: c_intel ghash_clmulni_intel aesni_intel aes_x86_64 snd_hda_codec_realtek aes_generic ablk_helper cryptd acpi_cpufreq uhci_hcd mperf snd_hda_intel snd_hda_codec iTCO_wdt iTCO_vendor_support gpio_ich freq_table snd_pcm snd_page_alloc snd_timer firewire_ohci i2c_i801 microcode lpc_ich processor sg r8169 firewire_core snd serio_raw button ehci_hcd wmi soundcore xhci_hcd crc_itu_t mfd_core mii
Dec 3 00:39:20 cheetah kernel: Pid: 12986, comm: bluetoothd Tainted: P W O 3.6.8 #1
Dec 3 00:39:20 cheetah kernel: Call Trace:
Dec 3 00:39:20 cheetah kernel: [<ffffffff81035419>] ? warn_slowpath_common+0x79/0xc0
Dec 3 00:39:20 cheetah kernel: [<ffffffff81035515>] ? warn_slowpath_fmt+0x45/0x50
Dec 3 00:39:20 cheetah kernel: [<ffffffff81229f73>] ? kobject_add_internal+0xf3/0x210
Dec 3 00:39:20 cheetah kernel: [<ffffffff8122a65e>] ? kobject_add+0x6e/0xc0
Dec 3 00:39:20 cheetah kernel: [<ffffffff810e2ac8>] ? kmem_cache_alloc+0xd8/0xe0
Dec 3 00:39:20 cheetah kernel: [<ffffffff812d5bd1>] ? device_add+0x101/0x690
Dec 3 00:39:20 cheetah kernel: [<ffffffff812d45f2>] ? dev_set_name+0x42/0x50
Dec 3 00:39:20 cheetah kernel: [<ffffffff81392bcc>] ? hid_add_device+0x1bc/0x410
Dec 3 00:39:20 cheetah kernel: [<ffffffffa010cbbb>] ? hidp_add_connection+0x3fb/0x880 [hidp]
Dec 3 00:39:20 cheetah kernel: [<ffffffff81052b80>] ? abort_exclusive_wait+0xb0/0xb0
Dec 3 00:39:20 cheetah kernel: [<ffffffffa010d47f>] ? hidp_sock_ioctl+0x20f/0x2c0 [hidp]
Dec 3 00:39:20 cheetah kernel: [<ffffffff813ad48a>] ? sock_do_ioctl.constprop.45+0x1a/0x50
Dec 3 00:39:20 cheetah kernel: [<ffffffff813ad73f>] ? sock_ioctl+0x5f/0x260
Dec 3 00:39:20 cheetah kernel: [<ffffffff810fd0d7>] ? do_vfs_ioctl+0x97/0x590
Dec 3 00:39:20 cheetah kernel: [<ffffffff813ac756>] ? sock_alloc_file+0xa6/0x120
Dec 3 00:39:20 cheetah kernel: [<ffffffff810ea443>] ? fd_install+0x33/0x70
Dec 3 00:39:20 cheetah kernel: [<ffffffff810fd619>] ? sys_ioctl+0x49/0x80
Dec 3 00:39:20 cheetah kernel: [<ffffffff814631a6>] ? system_call_fastpath+0x1a/0x1f
Dec 3 00:39:20 cheetah kernel: ---[ end trace 0dcb8b510e7dd42b ]---
Dec 3 00:39:20 cheetah kernel: VFS: Close: file count is 0
Dec 3 00:39:20 cheetah kernel: BUG: unable to handle kernel NULL pointer dereference at (null)
Dec 3 00:39:20 cheetah kernel: IP: [<ffffffff81462748>] _raw_spin_lock_irqsave+0x8/0x30
Dec 3 00:39:20 cheetah kernel: PGD 0
Dec 3 00:39:20 cheetah kernel: Oops: 0002 [#1] SMP
Dec 3 00:39:20 cheetah kernel: Modules linked in: hidp tcp_diag cpufreq_ondemand cpufreq_userspace cpufreq_stats cpufreq_conservative cpufreq_powersave rfcomm bnep ppdev autofs4 tun binfmt_misc nfsd auth_rpcgss nfs_acl nfs lockd fscache sunrpc xt_NOTRACK iptable_raw xt_set ip_set_hash_net ip_set ip6table_mangle xt_hl nf_conntrack_ipv6 nf_defrag_ipv6 xt_hashlimit xt_multiport xt_LOG xt_tcpudp iptable_mangle xt_mark xt_state ip6table_filter ip6_tables iptable_filter nf_nat_h323 nf_nat_pptp nf_nat_ftp nf_nat_sip nf_nat_irc iptable_nat ip_tables nf_nat_proto_dccp nf_nat_proto_gre nf_nat_proto_udplite nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_conntrack_sip nf_conntrack_h323 nf_conntrack_proto_dccp nf_conntrack_netlink nfnetlink xt_conntrack x_tables nf_conntrack_proto_udplite nf_conntrack_irc nf_conntrack_pptp nf_conntrack_proto_gre nf_conntrack_ftp nf_conntrack ipv6 btusb bluetooth rfkill dm_crypt hid_generic quota_v2 quota_tree fuse inet_diag pl2303 usbserial usb_storage uas nvidia(PO) coretemp kvm_intel kvm crc3
Dec 3 00:39:20 cheetah kernel: c_intel ghash_clmulni_intel aesni_intel aes_x86_64 snd_hda_codec_realtek aes_generic ablk_helper cryptd acpi_cpufreq uhci_hcd mperf snd_hda_intel snd_hda_codec iTCO_wdt iTCO_vendor_support gpio_ich freq_table snd_pcm snd_page_alloc snd_timer firewire_ohci i2c_i801 microcode lpc_ich processor sg r8169 firewire_core snd serio_raw button ehci_hcd wmi soundcore xhci_hcd crc_itu_t mfd_core mii
Dec 3 00:39:20 cheetah kernel: CPU 2
Dec 3 00:39:20 cheetah kernel: Pid: 14607, comm: khidpd_046db30c Tainted: P W O 3.6.8 #1 MSI MS-7666/Big Bang-XPower (MS-7666)
Dec 3 00:39:20 cheetah kernel: RIP: 0010:[<ffffffff81462748>] [<ffffffff81462748>] _raw_spin_lock_irqsave+0x8/0x30
Dec 3 00:39:20 cheetah kernel: RSP: 0018:ffff880194f47dc8 EFLAGS: 00010093
Dec 3 00:39:20 cheetah kernel: RAX: 0000000000000293 RBX: ffff880194f47e98 RCX: 0000000000000001
Dec 3 00:39:20 cheetah kernel: RDX: 0000000000000100 RSI: ffff880194f47e98 RDI: 0000000000000000
Dec 3 00:39:20 cheetah kernel: RBP: ffff880194f47eb0 R08: ffff880194f46000 R09: 0000000000000000
Dec 3 00:39:20 cheetah kernel: R10: 0000000000000001 R11: 0000000000000001 R12: 0000000000000000
Dec 3 00:39:20 cheetah kernel: R13: ffff8801a3a944b8 R14: ffff88019ab74468 R15: 0000000000000000
Dec 3 00:39:20 cheetah kernel: FS: 0000000000000000(0000) GS:ffff8801bfc40000(0000) knlGS:0000000000000000
Dec 3 00:39:20 cheetah kernel: CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
Dec 3 00:39:20 cheetah kernel: CR2: 0000000000000000 CR3: 00000000015d6000 CR4: 00000000000007e0
Dec 3 00:39:20 cheetah kernel: DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
Dec 3 00:39:20 cheetah kernel: DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Dec 3 00:39:20 cheetah kernel: Process khidpd_046db30c (pid: 14607, threadinfo ffff880194f46000, task ffff8801b712f2c0)
Dec 3 00:39:20 cheetah kernel: Stack:
Dec 3 00:39:20 cheetah kernel: ffffffff8105284a ffff8801a3a94400 0000000000000000 ffff88019ab74400
Dec 3 00:39:20 cheetah kernel: ffffffffa010c46d ffff8801b80b5940 ffff88019ab76068 ffff8801b712f2c0
Dec 3 00:39:20 cheetah kernel: ffff88019ab74400 ffff88019ab76000 ffff88019ab74468 ffff8801a3a94518
Dec 3 00:39:20 cheetah kernel: Call Trace:
Dec 3 00:39:20 cheetah kernel: [<ffffffff8105284a>] ? finish_wait+0x3a/0x90
Dec 3 00:39:20 cheetah kernel: [<ffffffffa010c46d>] ? hidp_session+0x52d/0x880 [hidp]
Dec 3 00:39:20 cheetah kernel: [<ffffffff8105e760>] ? try_to_wake_up+0x280/0x280
Dec 3 00:39:20 cheetah kernel: [<ffffffff8105e760>] ? try_to_wake_up+0x280/0x280
Dec 3 00:39:20 cheetah kernel: [<ffffffff81052b80>] ? abort_exclusive_wait+0xb0/0xb0
Dec 3 00:39:20 cheetah kernel: [<ffffffffa010bf40>] ? hidp_input_report.isra.8+0x2c0/0x2c0 [hidp]
Dec 3 00:39:20 cheetah kernel: [<ffffffff81052245>] ? kthread+0x85/0x90
Dec 3 00:39:20 cheetah kernel: [<ffffffff814642f4>] ? kernel_thread_helper+0x4/0x10
Dec 3 00:39:20 cheetah kernel: [<ffffffff810521c0>] ? kthread_freezable_should_stop+0x60/0x60
Dec 3 00:39:20 cheetah kernel: [<ffffffff814642f0>] ? gs_change+0xb/0xb
Dec 3 00:39:20 cheetah kernel: Code: 38 c2 74 10 0f 1f 80 00 00 00 00 f3 90 0f b6 07 38 d0 75 f7 c3 66 66 66 66 66 2e 0f 1f 84 00 00 00 00 00 9c 58 fa ba 00 01 00 00 <f0> 66 0f c1 17 0f b6 ce 38 d1 74 0d 0f 1f 40 00 f3 90 0f b6 17
Dec 3 00:39:20 cheetah kernel: RIP [<ffffffff81462748>] _raw_spin_lock_irqsave+0x8/0x30
Dec 3 00:39:20 cheetah kernel: RSP <ffff880194f47dc8>
Dec 3 00:39:20 cheetah kernel: CR2: 0000000000000000
Dec 3 00:39:20 cheetah kernel: ---[ end trace 0dcb8b510e7dd42c ]---
^ permalink raw reply
* Re: [PATCH v2 01/20] cyclingspeed: Add CSC profile plugin skeleton
From: Andrzej Kaczmarek @ 2012-12-03 9:09 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Johan Hedberg
In-Reply-To: <20121115093126.GA4414@x220>
Hi Johan,
On 11/15/2012 10:31 AM, Johan Hedberg wrote:
> Hi Andrzej,
>
> On Mon, Nov 05, 2012, Andrzej Kaczmarek wrote:
>> This patch adds stub profile driver plugin for CSC profile.
>> ---
>> Makefile.am | 9 +-
>> lib/uuid.h | 2 +
>> profiles/cyclingspeed/cyclingspeed.c | 163 +++++++++++++++++++++++++++++++++++
>> profiles/cyclingspeed/cyclingspeed.h | 26 ++++++
>> profiles/cyclingspeed/main.c | 53 ++++++++++++
>> profiles/cyclingspeed/manager.c | 79 +++++++++++++++++
>> profiles/cyclingspeed/manager.h | 24 ++++++
>> 7 files changed, 354 insertions(+), 2 deletions(-)
>> create mode 100644 profiles/cyclingspeed/cyclingspeed.c
>> create mode 100644 profiles/cyclingspeed/cyclingspeed.h
>> create mode 100644 profiles/cyclingspeed/main.c
>> create mode 100644 profiles/cyclingspeed/manager.c
>> create mode 100644 profiles/cyclingspeed/manager.h
>
> You'll need to rebase these against latest git since this one doesn't
> apply cleanly (due to Makefile.am) and doesn't compile either (due to
> main_opts.gatt_enabled having been removed).
Sure, will do.
>> +struct csc_adapter {
>> + struct btd_adapter *adapter;
>> + GSList *devices; /* list of registered devices */
>> +};
>> +
>> +struct csc {
>> + struct btd_device *dev;
>> + struct csc_adapter *cadapter;
>> +};
>
> I'm a bit worried that we've failed to create proper internal GATT APIs
> if they require this kind of per-profile tracking of devices and
> adapters. You can already get a list of btd_device from btd_adapter and
> the btd_adapter from a btd_device. Profiles should only need to track a
> very minimal amount of context.
Probably would be good to have some kind of API to attach profile
specific data for particular device and/or adapter so we can get rid of
duplicated code across plugins and just use one already existing list.
Not sure how this could look like at the moment though.
>> +++ b/profiles/cyclingspeed/main.c
>> @@ -0,0 +1,53 @@
<snip>
>> +static int cyclingspeed_init(void)
>> +{
>> + if (!main_opts.gatt_enabled) {
>> + DBG("GATT is disabled");
>> + return -ENOTSUP;
>> + }
>> +
>> + return cyclingspeed_manager_init();
>> +}
>> +
>> +static void cyclingspeed_exit(void)
>> +{
>> + cyclingspeed_manager_exit();
>> +}
>> +
>> +BLUETOOTH_PLUGIN_DEFINE(cyclingspeed, VERSION,
>> + BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
>> + cyclingspeed_init, cyclingspeed_exit)
>
> If this is all the main.c file does seems like it should be merged into
> manager.c or even cyclingspeed.c.
>
>> +++ b/profiles/cyclingspeed/manager.c
>> @@ -0,0 +1,79 @@
<snip>
>> +
>> +static struct btd_profile cscp_profile = {
>> + .name = "Cycling Speed and Cadence GATT Driver",
>> + .remote_uuids = BTD_UUIDS(CYCLING_SC_UUID),
>> +
>> + .adapter_probe = csc_adapter_probe,
>> + .adapter_remove = csc_adapter_remove,
>> +
>> + .device_probe = csc_device_probe,
>> + .device_remove = csc_device_remove,
>> +};
>> +
>> +int cyclingspeed_manager_init(void)
>> +{
>> + return btd_profile_register(&cscp_profile);
>> +}
>> +
>> +void cyclingspeed_manager_exit(void)
>> +{
>> + btd_profile_unregister(&cscp_profile);
>> +}
>
> Are these functions ever going to do anything else than make single
> Vcalls into cyclingspeed.c? If not it seems to me like all this should
> be merged into that file.
>
> Btw, I do realize that other profiles might have similar brain dead
> design but that's not a good enough excuse to keep replicating the bad
> design. Instead the other profiles should be fixed.
Probably I'll just merge all this code into single cyclingspeed.c since
all code in main.c and manager.c are just dumb calls and I don't see any
need to extend them in future.
I'll try to send new patchset later today.
BR,
Andrzej
^ permalink raw reply
* BLE: attribute-api and StartDiscovery
From: Ting Chou @ 2012-12-03 10:45 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
Hello,
We are trying to enable notification from a LE a device, but found the API
listed in attribute-api.txt haven't been implemented yet:
org.bluez.Characteristic.SetValue(),
org.bluez.Characteristic.GetValue()
Also we found there's an item in TODO to expose client characteristic
configuration, but the priority is low.
May I understand your possible schedule of the feature, or any workaround you
suggest?
BTW, it'd be great if we can set the device type to discover (e.g., LE public)
for the API org.bluez.Adapter.StartDiscovery(). How do you think?
Thank you,
Ting
^ permalink raw reply
* RE: [PATCH] Update patch and syscfg files for QCA9564.
From: Chen, Peng @ 2012-12-03 11:16 UTC (permalink / raw)
To: ben@decadent.org.uk; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1352697850-27915-1-git-send-email-pengchen@qca.qualcomm.com>
SGkgQmVuLA0KDQpTb3JyeSB0byB0cm91YmxlIHlvdS4gSG93IGlzIHRoaXMgcGF0Y2ggZ29pbmcg
b24/DQoNCi0tLS0tT3JpZ2luYWwgTWVzc2FnZS0tLS0tDQpGcm9tOiBDaGVuLCBQZW5nIA0KU2Vu
dDogMjAxMsTqMTHUwjEyyNUgMTM6MjQNClRvOiBiZW5AZGVjYWRlbnQub3JnLnVrDQpDYzogbGlu
dXgtYmx1ZXRvb3RoQHZnZXIua2VybmVsLm9yZzsgQ2hlbiwgUGVuZw0KU3ViamVjdDogW1BBVENI
XSBVcGRhdGUgcGF0Y2ggYW5kIHN5c2NmZyBmaWxlcyBmb3IgUUNBOTU2NC4NCg0KDQpTaWduZWQt
b2ZmLWJ5OiBQZW5nIENoZW4gPHBlbmdjaGVuQHFjYS5xdWFsY29tbS5jb20+DQotLS0NCiBhcjNr
L0F0aHJCVF8weDMxMDEwMDAwLmRmdSAgIHwgIEJpbiAzODkxNiAtPiA0MDY1MiBieXRlcw0KIGFy
M2svcmFtcHNfMHgzMTAxMDAwMF80MC5kZnUgfCAgQmluIDE0MzQgLT4gMTkyNiBieXRlcw0KIDIg
ZmlsZXMgY2hhbmdlZCwgMCBpbnNlcnRpb25zKCspLCAwIGRlbGV0aW9ucygtKQ0KDQpkaWZmIC0t
Z2l0IGEvYXIzay9BdGhyQlRfMHgzMTAxMDAwMC5kZnUgYi9hcjNrL0F0aHJCVF8weDMxMDEwMDAw
LmRmdSBpbmRleCAzYmQ3NmMwMmVjZjJlNDMzZDY0MGUxMjE1ZTIyNTNjZWJiZWQ3MzBkLi45MzVi
ZWIzOTJhNTM5Nzk2NjhiZjdkYTVlNGFjYjYyZWE3ZGI4MGZlIDEwMDY0NCBHSVQgYmluYXJ5IHBh
dGNoIGRlbHRhIDI0MTI3IHpjbWJybTJ+PDxwN0JHQT5rVStSVjc+bz0tTmcmS3hnMD9DU0M1Un1m
dClObzBgWU5MJCpnRXhHWXFjUilpX3YwQg0KemEmMDl6R2BXZmJsQD8tS0w4VD8+ZHgobmZMMlJF
eHJHPlBwU1prNElwRj9aJj97bVFwQEI3eGoqMXZ3JXk0KkFGDQp6dihHO0o/NmMzX2AofUcxenE2
SUVDRlUkNGgtRF9DYDUtfUQ9JiUxbE5jXyhxKUlJdDhgK19CZW9YI09+cHNXcWoNCnomRFdPQHk8
c14te1BSblElXjVqRm48al43XnZmWjdCWFM3b3E5dWVCJUVSQz51Wk8lTGhwNjl9THhqRFdMJlIq
eg0KekFAWXZwNWF0YXoySkxrSSNPRHA0Sik8U2MyeDc3e2hnYiVIZXNafmRxKWBONkY2Ui0lQVU4
YkU8QChLfmtBdVAyDQp6IVFpanQ1WWdqdWgpcGwmNWNnZEtAJG51MnRSYWExeXpoY3M3fiVUWDx0
aGF2ZV9kckYlKiMhTEZ5Qk8hN1FubUUNCnpMPT9QaUJEVExgQXx9NlRCQ1p2Z2goVVBnQWR7OUwq
Ty1WRSNVP0B6JiFWKl5WaGFvdXUpIyFCIUUrZ3poekZGMw0Kem08RTc0cDxOKVB3YFZVUSVIUjxL
QjNvZEYkdU1LJEgjZWc1dHNMVX0hI1R0UCRoJj9laCt7eXBNTD5sdUBhJWBADQp6RygwT3BWSXI+
cVF0LV4jWSQ5JlgoZEgwREdRcDhEeGc+e0ppcGpZV298I1pTbz0tRntVUDkhPTBOSD5sUzlZJUIN
CnpiJj4+TzNmZT9lMk5BQEMyXkAqYWRSQDtGVitvP248cFFiXlpRNEVDMEk1fiowSWJIcTlISlQw
RXwqS043UT56Yw0KeldwaV9nNFVqSF9jYmYrO09venJablg5fUJqNHl2Q2xmd193UEZuKi1ATyUk
UTN0YEZLO1lvbGU3blV5cUNTTCk0DQp6SCRtNjs7SEB6TXQ4Qzk5RCZLK1NlbWpSKWY8ZE9fNU1P
dUAjOUw1TDA3Mi1GYkJNTGptan4lSlBAZkQ0dUw1fEoNCnpwPyhZR2tITEcqVkgyQHdIbmNBU19I
PXk/RDd6bEpUKS0yKjA1SEJVTEVIZzZDdF8rN1Z0OFFrWXZKV1g1Ukx2aA0Kekx8MVNRcHxfWmIx
YkVoTmhiNGQwTUFZaEdXZSkrez8xQUBRJFhDRT4hbjVrMmk4eWBLTF99e2o1c21PJS1VbG11DQp6
MFA1O1ojSWh+MCFmWlM9dTd6M0VuVFUtYW51eTliT2hnMyRtfFNIZGo9QDkxak40ZX4xb2lJNm1g
SzRHP1hSIzwNCno2YTVIRz14MjI+Kis2fntAb05KUjMzemAhYUtpPzgxaDlCZXVPJVFJNGRvTUlL
WGdxOHFKPEdlRXdGVTBFe0F2aw0KeldvQGc2X3RxdzBfcntOYW92cHh+alc4cyU4SERecSRhbXFn
PDFtKkt6P0lvY1FhS0pIS0kwUjwwTCV9YnMlRUhZDQp6RiVqe3R1KnU+MUBeY2Qme1BWeFo8cSRW
K0tuZmw/dG1GZTV3Nm1MdDF2VjNOVVo3d0cxQFlScEkjYGhwYSk/cVcNCnp6eEBSZT4rZTkmZSpu
U1l4ZH47ZEBSb08maH5EIWlCRG9YeDhhJG1CVkVnPE4oKG9rdzMrVUdjVGQ1bXAxWT1CTg0KelV7
JDNBdkMjbz0rK3AoWWx0dCRkRTg9c0FqbGN6MWtXfDVZRWoldDQ/OCZ4Q09OZUNtTntsZEpoUWVl
M0dPNlFsDQp6bUg/bj80c0ApbjFXSHs1Oz17OFJAe18rYjVnbzd9fEJqI1BWZEBjfDBlQTM0TF5K
ZCtfekRuJE45cmpjMF5vcn4NCnpBX0NuN2dkODRzVG4yQjkxT2FKKyY9VDlyVHAoWE8xVmtWcTBF
YDhNNncoM2txeWkja3UpTS1XdXFQbkRAZilCWA0KejRgdjY1LU1hISp4ZGdNbTNZPkJjQzxAT2lj
I2dyZDx1WHRQPlhVbmJxckxec2c3PEFHQ3dwTlQ2WnUzTEpsbysoDQp6bjZNJD8qJV5lOHM3bH15
Wk5PODFob2BmMW9eLTZjNVV8I14wcFhyP3h5bkc/WCRmZmBAVD94RjtSTjtzI054akwNCnpzcSZx
UFg+dCFgRG4tJVMxK1RuUG54clpTT0w/X3VXQCt3KjRMQ2lnRnQ7RXt3SkJeLVpaWHR0bEU4Rns3
Z2RQYA0KeiVmc2V4U2VhZ3NsJn1kYHUzQz9xO1dUYkFIfHgyMXhIXyFwKXpWVCRTWE4+RkU5KG89
VW9JJXpsbXRCYHw3VStxDQp6TEJhWkAxYUEmaEB0VlM2SytHcWlIdip6bjF1QCoxVVhtQUhObT1C
RCk2N2Ztdi19cnB2S0M9bjJ4MkxCaEUhIVENCnpJb3s7e3c3P0F1SDVWaio1aTxjMUcyPksrI1dl
LSlIRnRSWnBZZHVVLTNtezs2K1MxYlN0MDZRRCg+SWxVUTswTQ0KemVAbT49eFl2fXJ0SmIrUXQw
VUNCPUh2UyNsKVRgPSpXNml+dzg8WmwkNyhqWVM4UXQpdT1hVzZ2M3w7KHh2YmhnDQp6dTIyV25W
YXJ+R2t9Xm9tU1RgQ1B3dSk2UnlKdmJMYnBWM0NubX1BNj5AUmdeYzFBYEF0NSYtPTF0VF9tRExK
cEwNCnpLOCE2MVpWPE5lMFFmMyo9NnZLT0ZWJjBnNE1NOTtOKipnKj5kdCU9NihwIXg/U0F9eDZy
VSU2ZzV6RCQ0fCMlYA0KekI9X1Q7djlJIVlDeXVBWUFMb3JlIUh5REVZX15aJHhBa2RgZSYlSCU1
JFJkOys2amduLSNfMCpHYE9XfUdAaHVIDQp6TUBSZ20lI2AtSjZYYTkyMzgtbHpUSzY7PkMjbHUr
SiVkS0NvPEhRemNsaCh9UGFvO05AJnZTam54VGs/bW1PQUwNCnpYJjNGNS1OOChJcyg2K3RucG9R
dCk+YXFCPUp7UTVrZGliJHZHendQOEEze1dLaUpsa2ZSNCg3RGs5PyhMa0VZbA0Kej0zMkFuTDBl
aTA0Y3FpI2JlXkEpJiYhO0lpbCM3cVBlcGpEUGZWTklLPXladF49ZHwlRml0N3phKkBJOSpJVyQo
DQp6RTA1XilCQ1AmPXlGYWYtYSQ9aFFlb3R1bGdfd0NNQSUrKm0+YFZ3eE9aKFdod3pWeiR7MTB9
JXV4USNkQGdDZz8NCnokVEFzYEAkJEt9LXpkX1gmZ0FQTigyKENhciQjaUNEV3MhMnR5djUwUyMj
Tn1FSnhQN0lFenVrMlUwTWZCLW5YVg0Kem1gIVJxRk50fHFvdkFFaiNkUldrZldSc2dvXnsobHdS
V09hQHdORl9uYCp4cDUtMDB4X0s2d3kjOH09YFc8dWYmDQp6LVpXLT87O1JESDRsIzJwKEV6ekU2
UF5ZeikoTEI7X1ArLTBkK1I/YWRgKjFxcyRKMm1ufnErUHlFenFLLVBre0cNCnpOWVNeO0hJJj1P
RHRlNUhLOWh1MWVBRFhJa0hreXNUaXB0Z217fnNZOEM0QT53ayFKVEpNRm9CcTUrcFI5PGxMTQ0K
elZ8YG93aHBxaG4mRWs1dG0wITQ3JXJzOS07bXYxJG5KQ3hoJUYlanIkSikpXkBqPElzU3xndWxN
Y1VLbmtHMlRvDQp6ZT81OXlPbk55PTstU3pQN2t9KUgyNFJvRFhfRyM3diRNeTVLdXJPTmp7ZjRA
c2dveHpWMHpTUEklQ0k0TEk8SiQNCnp3QU0/KGZfYm94dC0+RCNMcEpGVzl5R1RGQVAwTndZOX00
TnY0Py18NERgVVEyYDI2N2VjRGB0SzZERzEqTUYyWA0KemxTY31oQjlQSTRvSDB8ZHslaWhAVjQz
flU0e2hoI1djeGs0WFBeVlp1QiZhYmFndWZ0eFlLJipGJiVhMWYpSFRJDQp6bER4PGE3XlJnQE5C
aTNheEcyb0x1fmxJSUJBYnIteW9VJCpiUD8keE9CYyFLYSUpe0JxTjZeNWc/QjhSWFYpJkENCnol
UCEyYUU/bjNrMnk1SkUpRFh9YlY4T3lTO0VyX0V1PzdMV0V0NjJ5I2lwbF8qKDVieHl1TG4hNiVj
bUlyblltbw0KemJFbTl2VDUqWCk9TDNDR05sJDFTRWVhaD4oRm8mWE9kPkw8ejBkVSpXUkdvKnBU
ZkhGPk9fMDEtSjM1P2RSOzVQDQp6cjEpUl9wP21xRGk/am9naC1Xd292SHFqak9rVWFjd3FmY1JB
YG1IQWV9eWxyQEBTZlk4YjVCNiNrbjdsYmNvVkMNCnppMnNINGYxdzJsKUVFJWpIQUk2ejMjNVJG
fE5vekxoaUR1TDlEd0g/QUo1SkZgdFp6MjtnZn5SUFdtc041fXdkdQ0KenVOYH00d3p7IWpYamhP
R0hTQClxTGAxcTdnKWRzOU5FU21qVSRpfWlxSjlaPTJuZVRUUSpWIyRZTnRKM0pOaDxCDQp6VTtV
TWl1SCNuWmJiVklwaXsmYzlYZzJLS0dySVA+OWpwQ1hnfEtxKiFFfChRb29Ia284dStiKDMmSXta
b2lGLVANCnpxfGJSUWhIXn1CLTklKmxBeyF1UmhyPDBAY3hBNHpwP3RzVj56NmtPYmVeYzBNQE9G
XjwoTVdENVkjdjBgWDl5WQ0KenB+cXhBcGsjTyE+Nz1PZ3tWLXJSVzQ8M1dZdnM/cSRkVE9eNE98
ZFAmVlZ2dyNPUjlHcGRCNmtCSUs1Y05QZyZgDQp6QXNKUD1xfio4YUtxYTFtdEhneHhOVWNEbzJ8
IXVxanMqKzVtIT5Lc1RDelRMRWxeNjgxdWZqIz50SntNVTx+KWUNCnpFUiRKVERLdSR6PzIkRk4w
Z34yM0x2LXtWa182ent0QSZgWmMlRENzOSpiZUY0U2ZCb1I/TjVhQn1kaylzeC1HZg0KeipsPDdi
Pld+WTN0MGxmVzE/ZT1YPk8wbSNtYCZPK3tVJFFqXmN9UHZDaj5AfVpSTHw1S3Rfe0ArZXtiK2Jj
T3dYDQp6PkRDKzg1V21Kb3EzbUBEM19tVDJqe2NTI0xibGxoQF50aCEofl9YRXRsQXlkWDhjfVRF
Z3FAT3pfbGt1a2Vlc0ANCnp6NG9MUSZqbVdxbGk9I0JMVCglV0QxSXk/PCQlUSFTYyM4JW8tQyMm
MCMjK2sqQj1ja2pofVdWWGVHSXtQVUh+cQ0KekJCdk05NSMxYXI3eCtCX0dNSjg3KDJUbz9xeShO
MHRPPDBTZFhiSUBDRXRjKC1BdHN2RU1FO05ocT5hYV9UdjZuDQp6JXB7TStjSnEyVlYoWDglWEZI
RmVCZCN9aUtAeDlmNT1kZiNIeXRzWlY/RUkkU1V9OWg9MnYmVEUwMkV8KWlRZTgNCno9Qk9tVVJ5
UlBJZ3ZzXlJWTHBvJWhZbWpCemFLQGdEcGZXVVBydkRSOV5gbUhZZV99UFdkVl9zeTxSQWdCdiVE
PQ0KenJWc3daSHd+YElaYmtgbF9VaXRmKlFkeWkxbz5PZHRgcSlWeD49fH1LdTFxKFlyRl5XZmtC
P3A1byV6dWEwO0BEDQp6TF9BTlVhdHh+cyZPUiRMMkR8Nl9waD9BUm4kbDJYaWAyVCpvZVpgc2dC
ezhjRD1CbkB5NG1HRXNzfUVzUnZBbk4NCno4JDthYmh+bW8xP35PMEkxMD9JQVhQcj4mPCM+KlM5
IUJWfiUjLXlINHwldihOVXBzUDtPVTQmUilYYSQ5VEA9cw0Keih8fXl6SElOfHZMSTxyOFBxUnct
ZGI1aVM5K21aUGs9ZVg0cyg0a2VDcWE3QkRoMD1gJU96Q3NtbGRseWdgLWYqDQp6ZDx5YXJnTihD
IVZ2cmJvX3lKYnBmeChCcktWMVJea245b0FrJHlpKWhMcGszKygmSHA1ZUBtY0xBa2w/b0B+XysN
CnpESXI3cC1+TG98IylVQDtgRDNLRClvcnEhe35afnVyczk5YjB7R2Z0QExNSTI5IT9yTDFZbGVi
aX57NXlPUk9Heg0KenlOQjR9QSMhQFNQdk94KTl5QCo2QVc1QyNxNTg0ZD07M0Q0KDJAUVA5NSQ4
cldUcFgoampIXzlfQ3E4NHlnXjhNDQp6JUlFZF9pcGk9UyMlV2Y4ZkVEbnxQVnRDKC07PyFQdEFK
K3w1TWAlKVBuem1ZNjw1ZXVTWlo/R3Y8byVneElfWCUNCnpIeWU/JGBlLU52VHJoYlhfYHBjNTA9
PUYpYG1pVmlLfCtxc14raFRFSm80dWtfS1k+bUw5ezt+NHllNlZ7elZ5NQ0KeiFZXjRWXkNNPGts
OWdlflk9OGctVGtoZWFOdFdhWjNFQmp1d0VVcTlmVCg+QHFRNzYlTElFQklPRG97O2IpS2xmDQp6
amdJPU02YHpIcDMhK0YjRGBXP2BXdSY5M3JzR1o5JUt5PWdFYldvZFE0YlQkXyNrUWJBWClgNUN1
MnErJU9oMCgNCnpid051ZyM9P249MlpgN1VKN2c/LTckMjErVXB2Z2pQWCs9VjdLLWFLSkhQKH1n
dFkmenQyUHQxNzlHNn5EamlYUw0Kek1adTk2NkE7bH1GY2ctMWswcEgoQW9aTiVeTlY/TylYP0F7
TW5uVnl7QkpYNylWbUcqS2VmP3ZHbGkzb2U/aDQ2DQp6TUxsbCUhPDtBP0NwcWRMdkVeNjdLYlpf
PTFOP3xxMygoRUhQZzszXlgqLXFCU1Q3fF43UEJlTHhDbTFlJUt+TUINCnpUOHR7SFNhVGE0S0Jr
Xzk7akshKU9GI0o3bUZrTjl0b2lSeE8zNkBsMW5Oc2kmNW1pTz9JezluPzxyfUVMO08wfg0Keno7
fnBHPTx4bFYzU21fR1dkQCtpMkJHWWhjendlblFjZW97R0VtYzhibEhMVGEtTHNya0Y7eXZ3JFVa
eT9XNnB9DQp6eDEtNDx7ZGNXYzZJJnkoIWNvR3VaTFRqb0Q8Yk57VGxwNzZLTUx2YUJ1KSoyLVQ5
PlVqTDV1VDxFUVY2QlpsPzwNCno3ZUQ8UzFheHV4UVB7KHkhKUtFMzA3I2YwNlJSR3BaVD5AVzBr
YFBwcXJPYmtvclFxJjREKm9ZZDZmQWFmfD1jMg0KemZZXihDPHdmQzgtb351RjtgQVlGPl5YWlpX
NmJrIWspMEphRWt5UTxaZGF9aTlDTChnVFlqfk16aCMoPkc4WkZGDQp6SG9FJSl5N0cpT0psYEh9
WUFJcjQ/PjgrK2ImK1NZMmghKn5zezJMYyhCXytUaSV7UUVxYFdBeUVrcE1Gd30kZUANCnpyc1Ij
dSVKYkxjZmJ2aX5XJDI+RSExSHpHUz1vTCZyPTtaUDheaC0rbVZqKjNZd31RTEY1STBxVEp0dyU8
PENtVg0KekZXZFI0R0dBTVZPaD8jQD91TmYxTUx5RUtneXtVYSVLWWkzVUFaZXpVY01naEUxdFIj
ODQ1dDZEfmVFRXY0QF50DQp6aG1YVjR1X08/PU9zfjl2SCR+QnsycktVP21OKSolaFBMdj84Rn0j
fGA/Pk9mc3doWjYlRmhiKVNXbjxLdDdScTkNCnp0d1Boej5mS0c3cE9oNm9iVX5SdTh1RXI+WDdA
OD13WDJhbE5rNH5VMjE2ViZkSSpjQXhhJiRfM3hxPShPRFhEfQ0KejE9bHNseFRveHZSZ1E1WGhC
ZTV6KyhVSSVSQT5AbGV1VlhUOFBWPTtnZypSODtFU1l+NmxLT0IlUFlgRHtXN3tCDQp6bmpFaEdk
R216SjZLPjd+VT80MD07Z1BAeWw1Ymd5VDd7UGRgayR7bHdEd1NlQk5XU0hyJDMrZTdsZnFsUWwz
fWQNCnpoYDQ1VzhMZEFQMDc1VU1oJWtsa2pqVl5eeFdoMlVIPVU7d1ZgO1QlMGUzdnZPM3sydFVn
ek1pazFYcXVBX2lHUw0KekxqQk1iMSVTKmdNV2s1JW9uPHwwNzI5UlJXdG8ySFcrYXJLRkFBWTE/
WSpKOD1PVlJPZ2cqNlk/a1k0e1ZRLWc0DQp6XlZWSiRrZztua0MrPn5xdWd4UEs2Syh7dG9BQn19
ZHdXIUdtb0pmJCs7diZVaWlHQXttMkxrdFV5JnkrQmJ2c2UNCnp3bEttUGNQT08zQzBfblJPe002
OTg9RUZ2ZCkqJV9WMk8oYSZBI1VrVE5lcjhXXl9tZGlsWjM4eTNvO253T0ZLdQ0KejRrfEdUSHpF
Wj5ucGNyfTFHMjBfJjRNYV9RKjYzXyUhWndVN0xkRWxxaTRvekRQKio0c3g7Y3ZuXjFNTVFLP08r
DQp6bFVeIzgtWUU5NnlvUnNTVlZAM3ticTAlSGAkTWgqPSpfUz8tXjEhJDQtfDdQYCRJbzlucTdP
MSEjUCN4cnxRPWMNCnpaUGA+dCtqZFEwMT1gTmwhfCp+cldkJnVRWDJeOyUrem5maEYoenV2VWFN
cG5Lb0c3e2MlIWdiYjJQeyN6YHView0KemRYbDdKRTdGeFA/QGR4QFh8cnBgJE4rXy1KYEZRWnl1
T3J3SjwwY2FKXiVWSCYrOHxKPGlPcn4wVHplJjBEJTVZDQp6Wnk9aSU+Qj4tVHl4elRJOFhZfTt1
IypTWWh0M1h6NHBrY0krcSowQFlJaTRxJSNKdVNJcWVlWlchUSEqSXYtaUsNCnpxakVsQmMkM1Fv
VGdwLVE3Tm82ej1vbld4WG5SdyhSakFtMzdwTHpuV1MrKmU9dSE3aFdZfnIxeEZlUENPU3w7YQ0K
ek13Mmh4dnc5fjtFQT9TejZULXFLZ2hBdVBrfFhmbjhGd1Y/NCRlQURqLS1qO3U0NlRDY1VwK1NE
O3NyRHMyN1h8DQp6KFZjXzYraEdaSDYtZDh8SDVZS0ppNUR+T0RJbUVwYWBHIS16KTVqMWA9ZkZF
dXNwKUI4I1kmfCUpPEBuWF4mWjANCnp2fX1nYCUyaGtMdyZgdUFWc2FlczlqMUE1czhFYWFJbjAm
R1ZadHFfYCklZyY8Vm1DNjBiY1BaR1hPZHB6Ui1CPw0Kem0rVUVHT0NeJiZyOT15RFM4Oz5sWkRB
cSRlMzBHakc4b1dTelJya3A4QnBOcmN2PTVgbjl8WHV7NUxOI2F5eyluDQp6RHEmSnY8cGs7QTFt
ODEoRTl2b0FHbGVlTUMqZU0lNWY4WG9XIUYhSEtYMkhCdGlvOWklY2ljY1pQZj55OXtWZGsNCnpi
SD1EYj9xb2tWbGtgcHQ7SVlFbFhSM3RfcDBsbH52K28pPy1xfmRYZ01yVUIhV0RqZkVXYlJTJDZa
bV5rYUxJTw0KekNraipWektoejl4NT5WSzhpVCFQdjtPUHgkeVRSbCQtNEtAP0hTQ0xxO1QhQ0dt
Rk4hOEFJQS1idCRCMGkhV3clDQp6Izx1eDJoal9QVEZPblRfPipuXkRWX1pzQypUbCUoPEQ3MTde
KWRWSjREbXlYI3MrYX1lST0oYSEpKENOPDYrKm4NCnomNkVvfDRlMzNRbitEb1g0QyhWUW0qITdz
Jkx1K3xEPnEpcjxAU1RiRyphbnhNVm17MCk+TVVQKi1kOzUyTlUlYw0KekduaiozVHM2ZD5QP3RH
OEVsfntOOzdgQjNkYFBfZW09NnNEMlprOD1pNkVKLTJsO1hILVN8NU9wUzg7Z2c5JXBxDQp6ezNP
JGlYNVFXKHJafUt3UHgkckYxbHNNaEF2ZCgrKihmN0cydlJ1UURDXzdNbSFAaDFob1RmVy12MilW
TmVIOXgNCnp4bm9QTDtAJGg+RXtfYFdKS1dYJXthe2JxKDVQYDtVRWtrdF8wbmUhJHAreGdzSDtM
bEltTSh2QipQc2wmUikqNg0KeiRfQmJsZz5fZFU+KylpYlBLaClpZiNwRHFrdzVofG08QX1ULUAo
REZ6TCEzNUE2bGwmZ3djO3FfNChoS2tVPl51DQp6Q01tRjx6dSExeitnJndzJGJQdGdmYUsoVz5k
WXNZK0BDcHcmKG0oTj9PJCQ8UXRXODt6WSF1T08/eUs7aHRBKjQNCnp7PlpQS0Fnb2MkdCpPRDxE
N2leSklRVHMqTFhRdUpoNUlsJU0qX1dYZ21+YUNMaGBwOGAqQF9rXlpiMT5DP1IxWg0KekUjQlFi
VyF0Wk1vZTgkbktUbz9pblVMWEtXY0I8UHpObndGb2lySWUlN0ZZd2ZgcGBgVHUzfXpYTGJBUmlt
dXxWDQp6IVlDMm9ePGRwKS1UamxuSCt9ZDI0UTc4JD5xRVAoP1FBQiFqTjtBWSsodUJSV15jWmY2
cW8mLT0lI1A+S0Bse0cNCno5Mj9OQXUyTTliK0x7YlZ1VzIrJTJUaV92Q3FIKkh3XypuUShXVEY0
dkJLMGQhRD5TX3ZSWERacDUoP3kjPyh8YA0Kemc9QDc9SF9HOTZAV3luJXMhVW9vMEsmdmpnLTlR
SU4lMnREITZyMiN5fHU2cSZlWjN1JVMrKDBsbHJgKDNOYHh6DQp6ej40VzFKJjxrdW50fWdrZn5F
MyhYTSNObl9xeGNqTCNmSDNnSjkobHJqWUlpSDhOKEUoNWNWU3NuNF5pZldfPmwNCnpKcVlpbHRH
MUpeUj9wPSFQajlFJkpOck1SLVFGOD1gKXRTT09NeTwrMlpxVGJKMVpwcCk0LX11M2I/ZiQrNEUk
Tw0KemM/dHVVS1Q+ZSpLVVVleitFRVZLZlo2aFdCUGVeUHotVEVVeWA1UmJZfVY+IXAzcTNYNF5T
bjJoTyQ8KlV2ZEdEDQp6e3BmMSY+QFJvZXt2O0BYOz02WCEoVzwrbHNPKG5UOzJyN0VzUHl9dkBr
SWxfKFFmYV5abmd2KF9NeiRxUnpnbnENCnpsdk5MOWlqbVQ/REo7JlcrdDJXNCNBeVpQVSVFTyE+
I0loJGV6YmIpTHJ6KHIpMDFOI2BqIXY9V3xaQmMmNl9IIw0Keit1K0skeDAjPlQ/VUxeK2NldHp8
dVlTLXRXWV5oSShTdHB7VTB3R2FTdyU7dSVYQmVGS2JnJWM4V3VkfSReZEFIDQp6WFh5YiN0SXZR
Y0ZTVV9sMlkoNDBPNFdjYD5uS2AzUFNVb2tPOyErbiEjRkNzKHAwKGtQKFZ9bDJ4WUlIdlU9fDcN
CnpvSHt+KXs/fWM3QDFZXmZyb2taXzhUamJWa2xFJCpldk04fGNCYWxBeXdqSEx7VChnVDd8cCpg
PlpOcTVoQzlAQg0KekA0eih5RSl0eFEtP1d3U2VtMFBJZlFmb0doSWYkM2R7IT5mViV5MGtYMll8
cE9lMkR8ITd8VGlxb2NQflE+P2ZXDQp6V310Wj04OClOREZUWjlaXjc2anE2LWZmRTleVnRFIW1v
I245S19ve2YlO20xd2pqP0E2YGtTTjwtLSspK245bDgNCnpDKEYlPGoqTmY8ajRyNGdpaX5oWnNf
PGJ9VkNjX3I9YDc2ajxUIyMlRE5jXmBVe1NOP0M+ZHtncFElYnQzYGp5Tw0KejM3Km1YaXEpKUte
dWtIcmEqNCZuZTNMdyRjWmwpUUpVeENsVm5JUVNqY0djSlVZSHNSU0h5UF4rfCMwRSsmI19VDQp6
NFQ/Zz1iamJvIXpLS198SUpic2Jzfk9BTiM4aGVtQjkwKWlEWWNuK2FOR2hLcV5HZjlLYiloTS1F
Z3xxdUBaY3YNCnpaTCU7T25pJTtPdzZmVVNhdWhpfWBuPkNrKVVoKHVUb21SVUE3MTNgZEFGQUZO
KlIre2c2YjZkJHFvMXBMV1kyJQ0KelRCcHt9O2NgdU49enpyVDhRbVIrUEFfd2UzI2lMbnhuP3tv
VUpZJT9iVUojbmFjJiRRclVjcFFuTzlPSyRoTS1xDQp6MHt4V3dAKXVuMy1qeFUyKHpkKHNlMzw1
eHV7O0JGSVZCTyE7TUAtd0AwcWRnWDFFOEZaZlhtWUpUcWU0Rj8yVHkNCnoqKjJsMy1LaEhyR0g/
ZXxaVWJWQXcrKlhOUj9xM1hpbjI+UW4lK208bjtGQiooUSNObz5yZVp7dklTWU14KnFycw0Kem04
XnZ3T14xOUI5SiNrait+TUQ1YGAqNV4hMWZfQj59RD5gZTJ3PUpHZTMyI3VvMC1rdFdCTjVKSWQ2
akQqWV5vDQp6Xnc4Zmw3Vk8wSG89VEZMQ0NvUmV2Z3ZoYklUI0oxWkU7QXBQaVQpMVNYbnlMUWls
Pk1DJkh8YThGNFVlUmBmRC0NCnpHMU1XdU07dUpQdnk9PlZxPnBQQzV8KDtLSiFAalhSK0x6dmYy
fVN9UEkmSWp2SmhvMlpCd34xdWchfCR6MFgpPw0KekM2UWF2bVdRVXpTVyhOfCFyWWpaMEUkWHJU
RCl1JUdNan5BXn1jWEZoNG98JDRqM2NIU2RLN0QpMURifjZ0TiREDQp6Wm15RnlQNiVVKiMqfVkh
ZiNrTSh7IT49KmZTaEcoVm0/ZEAxcDF5eVFeanNaTHE2WChFXlhydSpwT2w2KClXfTkNCnpMdTBM
eGUhfEZSRHxzZW4lSXRYOUhyT1Y/bCp8cjtme05MWmEhbFBxKElATT9RU0xqYWJ+R0oxK0hCRmxq
T0Y3cQ0Kenc9KH5uRSNzTSl7QEpsJkU3aypiI35JbGltRV98bTteen0pKXxgbVJTYj52czhXdWtX
ajdPMF80Tz9WNmphJV80DQp6VnVreklUdl56b015SFI/bkpjZTZYZENqO1JfaEkkN3xXY1gmPVBi
eHNVeDtJeEs/NVU2WEo3Mnh1R3omdHI9TXINCnohTVBgeE9MTFVHNjZWcEk1Wj5GMkVXSHFqdzxV
ZHl1bXZtMTJoLUlyVmRaPmNnMSRgX098bXcqKWZOVygkIT8zRg0KenFoQkRnTmYyXnR6PVEkRDRR
d0pOPWh8KTJuQmdzU3dDYHx7UTR5bCMkdVp3NFpNdV52SGZvbnJfRTV6NzVtcGJmDQp6ZX0pP35L
MTBEZiNWcDhCMkUyPlR3Y0UpdWtQPkh9OytMTlNNOzVTcGQ0XilsWD1FcXdQTGp1aEModnBPJmBw
OHkNCnoxTF4yVkJqWXB3JFNDNXFGITZLYSFFdi0/P3BtMH14dyg7JHpCX2pvdWElaUpGREh6PGVs
JmxhQyMtSmU+cG4kIQ0KenZxSCtzODskTzc3LXQzTngkNnVrbjIrWCNFTj8tUiN5KlY/JmQrVXF5
QWVMUypFcWNzWlU7Pm9HeG1sfGUqZTg3DQp6LTQ9QkJlR21yZnE0I0BXWFlLZjBaMWtLUVZsdkwx
K197dnFheTVNbj5vQlJCRlNfT2U4Wj5+PmMhNTxoMkZSajUNCnohOT5rfTZLTDk8IzVCJWRCWk9g
RjBpJD4+ZlZaMUA9RDdyKUJ1PW4/Wkw1NldjMihjcSFvMiQyTj97Vn1ZaGlreQ0KemRxdW1oMW0k
aSg+TnNUZTZWUit8JEcle3JLeGpQc0lKLWB2dTB5T0tUNlF2Jmp2NVEybHk0JDN3VEtpTip8QkB+
DQp6c2FTIXFDYG0+fiR4fitHbj00c3VXcW45ZWsydEY3dnBJMVRJJXM1bF9VPXBSe3RWZVpNXj4r
Qzxjdj9KXjRuaHwNCnozfmd2Z0FaJl80TCl3Mm1tVkZkTCQ5KWJrdTwtT2F7cGwzWXBaXkQ1YCQ5
cXdyWCorc2hUJGxEdCE+YGMhWWN9JQ0Kel55fVFxR2pDdDh3N358RGxqTjl6bmY7XzJZYzZZUUx2
JlBGJTNPPllAVnNSX1Nuek1NdjQ+T3ghYTZ0SF80aCg4DQp6bC1BcjNIdUpMSThyX2xhKl9tQWBP
Vjc5MTVGRGRxa3A2KmJBd2EtSz5IfmAlO2Jhc24oNFRSMjRwKUFHRC1BRzUNCnpIPSlza3V6aU0o
byZFMXl2QlB6TEFFfEBCRGR+aks0SUdefFNYUGN+N1ZUIyFDMWFZMTJMakRIWig5MW9ecUp8fg0K
eigla0BzO1ZHJHprP0R7ekZkLXYxQTxJOUlSWUZ2Sm9zdlE1S3FMbX50NHRlVV5rRXtpbjheUTRs
S3lvKSh1OU9fDQp6ezxNXk4xVDI7WClOLUBTbjZhSylCclBUPlloRFlgSXJ8NDBXU2tqb1llIzBk
eElKYT1vcHxGWnpCIUw1ZUdDTF4NCnpDYzkyeU4hTFB9eHFKUVppYD1tUj0oaGlRYGk1M3ZnOWpg
Xz0jXzBYX2tfZENLbkRHZV9nXyhKfEpLI3ZYNiY0bA0KenhIcE5QZWVMRyhzPig4TXs8VCY0emde
aENhQCRWX1NIMFRkNkVCWVpUbFoob3kzQTBpM0FpIXdBRnROKHorPztWDQp6e1U0WnZuYm5lbUJX
ZVUoRHBSciZlR0k2fEFMTWtVTDFRK3hTcn0kcFJ0KVVtaE84alQ4U2RoeXZ7XmNzdH1JUlgNCnpT
dEpqPEFqcT85UWhURW5kQTNkZERIbEM1KCQ9b2kqYjZkdW9QUEdLIWY9azZ4S1FLJDM4R2JKPmty
aSowaDslbg0Keld3dEdoM09rUmdWayM+R3UxenM/MHRkZSpGN344fmA3NFh2WGpMY1huRyl2UUxZ
M2QyYCs+KCtaMjUlWUVzOWtDDQp6enhPcU1hVzZaNCRaezZkQTdMZiQkKlMpSHUkKUVWKCFUPDs4
Sk0+Z0E+SVhzemNAUztacC0xcittODs5VjFAVmANCnpQPWVKdSoyKVRXODw+PkVjPjFNX3FqO1kl
ZGxzakthfGQocSQyemNPcT9wVDY4fGk+bUR7bEBQTWhiJkl6V1hzVQ0KelkrKVdSLVhqT29jPD5Y
YElMS3RJKStKYmx7fm4lUkwtc2AzNzZiLT5FZjArYWxpMVc9UnlCcz9wSSl2MEN2IWkwDQp6d3c0
byohakYzZFRZaUg8R0pPek9QSDJeSFNaYnFIYy1ienojQnktSjJfWEQ7endAeXo2eEFQeEE7N20z
P2J+KXINCnpZQXUqeDxhZHhINz1TSUdBQFQhYiN2SE81IyRDNHNrJGc2NE9sfWw5b3V2TmYkZntR
fXAhNyNCYWZfVjdGR31+TA0KekJhSUR3RUZvI3RjI2U2WEp0JnpXJUNOQUZNLSNoMWluMm4rXitF
e21HIXYyJkQjRDFXP2xVdVR2UypyKk50WSkkDQp6bkkpKFdETyRVQGFvNkkoQkgjWjtqTSRIVUl6
SWF1Ump0bD8qamYwSiZ9X2EzaUpCIXNAUXgod0RfMXJUSD4meE8NCnp4cyk/NTsya3UjaUg/LU5X
ZGtKb1VQc1dmYChJNHBsNE1+UXZVRD1ibVEzKGNXZUxZZ3B1QVJCbT8+b1RGOXtMVQ0KekpUR0tV
RT5RPnk9TD94e21kSGxHZ1UmYjYoWmV3Rz5RJW1GTWZ0X1B3JH5aWXIzem93OU8hLVJtaC1UYTl7
cF9YDQp6ST5XITE9fVJPMUlFc0lIb0U3e1hTWU5qRTJKRDRibSVpaiVHaE5zIXh4akFfNjwmNV9D
a2dMdlclYCRuZzsqNksNCnpCWXNpQT50PHFKbHh6UW07NkM9WnZFPjhZIz18WigoITw3U2NzZDYl
bWl+aFZHaT4xYXpLZnspT1hUej5oN0puew0KekA3Tz9MeHoqenNfY1FHLT9PYiNCRF5PflBpdVhH
PThDZmlTcCVkUHslfEhQejUmPl4kQEB3RVkmQSQ8Qkhgcl5XDQp6K3Y/T0BBQ3hzYEtDTy0xMjFe
MT5JVVB1dmVPVXlvcHd+a0k9I0VWZSNLeStSKH5vKypWRCUpckZRVEg1PVdKZ2gNCnpoWm9eSUVD
a1BXLSZZN2J1WVUlLUk/Mj1IPX0wOWpUIVVkbnB7JiQzYm82NyhCYGt9e0JyNi1IK2tvSj4rUWMx
Sw0KeiF5MFQ+QGpwVGJ3U1gjSU47PGVKJWRvanNMbnkjMyQyWjAlY0Q0KiMyMHVRfFdzOEYxZkY/
aT9sM3hfNEd7I1BEDQp6eGBeJlM0Nj1MKVM5SFJEU2w5K3ZebTtiLVVRdyp1NkYxTVdGUGkzKTZ9
NlpxbXEqU3Qxc3AzJT5AUVVAcFM+djMNCnpOQCEmdDhHO2UjUE0qc2NYXmFhSEY4MnlyQ3IweCFH
Kj9tSTdMO1kjdj4/bW85M1AhQWk7a0V3QjswTmtRZjhNOA0Kell5eG49cSo4a0tNfFc7Vnp4QkBz
YU1pLX5zKEIwQGVXTXc+ZzcjT3AzUmMoOVFHVGBja1piM0lXOU5eb1JWJD9JDQp6IVpOc0s2QH5a
fiQtU3xqZ3lqMlJIKiF9VHFmb2NIcmdJN19gS3QzSTBMN0FFKnZeRyo7VEV7cDkxeVVhNUgrKGwN
Cno1VFNPI2VDeTJsODVzXj8mXmpNZndBK0pAK0F1UWZ2eGQ0e1EpYzlKazZ+bFZgXlAmQjdCazht
dWY9KzVtTVI3UQ0Kej1meGh4OTMle3Bkb0VabzVlJUVvKm1vVntWdFF7QjNARXozYV9mNEw+RTRX
cmZgbW5kSmhfe1U2aFVLcT5Ab1VDDQp6R0ZVTEd7R0FjPUs8QFhOK0QxJG4lfGJIN3k2QitPPi0p
MWg7IWdQV0YrUmlWeCVXN1gzeEdPdzVCdngzWVA5I3wNCnpmZEdoKHdWVm1gdUB9c2Z5QlI7KUwz
JnpLciZibjhgQFRqLXVnUStYTUFVJEliZ3tAVG9aTHl1LUU0RT1ed3t3PA0KenprTFJ3eU1gOGdR
bn5BdCpeX0FaQnQtQ2szUT5ORk5aVWlTdU9pd1A1I15KS3cxcUBAN1NUUnxOWHNTQzV7WXMoDQp6
KFZqckcmbjQySDBgKGx4K1VVdSFEJXJ1RmRkMXh5a1dqJStiN3liOEV3ODVlUU1KKi1vSyRaJW5P
Qj9XXmM0PGENCnpGbVMhJDh9I1Vjb2lyISliYWszbmNMTF5ZT3F1eTNwLWQ4UUg0bHp0azQ8Y1pQ
X311d1BHUFhzK31RfFEpYH1pfA0KejxNMSprLVJiUXl1a09MfmpuPmlnXlBxdGlze2dreD0xcUVq
S0daP2d0KUNwO1cpS3EzblQ/UCkqe2F7U2RZRnEmDQp6M0JmIylaVSVPVVQwPyNTXz4mTEBXTG4x
eEMqMGZ2ek9pZXVSZVArMD1ZSTY0KndePGg+SyV7ez59aHdvX1AqQGgNCnp6KmpBUStfez5MYGg/
PyhzJnkzKXdVTEVodFQzNjUrOXAyX2ZXV3Z0bEViVkV5eDF4TncrSDlfMz5+Yl5CfFVEew0Kejgj
NjJgNG8kNG5zMHRzfnNqZEZYeF4pJSVwZGxTeUc3TUIqYVJ0Wi1qd0N1TnhBOVojXn1NWE1OM0Re
eXhgRXcoDQp6VW9UMDMoTkxkek9GIWdwMzJfWis9VUEjVHlCPG19P0h0N2xMeUNnPSlPRkctb0Ik
aTVeSnxDVHhyKkpvWl8mKj8NCnpXcGBpPm92Iz4kKmFGKFFxO15rUnl8aXg2QGNlKGtYbnppdVk0
UXtSY09FNz5HOTV5N1o+TG4mQllLY3whKU1pNQ0KejN3Mz5qP2JqYWZ1LXgxO2BlbzZVJU4pcWpa
KW5HeXdUUnlzTy1IP0hJRCN5X3NQYlNLNHV0flAwMlZqNEJxSVE0DQp6e3QoN1g2TkJwa2xZQWY0
MGF0Y3BreyVvPk96WE5qck8qb1kmUGAzbzxEcGJfWnx9d2QtKXIpc0FVcSEkPUEjZXENCnp5dilM
VWM2RVA/bilpVG0qUnJSeClHMThWIXJ0aDdUUT9VeSppK19gS0hTckpnKH51RmBXaihjcDlFVUpi
YVQldA0Kei1gLUI0WUBUeU92bWhfPCRXVEtjMC07KVlQXiNaIys1XzA2PkE7aVJeKzxhMykrajVH
RiQ1M21mTUkqV0pBMGZrDQp6P0F3TktrJHctRGkqXkRUU3MtSjVjPDBqUUojREE3ZlhFK29PbmNl
Jkl9ZktWemAtQ0lMYkRaLTQtIStTRHBSTkoNCnpARG9TVSFwSWF9PSVCKWNTcEdpaitObUNLMmB4
UGkxJlJEcTtNNFdJOT90KV9mUGJDZ1Vrfj5zZG5TIzg8ZzM/QA0Kemled31TIWcqd3pIOHNnPGA1
UUxZclkzM2M5elpySHZNIVJoKWk8KHxHSkx0Kld3VUtUKnUtRHZoPndYSlljI1UhDQp6antjfjJU
KVhOUngzakQ1PjA+MFlUaTNeS1pLciUyUGx4R3E4bzRNaEpPOEJkKDd6eD1GZnxEQHtEYzxmZlR3
WWgNCnpKYWlFOWMoREhBJFFDZighKSY5NntyKGxaU2V9O1h6eFhRYHNmR2dzRyg9ZVBNeTEmbTYp
K29uUSkwcihDaG15QQ0Kei1qb0tSPlF8VEhkKGB3RHhgMEZDSzxhfHEkYjh0PWNzIzZhRHBQTXRU
JXY4akh5fn4mTlYjTWZyQDM9eU5pT2wxDQp6ZiVuJk1gSVFXQF5ka3ExWnd3fWcmfThEMjEtc3Uo
UXNZdHJwSD8/SDJJUnNaYlZRN1Q0OHxfNmJsKWpGSUE0M2oNCnpPRWotI0UqRyFzZ2s5SD9DQHhH
OXVRWkJfT3pRUHc/NGJiPDUkUSQ3RDg5aj4tRUpPcTxTaXFQYFppcmhvNzctRg0Kelh9Vz5oQ3wp
QmFIQihgPWlmLSl5WUNETmxLZUhLMkUhJDAkezR2ZyFlYz1sey1GN01yM1pXJUhUQSNOWnt1fWRf
DQp6PX50MEJhRTBgPVhpPl9jbnxLaUF2WEUxYWpyVUdgRUdGZ2xqT25ubl9xU1p7YWY3TjNvPmpT
JDVHMSNkamczdCQNCnpCJFIrOVQzR0BtYilJSChRPVFmbWllUHBqNUVjfiRIWWI9NjQxdk1Caz9C
eDFKU3Q0LSZqVW1HQTQ1dkk7aTRSRw0KenBGY2U2Y1RqZyhXOVA7Xjhgez5eMXBtVXxxayZ8cnZa
T19aYWdhZWlEe21QRE9xITJ8d1BgX3VhfSRHOzd3REYqDQp6VW98cDMjX053aylPZTYtRmJJX0RI
QTVXdWh3ZyllTyVMNk4hOD9eRDFFU3ZFclVCNn5ffFU9b1RUWndDMlA8fkcNCno5K0JrJmc2cW0t
O2c0P2YjaVpMaERAd143dipobFF6OXJwU3Q0RCE3XytnOTk4dk14VVFPcE1hMHt4eDJxYTMqYg0K
eiVHfClqK3xsYyEtV3wlN3Q8NFhwSyNgRldOQmQqaFIhe04+d2xjcUclbmYzNWdSUXdDX0ZPcmN4
MT9MR01RYUJtDQp6eiQ4Uzl2dH58ekVVZEx6WklrVmBYK1QocUV0IXIhP1g9QVMke0dkSkx5bEpM
Z2VJaFl0NXpaa0FaU0k8a1JzNWsNCno3e3d9Tk1uJE1vNXBlbCNNXyh+LXoremZncil4MWglLW9x
ZldKPkB6VX1qPCFBeDRHVnNUZSg9RzVPWGhUR1hzOQ0Keio9bjBaTTt+fEVDSWF9N3FneTQtLTk7
ZzhRNzhGbi0/KVlaKTV5VGEyaDdtU1kyYmhAUGprMit3eVE0KzlUND5KDQp6OF5vPHpATHIhKXdE
e0tYKShzIzxDKDQ2VWJkaGd6IWJJb3ptSzI1R2lwQTBlNlQ8VE5nPDFUU1drdFNnaT1edi0NCnpM
bF50NVRgVlFWRDs5QEFXJHR5OSNiMmY1N1pIbm5wP05Pd3gwMUkpRFYzS21QPStOYSE/Rn48T0Vp
Zko+NkZaQA0KekxwUm1tcGxlJUFZTX1BQHtBSUdiMDgtMHNFWU04N2lTfHNhS3x9ZDRKTkFnNyU8
d2RMZE5LREteRCp9V2l7I30kDQp6KiNIVikyPy1RaCE8VThCIV9ET0FDJHFeQCl8Nj5iYlhqMiFV
d1BJR1FxN3JjX15MWTBPalcqZ2MqI3g9TklsUnYNCnohJUdLemE2NnZYOSR3NWZiY1V9VXtmMVpS
UGxJPkQoczshRSpOPkZ7PW8lMTBuLVBUWT92VFVvQWhFJHU2VUNWcQ0KenxCVEs1cGR1I0UxMWZr
VXpKQUBJQENQXj9NcGohK0dlKDkoJTRsMHFyTnN6d2h6OzQ2Si18M3x4SClXI0VAU2xuDQp6Z2s5
LVJxdTx+SWMxQV91MFBaeDU3ZjI7S3FKYDchVlJeWkklbj1oQkREIylzcz1AUDklc31RWmw9fkJ8
VDE+WUwNCno4PDZxP3UqcEVmbitpd3gkfThURz5kM1QpdWlge1R0KjxlPiNEci1MZG9SM3srakJS
MGpfX2l4LVR6WVYoNFEjeA0KemA+Z143NVlTMyNWIytrVTFOaFZTI3tmYVdJSFZtZXYzdzUzOWIq
UCl7JXs4THtmSEV8UVBVbGl0M3tUZGtvcCFmDQp6Mz9nSEc4PUw9aik8dkhFcUw1YWQlVGtAK25Y
VVQpRWgpTUAqX3k5em5kfmY7RE45RWBzRzN1b2NeOD5oKXBjQSENCnptVjJvQ0tnalNpU340ZHFL
UVg9aTtpb2FSMTY3SjQ8aDx5NUZsTnEtdGN6fCZaRERad2RzZGIyIXl7TTUrPGwwOw0KemU/Y3dm
WUB1KD00OSRJSDM9Y05fSk47Rn4xQm1mPyhEVztFbG9tWmEtQXp6SzdrX0orUitrb1lPIUZBXkp3
Z1R7DQp6V3ozKUdFRzxtUWYxdnY+UXY4TjIwOy04bVNAWXhCe0FKNGc7R0ghWmNkRX5Zb1Vnbyts
SypRfnhKJShkKGN4enQNCnpgRGN7Km5aTkEzbz5lNVpAaEUkfkRecERBKyRjSWZIWS0wTVM0OEZJ
an5oOT84VSMlZWlrd0hAcSEkc1k5S3FafQ0Kek9gZWJ+ZF9pQyFET2k9YTQjNzdZXk5jWk82SGtA
UmU3LUREeTgkQGA1fWc7N2JqUnhMI2Q/IUNZelhnPjlsYE5CDQp6Wl80MDk/RmJJdjh5d2FvckFg
Q35VbDJmeSk7c1o3PEFlWmFVa2RKbz9qdmA/Xlp6ODFuKjFvZSo1UXY4R0tkcVUNCnpxY2I/cUhA
KlF1WX5MR3JCTitUKUtLfXNpMkdWcj9LaWF+eWdmaEclPHMpc2Y1KkkxK0pHZ2JWSVohNTtVanJ6
ZQ0KekFJMTYhR14zfjspeWRzNSVIVHk9YENjc2xjUCNmLXpoO0xCWk1mJWwrUmswRCN+WF5gTnhj
OFNJTm5FTUd6JVpODQp6Xm96TEA4az0zaV9FdH00TnkxOGtse0J2NjdoNCg5Yzk4Yj9pSUxPWGBh
fTM0NWRwWEx7b14yVGsmWn5fdTl8ZCYNCno4RkIjVWNPV29wZWMlV3tnRXZMV19FeVZ7ZD5gNClo
eVA3fjd1czQ2M21mNTlHTE5XbCRqaks4KjZacj9wPiRIfQ0Kek1zO3xyMiV1VW5BfXxoKzkhPn5P
b0pTMSliREU4bjVhJXUhPVdUXlNMfD9oZWNDfV5TeWhsZUFMZT9Vc0FXfDN7DQp6NTc3YWY8SDBa
czxyUi1eS2FXRXRObEV1O2l1clo8bzchQlZXKXspflFja3t2bCpIY288K0RVQChnO2hMTnRCczwN
Cnp0MHlFUit9cSpyZT5hR19AMUtFamtOI2E8VlpGV1dIZmF5OVApP0FmMUhSbnhVTWBee0c4K1U3
STVtd204KTA7YQ0Kemg2TUc9P3UlKGFNYFIzbGM3cV5MJnpoZkh4U1JIV2B+QTVVQWdZVlEyUCh3
OTcoS1N7LT9WPjsxKmBAVkhnQHY7DQp6TjFucUJHPGslOUFjOWQtZiM/VnNqNUpQQzZyODAwNypn
YWZDI248ckAxRioyZk9GI15GbmxJNVlUI0JqLWwqWVcNCno4ZmdQNXRaKUlwa3pSQ2tDZ319QHBA
Vjgpcz5ufnVLYDJVY0BCaHpmR1JVK3JiV28zQCZBNlFjPF9qUTMqOFhUcQ0KekBMITF4KlJ3Misy
VDNwV0VUb3g8WHVic2FCdiMpK1gxU0JKeU8lWTdhKyUoRCpXdntXPyVqV1ZNSVZlMEFhMERCDQp6
ZHZ3JVhONHxgWGg7cm5RaEVjZCsoU01NU0FTcihsWlU3NmFHLVQqdzNIZVZ9QkR2dTZzTlJgREl4
QFZuR1E1byQNCnpLNipXdzFudWJYVmZ1eSs5KH51ezVKRlklbE53N1dUamJReWNTcnBoRyMjO2Zn
YUx0cVRLJWUjMz5PMU9qeG0mPg0KenlZUmlzNHYyJXg2QShRUmZ1KSMqdFF2d3tPdnBzdT4hT2Zu
eCROY2AqNCE4d25MdlkqYXgrWTZ6OGpoTDNmdW1SDQp6Pn10JXFQKWNjaksoe31WYi0xKGI0YHRf
S0JnPzBaXlVnfnBsJk5yO0BWd0Mwdyg7b3hRdjBgamh2MDNlVjBXM2UNCnojfXxVMGBUfiRXelNy
P0x6cGdIIT8xRSQtI0xtR0x1UlZzU14/PGQ4SkR+WnFaUHJ4MmFURWIybjhqY2s2OCsldg0Kelk9
ISY0aU55NGZMbV5GWkh1X3U4X1ZzaFNmZXMqampPTXxrO1BFZ0opQUd1RFUyPGpHdz1RbnpzUXNo
QlFZV3RRDQp6N2NfYE5qQCEpLVI5WVNjajZ3SztUblNjalghc1N4QVlBc0twQmlId0g8PTZxd2I7
NjV2TX49Y1JlJCRzLTYpRVYNCnojIzsqeEllamcrSU9XJHw1Y20lPTtmcH1LeHhnfXAhajdKZEdj
fntQR3NsOF92d3BGS3RtdUVsWipVX2t0bWY/fQ0KemtFPFQ+RW55VjYhJD9ubks9eSpHMElzQzBw
d2NSTXJ3cUcyIXwrTiotREN3dXRIM1peVmlvTU0zbUF+QmZEVHVDDQp6aXhzQGZDMnE1VkR5dn1j
bFY7VStmJDJ9cD95IVJRcHFVe1VoWEZ2dUhYVkpETzx3e2ZuRkArRUFFMllZdVJvLVANCnpZPWhn
blVfXkZXJUApOUtrbmE+VUk4KGVGZik1PWotWHp+SGFJPz18KjhVRX1LPSpaY2JjYXlEej9Lak03
aDd4VA0KeldMOSNHakI3anpjTTV6Wj5RaHFTcldsYEE8d2BVKyN2TmA3cntvbz9BTldtVURFOTlg
SyVLJXtlRD8ySztxIzEmDQp6e3NEZnxTYzxHKiZEdUJYNTMyXj92aSpaMGZgWUhDdFhGPXUlbCso
Jlc/TXRQd0p3XiYyNUh6dT5CZ1dHPDA5LXgNCnpnKkkmSmRsMWdlMkYrdl8lYCpuMjhXK3VuYXlF
NEBZZCVPdl8xN1BVVCQ2JCNKNlNWWmY0Sn5Ge3VHNmlAOHdNVw0Keig4MmUxcTwmUUhNcUo+Pk8+
N1lLfEEqZm9uRUVsVGprP1E0IU53P1I2fkpFZ3J0KCFUe1pqeT5SVUNJMTdeTHU5DQp6JXlxRypf
QjxFTTwyQ3oyPzZ7ckIjUiV9ej0zK15qM254e2luJW9Sc0FPd0ZUMShHbF9rdD41fSkxQEU3e1hT
XjwNCnpSOERubDVuRUlzYXIqeWUtTWtURyhOcnleKlJNNi1nV2smfW94OFg/KXBCZC1WOTBpZEw7
fDwmYFgxJGNae3ZLRA0KenA2XnckMFl7NGUoeENiYFVtLV44N3hWUUZaaXJUaS1wSXg3KH4tJkNk
LSVsRWwlWG8yRiRVWEx4ZTtIbWEjPURNDQp6QiRxbXBpaXtDUFBUQGhBWVE8KHQ2dmdJQyg8SD01
UWBPPyhyYlIpY0V6eSoxN0hXIzI5UHpXQUBza0dwdUIyRT8NCnpDKUk3UmpIODwzRFAxZ09pPSYz
M0ZCcWVkQllMcWp4Xnk3JU59aGNjdmFZKG90fTE8fkgxWTJ+TUgkOVojI01gbA0KelI9cXFUSWE0
Zn5HRWJ4QTZkUzc9cFRSNzhOJjN0SVJKe2ojNz1uVCQ+JjF+bDBySy1GcyhvfGBmOU1ESmRKS0M4
DQp6MVQtaEMkWGxlQlBJSjhhQl9FIWJzKlZyV2R4Yndhd1dnTk9lN2ZRVkt8amw5cWA2UH42dSFA
MkV+JDhQeGI3Z0kNCnpTKEY8VXExdy1QRHRzTV5ffm51dHQpOTEmaEFYVDJgPlJKOV9NNzwzYD8m
QHxPKG1iMWtUKjR+em1tVzlUKkJJfg0KejZTXml5K211ckhiVkQofDx9TG1PTnZqQTwxQEd7Z3hB
V2MqNnpjaG1QeVhzTHN4Ml5MX00+ayZzRC1jZHYjKS1nDQp6dyNtZ1IhcFcoSG9CN1AlezhAOE9W
P1FBK29SPXNwbjAtQCNLWUg1Qk5HeGgjaTkoP2ozYjhkSktDRSUjaUZqO3sNCnpWOWhAbmg0Wmo9
UE17QTJiQ29mNTkoZkxVTUtndG9DYGJoZE9MME0qQiQ0V1YyRXZqMUNRIWA1Zzg5bWMpWkgqQA0K
emhhYk92RVlaTHREQFo7QjIkJTd9aV53Qk8zdCMzcEJ+cHg2O1UyT0VqZytZaF8pSjZMSHZwYG5O
Q0RyM2Vwb2J2DQp6LX5UTGdyenI0Z2pGIyRSUTxpXk9wOHZLTkNWSWRweUticiF6QiYwRz9YU3lR
NyhTQD9yNThyYnt6Tj1IZnZ6U30NCnptTnx1KXk3SnhoWERHfGxscjRjJE9yYlFCRGZKWWpuKnsz
U25EaiUre01GWCpJVn5pY0tnWEU9MklkSD8tNjw+eA0KempLIWVBKl4oIy03UHJRM2h4bHdUUFN8
UmhwajlFTnNneW8lOXlVZWp2em4kK2F1T3NDaHtFQkx5bV8ldXBgSzFMDQp6T0lBSjRwRnVKOHRI
JDhoeG1EdyVwUVJLVU58UXtmMHNJV0FuV0BAbDNRcGVeXlBpbXo0dTlyRzF8UGtsanRNSlANCnpA
Iz5raDtganY/cXtwOW4wSzJ1TC14YWwoNFRnVzltfkclXzleUDh1KSEqYCElIyttQUFASmc7T1ZC
ZCs5VTwjLQ0KeittWjNtbzBhPzhXSEZ4WHA+cCNGWlBgfm5uM0tpdk9GSCsxJDJMNWBtPkxiQnVA
aVdseG96VF5hZVF6QiE8P0glDQp6M3gtfDVxRzE7PmVEd3ZUaig4KEV6VzJ2NE5JRlo2M3dwNEE+
bkp0Q2V9RmBLKnlCeD42cEIlLTRvPSt3dkFyV18NCnpJMzJFcDVpMFFybUR+dUdkQm0wPHBpaXg2
SUgwQ1pSTEwydStWNWk3MXNfJX0hO3xQOSZuI2IhXyVrV3l0SlRweQ0KekYhNStrc3A1OEIyfTcz
NTZTWlJ3b1hxXktXUT08fGNJQ2B6NiktREdNdX41RlVeP1k2PTh9KlpDUkExLSVudE56DQp6Tn5J
aTxlZDx8TVZeNT5RPi1KNmZLOGp5SGdPSSk5VzQtdCpkLTJpVEIoJmJMWTMrSmpaVkI0I2RZQjdR
RllEP00NCnpeUk9mVyk/aUdqVnRnODlqSllHYjt0ZnU5UiZvYTEoMlhZeyN5N08tVmBURmxpSzRU
VXlLbz5+UyQ4Vk10U0pxRg0Kemp5cEAmYD1uN3JQdSkyXjdBKFhlSiNMMTJNelpGYVNAcDtvX3J0
WGtUUm10UHc8Pk9UciV7ZV5KPlhCOU9fNWBxDQp6dVlgaHIzSG90Vz1IOHE5X0E0JH5gaFA4SFI4
dHpvIyhyYXNgITsqJiYpSVE1K3RNaUolezlNakVyZ25MKnxGaksNCnpmVERGYytgJDxCS0t3V04h
YXFIKWF9flVyZVB0aER0QWpIZmAmYjRQQFhyeG00Z2FzOyhoanY7Q19EQzQ/a295cw0Kem9MUGM3
ejd7dU9eQUJ6cmZWVz0jPFpncXpKV3dCZk1HSjNaeFRTS3hrVnxRI05edlh7KEw1PFJtaD5vbGYx
N2MzDQp6WSpFbkMrOU81NTUqaSVEY3J6SHFQJjdMYE1jNDxFbHRiOEIpOTJ7JmF1KGNZRlV6fSpH
MztFLVV4cyM2PHVROTgNCno0Mks1RHtfTUFkSXQkY0VsMS1UUnhYWEMwZGh9e2ZKaWF+TGpRezdH
SDdTKHhPQmJYc3Q4SF9yOWN6TUZHU0kyfg0KejBPQ3QkJEFzSyo3TC0oTXJkNllAb2pBUy1UMi1t
ezdDKilIZTtAdnojaVZQLV5SREZxVFomZilUc340MUQjcXdADQp6ZGFObn16TnNKU1M5QGVxdjJX
KXNfYCotQ3swTGZyeyNXcUlhQW1GOXMlJCo3U19wQlMxIzFDVmh1V2NSSSNEVkYNCnpGR3w1VyRs
cH09NGhVcyRqRHFDSUlebDhrYy0jbEBKKkBRTXgpKXlBMiRgbUlpVmU0YntpMWR2NXU2TlBNRzx2
NA0KentIKUZaYkB1U1I9MXhvcGQla3VyeXNZN1M7cXhXMWZMe0NCV1dpZUN1ISQ2RSp6bW5vN0ts
eSo/TmdUVlRkaVRzDQp6WkBwSSZoOU9rSypDZU1CSTRkak8jbiR9MjU3ekRZaUMtUnVOeUNQbF5o
ZUMqcFgpTmdFdF9abCVfdnI1aiZFdHANCnpqYFF4d2w8anZUMSR9WC0/VjdMbE8wSGQqO3Y2NTQp
RzItPVlLUm9oVUFBKHBGSWYkMVhKeUNlSF8zNWlTMzN7Qg0Kel9kQVk+dj58VTZRNFhRJWYye3ts
Ums/e0BOY1M+VVY4N1otY0RBfkMtSTxjN1hgbmU0dXooUTk3XjRUMmEqNmQmDQp6YEpXZ0FlcjlC
WkdlRzcwZ0V1PFZRS2Ujcyh1JTNSOSRNVH5RIWs1JGwqaHAzUSYwK2R6NTBiIVZ4ekpGPEZwM3kN
Cnp3ZCZjbzszaTtJZXUmbyViYl5rfCVGZWQ3d3VyTWorM28pVnZ5dVhjdjI9Pm5GeGd3Kl80WT16
LVNOSEVEYyV+VA0KemIjaFo0XlojfHEwSjJJS0dHUS1NM297bWRHNGUmRD1JYlk0cj0oaGlXaGVa
VEJJRWMpQ0glO1JWVWFIZU4weUFYDQp6dHd4ZGxRSVJ0dmliQUNEOW4oRDA2S2wjTTkjSXRqSigm
KnlvaDJ3U3dNPjdSeVhKPXVhIXMmdnglfFAlMFAzJWkNCno5bG8hKCttZmFrMSFiQk5Cd0hkWkRw
cTNJcjJtcCEtdUUjZ1Z7WUFjZFkyOEVUQGROcGR3Pzt7RUNUP2NnT05jSA0KelcjT3MmKUF2JiNh
Szl2PCRNeSkpMTZ0dWpEM15lNS1qbEpRUHYhKURhdnNyX0w0bWl6e0RJOUBoaT1fNmRVcCt4DQp6
KFh1KkVuYndtZzZTNHo2JCs2dT1MQHY4cFBmSiNKJiF3MV4+KSsjKkZ1JCRlPFRqNTJzbUh2JlZm
diZKcXxidDMNCno9MVZGYndGPX45fDB9IShwYExEPGszWX1sUFJ2fEZRSUNke0gmMWB0ej1QT055
XnFtam4hMUdmWH5QdGNJPFQ5dA0KemJFNkByLWs5Un45SlV1Wk83fUhBUGNkKDc0Qjs9Sm4wKl9e
UERyRWRNPCMtTWF5XjY+e2llPk8/Qj1vdExFJDxjDQp6WWtwMGFNWVp6YWk/TWxsbz99UnxYJT59
WWNGRjNRQTIkWmlQTkIlUnJvPSs8b09MT1lHRSl1YURDPD9jb3lvXnsNCno9VExIWVc2VTE9JXRa
VWxTb19RYlc2NjV3JW93WWdGckk3WlRTJWM9dXtGS1NjczROUFJMVkB8eG1RJllpenc5Sw0Kelpk
XlVZb3w3QlQkfVF1TntwRDVtbS1GQ1Q1YzFpK2J9Vz83ZE5jMzU4cGx0a25BNUxAWTRKeUVwfmxy
TDtGVTVuDQp6SzRzPjM5akJ8JShjODwpLX1UaGZHcEY1NiNJcWZHWVd2e2Jlb3hvWCU7fStuJmJm
KT9RdSU7IXU5fV5qYURaKDgNCnpnYlYjM2gzZVQ5KnJ0PmhBRnFKTGkoU0VlNTRJdT96UGBNK3R7
b2xZanU3JGVBTE5gXmhGRlNNTmlXUUowS0d+cQ0Kem1xNTQ8cSlnKEplRUFDUTlMR1MkdD44RVNm
TE43MTZ+RXd+TEJsO1UhdWc/cHcyV0s5ZUtaNnVqbW1IS2QqR0lWDQp6eiUyUyM8QGdlbmwwV0FF
K0VsQ2pfRFMydCliRE1fNCE3bE85Y3EjU0VkbnMzZ145cFBpUSMrTCpkZnh4ZTVrRmcNCnpaZCps
X0V9TnA9ODs/JXJvbzJ+VjYpYkVXSXZWUktBXzx9MyRYJiUzNH1AWlFeWDh4QTRMNHswMCNnYDFj
dWY0UA0KeilJPmA/Tj9nNGp2bXc/UTRORURANX4/WU92YntpbzNJK0AzMiVtUTRaeDNjaFBlPSg1
cXIrd1BlMz47cnRac3M3DQp6PUVMVzlqKXxGKEtFOFZlYj4kMXFHREArVyghRUlDe1RwUXtwZSpA
UlF5eWlAck9zWm89OHRDY1Z+elF0TC17SD8NCnpmMHtDWGU3Wm9mbDJVMWtDfHgwX3VpK3tBazs/
cHR6TCUoaDxKQE16VSNLK3xRQFR9QFZLdCshQFlqfTU+TVdkMQ0KejNDfkQoU0xTRG93OS13Ym1m
aDBsRz9vNm9qWD5vRXJQakxhN0xXbXx2WU9XNUQhcXtfO0FtPCE9VUhCK3BjT2VxDQp6P2BPPXcm
VmEmU1R6VnpmMHRhZ00qTTJ4bTNOVT1WajdVKlJMfDc4bXtOZ0lQTUYhMUpfWEBSQFNrQllDTHRo
Kk0NCno1amBDZWVQc3hLO2xRJCVHT1ZNVCk+Q2t5aGo8djwySWZGVHB3fnVmLUskZytxQVYyRVNI
ez5ZVnVMbk9gVWwpKw0KenhsalpaOWxtIXJRalVndVEwdWxrbVY1JVVWd2JMaG5ZdWVnYHgtPll6
ISo9YWVJQlhISyQpeCtsPGdHQ3E5d3pADQp6S0lgQzhRTnVMVzNMcCFnRHJ2cSU1YUg5a25kLVF1
ZCE2Y25xdXtNPTVkRE1ncG5CVmApUmMmeTtafTxLNmpsIVINCnpRRVpfeWx+aHJYPGZjaz8kODg4
cWZ2JWo5Q1IpfG9qYTM0O15JRW4tZ01lbjBRUE5XSiVqamFTaW88IyhyeTdBMw0KelNKRU9iXzYz
Nm85by1KN1JAfkFqYXVgRGNkO28leEY5bHdJPGV2MXlFWjA7PD4yeUB6ODxiNTtieXB6OFl0KH49
DQp6aGtRakR2YWNDayVPN2FhIWp5SyNqVVpGPVg1JmFlbGJudjc3JiUjSDtZe2VwKmo7NEVAY0Mo
Nnl7ckZ7WWpfZEMNCnoobihWd3s0ZnNpKEZFN2p6Rkg1Z1o7VU4jSkJ6b3llUmJLRXVmY0gpTiE+
T2V2fmhKQTlVYnohXiRybCE1e1lKNA0Kek1NP3RRMkk1YD1aR2AmRTBNQW00X2Fedi1qakBJJkJP
OThNKEooQU1nd0JGPUd2SFlaXl4tWihEfDAoI2JrazE/DQp6bElZPGhEMTg7ajBZPGwtIXYoPTMx
LVcyfjZ8b1MmYjwqLUNVUV5WbDw/P3NTRFM0cCRweisrfSVBNENAVkNPNV8NCnpOd1J3Zm1YT1V0
YDxnQXlRenNlNEZidUA7QFczT0NmQTFpZW93YiNuI2EjITElcGU1eChIMUA0NXc/fTZXMWU5Yg0K
eilwb0FZdlc7cm1OITNiUDxpXnpAKyFvT1VQJEB6fW4oQ1dAcW5mNCZMJHhFS1ZMbzNHS3E+aXpS
T3VVd3pmXzNeDQp6bXBAKVYlVWhKe0g8dmxBVjF6LXpMb2xETzZvNkVSYiUlUCREeyshKlRTMzhv
Qm1HR0kwZzBzeXpSR34xZm5hY0UNCnpmTmxzO3VYfiQkXylBbUhZSEUzI3MoSWo9RjQwPXZxMk1Q
ZSVvQyZ1Mnx2cE8tbFE8V0VSPGEoR2U/MGJnSHxuVg0KeiNhNlBkNjRePTUrKUFvKGs/LW9sMjlm
RyNTRG8oP3AyYXtGLWdEKm5uaW9zT2g1aWo5XztgNTgxQD1aOSNHcjEpDQp6S2dKUE43fSEpbikk
JmYoIT48V0lnU3FgYnhoekl9THd+N3BRc01NcEMpVjg0eHtke3Q2JVo7MTkqeW4qcztMWXwNCnpA
ait9X2tJaX5zZXpvM1ZkMnFHOUBEYyVGVGczcERWO3o5PlJeYm4+KkBlLURRT0ZxZGx6MVJlJDUx
KUVVNWd2cw0KenB1QU9MJVlhYHtmYXx0dTA3akwyKjQlVUBzNUsjfSQ7bGhEMXcpdHM5SkxxPER6
d3VqbjhZXy1kZk42aGFgO0llDQp6N19BP2ItTCU0ZTltPXRtKTA1eFRSUkdAKTA9JmtgZkA9THZ5
NT44VnJHbTJVcmtkQmM8aVZBeyNfNEw+THM9TEsNCnoweHRVZE1zYE9vay1NQUg/NGRIPnJQTk8m
TGpia3pPTmE/Myp1ejR6JCk7Q1VRP2daX3V0P2ZrTnotUGtfU1Q4Jg0KelQrVVFteiVqR0Flc0ZE
bFY7enJgc0dIdVN4Yk8kP1FUNndAP3IlPE48fmFeVVNVbmVBckgqfVY3bmp8eHU8V0gmDQp6VkFB
eiRKUSlWYnt3cHBeNntZJngxeU40OHE+QWRsPzFJUkwqPTM9Rjc4NngtI2RYPWI7R0ZkS15ufXg0
a2tfZyUNCnp4dGpBVil6cGVwKCF6aGNFYm1jO210NHV2NC0jTCZSOUhYQnJJVjY2KzYqLTQzYC1r
d0hGJX17PmNTLVolQytGNg0Kel5zK1ZLUjlNOVl1MmxAUVlBWE9UTDJYU3BoRlhFNF9JSjV9RyU1
IU42JXQobHdaV19XLW11Y0NDRy0pJVlaWkUwDQp6SEc0IVoqIT19WU9aPjRkWElkbTJ2KCF2JGdk
K0kwRHN+I0pUNSE/fGowSGRMO1gkanlQMXRtYmYxWk9AQzIrcDQNCnpDdV4meEhUJFRkJCQ8Y3dS
ejEpODxaNiNzRi1LY2A4dzU0STd5LVVNbGB8TTxMQSl4em1aYnw+PHQtfjs0SThGJA0KelYmX3pB
ME1SKj5ea14zbzVIYUtkWDNmNH1zPWpCKSVnZjxLbWJyVyVefXVJI3kqK0pSYD91WlFQZFItRUdP
K1J7DQp6PDlyXjZWRXFYYipxI3RPQV82NGY3anVqakdsWkZXP3cwOFQqYjkka3Q0Ry17ezM1RmUp
SCpMYmt7dSs2RTxCVnkNCno/LXt3PDR9UHNBNng8dUYwJExTdjBxO0ZuMHMjP3Vpe0d2IXMjI2pI
aXE2PS0tZTFzMjwqIXxQRloreEs5JnY3fg0Kelh0PCRyZCRxa1lCWDN5KEx+PVVGVil6YGV1X3cm
MkVXenNGSC1LWSEwVH5iTmlWcCtqeEY4Xnl4PEVfWkhlc0RTDQp6SGtuaUZsMGhUJD1oM1FScElJ
YGV1eUkzLVRwSXBacjlWPUQ0c0Q0cTwxbTdPYXIwbn53cCU0dXA7d2c8REIxfCYNCnpQPm1hbGcy
cn00UkNFR3MhTE98fnhuOV5UWlUwNyNuRkYkb0Y3cWREKjxiJGB8RitOP19zRmVvXzZyWlBafnhw
Tg0KenlkZUo1eCZ0M2pgKUJgbzF9dldRd01RXiNwdS0zUTRWTndiT0J0PDdBRXx8Vjw0QjRXJClk
RXN0VGl1IWkqKWd9DQp6YmBUYlRJKyUkI1ZoIyVsLTlCbz4rciZFSDJaQFhzOT5ieSptdjc/MHtJ
IzRHQFFTS3BFZTl5fEM8K19Vcmg/eGQNCnp6JHhJYG95USkhMn13RX1kLT9TJlhCNVM4I3swMCVT
cFdOfHolO0RfRDZ9NklnM3hILWdVbkVUaVB9SkJSOD9hUQ0KejZreCt3OX10bFhLWnw5dHp7alo+
Izhyb0xld2xxZnU9MHAkNXxHMjFLajUyJWp8TUY1Zk82ZlZzQUtXOEZhZ3xVDQp6byUkKmQlVncl
LTtIV21wN3IwR20qaGtVaENmSnU/V2J5Nip7dX1wJXxBdjdZMXFtc0tyZDNTdyspMlpJTWNAUz0N
Cnp1MnhufnkhSF9HT3x2ODt1WDcpX1J9MS0jWSRXXj9rVXpqI0UrT1MyQTBpal9VfU9RT0NENClo
WFN1OGJ1WiVvaw0KemlXQWp4SGN+c0xMKDtpX2MlVDNGNWdSJD9ObmFkQTxWTUQ/MURBan03bylu
dSlGdW1aaHRBTTdgJGMhaEQ4QWhpDQp6ZjQ9OV5YKSlLa3xJdFRJSF82PiNZVXYlPytzZ0BWZVE7
VWM+RnZGRHxLTis5Q09JMzFtT1Q8KTc4bjAkPC1eWnwNCnpmU3xJJVByPE1QRlU3JFQ1JlFvJWFz
NHEoVHllYUdfSzxva3dnTT9AWWlPQFpBcmlydVdpZjA/WilCa14zJHxIfA0KejZPZkVZTncjR0ZL
LVJ+V242XmlCJDl8PX5IV1RlTytDd0tXUGkmY2tmXjYrPWslX3AzQ2ROND5sbTBjYlhiTktzDQp6
RUhVaFJ5Xykmb3k/ZnZIPyhARnkkR3p8U2UlYGxrK3w2IV8jYnRBdlJQKyRKfExWQjVaWENxaXI/
K01BKj44RjYNCnpmRGMzPDhRVGtVKHA2MVU/Zys8fjI1TUlTek85eGxmZjwlZk00I2p7QiNSZH4r
VGRQUWE/VD5BeFhmT0dlWkU1dg0KekhiR0BoKDA5I2xTQXt+ZGw7JCpXd1hMUWNVUEZSMy02I1hV
YjN0S05ObnhPRVAmTTVBSiRBM2V3T2E9VGRDUXxgDQp6JVNqMWYoVVNGKmNUQHQ5bUg7OGRraEMz
c1ozUXlLOyliNSpPJnQqSGhPeD8/WFh3aTdSckBMcUZ4Rz5EUzAzJGANCnpfWTFga2Z6NWhVKUR9
UyojIyZ6PkdKeHpTWiVjeCpvQ05HfVVaNFBzQm5yQH5IdT5VKSU5JHRzJWdXPTFqe1U/fg0Kej9q
TkJTVGx+WUE+QURhNENidXE/JUFJIWNja2N4SkA9NWpkJmghVShgcD5zWUpvNSY5Q1JSPUU1JjVQ
Q09aSnJwDQp6U045JVFHbjBBYTx5USM+WisoQUx2cDVYPjRUdCY8Q0xqcWhwYTR6MUNqVkhULX1E
SSpjX0pNRitKcl9sRChZc1QNCnpRTVlENjIhZVE3c1coVTlOdUkqeTJ5VHBHP2BIMmhZR3JqVFR8
PSU+ZGl2bmNtUzRGKW1ARkV8QVgtRXlmIWNVPA0Kem9JfncyWUcjbkxDQmJIZ0dOVTRvYFo/NmVw
Z3ROMkhyfDNwbz0hY2VhVll8NGJNKUFrRiY8a2VwYX41eVIyeFNqDQp6ayFzQ1MmRmZTPE8meTBT
dz5ubmV5P04/Znk/NXs+JExxO1lZZmJTT2g8RE9kenlBVWJqJG59KiR4Xn5QKXdsSSUNCnpiPyZD
WEF0IV57OWsqK2ojfC1BTHZIYz9VM3BqV2dyXm9UaUN8PGpTKlU+OyRMZnBvb0pfWlFAKk1lR08h
I01zOA0KemFCY2N8KU09aTtfQThpMTtMZjxVRz0/KD5OJjgyb21wb35sSF9uajZrYy14bHs7VCtX
Xk1fJHVxRFgtdzdINXgjDQp6UlNWTDs8cUlITXo8ej89bnxDfk4zJTwoTG91dkI0SzFCelNqXmli
X1hURHE9UHZFSnJhfiZkRG9BOXQ+S0NDNzYNCnpMJW9XPnc3R05EZnJ1KEY5WkgobXZNSyFtTW5f
WntOYGpMKHt3Kz56Y3ZIRCMkaVErc2J5RFQ/Wjc/cTQ/Mjl8SA0Kenc0JSNKMDZ+blc2PVgmNThh
XkFRY3p8QD9sPlFGO3J8YDswcDNQb0dORV9JJCZSdyVWb1pYZkM9ayhUJkIpUnc9DQp6RVQjMkBy
SWJ8cjBseXk1TC1TNmF4dzlSZCNfPVM0UXVeWVY+fj16Xz05TWIxJT5NYlR5aHJ+RilYNFUoJjA8
a1UNCnpMPzNvWD97K0pld1NtVjwheTtWYmhkPjV7eX09cDBieylmY3g5QFFeeWp6PllzbmtZcGNe
QStEP3hgfDV3ZGYtNQ0KekhmYURsYz48N3dzYkI9bzlraFUwbVJ1TCs/e1ZYIyRNNSNnbCozYE9B
Y3IoKW9gWn5JR354VUtsTFZZZWdjZD8+DQp6V25aV3ZZKCNkQ0lmWkxPUGUmSHFwXjs1MmU+IWhT
ZUkqYSV7TmdVWGt7VCk8ITJKc3JuYzxse3lOSnl7Oz5MRzgNCm4hOEQ5WjFCKFckWVNDQ0pqbGR3
OHs1WDZ7SWVHTitFNlJNdFVTKHF3JS1SMHttUzBXNA0KDQpkZWx0YSAxODIzNA0KemNtWnZFMnwh
Y0YqNl9famZhQyY2U09meD9nJj9iQ2FseTMmYVkze050YmtUcVNyUD58TTRnTSluJmVfSkQoeGZw
DQp6X0Vtem1PPTQtME49c3NFVH1uJnhUMH0qa3F+Qn1SWU09NS10SmIjMnYjblkrfEc3OFZ1a1U/
N2NJTTc8JlkzZjMNCnpYM21eQkdpaVN9Y1NqZGprSWg/eFZRVmJkQExta2RUWWQ4aEtLNVVLUTF8
JW4peHNyTTN8V1NpTDBMMVRoeVM/Kg0KenlEQmZrd21yMjMrZDk3dD4oUHs5VUQ3aF9ZSjM/Y1Vh
PHNRMHArejJ0YVhxI210aF43JH1zdW5HQXdDaDhDRyRxDQp6NDZ8LTVHd1d3P2NSWGVPV1JnQnhU
IXQrSkIwcWIqQT53ZnVXXkxxUGUrUHMkKEFXcHs3UjxXVmc3Ryg2dXItX0QNCnp5Vi0oJHcjfFpG
TWl3a2BpdmBQcEZkZ2I5eWE/cWZXZihzSSE/cj1BQHhUUTMkUGVxXlEtKiF9N0JIU3ZoT0xOJg0K
ej97PVVBQSFvSVpgSzl5QSFteXJ8KDFUZko3JmV9WlMpJUgoZWpLQnA7Nl9jJiR7Tk82cWNBTElS
VC04ODQwYzc5DQp6Vld+ailEQ0U2ZkZSenlBYDgrNXVEOG57RmRKfXtrcGtwWVl3e28rMUlUJUpD
O151TCQmIWQwaEQpbCpRJWRvZFYNCnpDWjlwKmdEQFRQIXwqSyFje0JscWRjYn1TekRmSCk/bU5u
YD1EJmRLVU1hJnFjKG57JCFuQmxJaFcjeE4hfWI2Uw0KemA5VEA+cGM2Ty1ac01PX2ZefihMVmR0
WnZPRkohP2UyKWRZLWV8JEhfZ2IpZDc3S1JCMnhZQzdDJEx2ckUhWjZoDQp6TyRSYHhkSkMza3V3
ZVpWPGJTYlhuKmd2RHpDRXY3dT1xRDJaPjZYNTxNZjM8ZX1XWGw+ZXJRRndaTGEyN3gtOFkNCnp5
dSRFb2Q7cD5ie183I1g/Sld6SSprLXsjaFZQb1VFIVotXkdvfD1NakQ1bnpCeXRSc0xKJmhwZjUo
RCNMSE8pbA0KejNzIWd0O05QPF8oKXslTT87KGI7MCZ0dFYwSChfbGZMKHZ6Zn57SnlncUhhIV89
bGs1Xm1NO2VKPkxPPz96Q1h8DQp6VkdIJlFnbjlAREQwPnlZWW1RaGooPW5oOUwzfHdHUEN5IWhf
KyNpYTFqe0Q/M29YRSg5REJycm1WZnRSK2hPakwNCnplMT9tRU0pb3ZDVTsmVTlAVWIze3dwYWpD
eylTbF9VSXhidHxNYn1UMzF3SWU0enFSIVJBTHc+Q1pyNlQ1Q3A/Rw0KejRWQ345Pzwhd3smNFcr
fl4qYlFIcldaczVGeGlsZzBmR3d2d2pKezZGbSY3Q3lNWHlaeEQwODNFQzZlVXdDTlJDDQp6M0ds
ckpaUVh6ezBPNmAxdzBCaD5mPyk9eFQ/fmYrNkNVRzdQQXRRWTBgT0dgY0xER1llM2BLY2ZWRWwo
T2ZecXUNCnoyeENUVUNMaGM4enp7P0UxUEpwV0dAcFRDS004WE0kYGlrXlVAT2pCdT5KaW9SbkEk
a3Q1Qzs+d0NRaDwyYmc3ag0KekFaMHk3Y0x5Sz0wMm1acjElIUVMO1JgKlVQNkxOeGAwc3lVOyhA
fGdrcVcob01pXiNsO2hQR0tmdGRBUEZFbCFODQp6MzY+TWslO2QzcHNRVlcxQztTOEVDRXl4QWZY
T2Y3VkhndSZJV1lLPmA8fUF9MW9FKEZoWSFQUzFPT2lOLXZIbjENCnpmRWRYcyF4QkxqPVloYmNG
RCtRVzF6Nit8T3FwRGFwOVUpcFY0JlJ8ejxBUUBITmFyJXZDbDMrTUAlcGpVcWtQcA0KektKVClI
ejdgTm09bENibWNsfT9gM3o/PmFncikwcXA5eH5xaT9yKmk8YTVmYSpDZVh6bFR6aXlXcUV+Nmlt
ZWw+DQp6SD5TI0d0eld5Z2R8ZyRkSS05OTQpWWV0NnVYOzlwYDMhWntBR3IpQjJOPD5HbjxgZzVV
OzE/RV5SdzVMU0ZGKTgNCnpaMyFWT19oa1ZAazZ+JUB4ejd+SD4kSSEyVGphWEJeMGl1ZDhyeFh1
YHFIV0xWcn1pM0AtNmJwXl8kbWkoJD5rVg0KenM7bEpkKV5Dem11ZEElbm1UJU41MEZzNTlVMDFp
aDR2T1Vxdmx3TFA0PFA1U3Q2WDFLcj4pIzFVems0JjZWNzNZDQp6dVZyfUJSPl5Aa3BnNFk9VCph
XnxUKVl2O21sTmZ5d0YpXjw1RWZ7KXdlcz5jKWtySlhmaVNjSDFCfXg8MTc/ZGINCnpZJD58fCsk
fj5uU2JfaUJ8OFAydns1aFAqPT5SPyo3TTdHWSNQP1ZLRHJpZ012Xyl+JFRYQD1iLXEyKmVkT20r
Qg0KeiMmMmsmSylZU2dNaFVkdjNlPUFUTHpxOFo2UENnRz08eG45Ql9+PVA8WnBNMDlpYSQ2cXth
UTQ4b0dJUV9YN00tDQp6bzUtS081V1hXIzlTK3M8V3pSeE03XkcleTd6MlJhe3pEeDlBYCF8Nkx4
OEpeV1F6RTBLekNPfVYpVzJNZmc+OCgNCnpSWkg7Jkpzb29VPmdZfj5Id1RENjVZVDVMejZ1KXBO
emxvNnkyU1YpXi1sdSZ7VmBFST9JWGVBR2g/X005dXlvdA0KekE5O18lKTFEST8/dkxLZztUJD1m
OCpgWDU9Nz5GPC0/WV5vJmg1RlRkRlBXTDg7KT5NK208NlY5eWU1QSEjZSUpDQp6NiZleGg9OCo5
fUR+a2ZJMjRKbyU8ZH1kcU9oanFJY0V6PHhYaVV3Kmt4O0hEbD1Jc1JBTSgpM0JMRCs2Qmt9aHgN
CnpjJHxgZV5RMiElSGEmQX1ITWR0eTl+PihpYCVYaz9RJGxLSD5+UVRCYEdgX18oYk1DVms1b3VX
RX5qV1IocStAUA0KeiM+Ul56QTVFWHVpNFQ8dE9jR2lxUHhHSlNAIzR7ZmY2YENPQllBQyQxYXly
Jmk2Zj84bTgkfDlrOWNkbGRyRj9ZDQp6TUwoM2dJb1dpTkI4REBDek0/NE5zVjUyTzN9dSpUPW1+
KlNAJThaej9HcG1KUD9ea2BPMjQzLSQoY3FVUzhuREYNCnpNR05SbWxeSnJNc1VgeTZlTzBackVl
UFBSY0QkPCY1P3NGSVIkTWhzcj88dEE2fUFabE9GTyMjKUl0SD43Qyh1bg0KejYkJDhYO3Y8RF4h
R2FFWkgmLTFqcHd6aHd4YGpJNzcrZWBVK3t4fGM4NzFmfS0hJCl2QUlMM0Q3KDJYUzJGa1ZlDQp6
PDspLTBgaiVhMm4wezw7RzthWmo7Ul5SaC1pUy09S0tiR2o0dzxtJl5rPHtzXmYmNSNkSlgxeTYx
aXB+ZyM7RGwNCnpCM2xtMWgofjQoJTJpYyp6VGxFeUBHVy0tKEB4dTBSVHI8P0c/R1QmPEdOUmN5
N0d7X3ZhKUN7dmR1PjNJVmVCWg0KemxsSSNVPjQte3lGTFVxPHpsJSFlRG5jXzQ8eU93N0QpcjxT
ZnpCQGsxR0NWQF93MWBmbSZ7WS1CVzB4X2M2Z0VvDQp6R3ROaUxQTiRqNTkwZHAlaVhGeDxENn1t
PSMpVC1nKzd3e2YlOWIqSzN5fj1qR1VsaH49OFVuTnJ8R1ZZdXFsT3oNCnpPakkkMk1XYGleTn03
LWBneyF7bld2RFBARz5lZXA4SSkwcyVuTU9GJmxJe1ZEaz0wfVVfS0EoPjhHO0I+bFkoMw0Kejs5
SmIzYFl6Sm5SPkk4ND8+P2xnLW8yREJII0dFTk1reWp+XiM7PGxKSWxffl90JnNjK0hYSSFeOSlE
a045ZzdVDQp6bjlDNUE2dH53WV54K1JPSEh1JilQcXJwWCszdDA2YVNASzJtbXAmeVFzI0B1TGBp
MTg1RXdSJkwlNjwhTyFWUisNCnp3dTNDYzE0fmhsOUNIQjhHJUtGSCpUaWo8VzlEVlpfQUZ7MUEp
UDdPNCkzdCpySEJ7IThPcz9zTUxEdUlhVTlRfg0Kell0Skx3M2N6e1dgbzgkOE1jbWFQPkZOOzZP
PTdEPi1mV1ZtbzgkbVl1Ni1MflchbF42Tit6cFpgfVEwRzlYMnMwDQp6cTVfIyMqe3hNOTZTaGla
dTBuSVpAcSRTKVE1S358Uk4kSjNLdEpmREo4NitfKi1aRHZPSyFaQHBgJlhqcmZebyQNCnpgek9a
b1MwUGcoLTkxc3hGR0ItNWByNT9GO1ZXVENMaDw9UCg1X2xVbyZMUktpb2RPelBNZnFeNTN0I3pv
eTh7RQ0KenV6P1dkczZvY25zQyo2VDxRP1E+VERgP3otbUNrUGxpUFFtTn5qfFAha2Vqe0V7a35C
QkMoV0RqO3RpcFk1PT5XDQp6ITtqKT97QlFXWEJmZExZZWxsZiZjYGI3Q1hTOzNuSiFmMzRgI3Bq
Q280UCRvWVQxPk53TnZtUSE3YT9ycEY2cGcNCnotempxRD1ncXlnOGphWk1od3I9WXwxPW9mZmM+
UVVFezsyZyZvUERvJnVqNGxBYikhdXZoKHc8V3VXeHFKclUyUQ0KelYkbkdhPDxsPGIteWFfVCpk
dG80U2RWVmFwcjR6cCh0RVJZdjNgYFNIPTtUbDdhZnp9cFNvJWg4RjN3dGFAeSo8DQp6aj1NMDY0
VE1qWXUxWmNKeHE4YjZtfVlOQlpYQHdDQDNoUW47cTFMSik2THpFXntjKiVuTW5HNTtfKld9WFFh
OXwNCnpBZDAqNF5jaGBMMF9qSjFWcks0fjVsZntpUEMwKEZndElKZTB0V2pXen15QFdyVSZUTFhG
VTk7NHlCUiElbGl7cw0KeiFreUM3JkV7e3JFSXJRZndDM2gtS1JQRDd1KSFIfDxOT0pediRQc1NG
JFQ9SnI8eiomSGMkfmFkTXQ5UHdBI2E2DQp6c2YoUkowd2NeQ05USWtwWiFJfXljMD0zSiZ4Vl5N
SjNFRHh2ZyRYQl5xQmVOakcjWF9mY0I0P0ByNi0lNVVAWmgNCnp0NF5PR2AraFRBWWBBRDZCWXJz
TF9gVzZCd0Bsdm51K01TOTJHQXE/cnp5V0pgfU5MTCNva1pEQHVORnNWJSlNPA0KekNMKyg9RSh3
cX1Wd2Z8UFVPRlhPJigpS3VGfmheKC1ZZVJiZm11fUZNRnNkK2RwbEIkQUtOUG4jOU1hQ2AxcmxP
DQp6YCM1K2tkRkQ0Zj5pcWRsJkBPY1VMNyV4NkNoTko2Xk5xRjB1QDA4Py16aSZ0diZwc2xnaX5h
fFBOPzFuTH04O0oNCnpjRiVheD1KZm1JbCV3Zmc/YU98bntNfExTNnp4NDh0dkBRK3wxOE59Y3t6
YWN0TDtDQWhkQS1BXyZmdU1aXjcyeg0KenJZY0wkYG41PCh3KWk9QEQtJmQ0Y1FZPDFoT2hNOHUw
ZWc4O1ZhX2RFMFY5S1BsdVReSWVOVWc0KjkwUWFTSWlRDQp6c0p1TGVYMSZMY2E3I2I/WUk7Yl4x
flRGWDk+UHdKPlhHOGwyMXs0dEI0XiVIeElTYmdAOUNvd0FreUB0JW5Sd1INCnotKVY+Xk1+aD9q
T155IUt6VXs/aCs8N14lIT9EQUZXOVI0TUw3dSMpSmI2I3NeUHQoaFlpcDVqc0B9WGM3YCF+PA0K
enkmI1hAVS1veTdfYE5waF9zTVVjbHA1RWUtQSFiRzBmc3VGZ154PztmVGhmMyRDTyFCYyQ3NnNQ
cVNzME4xUEdZDQp6K3IhLXZIPnxkQXlaWGdGQ3dmWnUzOEFnaFlJfHdURzckajk+O29xODtLOTtX
YjFyJnVadHN1WVBMY0xDQDlqVVcNCnojUVA2TW89eyhsTVo9ZVJ1M2l4amhVYjZaJjdDOWhqYDtt
MCF1dlAjTSRgKHQ7ND8lS2lUXkowTUBuMTBKaktOfA0KelpsWD1vUXVOJDh8TTIjQTU3ZVBjbXpf
Wi0qJEwtRDZGJkJ5cSVxMSVNY2dFPF8wNnE0RnVuSTQ8cUFDQm4wPDQ7DQp6QEgjO3N7NGYqcmZq
dkJOeEw/eEtiSGBuKGR1TXY2RiRvbG95O0tNTnZvP25UNnd8KnomPDZ1R3NNKzB2JDZmdEYNCnpL
QTVMRC0hRkZTPmU3VmlfakA5S3srYGxAQ3p7SGVFek50fCF5SSpeQjBVWSRYbXxnIyhheUsrQGVi
UFIyUjVMcQ0KemdSWXhiQEhrSjw3RWoqWCFNdlJHRD9LR3d7eCFuYWtrJl5BdVhyUitHckZHe1NF
NWNYbllme3cyZlIzekFVd3UlDQp6I18lQVQ1KjY0Kl5UJTExPjd0aVZCQUlQNyhwZGBXIV8oQ3FM
fD5kOUJVbEFrcmdgLTVQX1VYLSUhcnN1QW9GNkINCnpgOUVMVjwwfnJ1aG9jaWxJcz9Dais1TWYm
eEJxQ0RlK2MjTXE0dWZASCZpZyUjYUEpKEVXS2V5YzElNFk2WEtjOA0KenBzSU4hQSR+QUg0ZTd4
dXZ3RHIheFB8X0ZNaGEmT2VTMWJpOzh0ezBeQTRWQkJXVUB8JSY7bFFqYEl0YlI1c1B2DQp6Vis1
dGdJbT9CJVQzUj1BSm0mQGF1UU1rfndhNmFHKkNpKTh3eFFCI3Y3S0R3TzhXOWw4UnRkJT8jIWBN
d2otO1INCnpGSzcyN1h2JHZvSXlFbFZyYm9AcXsybUwoWTdzKnJFfjJYVCEpfEVQZih8fXQ3Y3kz
aVYrJnBRV1JpYXdUM0g9eg0Kekd0aD03IT1AVVU5ZEQjK1MxJCkra09JaTZVOFchS1hsQ2xsYTJ6
KCpnOT1sMkN6czdMeGVVYGhIcz5KZWI1RCt1DQp6Nzl1PktPdzZWVlFXKX11JGtqbXFfR0RKWDU+
ISFUbiRwbyY+UC0hOWV4cW0zNGxtbipvU2Q8bzhoUy1lQ2hUaEUNCnpKTHVQUGtefH5kSHhLdkEq
aDJUXiNPcSV8eDVwdlpjSTQyYTBYO0kwWEx1YGJNRTI/aWxDPjZgcThZbiZDOTRBKw0KejFSOCt4
YHVifmtPMEU1Q2p0LVglMjdTeCFJemNgYUlyYythOEZGNm8tVkdnRFUyRCFqcjBtO2tIRTNeKGVf
dj5pDQp6PnMkQklEJVZiQTJFaG42anModXtHSTB0YDs7VVdgeTtAVnZHMTMzZmpPRmhGeHpUcXVR
I2J9WEdncW5JZzc4NG8NCnpiKmdGP0JacH0/VWNeZGJxRTlaPDRyKXhaKmAlMzclWjFMc0x7fCFt
KnZFSUxoT0p5UCVTTkt+PF9SRD1ZSkxoeA0KeiR9VSgzR3l1PlltOyY8WlV4VVliXjMhX3huNX1f
Nm1PQ01BM0NnVDhaODxuNjF7M1dud3FiX244Pz0hJFhWeTNsDQp6S198X2NpWjRPaT9wZTB0VTtg
REUoZCVjV2dTQjl0bF5YR1g9Ui1vQU8tflFibmwjeWY/QypiU0p0KiRWbEd9QjANCnpqU1hIJEVw
bSZfTUtzO1RYUztTSWtMZDVQPUJ7M0c5U3l6ST9AclpzSVcoWXtUczhGNWRGdGZGWGU4dkB1QkFQ
Zw0KelNNfVhrbk5QR2dLUVI4Y2Q4ZllkMHNUZ3ZsMmMyJkA+MGpHZilPPjlvI2pJfVZ9fSFAX293
R2lwN0lOcyFkUjIrDQp6c3g5WHolY0N7NWJsQntLRVhGdC1gc1JaVCFLaSNDWTlCKTtqSXI3QDAy
bmpBMm9eSlVneF4wPjk8RSMqcW50ZjsNCnphUTE/TUB5SiRCdWJyTGp6bFdJXyN3UGxXKj1wZy1x
aVc5aDNWbjhWZD5tdFUjanNXcUh3aFAhMnx3ZDhLK3hFWA0KelZCPUUhZyR8aCRIRi1PJTJ6fmx7
SjxUUkQ5JSRYd0txO2NoQCtpQTI4JUY4RSlWfTFTKGR8TURoZkk4R3EmeWFJDQp6VEAtUkVxUlkr
bl5LK0UzRnBpMzcwUjEhRSg8Mkg3UE5BZFVuND92I0x7MyphblY4fnNPQFA3P1BPODBwWjJGciQN
Cno1eSQzc2hUeUFSRyszOzMhclk3cmoxKHVObnxkTT1hbDAkVj41X3ZvYkd6Y24jOE56bjtkbXVs
RDxsJm0/SHE9Rw0Kenl1al5CMWpJZGFxb2w4KjxaLSl8NSUmYWtEZHI1cyt1cjhXTjlIT3hmMkEr
WFJmZXJZcitlTUYwZCY7S0MlQkMjDQp6O01mSTxCWTIpNz9sdDdiWiU+WCVoR1ZKSTY9dXdhd2oj
O0kkKWohMjMrTCVMSDJ1TjZSNShSbG5eKCl4KFolQCoNCnprbHZDJW8zb2V4R3swO2ZHZ2ZOejJO
bkYqWm0jaCFzQTlJdihBWSU8WV5QPk5SfEZXJVg2VE5kRVJVbS1tS2pYVg0KeiVfZ2ZVcGl8JXpm
U0U+PCQ0K0dTP29WQ1V3RGp9eSE+NSZAK1hSZTQjPmtzalY2cEd+KVNuViUlUGRxdWNLPWRiDQp6
aHxBaGBlUEhNQm83fkQzVD12NENiUENBQ0xaPjFRJFlxJTZfdmdSRnJfc09eST1mJmsqd088I1Yz
dVprVWYoQGYNCnpGOHdXeUReT3NXdioqSTx7aUdtMFdDfUN0JjBvOGstKmpDdjRiYiQlZnxkTCE9
byhHMFRDaVU0VDdeZ3trRnRtQw0KelpDTjxiZntLY2ZHaVcrS15UOyVBPz1zOWI0c0EkNjxyYjhZ
ZzNORmw7Xy0xbCs0bkh3ZElYdkxEZXokcTJEfDl2DQp6QlU4OUBRWlQmTFglRTQxKGBIdGZqZkkk
TDRYWH1maHNoKWJ6I2VUbCM/ZUpqZCQ4eGl0T3I0ejAkZGI+PDhlMloNCnomUWZwWj1nIzNufExq
JStuSkRqTyMwQiUoSFhiPC1UKD43NVhqe3k4dFU/RHhlR1I4TGU9YikpISN+Tz9gOWEhTw0KekRl
NW9UQ2RzZH53SVYjcV5xWFo3NUhTNV8rZWRwQmhVPHFRd1Z5ZnJuT19IMXV8dWFJe3wxd1hPI3pD
P0x8MU07DQp6Mkg4PldAZ1E+eEdIdVN5cEFLY1A4I3IxSktHanxAZU0yRzJVejkmOXphaFZ9UXZm
MnZNZnJGUHVIQ0B6NzY5OUwNCno1Ozt5eiYwIVkxP00+dHFWb2hKPyZjfT9QRlpFSFQ3UnlFYDJo
bWNEVHp7UCt7IWM7bWE8UmRNKGB7ZzJURHtjIw0KeklAOTcmcTRqTnFaWX0lYSNsVVdVez5EeEwy
cktxdGdTS1kwIUtnblB7Ny02Z2UpZld9aioySy1QVjJ0Q1FATjgkDQp6VWljQTJPQ35aUzVPTXQw
ZT9ra3NeKWQoOVRUJncmcDZZI2lKT3pKbHBvUU1gYmdafSo7cnpfY0hAOTx+UnhmeUMNCnolSVBD
ZHcrYXpFbW5hdDspMFAleWhTWj56UH1xYzwlXkl0diRGXyN2U0N8eTlMck90anZESTVqMntRJGBY
P30mWA0KemRVOH5Cc2RUYyYlQVIrWEV9TTxNVVp+O04+RXQyPj1LI0grTkU3QERCR3NvbDRzXlQ/
ZHx0RURgLTtaTi0kRUAoDQp6JkNPdyNyPG1KZD13OT0kNzdeOWxtRFBUdngqdmMqNEdiMmtyR0xo
WTlxI3RHeStUSjdDeTQlcE9WMk5rI19nISUNCnpaTSpRYmh9UFNIUzZpJFN8MGY9M2BVQXk/XkVN
czVOQ2xoOCV0Yk96Rn0td0E1LTVOamleZyRZcCR7I1pxaGdsNg0Kel9RN0V6OUtkc31oUCpCXll9
THhecWxmd1hoaXxgKCV3PUA9R3ExK0hnWWFsbUFfJEcpKHIyMmJKTmFNd2M+ZXNFDQp6MkB6IzUp
dkxETXFwQnZgXlJDKn1hWDl6bW52OFpqV2JzQCp0NnNpNGUxKjV8a3RQQHdnJj9gb05+JEZ9JH1U
N08NCnpmfTh1NW95KlhmQSV0KCs/Kzt6RXNOKm0rZmsoczF6dnFQNVMmPkVZYCowa048fkVxUD9e
NSZVO2pJOH5tIyg2dQ0KeilqTXhTJiNlZzxKfF5rdngmeVhxY2M3OHdHfTZzLXh9Z2w9eXl4dVc7
PnlSTmtFZCRkKj5SPl90Kj1zbmhKKz00DQp6O1FHK3pPVVZTUGxRQSskXj8zRlI7R2tNJFM/VEdV
LXBNLTh0WVBrI3JsYV8/RUM+Wkw+fiUxfi0xYmAxX0RzPWgNCnpiVnkwOGZFREFIYllAQSh0WGdD
LVJgOEEmXklCIVArUW5WRjdaMitzenNDRFNze1pAb3hzJWxHTSgxMERMdVl3Yg0Kej5tNWpfYCo+
RXZvZzdwMSVBPSFsQDJBZ3txPWxfUzFyOVBIV3soUzZ5akY/O2FeTjcxbSooKDBrZ2JnX0VYQGpQ
DQp6PioxdmRwfWdIVl5lSztTRXx1fXJwWVo3U04pX290Q3dQNHRDLTN5WkB7e2BsMjY8O1plIVRC
diRLWE5gPmxwYGANCno9cCQ7JVNTMnkmRHl0PX5RcmNVcGtoQzJFYStoeG96Qk5kV2Q5cjxqYDU+
SzltTE8kJUhneCF+byViMG1pSE4xJg0KeiF5MmhCZHRSYkcjT29IRzwjcjBSN3JaND9gTH56UTd0
Ni0tKUNZTz0/X348a3lMOVo1ODJ2I2N5Vyk5bll+dX1mDQp6S2BPeEMjSEVybGA7VzJLaFdmMztZ
KnJWUTx+VzRSb3lhTXwrOzghRlBQbE9IYWY+dFhNY2FGKktjejNhPjQ3SzcNCnp0VjxLIzcyPEtq
PExUSThvYT5XNiQ7RiU2bktmPTJSVzZFZ2FJfTV9cUB9Kitqa3gmOypHSDRlWXEkJndte1pNTg0K
eit4dmAkOTZlbilLMHd6RnFsXy0oYS1pRXpiZ3k1aitNVFBhenAtWXBHVXZrZGQ7Y29fO15CeURQ
Zkl3ZFVmTXA8DQp6c29pakZgbjZUYWFSaitPTTVpV1JkfWBNI2BFaSEqMmlGfTdQYTEhM3J0KnRO
d0ApQylyXnhtWkc5TntuPEgmZG4NCnpjfnRyVipDKmliK2pIP2JRZF5VJlR9eD48KnxscSZsPl8h
S3l5aE0+UVczNUI4IzIxa0tzV01LP2p8Y1E8eUw7RA0Kel96WTFzRzBNdSpNUSY3RklkdHR+Rysw
XkJAUWg2PSQyeGhBJms/PT16Zkx9YnNvJiVrOUJ9a1BSe0k5ZWUzQ0ptDQp6XzhiNzBeOHpaI1lU
Pjl+PWl5dkVvfTRPayZjZn1wZjx9OS1sVE4pfGowU2xeVjtgRk9sUVRIVDkqaTRLTlJEXkYNCnpP
eHppcllDTUlecl9zKTYpIXR+aTt8JSZKSXtHWFJwS0FJYHM/WG5NPn1TcWEwcWxWK2NLRk9XZTUm
SXRHVSt7YA0KeiVuYHpQNClwUFNjSyFIPCQ5emBMPzdeLT5zTSp3MHZNU0tZNFlHNTZ0dlVNT2pD
MUZzUkBLMVkoSUFlRXl1fX4+DQp6Mn5MSGN2XiU9QTNmUkpNRnBqUlZQUUohNE8hRlF4cEYoKSgt
ZDR+TEEtYnVXRFNTWik8fldUOCZaQ2M3QzNZTW0NCnooe2ZtekBJVldINGpmZzBeSHYjfHJlJF9K
K1praldmRWkzQ2hPeCQ/YDVlbHU5JUMjPHJuMXBsMUhDZHVqOzRKcw0KelArVTBSTEcpK1VGWD1V
V0NzJTB2MHd0ZklMX3dKJSsrZE5rZj9CdzxHYzxAbk9KdmEpfE1CbmRZVlVZKWU0KzNQDQp6cjww
ZCk0JmxNMXN3ayg2YVh5aSVgOTNoZFp4fVVMMX1wQGdaejIyLXYkJDN0WDB2Iy1xOH13QkBlYChT
YUE4eDINCno7fnorR2B4NG4jaStsWXNTVGhXJHk0blktaXdiZ19MJDxHd0o3d31Jc2VTZTJmczUk
YzBKP252az5nKmMjIXM/dg0KemNQVTVLUDRjWEpuUlRlPCtVa3A1THBpeEZ5TCRabTQhZS1RfDVD
em5TO0V4RmdzdEpgJkImKD5xb05aIXsxYytXDQp6ViRPV2o4ZStWfTQ3SlFSKT1VUyVzM2E0TSpw
QT5nQGdVPlpocSlVPEk2Kl5DQHRTdHE2YH1Zdj9OZEJEdUNBMlYNCnpIamhXdypHJnZqJiptKWBI
b2ZHbCVqM30+Kk51eEcoKG5jcTV8MUt2eCR5Z0woWEZZeiR7Z1BRKT18Sz1Dd2E5MA0Kek1sKC00
aUFWMy1JOEVMKmlDMjMlejRxKCReSTc1XnJNVDEyc1RpLSM7R0dxQSEqJEJnMVJua0MjX2NAeWNw
Z25gDQp6cyktdj9LI0x7IXpoU0FXNn0qeTVVKGMhYys3JjglbnApMUl5Xztzb3pRKSlpQiE1OUJ6
aVJHdjlgMjRFLWIpS0ANCnptemhDYEsxYFF5anRwSk5vTnl4SG1gJnZeeikhPlFYfG4wMiYzVDtI
PXorfkMhWWdRQzYya3FqZVM+SExUQiFVZA0KenhfdVN4bHlaQj1WeDFoazNGcEZQTGtoMig1MUJQ
Pmt2enYwTH5sbH47elJQJEdIbyFBNGt4fD1Wc3s3eVQhPSl9DQp6JndSUlZoQDEweXZ1dTlPWSE/
fS1ubUA7bypPUVpUPVZXe2slVTBWQlhLfD5aQkRBNCZMTGw1SWAzLSV+d2RVTCoNCnpMeVotU1JL
cTMteGhRX19oeUswfWVDTmE/aW44ZWdeP3daO003Qz9sYnFPaGtrbWcmSWsmVFQxTGlCPHlGO1FG
Sw0KemtpfT5VKkxUUkFmfUZgYXM2YXAxVk8+VnJ4SjlPKGs0ek57ODI1bXcqenJBeiFNbCF3QlRN
Y3BzYVRLPDYmY3FODQp6P2JgQ1JAJis8N0glPnNLZVV+b1UteChES0V+aDE3azAtZUMyQkleIWp0
ezx4NnR8RygyYjJOckxlYVhkUTU9I3MNCnpaQj1zYD09WmohJmY5YGFFa0ZlKCpOO0dOYk98UEhH
ezE/RzhvKytfc1MmND9tcikydT9tKlhncSNAQz1mU3N9ZQ0Kej5jQzZRYCs2ZHgwX19KSC1gU185
bFYzPWtSKVlLQ1FLVHgyJTFaPkFqYmdeeV9NfXF5NlQ9VlhrUWBZPFpUa2tpDQp6WUUwPUczU3Qx
bzFLcF8+K2ZSc298QWxEZnBFTHJnUVpnaiZ2JThrdXhAajI+ciZBM3syVz47I3BBcjRpdyF7ISUN
CnpJRmkqbD9Baj0jS2k7LUxARk8jSTY2eFI8O3t0d1VSIT8+fWp+MmZlP3RlWHk+RUFyTUBJfjNv
VDRaU0FtcWJiJg0KeiFeazd0bXZJfClVRnFAIS1NVVU2PkV0JWYjM0h0YlkjPnAyQS1YK2ZeYipE
UyNlPzE2ZCp2ZWBkaXhqbT40UHVFDQp6Z1kzP3xzMkQjMmNQS3dhVG5xKmkrYiVvX1c/MntiLW9L
N0B5b19BSSRZWk5OZjYzKj5jVkEqJHhkWCQ5akA+UTsNCnojM3xlQkxQcFRZNkYrQEM3VmNQTlNO
ek5rXnpyU0pXO1k7YiRgNi1VeUJkJT9ePTh3cGZmM3xNeVZBZSpfUC1HeA0KekhASDY1bTshNCo0
RSgqPHh4RSo/NSY2SGBNdiE5ISpefEY8cnU/Jkg9YFNUSXpxbSNhSnlIS2FaXlNaSyZrbXtEDQp6
MlFzRXFafXZ3PDFTVWVWU29IP1BOPndYI0VAQ2hOZGRVPTR6T241X0dzTyVGUm9WSlojWnBNJVYr
VTA+Sm4tclENCnplJEpaPngmRiEyK35rdSNOc1lJV3NhK1EtQm9wRnJXK0dEbCQtMWJOVFJVOEBC
TzdvVDFxeXYyMUBAeCkzKEh+cQ0KemJtRE9HSWUoMEhGMkx8MHIjJUE0MGNBe3UyKj9rcnRWfj5L
KXJfRT42fHReNmg+VSsxa0R9JSMkeEw9VWxCe35TDQp6WClDeFlvYyt3bm9VJnVVb2tnO0BMSXBe
Nil0aU1LVippPmtqQCMoeXlFPlVhIV5+NncwfHl+NGd6d352c3duZXENCnopTj01MDZ4Z2xfYWE4
PktqLUw9NWVPSXJDK0xJTVJkd2RzRCZ8ek8pYCUjNl44U2lqRz91MnZBaENXSGUxMVU1Qw0KejB4
UHRMT1JHMFErVktrX0tAI0J4KCohSXMyVX4yeitMJH00Z0JwNCk4THFiIWIkdXVYbGxTc0lCalhp
ZXk/UUt4DQp6ejBIM1dII2dzanNEOU0wKzRpV1Y9PDIwKEQwaSMmN0l4amFkTGtWaHgzSikkIzk2
c189TUFudiNqRiFjNXZqNz0NCnp6S3NscVUrJXVZT0h1TXFMNTF9WjwpMS1YeUBwKnFCPntNZ0JF
c1RfXkJnSXQ9Yis+dSN+cldGYio2Kyg/ZX44bg0KeipATj43bWFVQUg7SEB3UVBKNWlHSzhBNXxH
OyVSMnt4Qj5xPXpoKHtpckg4cjU2MHZfSyE5MmNDLVpPT3o0WkduDQp6TUtDUm5EeDdtT1BGNj1V
OyQqWj9qTD48WTVpc0VOVUMqQXIkNWpaYWNxZEMhUHUwe0JqNmVeSzNVb349QmhiIUsNCnpmdiVs
OSRjWV94JEc8bEs0RGBGI3U4U1NNcGxINipiTituJSNmKnJjZCR0cmY3N1FrYmRIZ2ZuQHd1MTJm
YnlPeg0KemwxdSZtK3RVV3d7PXxqLTdxZnVqPnltRm9ee2JnYSZFZnhkcDgle1NMemNDZHcpZFc5
LXVie1chU3lTPDl6Q3YwDQp6e1o4RVFRSyZLQGd7eGM1Tzt7OT1AR0s8d0l1IUA2MVElKXslM05T
RFUxMDZpJEJIIUxGfE1sK09gU3BVNDFKZG0NCnotT3lGYkpOMi05QCNsPiVCWWdic20qSXYyd2wl
UF8zX3BXZyZ+T3o4KXlkcVVMSU13QFcqSGMyVV9IdmFIc3lUQg0KeiFfI3RsQ1koJjs9MlQkVWVu
V08hejRjdn1pJHBoWFFvLWooQFdoQ05xNm9jKyNNNFY2TWZsaSgpZCpqOXNlPV5PDQp6NEJTT21P
X0VDe21AU148U1M4SlNYKlp7a2Umd1psemszTU8wV0U1ckZ9VjwjaWVjT3EzWStlQ15KNEl9UkJr
OFYNCnpMXnwmT1ZSbn5laVV1Xkl5I0RiJkoyfkpjSEhBPXQoPSFUYmVkQ2xzNXt5MjNLX2NXX2pr
JSlWOFNVVSV2KE5EVw0KeihaTUBxKz1xeHgqKlB8QTFpOWF5KDgoUGQmdmpaS1dqc1B8dER6SU5m
M0RyUyNwczJuNVQ8JGYwJD4xLSEqTiluDQp6dXY8aFYoPVlDZnA4RkhSX2VARTRGMnlwZi1wc3JW
dSRHO2Q3X1NUZEBiKD1QNkY/PXM+ZHduXz1PdyVJKHk3JlQNCnpnTHozI0RATDh9eW9NMnwtUVNz
U3BpVmB+UEdzaU0tfFNTIWEwdHtISy1HLWNQc2RRRlZyKiYxeT42OXpUP09uQQ0Kel8+PVRGUXdz
TU5MX2NHYT5seWIlRUxDRiVlbHFoP0d4TnB8dXNnM09aTzhkOXwwPXJUJCghIUYhdH5PZXh9KFE2
DQp6QjxncVAmNDQ/cWczUTxQbjRqQDd2TEpuPUFmeHZxYl8+JEA1a0B7PzxgRmg3MGVoa0FOOTBz
WktlcGgpdG18MUwNCnpEIUViPlZYdXMhRCZfWkxjNGdnMiY3WU5vVSEzbUhpLT09Pzh3ZXk2MHp3
bClUbml3SyFOaEhVIVc9fXthTl4oPg0KelJPT2deSmhDISp1eVRCRVd2c0d0eH5FZEQ1RUlIdWx9
a3ZSST9UPSg0ZmQ7WnN6eVN7R24/bVVTJFVXTSQ5aU0yDQp6VUshUktoNHFmWGRjKDJhUF4/I2le
QGQ9KkwwR1F7PmtZKWZSUEZWe2RVPT8+bWppY1l2QlQyYFZ+M1JvP2xhTG4NCnpDYzRXK3pjSkFm
Q09XYEclfWxoMWk1aSl4bVdoQCFRNWg0SkdFcDhBPCo+JUE7d2VVS082ODZzREtXVnNCcypMYQ0K
ek5fX1FpfExfMEomdU5oRjNpbGJqUj1wfGF5WDlRYys3dkAoYGVBaWA5N0M0NHdsPUtwPGlweTho
UGdCK01MR0peDQp6Sz5nNTVTKGB7TUpPY3JyRj1hS3VPflNOZnhsKGdnRE0/VFRDV0ghZlMpMmxa
LVVFU00mPjl+REBoQCVyUzkmSSsNCnpOOzlpb2BlVldSPlFwYzNiOFQzVGxDZUNMbTI1MyZme2ZB
MSMjfGZzYVVKeFNDSGhBbFdpPlFZMz9BcnBzPExyWg0KendjRnA8VGtUOStfRGFBMlQ2a0U3bHFo
RWo3QU5lJDZhQlVSeHdHUSZSfnRkPko4KmE8SXg5WFNqMk5SR1c1fD02DQp6Q292TU1RPylrfTRC
QClVYzJIYzdhRHBNSFlLSnxBclE0NDhtKlFMaWhnYDBYezY5VSllUDVyV1dJK0V2OVVgcU8NCnoz
P3pke1J5TzlvX2E/eVVTLXs3PV5Oa3MpQik4PiprUXVsTlF2SlhTM0FAdEIjMSUkZ3VoZSpgSmNw
ayVpeWwrSw0KekV6RmJTdiZaP3FGQnpYZ2xpNElkPWRObFBtRCZiWTA1UmRZO35MbGVEfTkwKFB+
QHszNyFkdFJ3cnhmTXw0Rm5mDQp6eyE2cVN1c1pHVXp4a2h7LVMlJXk3JGNrRmNxPGNFRnxqaGZ5
XiFzRVcpPEAkQih2JXI7RERoJGhBPjdqen4pR3oNCnpJTUxYPW5DVj5jRHIxaXhhOHpUcmVmd0Jz
VjtfJW0xWXNQKlFjb088TT5Re0lnalQkMkVXfEw0bGA3LW9jPihmWg0Kej1mJGVyN085Q19SKENZ
QlU3MX5SeWtsdXI4UCNnKUZ0cnBYbEM4Uj4lSDZ0fXRmQCtRYFkjYTRAQSNQTjxlOClODQp6Z25e
WDZlZmNoNCt3YjFLMUotYHxzUk5FXjs7SjFFYF9SfUZJTVIoQ2NEWFE1cGhRYEBobUNpJHZCQF9h
Sk94e3ENCnpTPCVqdkQhV0ZSKCNUa2hzd09EU3RuIV5QeDgzcDRGfiQoWnMmPDNrKlJ4Nm5GfUtw
aiMmJE03entZUX1hVF47Uw0KeldNaFZ7K3skO15feilYKzshXmwzRHxmTlhZLUB5SmBJeTJkOGxf
Q0BfVn1pUXQ1JFN+M3AqR1ErRjQkeGMkVEMxDQp6bSM1VjBTN2VDYHZ6Ukppa2Y5T31ZfnNyeUg0
QCpuIVllLVNXJEgjKXZfVGZsOXNseCplKTBLIXJyZ2NxSTJqekQNCno9ZnhPSHVxVTJ7TE9mYWh6
SVFvYTVsNV5RJkpZJUNsXj9jdGFzYjdkVm8tMVlALUFtJkhnPXRKXn0xZCZJR2J+VQ0KemJOPjc8
cDRyPyFqeDRMRVo/ayhndVY2N2pwSXkkTTthQD1mMzkpU31penNGZzBaKCFQOzh7IypBRSNoM2l4
fm9WDQp6QH5eRGQjdTZFRjs8a2QzemBuT1ZYJEU8UjZfV08zMTIhK20rT3BZZChoUXIjRnopKXto
aGw/UWE9ejc9WlZgKjsNCno8KXFJTHBZSmVVP08rfV9VSHdzUGMjZE5AQVRlQ3czfTJDX1hLI2pQ
dCY4T184YEZRMVUlZXRYRVM0fFhhcS1vNg0KemQqJUhNYiQ2PWEpTFNReGJhTGI7bUBNP1BaOVQo
cVVhRjdieWZqfSZeVHpqYTctc1hISUNEaCpDK01MeVV0WnZODQp6XjNzYEZqWE4qbj5wem9IdVZ6
VlFqKmBrNkJ7Z0FgKVdqZUQ0NkklQ3JITW80T31maCZ6TjtDQG9CYUVDSFlwK2gNCnppUSNIK3lr
WVF9NypEVFFldWNeRUt7bFJlViVAekdVbXFNd2c2UmdRcnt8WWJjVW1+a2xxZktnc2hZNm5lR0wk
aw0Kenk7OFl9TDhFI0Akd1koUCFsZHpORCM8YHFOeXNYKHk0ZnFnI0ZRfnF0RTk1aWUrYjUxNmBG
R1Y1NGt3MiFsdCNkDQp6Km17Z2JoVjV1e25UZyFpNi02b3tCYzh9cmY4TlExR3JvRjFocU1NYylD
OHNlKz9HSWUhU2tYVEtpZkZNb0NzenwNCnpwZ1VSYnVHU1pINmomVGRMe1R5ayk3MHJWKVd7SnpW
e3A2bVhTbVR4QStEdG9CY0RDTXlwa28pLUNJV25SJHFMfA0KeitBaSlmJC04I2ItRmhBekxHcjhI
SzRsO0ZmdT4zZzc/MlZSTTE3c3xxWVh7bFREcVkqT0x5I1cmJTUlMm9uVFZeDQp6QCkrKHtSamVZ
N2tnSjtRUWJFJms8SmFJYFdsWDktcyN1VjItSzcyZjQ+KUNQTWpEWj5XWi1hS1F8bntNJXdtQ0EN
CnpOQFZLdSlzS35obHJWKmp0SXpzWG5PLW08SitzKnYlMEtpaGVqbmheYSF2SUU7fFdGd0ZCMEA7
Oz9ac1F5JkArYg0KempSJHRNSGMpdiQ7SVpgN040I3d4ZDV1cEhyZztFdU9EQ01DPEpDdks+U0pE
THQwaWpPSj9fdnVqflQ7LStSYXs8DQp6Szh8cEpwNGlPezhqUj5KblhJKms5YVJfPk9VayU8TW8m
fHotUEUmIT1IXzNoWFo9QXIxVlgwcTBhKSFJRW5LTUgNCno7NUQtfW4odGUkJUsmPEN5K0wtVmBI
SG5LMXV9THh7bUJJR3dGV3EpVmVESEN0TUFFUkhPTGgzK3d7S3lLYWdNcg0KejJIeS1ScH54VWVS
ayV7aFQrSGN8VD1nUl8kJjBfN1hrKyY8RHRYN1lBSz45MCEmYzE+PXJgYks7KXdFMDB7NkBpDQp6
ejtoQylBbWFeVzwoN2lIZn47Y2VYRU92RTZAam5IanNKWGw1PV5HdCZtUWRrZlV9JHJJSCg8ZlZn
QUx4NEU2JjkNCno0UF9aZ000Pz9YVjtIckhmRGtDUVY/M3RqQGVxdzhHVUF3cWhNXiVjcDRxI31O
Jn0wVSNNRGZXZn02XkFKYH4kNA0KelU7WSFgVzM0eT93NChNb0A5VnNRdT4+ZWFteDZIVTw7MEp8
aGVDV2w+ZDJCbVp6VGg8aWE9ZyZBbER3cSFTVz1BDQp6NCFDJldibV8hQjlwZHdPVnZyciE5Vj5q
TWh0P3FUN0ZhclkpSHl6QjwpaWoyZEFfd21DQHZPO2p0SGZzUHkrTWENCnpWM0hVWGJHbCUmSEd2
YCo4KzdzJlVVfWlETW1OWVQxcyE3anlxdSEzI0h0MzNvRzVHKj1lI1g4dmBQJjE4ZipKeg0KemdO
YjckPG4xJmwkcmJtRmc8ZGdlJkswZjM5T2xzXl5ZK3R2Y2U3YlJTbGN6dDlwZDIqZEdsKnhAY0lJ
YHorfCZkDQp6elVQZnZvIXFBJSRaRXNCP1EoKmRWSEdQND8+O0FBWUBOcSRaZHdDOGRgJV5KPDA7
K35CZks8JmcjKCV4R2ZCPmENCno+RW1UKyFaPFYzTyE1PE57NlZVWW1yPW4+SHhRQkBMSlVvdWBD
ck52eXYkdFFna3Mqckkkam9aOCRkdlVBVD1LIw0Kek5DNS1+aFJAZHcxSGVuSiktYn1HdG9RSUhM
OTB4QVNMOG9EbDZ6VjB3Y2hhaUljSTIkUGtUQW44MF9jN1JBe1ZrDQp6NTIwIWR1KFI1SktgczlW
WngzZFhmRF9iVXhDMn5MPU9xOGo8fmVERk84aUghaV9lOFp0NUF9d2xLOSVqcWxhZEENCno8O1Yz
X04rcEY3WVBDVk84KzdaNERpbUBmc3wrYk9MMEB9UlZVWTh6R2ZaUE5zWiRqV0liZXJmRnxibEpT
O1ZiRA0KelJ+VFdOS3BiVHglM2p+TlF9QEhkWCp1OXU5Y0plKGtpbkozQ2l8PWZOMlVyKVZYVjZW
PWU4ZWNJYyk5WGBgMilsDQp6di1BdTRMWXJqJUh2K2YpLWdQYDMxYTNKelpkO3UwRz4hfDBLN2Z9
S0xyMSY8OTtVayMyKzZ9PERFIWRkYXlTV3kNCnpeUi1XNDs0S0lwX2hOWGBmem9PTFIyX24pNDZt
eTJYZj1+RUY7NzMqJTYtZSpTY0d0P0RadXFLb2M4QVJFJTA5eg0KejcmRGJVYzxVUUVTal5PSkV9
WCRfODNnRS1yNU1QQ3NQUSpXQnZgTWZgN09CcW04NGooczJ0MzBZWVh8KHg5MEt0DQp6QElDOz8y
UFFKPTAqP2JOSWFyTEQ+TXkodWpvT1JCc1I0U1M/WUxJflI1R0U2SiNkPyhrZ2BvODlGcXdKMnJt
aXMNCnpOai1ZMHo7dEkmPkpLJT5ZQGg3e0p6ZTglayZmSEs5Vit3VUZzYW07I2V0Y3swaj8+OzBC
Z2cjKlojITtqVjlabA0KeiNmQ0lxYispJXtmPiVBcytjcCpDKWkmUjJ4P2BLbERDO1RxRE5iRDIy
R3s0JllLVmtkSklJMzduazFKYGFXVmh2DQp6VEt1I2dXeys7eWF3bkl3YSY7K2V6TVdqeWFAJiU8
JDtVbCMmMWRhNmBURmNaNSRFSV5QbVlNVngra1pZcnhCI2MNCnotel5mcigoVzxJX3FMPkwrcUc4
fj9ZNVIlenYlSXR5P2clcm92JUk/KitxQ2xhYD5TMihmODNJJTtFQ1Nmam9lQA0Kek1MfjhedW1O
NShjRjZVSGB7SkUlaDdtUUEkdjE8MipNSEwpPTklWUozPnYocGhTPzVvNkgwP284VjtyNVFXX3Ft
DQp6O2x0RllHPTkzb1NpMzlVRkBwZjdlbTxvTSgyNjxtaj5qPCpAQCpqOzBpM2FGPzMjY3hIcGkx
aDRESyVTKCp8PykNCnpJTD5uNVVMPVJHREc4SXc0IWArPCl8ZkZaWEJ3SSFGLTAhbmpKd08jWVBA
OTxUbSl0UyphTXhzcCV+ODVZaylEMw0Kek81bmtEWWJBcWdyU3t8fj8xWkgyTDswfkVVbCUxTGI5
Sz5TRSlDSm5GJmp+T2hvcEkqLTB+eDYmNFVrSllUfkc/DQp6PWFsQF5rRkh6LUZ1K3lzVHIxV2tq
Q0lXLXhfTnJ7K09WWU1jPVV+aCpiZDN7Zm45NV97c2hGcytuJDg2KG5he1cNCnpAYHlSVmRoTlhy
JjlqTkshUFpqXnkoNnI8c3ZPKClGUEtBa1dWX29iamRufEE5Jll2XmNnbyQ3VUdeM3lzVDZ9VA0K
elg+c28yV0dXPzdCdWI/O051ZUhMMjdpKGZvR3pXKjBWJVk2bVFOfDk3UUg0e0E8MHlUT2BWQ3xg
PiE4Nz5zJWh+DQp6VU0/JE1tfGR9TyU5ZStqWXNJOzFDRGRCIVJaX2tTY0ZZekhLSzkzO2QhNV5V
ZUNVN1BCZmp7X2tBZj9IUSNrbiYNCnppJFo7aVpOUD9ZVT88VklzNVhIWVo/ZmlXTmA5dW80X0N8
fj80TGB6eGtFbzxqd0pNNWJmRD5YK2d4VXhfMkIrPA0KemlMMT55aGtLSFlkblAqMSt8fWR8OzRk
fFd1fihHKyQ5OzJSOXM+KDZFT0AyflphPE83UHBIVHpEKlM/ZjxnUW98DQp6Wih1eHZvZFM8YlQr
azJpViomNm4pX2ZuOT40UEwybHF6Ni1EZWN4YkF2cj9gempyN2c7NXRlRk9fITtQWjdOTWoNCnpq
Zj84fGY7I282QnI0R0tZQTUzenkmXk97bGJpK3p3eUJKTnNMJDlmRnkoYkgyZV8kcW95P04kN00l
NHJuRm4yQg0KemF5R3RQWG9fI1E2JkJ1TWYyPmxUUDFzS3MhN3F0b2FFKzJzZX47RDBNPWUkRUEq
cXYoJk0yRGBYKH5QcCRvTjw1DQp6dnI+eEJhJS08ezhpfGtiQEdHNDB2Qng7ejBrKzQtOWg2WTxW
PVc1UHF8dil0KF81bn5IRDItLTZicFJ3SyFYKSENCno1TjBWc2hHU0hxe0UrRVp3SSZ3VXVxbUZz
XmtgfkBXWjM5RWFRUV4wMGA1TTVaKFRIS0Q0ZyVIRGZRPzckOTNyKw0KelIxcDdBZW1EMGwmIWo4
cGchPXRrTEcwYXB4UWshRmh8cml0bT9HSnFKO1Y7bkBeVyVFPjJgYnVaKygxNkYxU1AhDQp6O3I7
MyNGd0dPLT1wWiZNQnI8ekBsO2FCZk51UHhLOzU3UUstU212cEVlMkFlKWAoTDxaZzxXRmojS0tG
QnNzNzUNCnpHK2dBSWt+KWp8aVFKfiNneWV0QjtiNFFPQTRSKyhEd0V1MEM9MmFIZH1vcDB5Xk9T
dy1AKyVqZiRqKVBTTnBkdg0KenJeTEBMO1h7JF4xUyQzRiF4T24zP2UwcGs1MX5KJXFFYSZNdWpk
O3YzP04hP3MjNHFeMXg1WENBTnI/MGJVaHkqDQp6RD8wPGNmT2hEMzdqQy0mK3MoeXNTXnUoXzhT
bFY3eSRCRVBgbmg1TUJYPjktI0x5MEpaYC01WXtTVnhXYEEhTW4NCnpkRkJEa1JjOF9OXzZudkUy
UjtIOXZrcTdfSk1gTmw8SV9aJUBTT21FI3c0elhUNX05QkU+SjwjMXZ9VVN5RkVxRQ0Kej8zPyEw
Mlg8RCNCWXQ+JXklTjZCPk9EWmlYTi1jMlhxTm1qTEc/YyM7V0dha29UdiRXeWdrSlpgYGpqVzcy
fV93DQp6UkhRfnFTZCt4Pj9CZXomVjZIO3V7T0x8QHhFMTNHbE1NM1ptKFN8cnFTPnRySFl+PHBL
Y0Z2UzJINV9MMW14dCoNCnpsTlYoWDx3PVllaWMmUyZ0dDtSViVBX2tCQXkhcnpDcyF5PHp1Smwh
M3shWHZiQ29nKjM5Y0VSTno4Yj97NDNQMw0Kekp2bjhWbj1nK3peUlEoOUwtbk9jZlZhcXAjfkp+
Ryt0OS0/NmB2YVF1cWNeZEpfJndnVThvc2dkeHY1WGVJTnwmDQp6ISQlO0lpT2xYYihRNk9vWG48
b3MofmphcmpLVCl2IT9lUjVEdUU9a1pPJHVSIzNhPlVLNFJxMzQjQDszem13YmMNCno2X0MoZ2Rj
PGZ4Xz5tUHs5VlhoSVZZcyttIVlyQz1yQ3xScUttJXBPKEU/VyUoUklBYnd3TzM1dm4/ZVlPOSlm
eQ0KeiNoNHJUejtuZDQ8cGZ6QmVyJjxMUkwyVjlfQTxnOE9Ca09lYzEwYWJHRkF8LT1MeT9IIWR5
PD1ZclYxaVYpVXszDQp6N1U4TC1XKnk7cmZeY1l3Zmh5dSFIZ1VVPipjRXFnQ2ZvdCQ1WFpKemo8
WkFDJCN0d0VqNE8kQz00I21Xc2JAOTcNCno2Pn4/KVA4PnhJaz5OIzlvMiMwaUFFMno5Jno2XkNu
JC1qQCRjPmpiIX1VTil2dnRCZERjdDQ/JSgjWWw1bklrLQ0KentUe3w5Rm1Qcjd0IXFVbnFCWCNf
bU4yZyk5UDVkSjRGcyVjUzFuej5Dby1zeCpzemdzWSQ5eCVpRUJsNDxEVFJ3DQp6TTQwWV40RnVO
N1d+UVB+YT1WVzNibCFwNVErdHh9JDI2T0U4IUtxPHA0P1F6WFEoe3BiXz0xWUNvKEZLOE9qZ3IN
CnozZH0jQ3RRPDMxcmBidyh6N25QMU4rYExRU1NkK25VZyMmbnckNi0pP0Y5blBSI3Roe0NAaVZt
cCpmRXR0X3Z2VA0Kej92fHY0RDRrT29pcUdERWhXVXxNcmFQWERGSnZgZ0NsMyFLPDVnNWVERFdG
UWVBS3lMMkEzI05ATl5gO0FwS1lhDQp6NmZPYSQ9K0hneVcjUXY7e2IrXllwNFlhRzgyWilnY285
Wmg0KFlaI0ZiflEyLUpfUzx6SUJfaWx+fkFDXjAzQGwNCnpLJVpITHomP3s/bX5KNn4kTmwkMnlD
U2x+b3U/aX15Yno5dXlIN29nPW5xUUIkOH01bVpRRWcyUUxoSmA9VFl1eA0KelQwNXhSZVNOJTY5
flRIZWslJiljcFVNbXIhRnxYaFQoRT4oIW1DeX14cDFDOVZeKilNdnAlZWEzcU4+OW0mPERwDQp6
R1YyTTtPYEN5JFU5fUp4Z35VeTdrJiRyd25aflRpMHhSenFGRF4/SG56c19CRHRqUWFBVWU2KVUl
VT9YaTBWIWANCnoxNSZQN2VhN3gqYSojd1Y5SjFeTTBqMn1eQzAxWnY2aEdvI3pAWVdfdDNRWikm
V1lXKnlyVihUSyplZl9jNClMUQ0Kej9aM1FhezJvPiZmT2VCYnF3THE2JUNCMX5fPSNTb0B9YHJV
azxJSnNuc0RtYDhFODFQM0pgOFpHWSRiS1B2fmtPDQp6cms/UEtmfUhSUzJYXktZcGRqX3xvRT07
Uj5gem4lYmBiNiR0b2RgPXklM213RUVIeENCMVEqK2pGMCp3Xil4JT0NCno/VDFfRmNhRmlSYGAt
T0F3YEwzP15Jfmp0P2tIWCZHOCYwXyt9ejZBTTUoZThFK2wrSXNlcmM8JlNtPTMwSi1jbQ0Kekpl
U3pYPkw2K3ZRdmhRTm11PVFmPjl3MlNPQGc1OXN5RCtRLVFHJCN7KkY4JCp4Kn15YyMoZkY8SSlL
XnRoVnY7DQp6XkFvLXImeWBuVGwmel9DQURMd0tCdkRPJCpXTj5pVU0yJXl5cGBQLWVFRT80eUhO
UTU5bCRkdEdMY2IxQntqak8NCnpoRThUeyY8aUdHZVFePUQ5PWd0PGs8PHQ+YnhnPzw0QD5Tb2Ey
MjZyM1hBMDkqa2cqaiE0fUQoSCUpT1pfQFFqfQ0KengxTXE4SktxMDhGbVJOaEshcyglRzwrR0Mq
fHZoU0JGRH5KdjI1RHZPWTchdEFYUWNEcDYjXml5JnB3YW1peG0hDQp6d1hlandiaHcrfUUtQCtX
JHRKXyVFOzJ6e3tDUGFeUy19QGxWY2h3O0dkaWpXQm1MNTRDV0IhVUlYaGghOFFKMUANCnpjP3Z3
e0BncjQqWlY1QnROTDUtVl5Mcktfa0w/KmxYSklBaiN3fSpyVjBIJGw2Jmp1RVlnRXNje0hmSmx8
SkNZeg0KejlWR31SMXduUX0yOygjOGtXPmlwNCRFJWNpV1BUaXM/TytvenhKe31mXzNTTW1LIzAw
O0pOOzx4e3YwUHMpcWs8DQp6PT9TKGFVJXtVbStRVC1hfDNDZH1KbyNzZTJZVnUtWkBXK2FUPU1a
U0x6S0RIaDckKzs3QXhaNSZ5TmViYDlSakINCnpYYXxvKm0oZD57Uld5LV98NFd0KDxCfi1mQmVg
QSZ5T0VocWdsMEVrKyhrSEdYNm54KSNVOGt7RHxWflc/VylMdw0KekdPe3U8d3tqMHZuU00kJUkj
VzZBI2lTSEJIeFY2aHV7Ri1nI2JXd1Q/aSpZNUdHWCMjSksxeXo3ZG92NWxsbS1VDQp6V0Yqe188
TlJLQCkjbXJWV3FnSVA+bUktTSF9K0ZnMEdNO24+KlY7XkllaGxqcHgqak1tQGV3dXlUI2J3QnVE
R2ENCnomQlFmfHV6cG8jSEI+ZDVJTUB7bHl0aVNsZHJydkJYNXZgZ3BjSHJnZ31EQ3s9cHdnTig4
Vn1GI0QqKCE4RG1edQ0KejRFQkpqUjRuKnZJKnRlNyZrZzJjbz8tITx2dG05UyQlVlZGSWFoc2RJ
UiNCKkckRyhEU0N0UE5TWGdFTD1zR1JRDQp6NiVAUytuXj93NExfMXJ4QFhrNE1VKEF6VkJnSjJk
QnpROUZUZVI/OyFeUz84R2BffntqV3VzVGhhVDR7XzdXTFMNCnpCZEV3IyQoWEhDMXtIXyo/dDc2
bDUwdndmSmVob3Z5cyQ5cnZPMCY8cHE4TF5VSkxnZmk9YVNSa09odm53Un0tdA0KcjAkK2smMyRF
aX5hRlp4ZzUta0N1SlhzY1YoOE92SmQpUCh9aHJSd0Q5MzMrZmZTTGFYO2g0KnENCg0KZGlmZiAt
LWdpdCBhL2FyM2svcmFtcHNfMHgzMTAxMDAwMF80MC5kZnUgYi9hcjNrL3JhbXBzXzB4MzEwMTAw
MDBfNDAuZGZ1IGluZGV4IDFkYTM2MzFmZjI3ODMyNjRiY2U2ZDczN2Y3YzUzOTM3M2M3NWY5Zjgu
LmVmM2Q3OWRjZTc1Nzc1MWI0NzUwNzA3NGQ5ZWY5ZGExYjBhZDM1ZWQgMTAwNjQ0IEdJVCBiaW5h
cnkgcGF0Y2ggZGVsdGEgMTI4MSB6Y21YWmNaJTcrPTd6Z21AJXN0Tj9DZmN5WSZBS0ZZO01SWWtZ
ZSFrN3cyZDFNaXR8TWdVdH0mVmVQSyYkSjZBP3UNCnp4Rk5rMCgkJEdDRWIpYmVJUCR7THRhaFcp
IWg5aSVGQzJ7JGlnZG9uTD90aU10PXNHZiF4eXJ+LW9FKXxjaWlXbQ0Kej1sNlQ9Y1gjPmFjTTEx
YnlOKiVvJEsrdTkrI3QycCEwLVFre0A4PV8jc0F4Z3FHcj94WEBBcXElcSNRO3prSz1oDQp6X09Z
U1k/QT01eTh0UDJEV3s7Xjt0UnxRMV54bDQpKDVCOzt3UmNaLWVLYSNiOCglfnlOKmVqSmMycyhj
Rio7ZkwNCnpNVzNmSkVrdFhTWnhiNCh1MWA8YWtKSX0/V0sobDhPUVpCKWFXVmRAX0xrTGJSPm1p
OHtFJGZKMnQxXmYkbUg1eQ0KekFgZj4hRk9OVlVGVHFCeHkrR3ZXNCVvfml1IVduQHpLP3JnaCFn
Tkl1Zm42O2d4KiV9ZmhSWnQranRlV3ZwK18zDQp6bnhuOWpsTkxeQXhNXzswbnxva3s2RU1tX2Ml
SUx9VWo3RE47dGhDfWdXblFlPE5YVW4qWkRGVztQMm9ke3tlMDgNCnpnRTc3Zmh4dCE5JF9JV1g4
c2sxViZkMVIqITNUOyZOJCFJd3pGVn0ycnVZaHlja3RGfW88PyshfEFQMVY7OFVXOQ0KemQ8RCso
R0BScWYtLXphVTlXSFBmSENlVmBqeCV0WDlre3xfUk9aPSZZbipgdmMzX2RpeGF0e09hRmE4eiMx
N29EDQp6SVElPSZIZTBhRjhBJFRBQTUkVFYoM0QhfWtxK247SH1yYElIY0JWLU9DNDtNQ2ZGaTlh
R3hZI05JcnB3I1NmMjQNCnowSmgzbWN0UiMmbzI8aWoyP1M4MVN0VTl4WEF5U0ZCcz9SQihBaDJo
RmR7I3xzMDQkVTNPTlVScjVgbnk8UF9Taw0KeiRfO287ZXVDR2ZBSDQmVEt8Q203KVl4TGRtfUtD
dklCLTxMczJMTHJqIU9ua2ghWjQ+a2Btczd4ZXlDWk5kfjZIDQp6ZiVsYTZsQEZEKCR+b257YXpV
OUA9OUo2STY9aHp6cll0Q24kfEtxO0p5WCU5U2UwOXFSSTtWcVIrZzAkYm4oNGANCno4JWNga14k
aldOM2liOSlRUig9WFRBQmBHcDhUZDQmS2UoKCtueko+alFAc2xBPzxONTcrQ0QjdFRMeHV1R3FT
dw0Kejs9RlFBU3VoK0U5WXRnQlFnezVPPnJHOUktKkZ3YDBHOXVjQHBhZVUmckk1TVk8d2RBY35R
MEc2bUg+aFVzVDw0DQp6UVU7Y054JDNySy1fb2gwVCgjX0lNamhRT1NIPHMoRVFRTDdJQHgjWFhz
S00pTUFvM1BoV0w+RndsKStgPjtDPFkNCnozKlJpNGxZMkUrdndQTzxxWS0rMlM3RTJSTXxPTlds
X1JVc2QyanI9OTtpPH1zKkh6YDkjdXcpSH1hcnQxVF5vSA0KR0M7dEk1aSt6dikNCg0KZGVsdGEg
NzkxDQp6Y21YWlpQZUBjajkwJX48PzdyezF1OXt8Qm5ZZ3NVZn0haTVFS3M2YTQtejNBSSZ8Mj9n
OWlefm5uRTIhdG9JN2oNCnpoentFOEFrdHhqcGVXNlpBUD9ldDVFTk0/Qj5FIX05dDVTLW1oZDND
SSg/dHBKbDx6IXpRMzhyVzJRSEVENjNqKA0KenU4M3lxaDNxdks5cj9SSHBVdUFPZTxzcjU9fEVV
KiRrPHJFeWZiIXA5fWlVREp0UEdwQTtvb0clTX1xcmRSJnohDQp6WiZuVj41Mj5ocU87cl55Rz5t
bzFrRkthUmlXMHg3PEkyM3s5KkhEWmo0QTA/VlZNQHxeRjZtY3AkaENwNioyfCYNCnpNSXJfc1Fa
TUZjeGteZWxkO3hBbUpAdW9JWCNwQiY1ciR8R2khXzhuUiokMkJoRWMrIzUtcyE7VWVPeC1xLVJq
Vg0KellBc3I1OVpvYTNmS3F4OSpYYnBeSHJaWHFGQihORDdkNGBoSFgrUVU4TGpqeGhHe0RUJXNX
dVZAaCFCYFBLP2xRDQp6dFd5aFJ0b0VSZEtFUFFmazhxcHo7fCthKzRMWFEmUi1mVnFqb309Vj1l
U2QzaW9DPW1DbHpXfGhFYylNVGVRPm4NCno3XlVPKk8oIyZuTztjIzYoLUBfKmkxVDAqKDUhdyRn
IWwwWUNqRSp5e1NIbCs1YUdRcCFee18xTVYjWGBYcXJVQw0KekV3VHhkWnV0O3JteDZZU1pRX15g
YHgjRSkxODtsTXsoQHBOUSZ6UT1BQFhOQz9WN2d3Xz0pWWJOb34jV2Y+TFFXDQp6d2VgWX5gYyZG
Mik/OUwqSE9HeztSQEBSeHJSOW1PY3d+KzxNPzxXUExUOSQ4U0ZGQ0gmZGt3bl9rXyslRUhAQHEN
Cno7X357TWdGJkFUMjZiWThMTWZmZFBoPXs7MzxgZjxZcXc0dU5WdHhTWEMyTzIrRFNqcjlzaUU9
QH5BfVlaPVMldQ0KWXJrTlpMeTszYEsoMjB6VVpxSXhgPHQ7NHkxQ0QjIU5Ce3I7DQoNCi0tDQox
LjcuOS41DQoNCg==
^ permalink raw reply
* [PATCH] adaptername: Fix passing negative error code to strerror
From: Szymon Janc @ 2012-12-03 14:03 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
This also make error reporting code compliant with convention used.
---
plugins/adaptername.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/plugins/adaptername.c b/plugins/adaptername.c
index 018e6f0..179152f 100644
--- a/plugins/adaptername.c
+++ b/plugins/adaptername.c
@@ -288,9 +288,9 @@ static int adaptername_init(void)
inot_fd = inotify_init();
if (inot_fd < 0) {
- int err = errno;
+ int err = -errno;
error("Failed to setup inotify: %s (%d)", strerror(-err), -err);
- return -err;
+ return err;
}
mask = IN_CLOSE_WRITE;
@@ -301,11 +301,11 @@ static int adaptername_init(void)
watch_d = inotify_add_watch(inot_fd, MACHINE_INFO_DIR, mask);
if (watch_d < 0) {
- int err = errno;
+ int err = -errno;
error("Failed to setup watch for '%s': %s (%d)",
MACHINE_INFO_DIR, strerror(-err), -err);
close(inot_fd);
- return -err;
+ return err;
}
data = g_new(struct inotify_data, 1);
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH] adaptername: Fix passing negative error code to strerror
From: Johan Hedberg @ 2012-12-03 14:17 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1354543409-21258-1-git-send-email-szymon.janc@tieto.com>
Hi Szymon,
On Mon, Dec 03, 2012, Szymon Janc wrote:
> This also make error reporting code compliant with convention used.
> ---
> plugins/adaptername.c | 8 ++++----
> 1 file changed, 4 insertions(+), 4 deletions(-)
Applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH] Update patch and syscfg files for QCA9564.
From: Ben Hutchings @ 2012-12-03 14:47 UTC (permalink / raw)
To: Peng Chen; +Cc: linux-bluetooth, Chen, Kris
In-Reply-To: <1352697850-27915-1-git-send-email-pengchen@qca.qualcomm.com>
[-- Attachment #1: Type: text/plain, Size: 439 bytes --]
On Mon, 2012-11-12 at 13:24 +0800, Peng Chen wrote:
> Signed-off-by: Peng Chen <pengchen@qca.qualcomm.com>
> ---
> ar3k/AthrBT_0x31010000.dfu | Bin 38916 -> 40652 bytes
> ar3k/ramps_0x31010000_40.dfu | Bin 1434 -> 1926 bytes
> 2 files changed, 0 insertions(+), 0 deletions(-)
[...]
Applied; sorry for the delay.
Ben.
--
Ben Hutchings
Always try to do things in chronological order;
it's less confusing that way.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]
^ permalink raw reply
* [PATCH BlueZ 1/3] input: Remove leftover defines
From: Claudio Takahasi @ 2012-12-03 16:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
---
profiles/input/device.c | 8 --------
1 file changed, 8 deletions(-)
diff --git a/profiles/input/device.c b/profiles/input/device.c
index 8464062..c2db6d1 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -55,14 +55,6 @@
#include "sdp-client.h"
-#define INPUT_DEVICE_INTERFACE "org.bluez.Input"
-
-#define BUF_SIZE 16
-
-#define UPDOWN_ENABLED 1
-
-#define FI_FLAG_CONNECTED 1
-
struct pending_connect {
struct btd_profile *profile;
btd_profile_cb cb;
--
1.7.11.7
^ permalink raw reply related
* [PATCH BlueZ 2/3] input: Remove unneeded headers include
From: Claudio Takahasi @ 2012-12-03 16:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1354552880-31864-1-git-send-email-claudio.takahasi@openbossa.org>
---
profiles/input/device.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/profiles/input/device.c b/profiles/input/device.c
index c2db6d1..1a33337 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -30,23 +30,21 @@
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
+#include <sys/ioctl.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hidp.h>
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
#include <gdbus.h>
#include "log.h"
-#include "uinput.h"
#include "../src/adapter.h"
#include "../src/device.h"
#include "../src/profile.h"
#include "../src/storage.h"
-#include "../src/manager.h"
#include "../src/dbus-common.h"
#include "device.h"
--
1.7.11.7
^ permalink raw reply related
* [PATCH BlueZ 3/3] input: Remove leftover fields in input struct
From: Claudio Takahasi @ 2012-12-03 16:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1354552880-31864-1-git-send-email-claudio.takahasi@openbossa.org>
---
profiles/input/device.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/profiles/input/device.c b/profiles/input/device.c
index 1a33337..d713ebe 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -60,7 +60,6 @@ struct pending_connect {
struct input_device {
struct btd_device *device;
- DBusConnection *conn;
struct pending_connect *pending;
char *path;
char *uuid;
@@ -74,7 +73,6 @@ struct input_device {
guint sec_watch;
int timeout;
struct hidp_connadd_req *req;
- struct input_device *idev;
guint dc_id;
gboolean disable_sdp;
char *name;
--
1.7.11.7
^ permalink raw reply related
* Re: [PATCH] Bluetooth: Fix possible deadlock in SCO code
From: Gustavo Padovan @ 2012-12-03 17:40 UTC (permalink / raw)
To: Chan-yeol Park; +Cc: linux-bluetooth
In-Reply-To: <50B62135.7080507@gmail.com>
Hi Chan-yeol,
* Chan-yeol Park <chanyeol.park@gmail.com> [2012-11-28 23:35:33 +0900]:
> Hi Gustavo
>
> If we use the below patch, we face crash or circular locking
> dependency detected.
> *It's very easily reproduced(about 100%)
>
> I guess once sco_sock_shutdown() is called,"sk" would be destructed.
> but due to response from remote side,
> sco_disconn_cfm(),sco_conn_del() would be called in order.
> and finally in sco_conn_del() crash or circular locking dependency
> is happened.
> because it access "sk" that is already destructed.
>
> I think in sco_chan_del(), based on conn info, the relation between
> sk and conn should be cleaned
> like the original code before you commit.
>
> [ 104.889622] Bluetooth: [sco_sock_shutdown] sock e8856000, sk eb695000
> [ 104.894666] Bluetooth: [sco_sock_clear_timer] sock eb695000 state 1
> [ 104.900869] Bluetooth: [__sco_sock_close] sk eb695000 state 1
> socket e8856000
> [ 104.907976] Bluetooth: [sco_sock_set_timer] sock eb695000 state 8
> timeout 400
> [ 104.915106] Bluetooth: [sco_sock_release] sock e8856000, sk eb695000
> [ 104.921439] Bluetooth: [sco_sock_clear_timer] sock eb695000 state 8
> [ 104.927875] Bluetooth: [__sco_sock_close] sk eb695000 state 8
> socket e8856000
> [ 104.938762] Bluetooth: [sco_chan_del] sk eb695000, conn ed38da60, err 104
> [ 104.956861] Bluetooth: [sco_sock_kill] sk eb695000 state 9
> [ 104.962321] Bluetooth: [sco_sock_destruct] sk eb695000
> [ 105.071125] Bluetooth: [sco_disconn_cfm] hcon ed376000 reason 22
> [ 105.075875] Bluetooth: [sco_conn_del] hcon ed376000 conn
> ed38da60, err 103
> [ 105.082848] Bluetooth: [sco_conn_del] before bh_lock_sock () sk eb695000
>
> Could you give me your opinion?
The patch is now reverted. I pushed it to bluetooth-next.
Gustavo
^ permalink raw reply
* Re: [PATCH BlueZ 1/3] input: Remove leftover defines
From: Johan Hedberg @ 2012-12-03 19:42 UTC (permalink / raw)
To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <1354552880-31864-1-git-send-email-claudio.takahasi@openbossa.org>
Hi Claudio,
On Mon, Dec 03, 2012, Claudio Takahasi wrote:
> ---
> profiles/input/device.c | 8 --------
> 1 file changed, 8 deletions(-)
All three patches have been applied. Thanks.
Johan
^ permalink raw reply
* [PATCH BlueZ] test: Add a HFP HF endpoint to simple-endpoint
From: Vinicius Costa Gomes @ 2012-12-03 23:42 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Vinicius Costa Gomes
---
test/simple-endpoint | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/test/simple-endpoint b/test/simple-endpoint
index 20c8159..79e38c7 100755
--- a/test/simple-endpoint
+++ b/test/simple-endpoint
@@ -11,6 +11,7 @@ import gobject
A2DP_SOURCE_UUID = "0000110A-0000-1000-8000-00805F9B34FB"
A2DP_SINK_UUID = "0000110B-0000-1000-8000-00805F9B34FB"
HFP_AG_UUID = "0000111F-0000-1000-8000-00805F9B34FB"
+HFP_HF_UUID = "0000111E-0000-1000-8000-00805F9B34FB"
HSP_AG_UUID = "00001112-0000-1000-8000-00805F9B34FB"
SBC_CODEC = dbus.Byte(0x00)
@@ -38,6 +39,8 @@ MP3_CONFIGURATION = dbus.Array([dbus.Byte(0x21), dbus.Byte(0x02), dbus.Byte(0x00
PCM_CODEC = dbus.Byte(0x00)
PCM_CONFIGURATION = dbus.Array([], signature="ay")
+CVSD_CODEC = dbus.Byte(0x01)
+
class Rejected(dbus.DBusException):
_dbus_error_name = "org.bluez.Error.Rejected"
@@ -120,6 +123,11 @@ if __name__ == '__main__':
"Codec" : PCM_CODEC,
"Capabilities" : PCM_CONFIGURATION })
endpoint.default_configuration(dbus.Array([]))
+ if sys.argv[2] == "hfphf":
+ properties = dbus.Dictionary({ "UUID" : HFP_HF_UUID,
+ "Codec" : CVSD_CODEC,
+ "Capabilities" : PCM_CONFIGURATION })
+ endpoint.default_configuration(dbus.Array([]))
print(properties)
--
1.8.0.1
^ permalink raw reply related
* Re: [PATCH BlueZ] test: Add a HFP HF endpoint to simple-endpoint
From: Johan Hedberg @ 2012-12-04 5:56 UTC (permalink / raw)
To: Vinicius Costa Gomes; +Cc: linux-bluetooth
In-Reply-To: <1354578148-9089-1-git-send-email-vinicius.gomes@openbossa.org>
Hi Vinicius,
On Mon, Dec 03, 2012, Vinicius Costa Gomes wrote:
> ---
> test/simple-endpoint | 8 ++++++++
> 1 file changed, 8 insertions(+)
Applied. Thanks.
Johan
^ permalink raw reply
* Re: [RFC V3 01/12] doc: Update settings-storage.txt
From: Johan Hedberg @ 2012-12-04 8:18 UTC (permalink / raw)
To: Frédéric Danis; +Cc: linux-bluetooth
In-Reply-To: <1354286826-24016-1-git-send-email-frederic.danis@linux.intel.com>
Hi Frederic,
On Fri, Nov 30, 2012, Frédéric Danis wrote:
> Add missing Master key to LongTermKey group
> ---
> doc/settings-storage.txt | 2 ++
> 1 file changed, 2 insertions(+)
All patches in this set have been applied. Thanks.
Johan
^ permalink raw reply
* Bluez/Obexd upstream test result_20121204(bluez-4.101.1053+ obexd-0.47.77)
From: Li, XiaX @ 2012-12-04 8:32 UTC (permalink / raw)
To: 'linux-bluetooth@vger.kernel.org'
[-- Attachment #1: Type: text/plain, Size: 1172 bytes --]
Hi all,
QA finished upstream testing. The test is for bluez-4.101.1053 and obexd-0.47.77. Against last, BlueZ is changed from 4.101.851 to 4.101.1053, Obexd is changed from 0.47.69 to 0.47.77.
In this test, totally ran 100 case: 72 Pass, 10 Fail. Other 18 are blocked or unavailable (some cases validation method is still in investigating). The pass rate is 88% (pass / <pass + fail>). Ofono has not caught up with the BlueZ API changing in HFP profile.
New bugs:
===============================================
No
Re-open bugs:
===============================================
No
Verified bugs:
===============================================
No
Testing Environment
==============================================
Hardware: netbook Eeepc 1005HA | Acer AspireOne NAV50
Image: netbook-ia32-pinetrail-tizen_20120424.2
Linux Kernel: v3.4-rc7
bluez-4.101.1053.gf15478e-1.1.i586
obexd-0.47.77.g1ab367c-3.1.i586
obexd-server-0.47.77.g1ab367c-3.1.i586
connman-1.9.34.g86f2151-1.1.i586
ofono-1.11-1.i686
Pulseaudio: 67602d8743e8e529919bb9fbb956aa77724a8e50 (oct, 6th)
For detailed test results, please see attached file.
Thanks
Li Xia
[-- Attachment #2: Bluetooth_upstream_quality_20121204.txt --]
[-- Type: text/plain, Size: 7550 bytes --]
== Detail Result ==
[PASS]: case passed <br>
[FAIL]: case failed <br>
[Block]: case is blocked by one bug <br>
[N/A]: case not available to be tested
=== Audio-A2DP ===
[PASS] A2DP_001: audio sink connect/re-connect
[PASS] A2DP_002: stereo headset playback
[PASS] A2DP_003: stereo headset voice record
[PASS] A2DP_004: Codec support: SBC
[PASS] A2DP_005: Playback music on line
[PASS] A2DP_006: SINK role, as speaker for other device music playing
With some BT headset, we ever met issue [https://bugs.meego.com/show_bug.cgi?id=25480 Bug#25480 A2DP-source: pulseaudio fails to create bluez_sink and bluez_source]
=== Audio-AVRCP ===
[PASS] AVRCP_001: Volume Up/Down
[Block] AVRCP_002: Play/Pause (by unavailable media-player)
[Block] AVRCP_003: Next/Privious (by unavailable media-player)
[PASS] AVRCP_004: Connection Establish/Release
[N/A] AVRCP_005: Audio metadata get.
We still try to find avaliable media-player to support AVRCP-1.4
=== Audio-HFP ===
Ofono needs to update its API, since BlueZ already took the changes. Here is bug [https://bugs.meego.com/show_bug.cgi?id=25748 Bug#25748 HFP: Ofono List-modems shows no modem after paired with phone]
[FAIL] HFP_001: RFCOMM connection on AG
Need install sbc for latest pulseaudio
[FAIL] HFP_002: list (ofono) hfp modem
[FAIL] HFP_003: HFP modem establishment (Ofono)
[FAIL] HFP_004: Audio SNK and SRC establishment
[FAIL] HFP_005: voicecall, audio creates BT SNK/SRC
[FAIL] HFP_006: redirect AG SNK/SRC to local SRC/SNK
BlueZ interface has some regression, bug is reported as [https://bugs.meego.com/show_bug.cgi?id=25473 Bug#25473 HFP: latest bluez cannot support pulseaudio to create bluez_sink and bluez_source]
Pulseaudio has new crash bug: [https://bugs.meego.com/show_bug.cgi?id=25593 Bug#25593 Pulseaudio crashes after connect BT sink to alsa source]
[FAIL] HFP_007: Check AT-commands from HF part
[FAIL] HFP_008: Connect BT Headset to HFP phone
=== Audio-HSP ===
[PASS] HSP_001: Use mono headset to play music
*** DUT is a Netbook, unable to take phone ***
[N/A] HSP_002: Take incoming call by button-press
[N/A] HSP_003: Audio transfer between AG and HS
[PASS] HSP_004: Adjust Volume Up/Down
=== OBEX-FTP ===
[PASS] FTP_001: pull/push files from/to server.
[PASS] FTP_002: browse server files
[PASS] FTP_003: Client "delete file", "rename file"
[PASS] FTP_004: Server enables FTP parameter
[PASS] FTP_005: Server sets sharing root path
[PASS] FTP_006: Server handles all requirements
[PASS] FTP_007: Server has ability to set permission for FTP
[PASS] FTP_008: FTP data-rate about 30k/s~230k/s
[PASS] FTP_009: Big size file transferred stable
=== OBEX-OPP ===
[PASS] OPP_001: pull un-patterned object from server.
[PASS] OPP_002: Server enables OPP parameter
[PASS] OPP_003: During object transferring, the progress is clear
=== OBEX-PBAP ===
[PASS] PBAP_001: Client gets phone book entries from server
[PASS] PBAP_002: Client gets ICH, OCH, MCH and CCH from server
[FAIL] PBAP_003: PSE can provide PBAP daemon by enabling corresponding parameter
Case failed due to [https://bugs.meego.com/show_bug.cgi?id=25598 Bug#25598, PBAP server fails to open /telecom/pb.vcf file]
[PASS] PBAP_004: Both sides support vCard2.1/vCard3.0
=== OBEX-SYNC ===
[PASS] SYNC_001: Server enables SYNC daemon
[PASS] SYNC_002: During sync, Server can show "syncing..."
[PASS] SYNC_003: client can set PIM fetching from INT
[PASS] SYNC_004: Server get/put entire phonebook from/to client.
[PASS] SYNC_005: Client can support vCard2.1, vCard3.0
=== OBEX-MAP MCE ===
[FAIL] MAP_001: MCE can browse message/folder list on MSE
Regression happened on client side, bug is reported as [https://bugs.meego.com/show_bug.cgi?id=25595 Bug#25595 MAP client fail to get message list from Samsung GT-i9100]
[BLOCK] MAP_002: MCE can upload local message to MSE
[BLOCK] MAP_003: MCE can delete the message on MSE side
[BLOCK] MAP_004: MCE can take use of MSE to send message
=== Network-PAN ===
[PASS] PAN_001: PANU can init nap0 device connect to NAP
[PASS] PAN_002: PANU can get ip address or assigned static ip
[PASS] PAN_003: PANU can logon internet website
[N/A] PAN_004: NAP can init bridge bnep
[N/A] PAN_005: NAP can support one or multiple PANU connection
[N/A] PAN_006: NAP can have DHCP responding to each PANU
Current connman does not support DHCP functions.
=== Network-BNEP ===
[PASS] BNEP_001: Check BNEP support on DUT
=== Network-DUN ===
[PASS] DUN_001: GW (DUT) can parse a series of AT commands from the data terminal.
[PASS] DUN_002: DT can build up rfcomm device by bluetooth and DUN modem by Ofono.
[PASS] DUN_003: DT can use Ofono to dial up special service number ("*99#").
[PASS] DUN_004: When network connected, DT can log on website in internet.
=== SIM-SAP ===
The SAP test method is still in investigation.
[N/A] SAP_001: Server can enable a module to register Client
[N/A] SAP_002: Server can power on/off SIM Card or reset it
[N/A] SAP_003: Server can disconnect Client
[N/A] SAP_004: Server can disconnect SIM
[N/A] SAP_005: Client can connect to Server SIM
[N/A] SAP_006: Client can power on Server SIM
[N/A] SAP_007: Client can disconnect Server
=== Generic-GAP ===
[PASS] GAP_001: PSCAN/ISCAN mode setting.
[PASS] GAP_002: Active pairing to another bluetooth device.
[PASS] GAP_003: Passive pairing, accepte pair master requirement
[PASS] GAP_004: SSP supports
[PASS] GAP_005: If lost link-key, it needs re-pair
[PASS] GAP_006: reboot DUT with link-key restored, no need to re-pair
[PASS] GAP_007: Pair can be released
=== Generic-SDP ===
[PASS] SDP_001: browse available service list in local
[PASS] SDP_002: browse available service list from remote
[PASS] SDP_003: browse service by RecHandle for detail info
[PASS] SDP_004: Server can answer SDP searching request
[PASS] SDP_005: Server can add/del/update service records
=== Others-HID ===
[PASS] HID_001: Host can search nearby HID device.
[PASS] HID_002: [BAT] Host can connect to HID device.
[PASS] HID_003: Host can handle multiple human input/output devices.
=== HCI ===
[PASS] HCI_001: Build hci connection between Dev_A and Dev_B.
[PASS] HCI_002: Receive ACL data with HCI.
[PASS] HCI_003: Send ACL data with HCI.
[PASS] HCI_004: Change name of remote Dev by HCI.
[PASS] HCI_005: Change class of remote Dev by HCI.
[PASS] HCI_006: Read local HCI controller information.
[PASS] HCI_007: Read remote HCI controller information.
=== L2CAP ===
[PASS] L2CAP_001: Build l2cap connection between Dev_A and Dev_B.
[PASS] L2CAP_002: Dev_A and Dev_B take l2cap protocol to do pingpong.
=== RFCOMM ===
[PASS] RFCOMM_001: Build rfcomm connection between Dev_A and Dev_B.
[PASS] RFCOMM_002: Dev_A and Dev_B take rfcomm protocol to do pingpong.
=== Settings ===
[PASS] SET_001: [BAT] No error output during bluetoothd startup process.
=== Bluetooth Utils ===
Some basic checking for hciconfig, hcitool, sdptool commands.
[PASS] BTCMD_001: hciconfig -a
[PASS] BTCMD_002: hciconfig <adapter> piscan
[PASS] BTCMD_003: hciconfig <adapter> up/down
[PASS] BTCMD_004: hcitool scan
[PASS] BTCMD_005: sdptool browse local
[PASS] BTCMD_006: sdptool browse <ermote MAC>
[PASS] BTCMD_007: sdptool add/del
^ permalink raw reply
* [PATCH 1/2] profile: Fix possible NULL pointer dereference
From: Szymon Janc @ 2012-12-04 10:15 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
If send_new_connection failed NULL err pointer would be dereferenced.
---
src/profile.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/profile.c b/src/profile.c
index c9ff553..b98db36 100644
--- a/src/profile.c
+++ b/src/profile.c
@@ -800,7 +800,7 @@ static void ext_connect(GIOChannel *io, GError *err, gpointer user_data)
drop:
if (conn->cb) {
- conn->cb(&ext->p, conn->device, -err->code);
+ conn->cb(&ext->p, conn->device, err ? -err->code : -EIO);
conn->cb = NULL;
}
if (io_err)
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox