2010-03-15 05:01:36

by Suraj Sumangala

[permalink] [raw]
Subject: [PATCH] Added support for Atheros AR300x Bluetooth Chip


This protocol implements support for power management feature provided by AR300x chip.
This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time.
It then wakes up the chip in case of a Bluetooth activity.


Signed-off-by: Suraj <[email protected]>

---
drivers/bluetooth/Kconfig | 11 ++
drivers/bluetooth/Makefile | 1 +
drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++
drivers/bluetooth/hci_ldisc.c | 6 +
drivers/bluetooth/hci_uart.h | 8 +-
5 files changed, 378 insertions(+), 1 deletions(-)
create mode 100755 drivers/bluetooth/hci_ath.c

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 058fbcc..81abeff 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP

Say Y here to compile support for HCI BCSP protocol.

+config BT_HCIUART_ATH
+ bool "Atheros AR300x Board support"
+ depends on BT_HCIUART
+ help
+ HCIATH (HCI Atheros) is a serial protocol for communication
+ between Bluetooth device and host with support for Atheros AR300x
+ power management feature. This protocol is required for
+ serial Bluetooth devices that are based on Atheros AR300x chips.
+
+ Say Y here to compile support for HCIATH protocol.
+
config BT_HCIUART_LL
bool "HCILL protocol support"
depends on BT_HCIUART
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 7e5aed5..1481faa 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
+hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
hci_uart-objs := $(hci_uart-y)
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
new file mode 100755
index 0000000..13e4404
--- /dev/null
+++ b/drivers/bluetooth/hci_ath.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+
+/* HCIATH receiver States */
+#define HCIATH_W4_PACKET_TYPE 0
+#define HCIATH_W4_EVENT_HDR 1
+#define HCIATH_W4_ACL_HDR 2
+#define HCIATH_W4_SCO_HDR 3
+#define HCIATH_W4_DATA 4
+
+struct ath_struct {
+ struct hci_uart *hu;
+ unsigned int rx_state;
+ unsigned int rx_count;
+ unsigned int cur_sleep;
+
+ spinlock_t hciath_lock;
+ struct sk_buff *rx_skb;
+ struct sk_buff_head txq;
+ wait_queue_head_t wqevt;
+ struct work_struct ctxtsw;
+};
+
+int ath_wakeup_ar3001(struct tty_struct *tty)
+{
+ struct termios settings;
+ int status = 0x00;
+ mm_segment_t oldfs;
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ if ((status & TIOCM_CTS))
+ return status;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+
+ settings.c_cflag &= ~CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+ set_fs(oldfs);
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ /* Wake up board */
+ tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
+ mdelay(20);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
+ mdelay(20);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+
+ settings.c_cflag |= CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+ set_fs(oldfs);
+ return status;
+}
+
+static void ath_context_switch(struct work_struct *work)
+{
+ int status;
+ struct ath_struct *ath;
+ struct hci_uart *hu;
+ struct tty_struct *tty;
+
+ ath = container_of(work, struct ath_struct, ctxtsw);
+
+ hu = ath->hu;
+ tty = hu->tty;
+
+ /* verify and wake up controller */
+ if (ath->cur_sleep) {
+
+ status = ath_wakeup_ar3001(tty);
+ if (!(status & TIOCM_CTS))
+ return;
+ }
+
+ /* Ready to send Data */
+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
+ hci_uart_tx_wakeup(hu);
+}
+
+int ath_check_sleep_cmd(struct ath_struct *ath, unsigned char *packet)
+{
+ if (packet[0] == 0x04 && packet[1] == 0xFC)
+ ath->cur_sleep = packet[3];
+
+ return 0;
+}
+
+
+/* Initialize protocol */
+static int ath_open(struct hci_uart *hu)
+{
+ struct ath_struct *ath;
+ BT_DBG("hu %p", hu);
+
+ ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
+ if (!ath)
+ return -ENOMEM;
+
+ skb_queue_head_init(&ath->txq);
+ spin_lock_init(&ath->hciath_lock);
+
+ ath->cur_sleep = 0;
+ hu->priv = ath;
+ ath->hu = hu;
+
+ init_waitqueue_head(&ath->wqevt);
+ INIT_WORK(&ath->ctxtsw, ath_context_switch);
+ return 0;
+}
+
+/* Flush protocol data */
+static int ath_flush(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+ BT_DBG("hu %p", hu);
+ skb_queue_purge(&ath->txq);
+
+ return 0;
+}
+
+/* Close protocol */
+static int ath_close(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ath->txq);
+
+ if (ath->rx_skb)
+ kfree_skb(ath->rx_skb);
+
+ wake_up_interruptible(&ath->wqevt);
+ hu->priv = NULL;
+ kfree(ath);
+ return 0;
+}
+
+/* Enqueue frame for transmittion */
+static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+ struct ath_struct *ath = hu->priv;
+ if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
+
+ /* Discard SCO packet.AR3001 does not support SCO over HCI */
+ BT_DBG("SCO Packet over HCI received Dropping\n");
+ kfree(skb);
+ return 0;
+ }
+ BT_DBG("hu %p skb %p", hu, skb);
+
+ /* Prepend skb with frame type */
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+ skb_queue_tail(&ath->txq, skb);
+ set_bit(HCI_UART_SENDING, &hu->tx_state);
+
+ schedule_work(&ath->ctxtsw);
+ return 0;
+}
+
+static struct sk_buff *ath_dequeue(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+ struct sk_buff *skbuf;
+
+ skbuf = skb_dequeue(&ath->txq);
+ if (skbuf != NULL)
+ ath_check_sleep_cmd(ath, &skbuf->data[1]);
+
+ return skbuf;
+}
+
+static inline int ath_check_data_len(struct ath_struct *ath, int len)
+{
+ register int room = skb_tailroom(ath->rx_skb);
+ BT_DBG("len %d room %d", len, room);
+
+ if (len > room) {
+ BT_ERR("Data length is too large");
+ kfree_skb(ath->rx_skb);
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_skb = NULL;
+ ath->rx_count = 0;
+ } else {
+ ath->rx_state = HCIATH_W4_DATA;
+ ath->rx_count = len;
+ return len;
+ }
+
+ return 0;
+}
+
+/* Recv data */
+static int ath_recv(struct hci_uart *hu, void *data, int count)
+{
+ struct ath_struct *ath = hu->priv;
+ register char *ptr;
+ struct hci_event_hdr *eh;
+ struct hci_acl_hdr *ah;
+ struct hci_sco_hdr *sh;
+ struct sk_buff *skbuf;
+ register int len, type, dlen;
+
+ skbuf = NULL;
+ BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
+ ath->rx_state, ath->rx_count);
+ ptr = data;
+ while (count) {
+ if (ath->rx_count) {
+
+ len = min_t(unsigned int, ath->rx_count, count);
+ memcpy(skb_put(ath->rx_skb, len), ptr, len);
+ ath->rx_count -= len;
+ count -= len;
+ ptr += len;
+
+ if (ath->rx_count)
+ continue;
+ switch (ath->rx_state) {
+ case HCIATH_W4_DATA:
+ hci_recv_frame(ath->rx_skb);
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_skb = NULL;
+ ath->rx_count = 0;
+ continue;
+ case HCIATH_W4_EVENT_HDR:
+ eh = (struct hci_event_hdr *)ath->rx_skb->data;
+ BT_DBG("Event header: evt 0x%2.2x plen %d",
+ eh->evt, eh->plen);
+ ath_check_data_len(ath, eh->plen);
+ continue;
+ case HCIATH_W4_ACL_HDR:
+ ah = (struct hci_acl_hdr *)ath->rx_skb->data;
+ dlen = __le16_to_cpu(ah->dlen);
+ BT_DBG("ACL header: dlen %d", dlen);
+ ath_check_data_len(ath, dlen);
+ continue;
+ case HCIATH_W4_SCO_HDR:
+ sh = (struct hci_sco_hdr *)ath->rx_skb->data;
+ BT_DBG("SCO header: dlen %d", sh->dlen);
+ ath_check_data_len(ath, sh->dlen);
+ continue;
+ }
+ }
+
+ /* HCIATH_W4_PACKET_TYPE */
+ switch (*ptr) {
+ case HCI_EVENT_PKT:
+ BT_DBG("Event packet");
+ ath->rx_state = HCIATH_W4_EVENT_HDR;
+ ath->rx_count = HCI_EVENT_HDR_SIZE;
+ type = HCI_EVENT_PKT;
+ break;
+ case HCI_ACLDATA_PKT:
+ BT_DBG("ACL packet");
+ ath->rx_state = HCIATH_W4_ACL_HDR;
+ ath->rx_count = HCI_ACL_HDR_SIZE;
+ type = HCI_ACLDATA_PKT;
+ break;
+ case HCI_SCODATA_PKT:
+ BT_DBG("SCO packet");
+ ath->rx_state = HCIATH_W4_SCO_HDR;
+ ath->rx_count = HCI_SCO_HDR_SIZE;
+ type = HCI_SCODATA_PKT;
+ break;
+ default:
+ BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
+ hu->hdev->stat.err_rx++;
+ ptr++;
+ count--;
+ continue;
+ };
+ ptr++;
+ count--;
+
+ /* Allocate packet */
+ ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!ath->rx_skb) {
+ BT_ERR("Can't allocate mem for new packet");
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_count = 0;
+ return -ENOMEM;
+ }
+ ath->rx_skb->dev = (void *)hu->hdev;
+ bt_cb(ath->rx_skb)->pkt_type = type;
+ } return count;
+}
+
+static struct hci_uart_proto athp = {
+ .id = HCI_UART_ATH,
+ .open = ath_open,
+ .close = ath_close,
+ .recv = ath_recv,
+ .enqueue = ath_enqueue,
+ .dequeue = ath_dequeue,
+ .flush = ath_flush,
+};
+
+int ath_init(void)
+{
+ int err = hci_uart_register_proto(&athp);
+ if (!err)
+ BT_INFO("HCIATH protocol initialized");
+
+ else
+ BT_ERR("HCIATH protocol registration failed");
+ return err;
+}
+
+int ath_deinit(void)
+{
+ return hci_uart_unregister_proto(&athp);
+}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 76a1abb..7dd76d1 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_init();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH
+ ath_init();
+#endif

return 0;
}
@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_deinit();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH
+ ath_deinit();
+#endif

/* Release tty registration of line discipline */
if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 50113db..385537f 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -33,13 +33,14 @@
#define HCIUARTGETDEVICE _IOR('U', 202, int)

/* UART protocols */
-#define HCI_UART_MAX_PROTO 5
+#define HCI_UART_MAX_PROTO 6

#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH 5

struct hci_uart;

@@ -91,3 +92,8 @@ int bcsp_deinit(void);
int ll_init(void);
int ll_deinit(void);
#endif
+
+#ifdef CONFIG_BT_HCIUART_ATH
+int ath_init(void);
+int ath_deinit(void);
+#endif
--
1.6.3.3


2010-03-31 10:59:27

by Suraj Sumangala

[permalink] [raw]
Subject: [PATCH] Added Host level support for Atheros AR3xxx Bluetooth Chip

Added support for Atheros AR3xxx Bluetooth chip

Implemented feature to download firmware configuration from host.


Signed-off-by: Suraj <[email protected]>

---
Makefile.tools | 1 +
tools/hciattach.8 | 6 +
tools/hciattach.c | 159 +++++++-
tools/hciattach.h | 2 +
tools/hciattach_ar3k.c | 1228 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 1395 insertions(+), 1 deletions(-)
create mode 100755 tools/hciattach_ar3k.c

diff --git a/Makefile.tools b/Makefile.tools
index 2735d68..48cf097 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -23,6 +23,7 @@ tools_l2ping_LDADD = lib/libbluetooth.la
tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
tools/hciattach_st.c \
tools/hciattach_ti.c \
+ tools/hciattach_ar3k.c \
tools/hciattach_tialt.c
tools_hciattach_LDADD = lib/libbluetooth.la

diff --git a/tools/hciattach.8 b/tools/hciattach.8
index f750222..af648f2 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -49,6 +49,12 @@ specific identifier. Currently supported types are
.B any
Unspecified HCI_UART interface, no vendor specific options
.TP
+.B ar3kalt
+Atheros AR3xxx based modules with power management disabled
+.TP
+.B ar3k
+Atheros AR3xxx based modules
+.TP
.B ericsson
Ericsson based modules
.TP
diff --git a/tools/hciattach.c b/tools/hciattach.c
index 364c5ff..3557554 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -653,7 +653,156 @@ static int csr(int fd, struct uart_t *u, struct termios *ti)
}

/*
- * Silicon Wave specific initialization
+ * Atheros AR3xxx specific initialization code with power management disabled.
+ * Suraj Sumangala <[email protected]>
+ */
+static int ar3kpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ int dev_id, dd;
+ struct timespec tm = {0, 50000};
+ int status = 0;
+
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
+ if (dev_id < 0) {
+ perror("cannot get device id");
+ return -1;
+ }
+
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ return -1;
+ }
+ sleep(2);
+ /* send command with Sleep feature disabled */
+ hci_send_cmd(dd, OGF_VENDOR_CMD, 0x04, 1, &status);
+
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+
+}
+/*
+ * Atheros AR3xxx specific initialization post callback
+ * with power management enabled
+ * Suraj Sumangala <[email protected]>
+ */
+static int ar3kpmpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ int dev_id, dd;
+ struct timespec tm = {0, 50000};
+ int status = 1;
+
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
+ if (dev_id < 0) {
+ perror("cannot get device id");
+ return -1;
+ }
+
+
+ dd = hci_open_dev(dev_id);
+ if (dd < 0) {
+ perror("HCI device open failed");
+ return -1;
+ }
+ sleep(2);
+ /* send command with Sleep feature disabled */
+ if (hci_send_cmd(dd, OGF_VENDOR_CMD, 0x04, 1, &status) < 0)
+ perror("sleep enable command not sent");
+
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+}
+/*
+ * Atheros AR3xxx specific initialization
+ * Suraj Sumangala <[email protected]>
+ */
+static int ar3kinit(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = { 0, 500000 };
+ unsigned char cmd[14], rsp[100];
+ int r;
+ int baud;
+
+ /* Download PS and patch */
+ r = ath_ps_download(fd);
+ if (r < 0) {
+ perror("Failed to Download configuration");
+ return -1;
+ }
+ /* Write BDADDR if user has provided any */
+ if (u->bdaddr != NULL) {
+ /* Set BD_ADDR */
+ memset(cmd, 0, sizeof(cmd));
+ memset(rsp, 0, sizeof(rsp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x0B;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x0A;
+ cmd[4] = 0x01;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x06;
+ str2ba(u->bdaddr, (bdaddr_t *) (cmd + 8));
+
+ /* Send command */
+ if (write(fd, cmd, 14) != 14) {
+ fprintf(stderr, "Failed to write BD_ADDR command\n");
+ return -1;
+ }
+
+ /* Read reply */
+ if (read_hci_event(fd, rsp, 10) < 0) {
+ fprintf(stderr, "Failed to set BD_ADDR\n");
+ return -1;
+ }
+ }
+
+ /* Send HCI Reset to write the configuration */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x03;
+ cmd[2] = 0x0c;
+ cmd[3] = 0x00;
+ /* Send reset command */
+ r = write(fd, cmd, 4);
+
+ if (r != 4)
+ return -1;
+
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -1;
+
+ /* Set baud rate command,
+ * set controller baud rate to user specified value */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x0C;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x02;
+ baud = u->speed/100;
+ cmd[4] = (char)baud;
+ cmd[5] = (char)(baud >> 8);
+
+ if (write(fd, cmd, 6) != 6) {
+ perror("Failed to write init command");
+ return -1;
+ }
+
+ /* Wait for the command complete event for Baud rate change Command */
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -1;
+
+ return 0;
+}
+/*
+ * Silicon Wave specific initialization
* Thomas Moser <[email protected]>
*/
static int swave(int fd, struct uart_t *u, struct termios *ti)
@@ -1071,6 +1220,14 @@ struct uart_t uart[] = {
/* Broadcom BCM2035 */
{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },

+ /* ATHEROS AR3xxx */
+ { "ar3kalt", 0x0000, 0x0000, HCI_UART_ATH,
+ 115200, 115200, FLOW_CTL, NULL, ar3kinit, ar3kpost },
+
+ { "ar3k", 0x0000, 0x0000, HCI_UART_ATH,
+ 115200, 115200, FLOW_CTL, NULL, ar3kinit, ar3kpmpost },
+
+
{ NULL, 0 }
};

diff --git a/tools/hciattach.h b/tools/hciattach.h
index 867563b..5b68668 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -36,6 +36,7 @@
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH 5

int read_hci_event(int fd, unsigned char* buf, int size);
int set_speed(int fd, struct termios *ti, int speed);
@@ -45,3 +46,4 @@ int texas_post(int fd, struct termios *ti);
int texasalt_init(int fd, int speed, struct termios *ti);
int stlc2500_init(int fd, bdaddr_t *bdaddr);
int bgb2xx_init(int dd, bdaddr_t *bdaddr);
+int ath_ps_download(int fd);
diff --git a/tools/hciattach_ar3k.c b/tools/hciattach_ar3k.c
new file mode 100755
index 0000000..ca418d9
--- /dev/null
+++ b/tools/hciattach_ar3k.c
@@ -0,0 +1,1228 @@
+/*
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <termios.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+
+/* Helper data type declaration */
+
+#define FALSE 0
+#define TRUE 1
+
+/* The maximum number of bytes possible in a patch entry */
+#define MAX_PATCH_SIZE 20000
+
+/* Maximum HCI packets that will be formed from the Patch file */
+#define MAX_NUM_PATCH_ENTRY ((MAX_PATCH_SIZE/MAX_BYTE_LENGTH) + 1)
+
+#define FPGA_REGISTER 0x4FFC
+
+#define PS_ASIC_FILE "PS_ASIC.pst"
+#define PS_FPGA_FILE "PS_FPGA.pst"
+#define FW_PATH "/lib/firmware/"
+#define PATCH_FILE "RamPatch.txt"
+#define BDADDR_FILE "ar3kbdaddr.pst"
+
+
+
+#define PS_RESET 2
+#define PS_WRITE 1
+#define WRITE_PATCH 8
+#define PS_VERIFY_CRC 9
+#define ENABLE_PATCH 11
+
+
+#define NUM_WAKEUP_RETRY 10
+
+#define HCI_CMD_HEADER_LEN 7
+
+#define RAM_PS_REGION (1<<0)
+#define RAM_PATCH_REGION (1<<1)
+
+#define RAMPS_MAX_PS_TAGS_PER_FILE 50
+#define PS_MAX_LEN 500
+#define LINE_SIZE_MAX (PS_MAX_LEN * 2)
+
+/* Constant values used by parser */
+#define BYTES_OF_PS_DATA_PER_LINE 16
+
+#define MAX_BYTE_LENGTH 244
+
+#define skip_space(str) while (*(str) == (' ')) ((str)++)
+
+#define IS_BETWEEN(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
+
+#define tohexval(c) (isdigit(c) ? ((c) - '0') : \
+ (IS_BETWEEN((c), 'A', 'Z') ? \
+ ((c) - 'A' + 10) : ((c) - 'a' + 10)))
+
+enum ps_entry_type {
+ hex_type,
+ decimal_type
+};
+
+struct ps_tag_entry {
+ uint32_t tag_id;
+ uint32_t tag_len;
+ uint8_t *tag_data;
+};
+
+struct ps_ram_patch {
+ int16_t Len;
+ uint8_t *Data;
+};
+struct ps_data_format {
+ enum ps_entry_type data_type;
+ unsigned char is_array;
+};
+
+struct ps_cmd_packet {
+ uint8_t *Hcipacket;
+ int packetLen;
+};
+
+struct st_read_status {
+ unsigned section;
+ unsigned line_count;
+ unsigned char_cnt;
+ unsigned byte_count;
+};
+
+/* Stores the number of PS Tags */
+static uint32_t tag_count;
+
+/* Stores the number of patch commands */
+static uint32_t patch_count;
+static uint32_t total_tag_len;
+static uint32_t rom_version;
+static uint32_t build_version;
+
+struct ps_tag_entry ps_tag_entry[RAMPS_MAX_PS_TAGS_PER_FILE];
+struct ps_ram_patch ram_patch[MAX_NUM_PATCH_ENTRY];
+
+
+/* PS parser helper function */
+static void load_hci_header(uint8_t *hci_ps_cmd,
+ uint8_t opcode, int length, int index)
+{
+ hci_ps_cmd[0] = 0x0B;
+ hci_ps_cmd[1] = 0xFC;
+ hci_ps_cmd[2] = length + 4;
+ hci_ps_cmd[3] = opcode;
+ hci_ps_cmd[4] = (index & 0xFF);
+ hci_ps_cmd[5] = ((index >> 8) & 0xFF);
+ hci_ps_cmd[6] = length;
+}
+
+
+static int ath_create_ps_command(uint8_t opcode, uint32_t param_1,
+ struct ps_cmd_packet *ps_patch_packet,
+ uint32_t *index)
+{
+ uint8_t *hci_ps_cmd;
+ uint32_t len;
+ int i;
+
+ hci_ps_cmd = NULL;
+
+ switch (opcode) {
+
+ case WRITE_PATCH:
+
+ for (i = 0; i < param_1; i++) {
+ /* Allocate command buffer */
+ hci_ps_cmd =
+ (uint8_t *) malloc(ram_patch[i].Len +
+ HCI_CMD_HEADER_LEN);
+
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0,
+ ram_patch[i].Len + HCI_CMD_HEADER_LEN);
+
+ /* Update commands to buffer */
+ load_hci_header(hci_ps_cmd, opcode, ram_patch[i].Len,
+ i);
+ memcpy(ram_patch[i].Data,
+ &hci_ps_cmd[HCI_CMD_HEADER_LEN],
+ ram_patch[i].Len);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen =
+ ram_patch[i].Len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+ }
+ break;
+ case ENABLE_PATCH:
+
+ len = 0;
+ i = 0;
+
+ hci_ps_cmd = (uint8_t *) malloc(len + HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0, len + HCI_CMD_HEADER_LEN);
+
+ load_hci_header(hci_ps_cmd, opcode, len, i);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen
+ = len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+
+ break;
+ case PS_RESET:
+
+ len = 0x06;
+ i = 0;
+
+ hci_ps_cmd = (uint8_t *) malloc(len + HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0, len + HCI_CMD_HEADER_LEN);
+
+ load_hci_header(hci_ps_cmd, opcode, len, i);
+
+ hci_ps_cmd[7] = 0x00;
+ hci_ps_cmd[len + HCI_CMD_HEADER_LEN - 2] = (param_1 & 0xFF);
+ hci_ps_cmd[len + HCI_CMD_HEADER_LEN - 1] =
+ ((param_1 >> 8) & 0xFF);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen
+ = len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+
+ break;
+ case PS_WRITE:
+ for (i = 0; i < param_1; i++) {
+ hci_ps_cmd =
+ (uint8_t *) malloc(ps_tag_entry[i].tag_len +
+ HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0,
+ ps_tag_entry[i].tag_len + HCI_CMD_HEADER_LEN);
+
+ load_hci_header(hci_ps_cmd, opcode,
+ ps_tag_entry[i].tag_len,
+ ps_tag_entry[i].tag_id);
+ memcpy(&hci_ps_cmd[HCI_CMD_HEADER_LEN],
+ ps_tag_entry[i].tag_data,
+ ps_tag_entry[i].tag_len);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+
+ ps_patch_packet[*index].packetLen =
+ ps_tag_entry[i].tag_len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+ }
+ break;
+ case PS_VERIFY_CRC:
+
+ len = 0x0;
+
+ hci_ps_cmd = (uint8_t *) malloc(len + HCI_CMD_HEADER_LEN);
+ if (hci_ps_cmd == NULL)
+ return -1;
+
+ memset(hci_ps_cmd, 0, len + HCI_CMD_HEADER_LEN);
+
+ load_hci_header(hci_ps_cmd, opcode, len, param_1);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen
+ = len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+unsigned int get_input_data_format(char *line,
+ struct ps_data_format *pst_format)
+{
+ if (line[0] != '[') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ return 0;
+ }
+
+ switch (line[1]) {
+
+ case 'H':
+ case 'h':
+ if (line[2] == ':') {
+ if ((line[3] == 'a') || (line[3] == 'A')) {
+
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+
+ }
+
+ if ((line[3] == 'S') || (line[3] == 's')) {
+
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = FALSE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+
+ } else if (line[3] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 4;
+ return 0;
+ } else
+ return 1;
+
+ } else if (line[2] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 3;
+
+ return 0;
+ } else
+ return 1;
+
+ break;
+
+ case 'A':
+ case 'a':
+
+ if (line[2] == ':') {
+
+ if ((line[3] == 'h') || (line[3] == 'H')) {
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+ } else if (line[3] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 4;
+ return 0;
+ } else
+ return 1;
+
+ } else if (line[2] == ']') {
+
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 3;
+ return 0;
+
+ } else
+ return 1;
+
+ break;
+
+ case 'S':
+ case 's':
+ if (line[2] == ':') {
+
+ if ((line[3] == 'h') || (line[3] == 'H')) {
+
+ if (line[4] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 5;
+ return 0;
+ } else
+ return 1;
+ } else if (line[3] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 4;
+ return 0;
+ } else
+ return 1;
+
+ } else if (line[2] == ']') {
+ pst_format->data_type = hex_type;
+ pst_format->is_array = TRUE;
+ line += 3;
+ return 0;
+ } else
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+}
+
+static unsigned int read_data_in_section(char *line,
+ struct ps_data_format format_info)
+{
+ char *token_ptr = line;
+
+ if (token_ptr[0] == '[') {
+ while (token_ptr[0] != ']' && token_ptr[0] != '\0')
+ token_ptr++;
+
+ if (token_ptr[0] == '\0')
+ return 0x0FFF;
+
+ token_ptr++;
+ }
+
+ if (format_info.data_type == hex_type) {
+ if (format_info.is_array == TRUE)
+ return 0x0FFF;
+ else
+ return strtol(token_ptr, NULL, 16);
+ } else
+ return 0x0FFF;
+}
+
+static int ath_parse_file(FILE *stream)
+{
+ char *buffer;
+ char *line;
+ uint8_t tag_cnt;
+ int16_t byte_count;
+ uint32_t pos;
+ int read_count;
+ struct ps_data_format stps_data_format;
+
+ int line_read = 0;
+ struct st_read_status read_status = {
+ 0, 0, 0, 0
+ };
+
+ pos = 0;
+ buffer = NULL;
+ tag_cnt = 0;
+ byte_count = 0;
+
+ if (stream == NULL) {
+ perror("Could not open config file .\n");
+ return -1;
+ }
+
+ buffer = malloc(LINE_SIZE_MAX + 1);
+ if (NULL == buffer)
+ return -1;
+
+ while ((line = fgets(buffer, LINE_SIZE_MAX, stream)) != NULL) {
+ skip_space(line);
+
+ if ((line[0] == '/') && (line[1] == '/'))
+ continue;
+
+ if ((line[0] == '#')) {
+ if (read_status.section != 0) {
+ perror("error\n");
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ } else {
+ read_status.section = 1;
+ continue;
+ }
+ }
+
+ if ((line[0] == '/') && (line[1] == '*')) {
+
+ line += 2;
+ skip_space(line);
+ line_read = 0;
+ read_status.section = 0;
+
+ continue;
+ }
+
+ if (read_status.section == 1) {
+ skip_space(line);
+
+ if (get_input_data_format(line, &stps_data_format)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+
+ ps_tag_entry[tag_cnt].tag_id =
+ read_data_in_section(line, stps_data_format);
+ read_status.section = 2;
+
+ } else if (read_status.section == 2) {
+
+ if (get_input_data_format(line, &stps_data_format)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+
+ byte_count =
+ read_data_in_section(line, stps_data_format);
+
+ if (byte_count > LINE_SIZE_MAX / 2) {
+ if (buffer != NULL)
+ free(buffer);
+
+ return -1;
+ }
+
+ ps_tag_entry[tag_cnt].tag_len = byte_count;
+ ps_tag_entry[tag_cnt].tag_data = (uint8_t *)
+ malloc(byte_count);
+
+ read_status.section = 3;
+ read_status.line_count = 0;
+
+ } else if (read_status.section == 3) {
+
+ if (read_status.line_count == 0) {
+ if (get_input_data_format(line,
+ &stps_data_format)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+ }
+
+ skip_space(line);
+ read_status.char_cnt = 0;
+ if (line[read_status.char_cnt] == '[') {
+
+ while (line[read_status.char_cnt] != ']' &&
+ line[read_status.char_cnt] != '\0')
+ read_status.char_cnt++;
+
+ if (line[read_status.char_cnt] == ']')
+ read_status.char_cnt++;
+ else
+ read_status.char_cnt = 0;
+
+ }
+
+ read_count = (byte_count > BYTES_OF_PS_DATA_PER_LINE)
+ ? BYTES_OF_PS_DATA_PER_LINE : byte_count;
+
+ if ((stps_data_format.data_type == hex_type)
+ && stps_data_format.is_array == TRUE) {
+
+ while (read_count > 0) {
+
+ ps_tag_entry[tag_cnt].tag_data
+ [read_status.byte_count]
+ = (uint8_t)(tohexval
+ (line[read_status.char_cnt])
+ << 4)
+ | (uint8_t)(tohexval
+ (line[read_status.char_cnt + 1]));
+
+ ps_tag_entry[tag_cnt].tag_data
+ [read_status.byte_count
+ + 1] = (uint8_t)(tohexval
+ (line[read_status.char_cnt + 3])
+ << 4)
+ | (uint8_t)(tohexval
+ (line[read_status.char_cnt + 4]));
+
+ read_status.char_cnt += 6;
+ read_status.byte_count += 2;
+ read_count -= 2;
+
+ }
+
+ if (byte_count > BYTES_OF_PS_DATA_PER_LINE)
+ byte_count -= BYTES_OF_PS_DATA_PER_LINE;
+ else
+ byte_count = 0;
+ }
+
+ read_status.line_count++;
+
+ if (byte_count == 0) {
+ read_status.section = 0;
+ read_status.char_cnt = 0;
+ read_status.line_count = 0;
+ read_status.byte_count = 0;
+ } else
+ read_status.char_cnt = 0;
+
+ if ((read_status.section == 0) &&
+ (++tag_cnt == RAMPS_MAX_PS_TAGS_PER_FILE)) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+
+ }
+ line_read++;
+ }
+
+ tag_count = tag_cnt;
+
+ if (tag_cnt > RAMPS_MAX_PS_TAGS_PER_FILE) {
+ if (buffer != NULL)
+ free(buffer);
+ return -1;
+ }
+
+ if (buffer != NULL)
+ free(buffer);
+
+ return 0;
+}
+
+static int parse_patch_file(FILE *stream)
+{
+ char byte[3];
+ char line[MAX_BYTE_LENGTH + 1];
+ int byte_cnt, byte_cnt_org;
+ int count;
+ int i, j, k;
+ int data;
+ uint32_t filepos;
+
+ byte[2] = '\0';
+ j = 0;
+ filepos = 0;
+
+ while (NULL != fgets(line, MAX_BYTE_LENGTH, stream)) {
+ if (strlen(line) <= 1 || !isxdigit(line[0]))
+ continue;
+ else
+ break;
+ }
+
+ byte_cnt = strtol(line, NULL, 16);
+ byte_cnt_org = byte_cnt;
+
+ while (byte_cnt > MAX_BYTE_LENGTH) {
+
+ /* Handle case when the number of patch buffer is
+ * more than the 20K */
+ if (MAX_NUM_PATCH_ENTRY == patch_count) {
+ for (i = 0; i < patch_count; i++)
+ free(ram_patch[i].Data);
+ return -1;
+ }
+ ram_patch[patch_count].Len = MAX_BYTE_LENGTH;
+ ram_patch[patch_count].Data =
+ (uint8_t *) malloc(MAX_BYTE_LENGTH);
+
+ patch_count++;
+ byte_cnt = byte_cnt - MAX_BYTE_LENGTH;
+ }
+
+ ram_patch[patch_count].Len = (byte_cnt & 0xFF);
+
+ if (byte_cnt != 0) {
+ ram_patch[patch_count].Data = (uint8_t *) malloc(byte_cnt);
+ patch_count++;
+ }
+
+ count = 0;
+
+ while (byte_cnt_org > MAX_BYTE_LENGTH) {
+ for (i = 0, k = 0; i < MAX_BYTE_LENGTH * 2;
+ i += 2, k++, count += 2) {
+ if (fgets(byte, 2, stream) == NULL)
+ return -1;
+ data = strtoul(&byte[0], NULL, 16);
+ ram_patch[j].Data[k] = (data & 0xFF);
+ }
+
+ j++;
+ byte_cnt_org = byte_cnt_org - MAX_BYTE_LENGTH;
+ }
+
+ if (j == 0)
+ j++;
+
+ for (k = 0; k < byte_cnt_org; i += 2, k++, count += 2) {
+
+ if (fgets(byte, 2, stream) == NULL)
+ return -1;
+
+ data = strtoul(byte, NULL, 16);
+ ram_patch[j].Data[k] = (data & 0xFF);
+ }
+
+ return 0;
+}
+
+static int ath_parse_ps(FILE *stream)
+{
+ int status;
+ int i;
+ unsigned char bdaddr_present = 0;
+ status = -1;
+
+
+ if (NULL != stream)
+ status = ath_parse_file(stream);
+
+ if (tag_count == 0)
+ total_tag_len = 10;
+ else {
+
+ for (i = 0; i < tag_count; i++) {
+
+ if (ps_tag_entry[i].tag_id == 1)
+ bdaddr_present = 1;
+ if (ps_tag_entry[i].tag_len % 2 == 1)
+ total_tag_len = total_tag_len
+ + ps_tag_entry[i].tag_len + 1;
+ else
+ total_tag_len =
+ total_tag_len + ps_tag_entry[i].tag_len;
+
+ }
+ }
+ if (tag_count > 0 && !bdaddr_present)
+ total_tag_len = total_tag_len + 10;
+
+ total_tag_len = total_tag_len + 10 + (tag_count * 4);
+
+ return status;
+}
+
+static int ath_create_cmd_list(struct ps_cmd_packet **hci_packet_list,
+ uint32_t *num_packets)
+{
+ uint8_t count;
+ uint32_t num_cmd_entry = 0;
+ uint32_t crc = 0;
+
+ *num_packets = 0;
+
+ if (patch_count > 0)
+ crc |= RAM_PATCH_REGION;
+ if (tag_count > 0)
+ crc |= RAM_PS_REGION;
+
+ if (patch_count || tag_count) {
+
+ /* CRC Packet + PS Reset Packet + Patch List + PS List */
+ num_cmd_entry += (2 + patch_count + tag_count);
+ if (patch_count > 0)
+ num_cmd_entry++; /* Patch Enable Command */
+
+ (*hci_packet_list) =
+ malloc(sizeof(struct ps_cmd_packet) * num_cmd_entry);
+ if (NULL == *hci_packet_list)
+ perror("memory allocation failed \r\n");
+
+ ath_create_ps_command(PS_VERIFY_CRC, crc, *hci_packet_list,
+ num_packets);
+
+ if (patch_count > 0) {
+
+ ath_create_ps_command(WRITE_PATCH, patch_count,
+ *hci_packet_list, num_packets);
+ ath_create_ps_command(ENABLE_PATCH, 0,
+ *hci_packet_list,
+ num_packets);
+
+ }
+
+ ath_create_ps_command(PS_RESET, total_tag_len,
+ *hci_packet_list, num_packets);
+
+ if (tag_count > 0)
+ ath_create_ps_command(PS_WRITE, tag_count,
+ *hci_packet_list, num_packets);
+ }
+
+ for (count = 0; count < patch_count; count++)
+ free(ram_patch[patch_count].Data);
+
+ for (count = 0; count < tag_count; count++)
+ free(ps_tag_entry[count].tag_data);
+
+ return *num_packets;
+}
+
+static int ath_free_command_list(struct ps_cmd_packet **hci_packet_list,
+ uint32_t num_packets)
+{
+ int i;
+
+ if (*hci_packet_list == NULL)
+ return -1;
+
+ for (i = 0; i < num_packets; i++)
+ free((*hci_packet_list)[i].Hcipacket);
+
+ free(*hci_packet_list);
+
+ return 0;
+}
+
+static int wake_up_ar3k(int fd)
+{
+ struct termios ti;
+ int status;
+ int retrycount = 0;
+ if (tcgetattr(fd, &ti) < 0) {
+ perror("Can't get port settings");
+ return -1;
+ }
+ ioctl(fd, TIOCMGET, &status);
+ if (status & TIOCM_CTS)
+ return 0;
+
+ ti.c_cflag &= ~CRTSCTS;
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Can't set port settings");
+ return -1;
+ }
+
+ do {
+ ioctl(fd, TIOCMGET, &status);
+
+ /* deassert */
+ status &= (~TIOCM_RTS);
+ ioctl(fd, TIOCMSET, &status);
+
+ /* read */
+ ioctl(fd, TIOCMGET, &status);
+
+ /* assert */
+ status |= (TIOCM_RTS);
+ ioctl(fd, TIOCMSET, &status);
+ usleep(200);
+
+ /* read */
+ ioctl(fd, TIOCMGET, &status);
+ retrycount++;
+ if (retrycount > NUM_WAKEUP_RETRY)
+ break;
+ } while (!(status & TIOCM_CTS));
+ if (!(status & TIOCM_CTS))
+ return -1;
+
+ ti.c_cflag |= CRTSCTS;
+ if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+ perror("Can't set port settings");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * This API is used to send the HCI command to controller and return
+ * with a HCI Command Complete event.
+ */
+static int send_hci_cmd_wait_event(int dev,
+ uint8_t *hci_command,
+ int cmd_length,
+ uint8_t **event, uint8_t **buffer_to_free)
+{
+ int r;
+ uint8_t *hci_event;
+ uint8_t pkt_type = 0x01;
+
+ if (cmd_length == 0)
+ return -1;
+
+ /*
+ * Try to wake up the board if it is asleep
+ * The assumption here is that the board is asleep.
+ */
+ if (wake_up_ar3k(dev) < 0)
+ return -1;
+
+ if (write(dev, &pkt_type, 1) != 1)
+ return -1;
+
+ if (write(dev, (unsigned char *)hci_command, cmd_length) != cmd_length)
+ return -1;
+
+ hci_event = (uint8_t *) malloc(100);
+ r = read_hci_event(dev, (unsigned char *)hci_event, 100);
+ if (r > 0) {
+ *event = hci_event;
+ *buffer_to_free = hci_event;
+ } else {
+
+ /* Did not get an event from controller. return error */
+ free(hci_event);
+ *buffer_to_free = NULL;
+ return -1;
+ }
+ return 0;
+}
+
+static int read_ps_event(uint8_t *data)
+{
+
+ if (data[5] == 0xFC && data[6] == 0x00) {
+ switch (data[4]) {
+ case 0x0B:
+ return 0;
+ break;
+ case 0x0C:
+
+ /* Change Baudrate */
+ return 0;
+ break;
+ case 0x04:
+ return 0;
+ break;
+ case 0x1E:
+ rom_version = data[10];
+ rom_version = ((rom_version << 8) | data[9]);
+ rom_version = ((rom_version << 8) | data[8]);
+ rom_version = ((rom_version << 8) | data[7]);
+ build_version = data[14];
+ build_version = ((build_version << 8) | data[13]);
+ build_version = ((build_version << 8) | data[12]);
+ build_version = ((build_version << 8) | data[11]);
+ return 0;
+ break;
+ }
+ }
+ return -1;
+}
+
+static int get_ps_file_name(int devtype, char *path)
+{
+ char *filename;
+ int status = 0;
+
+ if (devtype == 0xdeadc0de) {
+ filename = PS_ASIC_FILE;
+ status = 1;
+ } else {
+ filename = PS_FPGA_FILE;
+ status = 0;
+ }
+
+ sprintf(path, "%s%s", FW_PATH, filename);
+ return status;
+}
+
+static int get_patch_file_name(int dev_type, int rom_version,
+ int build_version, char *path)
+{
+ if ((dev_type != 0) && (dev_type != 0xdeadc0de)
+ && (rom_version == 0x99999999) && (build_version == 1)) {
+ path[0] = '\0';
+ } else
+ sprintf(path, "%s%s", FW_PATH, PATCH_FILE);
+
+ return 0;
+}
+
+static int get_device_type(int dev, uint32_t *code)
+{
+ uint8_t hciCommand[] = {
+ 0x05, 0xfc, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04
+ };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ uint32_t reg;
+
+ int result = -1;
+ *code = 0;
+
+ hciCommand[3] = (uint8_t) (FPGA_REGISTER & 0xFF);
+ hciCommand[4] = (uint8_t) ((FPGA_REGISTER >> 8) & 0xFF);
+ hciCommand[5] = (uint8_t) ((FPGA_REGISTER >> 16) & 0xFF);
+ hciCommand[6] = (uint8_t) ((FPGA_REGISTER >> 24) & 0xFF);
+
+ if (send_hci_cmd_wait_event(dev, hciCommand,
+ sizeof(hciCommand), &event,
+ &buffer_to_free) == 0) {
+ if (event[5] == 0xFC && event[6] == 0x00) {
+
+ switch (event[4]) {
+
+ case 0x05:
+ reg = event[10];
+ reg = ((reg << 8) | event[9]);
+ reg = ((reg << 8) | event[8]);
+ reg = ((reg << 8) | event[7]);
+ *code = reg;
+ result = 0;
+ break;
+
+ case 0x06:
+ break;
+ }
+ }
+ }
+
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ return result;
+}
+
+static int read_ar3k_version(int pConfig)
+{
+ uint8_t hciCommand[] = {
+ 0x1E, 0xfc, 0x00
+ };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ int result = -1;
+
+ if (0 ==
+ send_hci_cmd_wait_event(pConfig, hciCommand,
+ sizeof(hciCommand), &event,
+ &buffer_to_free)) {
+ result = read_ps_event(event);
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ return result;
+}
+
+static int str2bdaddr(char *str_bdaddr, char *bdaddr)
+{
+ char bdbyte[3];
+ char *str_byte = str_bdaddr;
+ int i, j;
+ unsigned char colon_present = 0;
+
+ if (strstr(str_bdaddr, ":") != NULL)
+ colon_present = 1;
+
+ bdbyte[2] = '\0';
+
+ bdbyte[0] = str_byte[0];
+ bdbyte[1] = str_byte[1];
+
+ for (i = 0, j = 5; i < 6; i++, j--) {
+ bdaddr[j] = strtol(bdbyte, NULL, 16);
+
+ if (colon_present == 1)
+ str_byte += 3;
+ else
+ str_byte += 2;
+ }
+ return 0;
+}
+
+static int write_bdaddr(int pConfig, char *bdaddr)
+{
+ uint8_t bdaddr_cmd[] = { 0x0B, 0xFC, 0x0A, 0x01, 0x01,
+ 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ int result = -1;
+
+ str2bdaddr(bdaddr, (char *)&bdaddr_cmd[7]);
+
+ if (0 == send_hci_cmd_wait_event(pConfig, bdaddr_cmd,
+ sizeof(bdaddr_cmd),
+ &event, &buffer_to_free)) {
+
+ if (event[5] == 0xFC && event[6] == 0x00) {
+ if (event[4] == 0x0B)
+ result = 0;
+ }
+
+ } else
+ perror(" Write failed \n");
+
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ return result;
+}
+
+int ath_ps_download(int hdev)
+{
+ int i;
+ int status;
+ struct ps_cmd_packet *hci_cmd_list; /* List storing the commands */
+ uint32_t numCmds;
+ uint8_t *event;
+ uint8_t *buffer_to_free;
+ uint32_t DevType;
+ char patchFileName[PATH_MAX];
+ char PsFileName[PATH_MAX];
+ char bdaddr_file_name[PATH_MAX];
+ FILE *stream;
+ char bdaddr[21];
+
+ status = 0;
+ hci_cmd_list = NULL;
+
+ /* First verify if the controller is an FPGA or ASIC,
+ *so depending on the device type the PS file to be written
+ * will be different.
+ */
+ do {
+ if (get_device_type(hdev, &DevType) == -1) {
+ status = -1;
+ break;
+ }
+ if (read_ar3k_version(hdev) == -1) {
+ status = -1;
+ break;
+ }
+
+ get_ps_file_name(DevType, PsFileName);
+ get_patch_file_name(DevType, rom_version, build_version,
+ patchFileName);
+
+ /* Read the PS file to a dynamically allocated buffer */
+ stream = fopen(PsFileName, "r");
+ if (stream == NULL) {
+ perror("firmware file open error\n");
+ status = -1;
+ break;
+ }
+ status = ath_parse_ps(stream);
+ fclose(stream);
+
+ /*
+ * It is not necessary that Patch file be available,
+ * continue with PS Operations if.
+ * failed.
+ */
+ if (patchFileName[0] == '\0')
+ status = 0;
+ stream = fopen(patchFileName, "r");
+ if (stream == NULL)
+ status = 0;
+ else {
+ /* parse and store the Patch file contents to
+ * a global variables
+ */
+ status = parse_patch_file(stream);
+ fclose(stream);
+ }
+
+ /* Create an HCI command list
+ * from the parsed PS and patch information */
+ ath_create_cmd_list(&hci_cmd_list, &numCmds);
+
+ /*
+ * First Send the CRC packet,
+ * We have to continue with the PS operations
+ * only if the CRC packet has been replied with
+ * a Command complete event with status Error.
+ */
+ if (send_hci_cmd_wait_event
+ (hdev, hci_cmd_list[0].Hcipacket, hci_cmd_list[0].packetLen,
+ &event, &buffer_to_free) == 0) {
+
+ if (read_ps_event(event) == 0) {
+
+ /* Exit if the status is success */
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ status = 0;
+ break;
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+ } else {
+ status = -1;
+ break;
+ }
+ for (i = 1; i < numCmds; i++) {
+
+ if (send_hci_cmd_wait_event
+ (hdev, hci_cmd_list[i].Hcipacket,
+ hci_cmd_list[i].packetLen, &event,
+ &buffer_to_free) == 0) {
+
+ if (read_ps_event(event) < 0) {
+
+ /* Exit if the status is not success */
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+
+ status = -1;
+ break;
+ }
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+ } else {
+ status = 0;
+ break;
+ }
+ }
+ /* Read the PS file to a dynamically allocated buffer */
+ sprintf(bdaddr_file_name, "%s%s", FW_PATH, BDADDR_FILE);
+ stream = fopen(bdaddr_file_name, "r");
+
+ if (stream == NULL) {
+ status = 0;
+ break;
+ }
+
+ if (fgets(bdaddr, 20, stream) != NULL)
+ status = write_bdaddr(hdev, bdaddr);
+
+ fclose(stream);
+
+ } while (FALSE);
+
+ if (hci_cmd_list != NULL)
+ ath_free_command_list(&hci_cmd_list, numCmds);
+
+ return status;
+}
--
1.7.0

2010-03-29 09:01:26

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH] Added support for Atheros AR300x Bluetooth Chip

On Wed, 2010-03-24 at 10:57 +0530, suraj wrote:
> On Mon, 2010-03-15 at 10:31 +0530, suraj wrote:
> > This protocol implements support for power management feature provided by AR300x chip.
> > This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time.
> > It then wakes up the chip in case of a Bluetooth activity.
> >
> >
> > Signed-off-by: Suraj <[email protected]>
> >
> > ---
> > drivers/bluetooth/Kconfig | 11 ++
> > drivers/bluetooth/Makefile | 1 +
> > drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++
> > drivers/bluetooth/hci_ldisc.c | 6 +
> > drivers/bluetooth/hci_uart.h | 8 +-
> > 5 files changed, 378 insertions(+), 1 deletions(-)
> > create mode 100755 drivers/bluetooth/hci_ath.c
> >
> > diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> > index 058fbcc..81abeff 100644
> > --- a/drivers/bluetooth/Kconfig
> > +++ b/drivers/bluetooth/Kconfig
> > @@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
> >
> > Say Y here to compile support for HCI BCSP protocol.
> >
> > +config BT_HCIUART_ATH
> > + bool "Atheros AR300x Board support"
> > + depends on BT_HCIUART
> > + help
> > + HCIATH (HCI Atheros) is a serial protocol for communication
> > + between Bluetooth device and host with support for Atheros AR300x
> > + power management feature. This protocol is required for
> > + serial Bluetooth devices that are based on Atheros AR300x chips.
> > +
> > + Say Y here to compile support for HCIATH protocol.
> > +
> > config BT_HCIUART_LL
> > bool "HCILL protocol support"
> > depends on BT_HCIUART
> > diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> > index 7e5aed5..1481faa 100644
> > --- a/drivers/bluetooth/Makefile
> > +++ b/drivers/bluetooth/Makefile
> > @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
> > hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
> > hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
> > hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
> > +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
> > hci_uart-objs := $(hci_uart-y)
> > diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
> > new file mode 100755
> > index 0000000..13e4404
> > --- /dev/null
> > +++ b/drivers/bluetooth/hci_ath.c
> > @@ -0,0 +1,353 @@
> > +/*
> > + * Copyright (c) 2009-2010 Atheros Communications Inc.
> > + *
> > + * This program is free software; you can redistribute it and/or modify
> > + * it under the terms of the GNU General Public License as published by
> > + * the Free Software Foundation; either version 2 of the License, or
> > + * (at your option) any later version.
> > + *
> > + * This program is distributed in the hope that it will be useful,
> > + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> > + * GNU General Public License for more details.
> > + *
> > + * You should have received a copy of the GNU General Public License
> > + * along with this program; if not, write to the Free Software
> > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> > + *
> > + */
> > +
> > +#include <linux/module.h>
> > +#include <linux/kernel.h>
> > +
> > +#include <linux/init.h>
> > +#include <linux/slab.h>
> > +#include <linux/tty.h>
> > +#include <linux/errno.h>
> > +#include <linux/ioctl.h>
> > +#include <linux/skbuff.h>
> > +
> > +#include <net/bluetooth/bluetooth.h>
> > +#include <net/bluetooth/hci_core.h>
> > +
> > +#include "hci_uart.h"
> > +
> > +
> > +/* HCIATH receiver States */
> > +#define HCIATH_W4_PACKET_TYPE 0
> > +#define HCIATH_W4_EVENT_HDR 1
> > +#define HCIATH_W4_ACL_HDR 2
> > +#define HCIATH_W4_SCO_HDR 3
> > +#define HCIATH_W4_DATA 4
> > +
> > +struct ath_struct {
> > + struct hci_uart *hu;
> > + unsigned int rx_state;
> > + unsigned int rx_count;
> > + unsigned int cur_sleep;
> > +
> > + spinlock_t hciath_lock;
> > + struct sk_buff *rx_skb;
> > + struct sk_buff_head txq;
> > + wait_queue_head_t wqevt;
> > + struct work_struct ctxtsw;
> > +};
> > +
> > +int ath_wakeup_ar3001(struct tty_struct *tty)
> > +{
> > + struct termios settings;
> > + int status = 0x00;
> > + mm_segment_t oldfs;
> > + status = tty->driver->ops->tiocmget(tty, NULL);
> > +
> > + if ((status & TIOCM_CTS))
> > + return status;
> > +
> > + oldfs = get_fs();
> > + set_fs(KERNEL_DS);
> > + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> > +
> > + settings.c_cflag &= ~CRTSCTS;
> > + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> > + set_fs(oldfs);
> > + status = tty->driver->ops->tiocmget(tty, NULL);
> > +
> > + /* Wake up board */
> > + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
> > + mdelay(20);
> > +
> > + status = tty->driver->ops->tiocmget(tty, NULL);
> > +
> > + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
> > + mdelay(20);
> > +
> > + status = tty->driver->ops->tiocmget(tty, NULL);
> > + oldfs = get_fs();
> > + set_fs(KERNEL_DS);
> > + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> > +
> > + settings.c_cflag |= CRTSCTS;
> > + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> > + set_fs(oldfs);
> > + return status;
> > +}
> > +
> > +static void ath_context_switch(struct work_struct *work)
> > +{
> > + int status;
> > + struct ath_struct *ath;
> > + struct hci_uart *hu;
> > + struct tty_struct *tty;
> > +
> > + ath = container_of(work, struct ath_struct, ctxtsw);
> > +
> > + hu = ath->hu;
> > + tty = hu->tty;
> > +
> > + /* verify and wake up controller */
> > + if (ath->cur_sleep) {
> > +
> > + status = ath_wakeup_ar3001(tty);
> > + if (!(status & TIOCM_CTS))
> > + return;
> > + }
> > +
> > + /* Ready to send Data */
> > + clear_bit(HCI_UART_SENDING, &hu->tx_state);
> > + hci_uart_tx_wakeup(hu);
> > +}
> > +
> > +int ath_check_sleep_cmd(struct ath_struct *ath, unsigned char *packet)
> > +{
> > + if (packet[0] == 0x04 && packet[1] == 0xFC)
> > + ath->cur_sleep = packet[3];
> > +
> > + return 0;
> > +}
> > +
> > +
> > +/* Initialize protocol */
> > +static int ath_open(struct hci_uart *hu)
> > +{
> > + struct ath_struct *ath;
> > + BT_DBG("hu %p", hu);
> > +
> > + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
> > + if (!ath)
> > + return -ENOMEM;
> > +
> > + skb_queue_head_init(&ath->txq);
> > + spin_lock_init(&ath->hciath_lock);
> > +
> > + ath->cur_sleep = 0;
> > + hu->priv = ath;
> > + ath->hu = hu;
> > +
> > + init_waitqueue_head(&ath->wqevt);
> > + INIT_WORK(&ath->ctxtsw, ath_context_switch);
> > + return 0;
> > +}
> > +
> > +/* Flush protocol data */
> > +static int ath_flush(struct hci_uart *hu)
> > +{
> > + struct ath_struct *ath = hu->priv;
> > + BT_DBG("hu %p", hu);
> > + skb_queue_purge(&ath->txq);
> > +
> > + return 0;
> > +}
> > +
> > +/* Close protocol */
> > +static int ath_close(struct hci_uart *hu)
> > +{
> > + struct ath_struct *ath = hu->priv;
> > + BT_DBG("hu %p", hu);
> > +
> > + skb_queue_purge(&ath->txq);
> > +
> > + if (ath->rx_skb)
> > + kfree_skb(ath->rx_skb);
> > +
> > + wake_up_interruptible(&ath->wqevt);
> > + hu->priv = NULL;
> > + kfree(ath);
> > + return 0;
> > +}
> > +
> > +/* Enqueue frame for transmittion */
> > +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> > +{
> > + struct ath_struct *ath = hu->priv;
> > + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
> > +
> > + /* Discard SCO packet.AR3001 does not support SCO over HCI */
> > + BT_DBG("SCO Packet over HCI received Dropping\n");
> > + kfree(skb);
> > + return 0;
> > + }
> > + BT_DBG("hu %p skb %p", hu, skb);
> > +
> > + /* Prepend skb with frame type */
> > + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
> > +
> > + skb_queue_tail(&ath->txq, skb);
> > + set_bit(HCI_UART_SENDING, &hu->tx_state);
> > +
> > + schedule_work(&ath->ctxtsw);
> > + return 0;
> > +}
> > +
> > +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
> > +{
> > + struct ath_struct *ath = hu->priv;
> > + struct sk_buff *skbuf;
> > +
> > + skbuf = skb_dequeue(&ath->txq);
> > + if (skbuf != NULL)
> > + ath_check_sleep_cmd(ath, &skbuf->data[1]);
> > +
> > + return skbuf;
> > +}
> > +
> > +static inline int ath_check_data_len(struct ath_struct *ath, int len)
> > +{
> > + register int room = skb_tailroom(ath->rx_skb);
> > + BT_DBG("len %d room %d", len, room);
> > +
> > + if (len > room) {
> > + BT_ERR("Data length is too large");
> > + kfree_skb(ath->rx_skb);
> > + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> > + ath->rx_skb = NULL;
> > + ath->rx_count = 0;
> > + } else {
> > + ath->rx_state = HCIATH_W4_DATA;
> > + ath->rx_count = len;
> > + return len;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +/* Recv data */
> > +static int ath_recv(struct hci_uart *hu, void *data, int count)
> > +{
> > + struct ath_struct *ath = hu->priv;
> > + register char *ptr;
> > + struct hci_event_hdr *eh;
> > + struct hci_acl_hdr *ah;
> > + struct hci_sco_hdr *sh;
> > + struct sk_buff *skbuf;
> > + register int len, type, dlen;
> > +
> > + skbuf = NULL;
> > + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> > + ath->rx_state, ath->rx_count);
> > + ptr = data;
> > + while (count) {
> > + if (ath->rx_count) {
> > +
> > + len = min_t(unsigned int, ath->rx_count, count);
> > + memcpy(skb_put(ath->rx_skb, len), ptr, len);
> > + ath->rx_count -= len;
> > + count -= len;
> > + ptr += len;
> > +
> > + if (ath->rx_count)
> > + continue;
> > + switch (ath->rx_state) {
> > + case HCIATH_W4_DATA:
> > + hci_recv_frame(ath->rx_skb);
> > + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> > + ath->rx_skb = NULL;
> > + ath->rx_count = 0;
> > + continue;
> > + case HCIATH_W4_EVENT_HDR:
> > + eh = (struct hci_event_hdr *)ath->rx_skb->data;
> > + BT_DBG("Event header: evt 0x%2.2x plen %d",
> > + eh->evt, eh->plen);
> > + ath_check_data_len(ath, eh->plen);
> > + continue;
> > + case HCIATH_W4_ACL_HDR:
> > + ah = (struct hci_acl_hdr *)ath->rx_skb->data;
> > + dlen = __le16_to_cpu(ah->dlen);
> > + BT_DBG("ACL header: dlen %d", dlen);
> > + ath_check_data_len(ath, dlen);
> > + continue;
> > + case HCIATH_W4_SCO_HDR:
> > + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
> > + BT_DBG("SCO header: dlen %d", sh->dlen);
> > + ath_check_data_len(ath, sh->dlen);
> > + continue;
> > + }
> > + }
> > +
> > + /* HCIATH_W4_PACKET_TYPE */
> > + switch (*ptr) {
> > + case HCI_EVENT_PKT:
> > + BT_DBG("Event packet");
> > + ath->rx_state = HCIATH_W4_EVENT_HDR;
> > + ath->rx_count = HCI_EVENT_HDR_SIZE;
> > + type = HCI_EVENT_PKT;
> > + break;
> > + case HCI_ACLDATA_PKT:
> > + BT_DBG("ACL packet");
> > + ath->rx_state = HCIATH_W4_ACL_HDR;
> > + ath->rx_count = HCI_ACL_HDR_SIZE;
> > + type = HCI_ACLDATA_PKT;
> > + break;
> > + case HCI_SCODATA_PKT:
> > + BT_DBG("SCO packet");
> > + ath->rx_state = HCIATH_W4_SCO_HDR;
> > + ath->rx_count = HCI_SCO_HDR_SIZE;
> > + type = HCI_SCODATA_PKT;
> > + break;
> > + default:
> > + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> > + hu->hdev->stat.err_rx++;
> > + ptr++;
> > + count--;
> > + continue;
> > + };
> > + ptr++;
> > + count--;
> > +
> > + /* Allocate packet */
> > + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> > + if (!ath->rx_skb) {
> > + BT_ERR("Can't allocate mem for new packet");
> > + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> > + ath->rx_count = 0;
> > + return -ENOMEM;
> > + }
> > + ath->rx_skb->dev = (void *)hu->hdev;
> > + bt_cb(ath->rx_skb)->pkt_type = type;
> > + } return count;
> > +}
> > +
> > +static struct hci_uart_proto athp = {
> > + .id = HCI_UART_ATH,
> > + .open = ath_open,
> > + .close = ath_close,
> > + .recv = ath_recv,
> > + .enqueue = ath_enqueue,
> > + .dequeue = ath_dequeue,
> > + .flush = ath_flush,
> > +};
> > +
> > +int ath_init(void)
> > +{
> > + int err = hci_uart_register_proto(&athp);
> > + if (!err)
> > + BT_INFO("HCIATH protocol initialized");
> > +
> > + else
> > + BT_ERR("HCIATH protocol registration failed");
> > + return err;
> > +}
> > +
> > +int ath_deinit(void)
> > +{
> > + return hci_uart_unregister_proto(&athp);
> > +}
> > diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> > index 76a1abb..7dd76d1 100644
> > --- a/drivers/bluetooth/hci_ldisc.c
> > +++ b/drivers/bluetooth/hci_ldisc.c
> > @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
> > #ifdef CONFIG_BT_HCIUART_LL
> > ll_init();
> > #endif
> > +#ifdef CONFIG_BT_HCIUART_ATH
> > + ath_init();
> > +#endif
> >
> > return 0;
> > }
> > @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
> > #ifdef CONFIG_BT_HCIUART_LL
> > ll_deinit();
> > #endif
> > +#ifdef CONFIG_BT_HCIUART_ATH
> > + ath_deinit();
> > +#endif
> >
> > /* Release tty registration of line discipline */
> > if ((err = tty_unregister_ldisc(N_HCI)))
> > diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> > index 50113db..385537f 100644
> > --- a/drivers/bluetooth/hci_uart.h
> > +++ b/drivers/bluetooth/hci_uart.h
> > @@ -33,13 +33,14 @@
> > #define HCIUARTGETDEVICE _IOR('U', 202, int)
> >
> > /* UART protocols */
> > -#define HCI_UART_MAX_PROTO 5
> > +#define HCI_UART_MAX_PROTO 6
> >
> > #define HCI_UART_H4 0
> > #define HCI_UART_BCSP 1
> > #define HCI_UART_3WIRE 2
> > #define HCI_UART_H4DS 3
> > #define HCI_UART_LL 4
> > +#define HCI_UART_ATH 5
> >
> > struct hci_uart;
> >
> > @@ -91,3 +92,8 @@ int bcsp_deinit(void);
> > int ll_init(void);
> > int ll_deinit(void);
> > #endif
> > +
> > +#ifdef CONFIG_BT_HCIUART_ATH
> > +int ath_init(void);
> > +int ath_deinit(void);
> > +#endif
>
> Hi Marcel,
>
> Can you please give your comments regarding the patch that I have sent
> you?
>
> Regards
> Suraj

Hi marcel,

A gentle remainder.

Can you please update the above driver to the Linux tree? If you find
any issues please let me know so that I can do the needful.

Regards
Suraj

2010-03-24 05:27:25

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH] Added support for Atheros AR300x Bluetooth Chip

On Mon, 2010-03-15 at 10:31 +0530, suraj wrote:
> This protocol implements support for power management feature provided by AR300x chip.
> This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time.
> It then wakes up the chip in case of a Bluetooth activity.
>
>
> Signed-off-by: Suraj <[email protected]>
>
> ---
> drivers/bluetooth/Kconfig | 11 ++
> drivers/bluetooth/Makefile | 1 +
> drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++
> drivers/bluetooth/hci_ldisc.c | 6 +
> drivers/bluetooth/hci_uart.h | 8 +-
> 5 files changed, 378 insertions(+), 1 deletions(-)
> create mode 100755 drivers/bluetooth/hci_ath.c
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 058fbcc..81abeff 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
>
> Say Y here to compile support for HCI BCSP protocol.
>
> +config BT_HCIUART_ATH
> + bool "Atheros AR300x Board support"
> + depends on BT_HCIUART
> + help
> + HCIATH (HCI Atheros) is a serial protocol for communication
> + between Bluetooth device and host with support for Atheros AR300x
> + power management feature. This protocol is required for
> + serial Bluetooth devices that are based on Atheros AR300x chips.
> +
> + Say Y here to compile support for HCIATH protocol.
> +
> config BT_HCIUART_LL
> bool "HCILL protocol support"
> depends on BT_HCIUART
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 7e5aed5..1481faa 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
> hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
> hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
> hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
> +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
> hci_uart-objs := $(hci_uart-y)
> diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
> new file mode 100755
> index 0000000..13e4404
> --- /dev/null
> +++ b/drivers/bluetooth/hci_ath.c
> @@ -0,0 +1,353 @@
> +/*
> + * Copyright (c) 2009-2010 Atheros Communications Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/errno.h>
> +#include <linux/ioctl.h>
> +#include <linux/skbuff.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include "hci_uart.h"
> +
> +
> +/* HCIATH receiver States */
> +#define HCIATH_W4_PACKET_TYPE 0
> +#define HCIATH_W4_EVENT_HDR 1
> +#define HCIATH_W4_ACL_HDR 2
> +#define HCIATH_W4_SCO_HDR 3
> +#define HCIATH_W4_DATA 4
> +
> +struct ath_struct {
> + struct hci_uart *hu;
> + unsigned int rx_state;
> + unsigned int rx_count;
> + unsigned int cur_sleep;
> +
> + spinlock_t hciath_lock;
> + struct sk_buff *rx_skb;
> + struct sk_buff_head txq;
> + wait_queue_head_t wqevt;
> + struct work_struct ctxtsw;
> +};
> +
> +int ath_wakeup_ar3001(struct tty_struct *tty)
> +{
> + struct termios settings;
> + int status = 0x00;
> + mm_segment_t oldfs;
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + if ((status & TIOCM_CTS))
> + return status;
> +
> + oldfs = get_fs();
> + set_fs(KERNEL_DS);
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + settings.c_cflag &= ~CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> + set_fs(oldfs);
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Wake up board */
> + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> + oldfs = get_fs();
> + set_fs(KERNEL_DS);
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + settings.c_cflag |= CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> + set_fs(oldfs);
> + return status;
> +}
> +
> +static void ath_context_switch(struct work_struct *work)
> +{
> + int status;
> + struct ath_struct *ath;
> + struct hci_uart *hu;
> + struct tty_struct *tty;
> +
> + ath = container_of(work, struct ath_struct, ctxtsw);
> +
> + hu = ath->hu;
> + tty = hu->tty;
> +
> + /* verify and wake up controller */
> + if (ath->cur_sleep) {
> +
> + status = ath_wakeup_ar3001(tty);
> + if (!(status & TIOCM_CTS))
> + return;
> + }
> +
> + /* Ready to send Data */
> + clear_bit(HCI_UART_SENDING, &hu->tx_state);
> + hci_uart_tx_wakeup(hu);
> +}
> +
> +int ath_check_sleep_cmd(struct ath_struct *ath, unsigned char *packet)
> +{
> + if (packet[0] == 0x04 && packet[1] == 0xFC)
> + ath->cur_sleep = packet[3];
> +
> + return 0;
> +}
> +
> +
> +/* Initialize protocol */
> +static int ath_open(struct hci_uart *hu)
> +{
> + struct ath_struct *ath;
> + BT_DBG("hu %p", hu);
> +
> + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
> + if (!ath)
> + return -ENOMEM;
> +
> + skb_queue_head_init(&ath->txq);
> + spin_lock_init(&ath->hciath_lock);
> +
> + ath->cur_sleep = 0;
> + hu->priv = ath;
> + ath->hu = hu;
> +
> + init_waitqueue_head(&ath->wqevt);
> + INIT_WORK(&ath->ctxtsw, ath_context_switch);
> + return 0;
> +}
> +
> +/* Flush protocol data */
> +static int ath_flush(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + BT_DBG("hu %p", hu);
> + skb_queue_purge(&ath->txq);
> +
> + return 0;
> +}
> +
> +/* Close protocol */
> +static int ath_close(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + if (ath->rx_skb)
> + kfree_skb(ath->rx_skb);
> +
> + wake_up_interruptible(&ath->wqevt);
> + hu->priv = NULL;
> + kfree(ath);
> + return 0;
> +}
> +
> +/* Enqueue frame for transmittion */
> +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> +{
> + struct ath_struct *ath = hu->priv;
> + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
> +
> + /* Discard SCO packet.AR3001 does not support SCO over HCI */
> + BT_DBG("SCO Packet over HCI received Dropping\n");
> + kfree(skb);
> + return 0;
> + }
> + BT_DBG("hu %p skb %p", hu, skb);
> +
> + /* Prepend skb with frame type */
> + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
> +
> + skb_queue_tail(&ath->txq, skb);
> + set_bit(HCI_UART_SENDING, &hu->tx_state);
> +
> + schedule_work(&ath->ctxtsw);
> + return 0;
> +}
> +
> +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + struct sk_buff *skbuf;
> +
> + skbuf = skb_dequeue(&ath->txq);
> + if (skbuf != NULL)
> + ath_check_sleep_cmd(ath, &skbuf->data[1]);
> +
> + return skbuf;
> +}
> +
> +static inline int ath_check_data_len(struct ath_struct *ath, int len)
> +{
> + register int room = skb_tailroom(ath->rx_skb);
> + BT_DBG("len %d room %d", len, room);
> +
> + if (len > room) {
> + BT_ERR("Data length is too large");
> + kfree_skb(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + } else {
> + ath->rx_state = HCIATH_W4_DATA;
> + ath->rx_count = len;
> + return len;
> + }
> +
> + return 0;
> +}
> +
> +/* Recv data */
> +static int ath_recv(struct hci_uart *hu, void *data, int count)
> +{
> + struct ath_struct *ath = hu->priv;
> + register char *ptr;
> + struct hci_event_hdr *eh;
> + struct hci_acl_hdr *ah;
> + struct hci_sco_hdr *sh;
> + struct sk_buff *skbuf;
> + register int len, type, dlen;
> +
> + skbuf = NULL;
> + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> + ath->rx_state, ath->rx_count);
> + ptr = data;
> + while (count) {
> + if (ath->rx_count) {
> +
> + len = min_t(unsigned int, ath->rx_count, count);
> + memcpy(skb_put(ath->rx_skb, len), ptr, len);
> + ath->rx_count -= len;
> + count -= len;
> + ptr += len;
> +
> + if (ath->rx_count)
> + continue;
> + switch (ath->rx_state) {
> + case HCIATH_W4_DATA:
> + hci_recv_frame(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + continue;
> + case HCIATH_W4_EVENT_HDR:
> + eh = (struct hci_event_hdr *)ath->rx_skb->data;
> + BT_DBG("Event header: evt 0x%2.2x plen %d",
> + eh->evt, eh->plen);
> + ath_check_data_len(ath, eh->plen);
> + continue;
> + case HCIATH_W4_ACL_HDR:
> + ah = (struct hci_acl_hdr *)ath->rx_skb->data;
> + dlen = __le16_to_cpu(ah->dlen);
> + BT_DBG("ACL header: dlen %d", dlen);
> + ath_check_data_len(ath, dlen);
> + continue;
> + case HCIATH_W4_SCO_HDR:
> + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
> + BT_DBG("SCO header: dlen %d", sh->dlen);
> + ath_check_data_len(ath, sh->dlen);
> + continue;
> + }
> + }
> +
> + /* HCIATH_W4_PACKET_TYPE */
> + switch (*ptr) {
> + case HCI_EVENT_PKT:
> + BT_DBG("Event packet");
> + ath->rx_state = HCIATH_W4_EVENT_HDR;
> + ath->rx_count = HCI_EVENT_HDR_SIZE;
> + type = HCI_EVENT_PKT;
> + break;
> + case HCI_ACLDATA_PKT:
> + BT_DBG("ACL packet");
> + ath->rx_state = HCIATH_W4_ACL_HDR;
> + ath->rx_count = HCI_ACL_HDR_SIZE;
> + type = HCI_ACLDATA_PKT;
> + break;
> + case HCI_SCODATA_PKT:
> + BT_DBG("SCO packet");
> + ath->rx_state = HCIATH_W4_SCO_HDR;
> + ath->rx_count = HCI_SCO_HDR_SIZE;
> + type = HCI_SCODATA_PKT;
> + break;
> + default:
> + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> + hu->hdev->stat.err_rx++;
> + ptr++;
> + count--;
> + continue;
> + };
> + ptr++;
> + count--;
> +
> + /* Allocate packet */
> + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> + if (!ath->rx_skb) {
> + BT_ERR("Can't allocate mem for new packet");
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_count = 0;
> + return -ENOMEM;
> + }
> + ath->rx_skb->dev = (void *)hu->hdev;
> + bt_cb(ath->rx_skb)->pkt_type = type;
> + } return count;
> +}
> +
> +static struct hci_uart_proto athp = {
> + .id = HCI_UART_ATH,
> + .open = ath_open,
> + .close = ath_close,
> + .recv = ath_recv,
> + .enqueue = ath_enqueue,
> + .dequeue = ath_dequeue,
> + .flush = ath_flush,
> +};
> +
> +int ath_init(void)
> +{
> + int err = hci_uart_register_proto(&athp);
> + if (!err)
> + BT_INFO("HCIATH protocol initialized");
> +
> + else
> + BT_ERR("HCIATH protocol registration failed");
> + return err;
> +}
> +
> +int ath_deinit(void)
> +{
> + return hci_uart_unregister_proto(&athp);
> +}
> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> index 76a1abb..7dd76d1 100644
> --- a/drivers/bluetooth/hci_ldisc.c
> +++ b/drivers/bluetooth/hci_ldisc.c
> @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_init();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_init();
> +#endif
>
> return 0;
> }
> @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_deinit();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_deinit();
> +#endif
>
> /* Release tty registration of line discipline */
> if ((err = tty_unregister_ldisc(N_HCI)))
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index 50113db..385537f 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -33,13 +33,14 @@
> #define HCIUARTGETDEVICE _IOR('U', 202, int)
>
> /* UART protocols */
> -#define HCI_UART_MAX_PROTO 5
> +#define HCI_UART_MAX_PROTO 6
>
> #define HCI_UART_H4 0
> #define HCI_UART_BCSP 1
> #define HCI_UART_3WIRE 2
> #define HCI_UART_H4DS 3
> #define HCI_UART_LL 4
> +#define HCI_UART_ATH 5
>
> struct hci_uart;
>
> @@ -91,3 +92,8 @@ int bcsp_deinit(void);
> int ll_init(void);
> int ll_deinit(void);
> #endif
> +
> +#ifdef CONFIG_BT_HCIUART_ATH
> +int ath_init(void);
> +int ath_deinit(void);
> +#endif

Hi Marcel,

Can you please give your comments regarding the patch that I have sent
you?

Regards
Suraj

2010-03-11 17:35:36

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [PATCH] Added support for Atheros AR300x Bluetooth Chip

On Thu, Mar 11, 2010 at 09:15:44AM -0800, Marcel Holtmann wrote:
> Hi Suraj,
>
> > Signed-off-by: Suraj <[email protected]>
> >
> > ---
> > drivers/bluetooth/Kconfig | 11 ++
> > drivers/bluetooth/Makefile | 1 +
> > drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++
> > drivers/bluetooth/hci_ldisc.c | 6 +
> > drivers/bluetooth/hci_uart.h | 8 +-
> > 5 files changed, 378 insertions(+), 1 deletions(-)
> > create mode 100755 drivers/bluetooth/hci_ath.c
> >
> > diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> > index 058fbcc..81abeff 100644
> > --- a/drivers/bluetooth/Kconfig
> > +++ b/drivers/bluetooth/Kconfig
> > @@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
> >
> > Say Y here to compile support for HCI BCSP protocol.
> >
> > +config BT_HCIUART_ATH
> > + bool "Atheros AR300x Board support"
> > + depends on BT_HCIUART
> > + help
> > + HCIATH (HCI Atheros) is a serial protocol for communication
> > + between Bluetooth device and host with support for Atheros AR300x
> > + power management feature. This protocol is required for
> > + serial Bluetooth devices that are based on Atheros AR300x chips.
> > +
> > + Say Y here to compile support for Atheros AR300x Chips.
>
> your patch is messed up. Make sure your mailer doesn't mess with tabs
> and whitespaces.

I had issues with our Exchange server for patches but that was only for
receiving patches [1], but that is now fixed. I don't think the SMTP
server should screw with patches on their way out. Suraj, did you
actually intend for the patch to go out as is?

[1] http://bombadil.infradead.org/~mcgrof/MS-exchange-sucks-for-patches/

Luis

2010-03-11 17:15:44

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH] Added support for Atheros AR300x Bluetooth Chip

Hi Suraj,

> Signed-off-by: Suraj <[email protected]>
>
> ---
> drivers/bluetooth/Kconfig | 11 ++
> drivers/bluetooth/Makefile | 1 +
> drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++
> drivers/bluetooth/hci_ldisc.c | 6 +
> drivers/bluetooth/hci_uart.h | 8 +-
> 5 files changed, 378 insertions(+), 1 deletions(-)
> create mode 100755 drivers/bluetooth/hci_ath.c
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 058fbcc..81abeff 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
>
> Say Y here to compile support for HCI BCSP protocol.
>
> +config BT_HCIUART_ATH
> + bool "Atheros AR300x Board support"
> + depends on BT_HCIUART
> + help
> + HCIATH (HCI Atheros) is a serial protocol for communication
> + between Bluetooth device and host with support for Atheros AR300x
> + power management feature. This protocol is required for
> + serial Bluetooth devices that are based on Atheros AR300x chips.
> +
> + Say Y here to compile support for Atheros AR300x Chips.

your patch is messed up. Make sure your mailer doesn't mess with tabs
and whitespaces.

Regards

Marcel



2010-04-27 15:55:55

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [PATCH] patch to request new firmware for AR3011 Chip

On Tue, Apr 27, 2010 at 01:28:42AM -0700, Suraj Sumangala wrote:
>
> Signed-off-by: Vikram Kandukuri <[email protected]>
> ---
> drivers/bluetooth/ath3k.c | 9 ++++++---
> 1 files changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
> index 128cae4..7bda549 100644
> --- a/drivers/bluetooth/ath3k.c
> +++ b/drivers/bluetooth/ath3k.c
> @@ -122,9 +122,12 @@ static int ath3k_probe(struct usb_interface *intf,
>
> data->udev = udev;
>
> - if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
> - kfree(data);
> - return -EIO;
> + if (request_firmware(&firmware, "ath3k-2.fw", &udev->dev) < 0) {
> + BT_DBG("requesting old firmware");
> + if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
> + kfree(data);
> + return -EIO;
> + }
> }
>
> size = max_t(uint, firmware->size, 4096);
>

Looks OK but your subject should be something like:

[PATCH] ath3k: add support for new firmware

And your commit log is empty, other than your subject, please
be a little more descriptive. Describe what are the shiny new bells
and whistles added onto the new firmware. The more description
you can provide, the better.

Luis

2010-04-27 08:28:42

by Suraj Sumangala

[permalink] [raw]
Subject: [PATCH] patch to request new firmware for AR3011 Chip


Signed-off-by: Vikram Kandukuri <[email protected]>
---
drivers/bluetooth/ath3k.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 128cae4..7bda549 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -122,9 +122,12 @@ static int ath3k_probe(struct usb_interface *intf,

data->udev = udev;

- if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
- kfree(data);
- return -EIO;
+ if (request_firmware(&firmware, "ath3k-2.fw", &udev->dev) < 0) {
+ BT_DBG("requesting old firmware");
+ if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
+ kfree(data);
+ return -EIO;
+ }
}

size = max_t(uint, firmware->size, 4096);
--
1.7.0




2010-04-27 06:19:50

by Suraj Sumangala

[permalink] [raw]
Subject: [PATCH] New Firmware for Atheros bluetooth chipset AR3011



Signed-off-by: Vikram Kandukuri <[email protected]>
Signed-off-by: Jothi Kumar <[email protected]>
---
WHENCE | 9 +++++++++
ath3k-2.fw | Bin 0 -> 246804 bytes
2 files changed, 9 insertions(+), 0 deletions(-)
create mode 100644 ath3k-2.fw

diff --git a/WHENCE b/WHENCE
index 39ff025..ab7b390 100644
--- a/WHENCE
+++ b/WHENCE
@@ -1229,3 +1229,12 @@ Licence: Redistributable, provided by Realtek in their driver
source download.

--------------------------------------------------------------------------
+
+Driver: DFU Driver for Atheros bluetooth chipset AR3011
+
+File: ath3k-2.fw
+Info: v2.0
+
+Licence: Redistributable. See LICENCE.atheros_firmware for details
+
+--------------------------------------------------------------------------
diff --git a/ath3k-2.fw b/ath3k-2.fw
new file mode 100644
index 0000000000000000000000000000000000000000..3fa8cff36301a7005936d54a407d6879923aa354
GIT binary patch
literal 246804
zcmeFZdstIfx-h<Pxi26AjADW&fgm7Y09&oqGfAWfqAg&h)~Tn28miWIsK?Q2ooR?I
z2Bk9)+YziiXOkKQDkG*Hiy}3|7C~VK>BUP+i<zcXt2R=vsO;}uJ7_!e%$e_;=X-vC
zeBbZzuy1Rx^{#il>%FhFLlF5yHCas%AJGK<yTgeH;^SQTXStd{uHjlPF_ka=@0~uD
z$Ul>40usYD3Gu*xuPI-<JC`^ik)O`hoX<7f$~D?@^Q&`<+1#?0{~|iw&{(25FDW}A
zG2D_EH%aohNs4z%%0BonqSMRwKai`rlxw(~Yc%HO=jRp|=a!Y_+HASi)wwL2+w#wF
z>6OR_B$`W-7U=)3#F!_^|D~k(IZ4^e65AF@^;;75T}eyZe-RfTh>#?RYGx~;;5Zg;
z|L5<2DDeLr1vLE@mii~7itMOPGCfp~zC@@wN9S4$8SHfW$rss>()uUu@GGN<$R6ST
zH<kWxfBi`mIZw#`r=y7MIMuD~cudHme^7;5L=bQ+6M`LptAP&P<EvP_h^Q4+^H+Rd
zhW^j)f8P6#h%!Wya&nL)jrg9|ZKMR)fFg;(3<*OJG`u53f^u3;kRpMdGU5w`FA|0%
zsL<Pu&=87ge1T%}ez7D}3>PS-?iVXU#c+XQ`hIats2DC#%-k>5hKk_=#e)0A>7in{
z+#k|Jpj{#yQ{Z?Ij#+SI!!aL@$KhB4$5J?+gJU%uFT-JnV+$NkIO^bV!O;ju3mgaF
z@WOHL5BDU8gOVTurjf*5llTwH@bM6wxHKJ6CZ-65fgqR&nm7j%a`0asg17%~{c!^R
zkK;I_2LCYv#poYN#K2HFft(^K65i+MQ#4I60*+HCX!s+EjGvJL)9tI_pH1S=-aVK$
zH7z|Y^JgW0duw><q0zs;Ex-2!T>LkGBrr7oiy6HNMz5jL&>Z3>5d;a$jju7IR{?(w
zCn)}UuNhW;xL(TWHFfkFIeG<8j(;zJEB+%13BeGL@b|1`0e}6!`K0+f<Vlhn2^*<>
zW!*;d?<gOt7#95DLmAwL<HrdGf|?{IXt9`KgknZ8VH_c#ZxTWZ<a*pVLPU#6u>cVg
zIHW*28MA>vaA3fOUx(<*K28$&05x@Rx;JEsKqw=}zht!8KupC{P{20`c0nD2fZmAT
zBJpoY^0#mU|Ib){TT=Ynl`DSB5TE{dbGDWkB!p1!G8|Roy~Ge)qcvXQI$X)xSBYVK
zb-YQ8z|}<TBCx$QQ64z|^FLbjg<z|KAZ)KrAflu#qJJf&*^4NlG(V=FSVZ-Sru~!V
z%>RdWlZAe5aX;y|e}cyUy!!ts1s*hk*jc`%gbd+rHn<)kR9Utx(wLK;@V-9z@fEMm
z_{fI{yO`(~5H<&CbEGSm-SyNH$C_DowSME2&LJ)~2ryp!mI{_Ayrl~CGe|m{j?^Tk
zCwSu5+gJEz6atK69|0_YI0`H0?y+Wo=Kk#z;g0|a<^W(7d`BUs{v4IT%AIG(HSbLD
z2#Dm>sw~yQ5)ol*BU@V2w^uZkwk+FPA|y)Y5ck@>c>ceIgZyuCu&((DhjIc*+DUo3
z#?H#uG=v}Q-tKZq3D-PARaafTy0AlDLX&2i0L+VbRtHv1fg6{Zn7d2AYRcqHmzkWb
zdt&PsJY80?@0GB-3)wf#>_!(wc-Zp?oA7{t#kZMF^i!mt4Gaz#`e&0ait@2vA8QIc
zKgBhh@=&yo?eMl4JhN#R#XzI=P5PDahVf8>Vq7e6Q9>wQ+~i&X#lj&<1W!iJFf?1#
zPl^5Pc^<6TMM->Y;8>G&S*TA*KPC0EU-K`eE=mTy9BXoy0tlIhLS+~-a#3LbYekdZ
z3dLa_Dm)(-hr6f<D4yHoeg=vo?$I4F%?x_ZS~5kImAo0I*FKw2WtP5wKJ>nv$e>6w
zMU_wyb_zKunTrwwKp(~9K?#N^;gCt_H;MX9VxLLkF-ct}!f7JyCaT0ln@voHNuZ|9
z6kS3wc1q-=z=aEQnPg5AvYWz6OyOoz1Y({CJ_(;|U-5XMfGErXCN>&Z-^WkTENG{C
z8TV&gGZi?^g`NUm!jttZF1iLM_aL0~_)d@S+*jdb{hC7(wYczOGCzMc@WJ-?LVS=H
z;)BxHcA?D}aNsYTTD+z~0=TJkPCR;k?vb!GLD)>S)9!ArSqK#c)?R=bI5GMZ_!RdB
z_)zXk_;d<C;=8~}I9V^^(@7o!RcUcCkHGtXi$KNOJOYBi(Vrub1;Y=G-9jL#TKqO$
zr$CZ54M=sY$>Wg`UUqf$TLvUk(=T42)M}?$jwE&Df%I;zLs6Z-y4vbp@!b0C&85u(
zwMxHeijN`KveoNXxkQ-Zfjwu#M5`8V*y742>>@%{YI`%j&!K2>$g3S1`yAqltsmEt
z0J&G<>Xz?5K=w+ZL$%7fV2Ubp!|%JawPb5L+qe2mzvsAIRp$yLWIb#kzOP9UY?2Q)
zX<YM(qC3|^_-iRwy~g@#bi1^XM3RyY`A~<!-;v+nQHJTQ8?HRlxZMZZ#5b4l<q#_>
zx4(0t8w+aAeOYyNl(~Q4Tpjscq^IK*&v8ZID|j+^I?D8&a8uSwV%jtOyLA00oU=pj
zW91ngujt_4r!XJUuGtd-f@_z+oU;yt-3(K#JEF)qlJ28{6GJ3%XTaD%1E_R!oZqSE
zJ3C%+bt|0R1#6lm9x0(}^5jD6Uco7hgX_4$bG$(R71vA#R!5JHlZ0^wejV-UkT;Ue
zwEGx`q!}HCp$<8W7Fp3<UJp%3J~(6Z@G(5z90KO?!m*R%6Fi`lnruxZ+mH^Ugy9Tw
zy^O0v?&&a`BHh49r27Tv1?0ElDt0v<G~vEp7uqecffu6HVeQfb<eXWI$1<TOYs0n9
zu>=7mShG{&5)i6|E{r!)uIiAZcb|K_(4w9*nMA_kC0nn*uUP+v@ni3rJrX|+{O;!~
z(&i3%Gu<w5Yk?f=hle7FA<T=V@16H(ClqScYH{(RttiagVaR}Cacaq$M%9c<b6-zx
zhDo~-oAS2Q^(f&4=^d~QkbS4pb=p`MiTe|-mx8f{Msy5DWVOJE*f$N$60jP0Ogx_i
zEdOVGqVN4VpI8r#@`?MM5TEFebBF@QfSGTm&~a<j6qRo7sJhEILY8{Y0pVPK$2(2`
zd)^6z|95%EdJt%!FBs(=6H&+#29s&c8{_l;&AZrHA|ckVT6NT>S_n$ZE_%hD3pVnV
z5TBJ3uTyU`bp@3sWu~~91QmeXs|^hWyT<<-Q5)Vsf@P+@Rf-iQb|H~}()+}s2Mhz=
zIjK|7mP_Qz&EMZ;hu;hSxO({Vd5fE#!g^QNTF}cN7~bPvLTyB9VoyB_8UR>fp=}|V
zzbL)*wLduuRHI(Nq}u;TG|6i;peJ1tU@Kl+cs)5QxMpXBnIZ}?C*@}u%vg{x!Vi`c
za*M{v5^LOw6$g?Vv1nu6YpWxxYtvEKt}!!JfH+#;_px_IJ4i%dk7D;P$2VQ{|M}*3
zuE;^n>H*O`UV0++WQB~7jfzUC^z+V}9B!N~Bv3eTS+79zp|_=FHC6{8rtoaN&V6YH
zA@8~KHo3+v>BmU-hjeSZpqFkYWo`Y4@MHN__3TnnCnsF$8}aU%*ay%sW%W-RnrSRd
zZiyXN!i1?qXxEtEp>VX``<ZveA&l|>psYSKJoJ~FH~ttM99-QiLhDsMwjR>kmHtG^
z$?Q{{Y}mFJ%lFz}eVTof=l6Qzd8VCeCVK_1)0H*)Tm#=_uORS*Vb_?&h(R<8TVDP=
zji{GujIVh&uLXW^ie8!Y<T%`>Z$BQW{%hcCc{@A@zT*ajs#2A%)P5RKs;n)UhG#TS
zym7>=6^GFG;i3CNLkIt?nNrKZSoPBCuzlZC&6GD@anPd=aLsftz3(EW4m;?<CY4sp
z^q+&wz#Lm3MUzV^|4nGPVnX2??jp7F7lK4`6-x~2Y$X)2=0D8DSYz32uPlq$QD1Fa
zO+*`Q`{jTo@YHUhz*ee(xUsL&V6&~ZmCD)b)qR@{s<mZht8qbvyt-7=vTS1s@Xh7H
z!PVbwW%)iagQF^UwgEeHX!@Flh=bkLF0V^Ux#p3)C)Z4>XQmwQC&34^4Gzfr4sAtM
z9&m^!gQ0$#)Lx>{W6ji>y%8P>!B1fe7yvwr&164&$8?$Uk#sxL*CR)-`%Ltf4lw9`
zQa0%YaXYi69#vWUxrgi9YETt=dd=Q&003ZAbq5{xxxfw06qbcO5q=5LkGTW8V<FIJ
zi`xg(1C*<*lMOJ4ErIXv`^L&$43Yo=RlSt=_|`RlcxV}umsNHCH(}nFx9)Hz2*>X*
zBgy*G20`A!9l8~pE9qxjqu-Ww(nL||2#NuoXTSBHr@wpfLSAMz0bXvZ1OyG{v`3F8
z3Q3Clt`&Q)u6c9LA|}81YH_nYKmS_(A$##kd;Svp_R?+pN!7x<td{C)Ey1fzT-B<V
z=oQbd#f8PTtJ~i!9=tYuc`$fwxQ@82xZtRy^D=P<4_Zhh-4z|lKJGQV#@bJD_QYSP
zntF2PY`+La$_K)MQ>DR26nRdkWrF5?*7L=P>$z7Nsa^Vs?Go9q^PcGy4v74pbN;kn
zSg&z*?F8EmwlQLh!)}?7VbPi`6Ll617^htiJc6jaY?pR|Q>*@sbe6=~J+ef?*0ne-
zv1oj|sFxWKoD=G=aI%GYrFmIf)+WE_(@v0OdfP%h{??_9ovhovtshKPhE|Kl>$DoP
zb|N@#)Bt7tMx#H+$@gj2xF?;0arF&e>+8GP*J~dfun%6g_w6-ZXbKLHXL`D2Cl8UT
zrbgA4Hrx`8A0RI=)^G3(0-c|y?7kj!G^ewq^G?s>vbCH3@Z*LX38KtDh-l4P*6F*0
z#Ol{(B%-+`lL&hkv+C%bHBDiJz*zY4&El3C57vz8*U;P<iQBe)8Pe${VhN3wq18yZ
z{F601ndKiBetc(5gVsqw)IfMBGULb{qD=uF0t6lum8Y|{DGt^()zv-2>s}-%@%2sj
z^=y4ML!?@$^W72N;gBz1=jHV;mUSeXInNqtK;p{&`(@S<4vnh>hT-EiBwAGxwqvQL
zM6>1%(ITMDlft~xSt8@q_d0P<Jxhc-r#%?1iDS_zgTuR~mR<*F+=u19!F@Yk=%7&K
zv~i%YVuL(hxL^GUmnt2t2UJ^j<Ru>r=Gko$Ky#Dx2cBUg*FH#Z7{ZNs-v;n)r}cNa
z+WxB3j!#%kag{hWSe1lp)P8~@tCKg5!W&?E>2?Z9(O2MXjh5AZ+VGh&L)6oV#vut?
zyO9rNQRLgwYUkDpl0cDA>fBg$3-b~16OFzKbaF|b#0Hxg@OiFrpErT;2Bv`t+~Ux9
z6jS%fAsvcA6q~fM;u_bpy_p7DR=Mv^ffk@Qz{1=BKMzTS*SI3dFj7HBZ*A>7dtcV?
z;RuF^*Jp1tNVw;(b>yC%=;SFf|4mcAEvr&{(Z7L1#|A4EIV3t%-Q%@oc^%rEkBD(b
zBCB2~AsS9sZEmIm7dWJ1pWC<`&_xrQg*l|E+nCGdFof7>G}a70tuP#9`@UprwJG9i
zhqqEuWk(a%rpQn@9{D&F?mhRO@<XOJ>`OlqpHn2I6XC{l+G<S=F~K;PxN)wI$gNM3
zC8i5SL{fU90)-Qi#zZYqSx-<#&F?nO%}Gqpl~o&Sn)WUpIQEytZQ0*(wPdcWX)kmO
zU8&b5%Mc26h1jn5lpC%#?OiTg+$O{Z59EfQt??)poOz%{2hmLHKjoH4KVJbe4sl&<
zaGH~uPl8IDPc<{vPq}tl^)cMEa=^ErPKp)-UobPPte*qz0bU2;=vOWiHB%nnH|Wn0
z{q%Poa~-?W^OWrJ2it!{|JqDx9%T{Qa1BkI{JZ`?-_H2+T}>vd8DQ5m%shDzA(=zE
zXWo}zY`9$^B2I2+HheF<%}s;r7s6XyyI}YGU$;k8T<5%PUW9C0yp__trcG^RZ^W#i
z>QSt9KiakQiNU1`%{OeJFS<4y$qse<SmDq|!x<ml!ToS-a4*<~xKmQ3J~(h%`oSy`
zp>}j*JT+}Qa)iGvKI5pAZfhk~ZFx-x!aGSqmIdm>|K~g3J<zgiYJ_GdyTwy0g#ndH
zCVsH}YBRa-2MVpUehdL+I|+X5A2wq-p?XR8X`b1DzL?jLw4H(yh(9m!#hC8xG)SU4
zaQAQOjc=#)e2Ds!UE<qAx%)V7fBt^^UIs&ezzU}694;M&8Tc!dSic*scNUgzroAEI
zh1btzCliyRs7Y^-sW=w;6ZgCnX7W$mZ=?WuKc}it){0fzl)2*H(9er+esb>9UdaG+
z`ijpY4_@}7iGx3EJ>S2r72&rf7Wuj>zhR!2;Gy-3&RrQ0o(tF4aD^5{(pk+P*deXF
zQL=wZQqGkn631DcR-QLq2JR}Gr^E8yD}w6L`rmPRS$Ua_WAYYG+WKAM*+Q*i(iky#
zUjpE#eN&nR`Y-r#m4iQK!gOwD+<yfAb9GFI3VWxtLo`+f)NclN>lN3rq`<qO8;iaP
zZl)uZdoOqA46dUJ{E@peqxG!l`z7$AUFz=ReA;Bu%5XHkHx#`l4ak5HAvo~<&m2^K
zu0LBw@PPF1a#a_ashL#}WqOV$xpz+y(lF7Z&ldNtDM0c*K-Q;Ki!P=@m+eyPF|J=b
zUG)4<eOLx$`n{tl!uu}H1GS$!0X;y_Y~9WM;UMYjC<`I@C(Z|B>Pc#s`g$yZ_c`Hl
zD45Oz4!jq7XTk51^zU)Pk2sinm#<9k8ddAWgCqqLJi?iMWmSut8GRk#)=ZWhDQg$H
z2QYD94oLkOxGUrDzTjQ+>CinSZ}4j}@EPanm<~>@6hd7n=@k|pncgl4oZ(~o>48r`
z97E)?p5o`E3=jr<0;f2X!sDs$!|iZB0Marb9sm)`hOc8fC>Z_?Ps>knKWJtMR-k9J
zO)pO7w3E1FDTJvm9{>XMa1Q_%s~SAUIa_)41C9q){Gh?A!24@wd~AdDb!-b5>*Y`p
zB>WomRZ!&m2)F?lPq{wq9zFOj!CMzXnA*!UlQ8`~obMwbHgHPdIC$f@EYQUP0r;|B
zfxZjJiCefGQYdh5=9C9{Ja{>57s5>Rk}$oP3Z%Oe#s|-%<Ld-)Jaw#{Jju(fhk+_E
zHvLCDb)X@*s63hQSgjp=gbwT!@ZM(taAJE$X%FQcA>xdZ-})ht0uTtS<B9Yj$PNV=
zk*Z`Ai8%n&NIO8p1A>}>yvJ9@$Kz#yLZA(!3WdE=C~JqzKv}Q!ULh7R_xpeYRKWM`
zQvH6+hZq!|_Wj(xAc!dc(qdhWU-85O_H}=NQO6a5Sv@{XME##a3};=>p;)lvso*_e
z+d~4wwlgr+UNXZs9c(!b+|IZ3jFKk+H&6_8f*Z!Ya+DY9u|iwMl}Z^T$QBVuW;ny1
z3Ts)cxN%q7afMQ~c{@x;!)~-J^cH@s`F4y1NaTK&520X``e(UaW6Vei=~j$n4~M#p
zfAY%OTHM;*4G<M%3y7A!EW>uTRzk!YiOza&ogAsFcWkX%H%iNsoGNS1n_kT3z-eyl
zl!|j4mO*%S{}R)A-w+TdP{Qr|5w5z9GMJSTD94nv7UK#~@ke|Oe8cr5V+Rc1U*_M?
z`a(Q-#$CYSSsaC{F9JfqthpER5?Q8Scn==mp>>ekgSivT5)TD3t|4wc&%+c1=JCLA
zPa*$qRHkUi2%osSgetV;m_K^O{E>ADwdS4p62TO^Aa#`>g>WcrYf0N$ja`tIx6lSp
zrJAx*P07+td0Dy>BRXHa&N8n=w{Degy<PXRQ@6pT`;ABUTc7Tgex1#)D<9I?GjtVZ
z-D`!qR|_qVnJtfISmw{9&APRPx|ejijceYiHd_iyECo7CzI?VZL;I-R^7!kLx24T8
zLtJ?~>J5{djD}~*HKhi**_i)GIWfnWuP-<14EeK7a5ifT3oV7oS%zd2RMBY*Ry;ot
zz6yg|pwrG@rG4yD#E>?BiRd?Up(VdiyI_^&u~}4x<<V8zc`M>ev<1*!XPK{ic9Tw<
zpSO0EW!@_7<Cd$`hLL%6zcy#piMy+gzOw45bx~MXYU`|=`3*~IpLhJmZkgk>WV<Yn
zm@Qcz%WR*;Txc=&r;_~^)0%fS5qU=A)p8=+X#A!;c-bI_U3pW>2Qv-Ce2n=FN8e02
z0YkY~uHg*wY-4_)JQ2KnsM&YN5WFT2W*Usc@(Y<8Mh3qz44wy5Y`EaKD;=`T^-tQA
zxAtz>1>GfPv+i|?-;#GpV7KJ*)MAqJ+L6by5L0YGFr!eXU6`TGvuksl+N^%9(WRa3
z)0#Y5^M#(_w&bS819R)@a!!jIryoe{9_Q1}^=Kj3%k9@b;?&NWF>rbjqMPcDwH;Vi
z_tHZRm{GvqETNR~!m6RFPwYC#+p4Q-QHIW{1|Jw$w5WuuzedTj5*VXXufEfG&W$9h
zk;Rv9x%+9N|Iw7L*Se)!4jp*yXd808sd7}l*)ttNXpVDQ)jgH9?$Xmtvj7tGs?3T@
zyo}=hdNNS75E1*X!xC1mJ=dA*GMA{#CF<!fFM4j-FJH=YJX|}uLDd*pr>o3ZXI@_T
zWXVITT4e{QR0a@+_VX#FU!r_Z0=O1sNbK>d&Uj+(X4Uq(ot~VOhMl|hVXA`%cFt|m
z&BagdD~>n1UiD=?XU}@p#$NNDGI<BDd2jyOR%^1g{@RnZ)R|Q}l(o#CwY)!Tg)7Sn
zrlyC3Fe28+8rSS$bh#<2x};Z=-soSdf`yJPDdB7W7+XE0t+qu&Lf^=-s=AvI;J`wR
z5DeA~;f0M*&;_(Rbq7%%*4D6d=C60_sqD|Wx!YC8x_5eV0k3b*gv~vpx^RA{ZazHi
zI&-C&34Fv={Dse5kyMWkQ-7Xdjyt89bYJ9(&Oj~_lqCaNrD#0dga4vx)BnH~%@u)K
zQxho+<Xu&nZ^QD~Qy%s~ULk4M>>P_z&vh-A4St+ZfjLuUdT|!z-;l)k#(UqMj;X%p
z4b^RGOs-qASK`6-e7UP3fkQ#Qs^?5IH4pL5lGZvfYJK<t#wZ(a@|h8yheG&*Zo?>^
z`6(v-sT{)li;KZK{hIp{959b>^*p3M#eJEK+oT|HO?uYj+rZhMb%OO-2V~#cL7lrV
z<H}(7dg;JTT$yYaLJ%3Uhau(nU^$5^sH^nSDXxxj9^W{1l~ppu=YtH<OqDv!-|@;2
zl|N)Ms4lyQaq<lhOx0!;fjhys#VwFk2#w_)Um_%a1#qhYLx<)C7`To1_-2Beif@xW
zJ~LVgIbLixX3EsB18~)4J)hGHfeny2kopO3fPiKpxO#kx;X-d*8eVJh<)E2?5xC9t
z`0~(7J-&U&<12vP?xyiw+#c-$Ov!!B-M7<t83x~gAGdoLnuW$4xD|qHfG%#Od3;7!
zhY<#J6G~rEHMx&+^U1=F{HLgS!d~H|2gzQrO8lF^hn&vm?G>6oGCnai;5mWa9aU4i
z47?yT4<4Ikp5to$)iem0Zcx4xq#u!x;e}KdEJs`z@FU8HXd5K9dd~C&{xS)N^Js&c
zn9@vI_ohKQ97)ixJSRBM@t4=^m2dxK`<|wEA<Zp)1y;0R)!0cBh}w~)(XrLKYMrmo
zNt3F~qVpp-AO!OUvR`nM$`IhtNB7A6HEq)^3XPdX86Mc0k;NB6y^di@(;w_YEdz=(
zJtuAhR<V6OY!@19jjq1~Y{u@9yLY6rao*&3jpiyiR0x(J-%9Nq=H;)0C}vl;(;CC-
z{c%)<p3vT<3`bZ^59?Di{q=;`#wf>$SDB_3no`WBM2{&x!=!PU3@1@p(HS9X?k^D6
zk3e$9$G)V$l4kstMoC87)J;j0v4lvWGdeUGG+}s$)ikj#X}EhQ1nMZvL&p2aL_3)>
zL>in5aUEHwxD-*T)o(|x0!hyba1h9;)=!b~+bFq)=w);Y$Qh!H*r04!{iym<@T-lG
z6al|$03&@pE*xXLk<~a@`#45)j>a_s-x8A{gmQlfWuJpb(*5m!h9rPUWL;Fabvq#G
zArpOMN<V4vlT(MtV!L8$A-U42$fzTq)K)62zXwdkAmUK3%uhw17^a5E_#w0MRM_C<
zU<<IsKv(L#@WCEUcWU71=s@nmKp^`R@>?=kZd#<W{4S+2v$iZ&7tNqtQHh}1sc}Az
zRX^7K&9qfP;EWf4?;d-PFPdq6%)N38M|m}bIpMVpf&46aX(WTj*|IdasPwgaeIa21
zNtaVJE=_zjouHwnVX8(mdn+zk_Uiq5;umSUp08Ju{3;q#Rw~ag(rB!>n(YmRj~xlV
zr|`DPI~clUzXrU?mO71d1vCfzpo&QV^YM7b((?Q8L>VrkK*0B_x0N(=#Xs-YYP(l2
z#j$BCxo2w4ZE7EIvM<;wYw1xOYwHlw4U?TQG2SLk<K%7cG0k+~4Z*!ODCUHSMuJsg
zM8|DPHSPLFLkUVmFPF7>*T1H6;AB^0{j-}RinnW=^Ahc5!akp;o@(I-Zw^2f5*r*O
zP(I5+E7fbb`jhp~z9uVnYg~Nw>>s%$;<dGZg;ZQ<zIM2-+sAFV4p}VIZIHkWCXrZJ
zU%b$epDEACN(8Kc2B80e_0Sm0Z3^n?gt*Ei0gYU-LCtF#dv@ZeT%$2CR5Y$clJrE8
zP_?l1ksIid{g2QXr*w*z{hAnKBpT}3T^d(z5-fwfD5i;=`a(0Nad8$|mL=E4+2P)(
z)99YDkHQ4}%zuMl($DZq3gOpGxnGiv);CFLUHo_yWzcD$Pu<e-08sZ#6U?Or=YmKy
z)6Q~s6Jh5!UIg9=>E3_z&Rv%_n$!%<O+ENnbDj~rD5Wb1;zb#VJBp|w=zWN;4}&q5
z>?G7;6ptSDfo}O&J{XW2ACcQ$lNVd%#U)#9_N}a2-ts4T^_z0YvbK1(vaYR_<Z^{^
zXyai2#?zKt1xSd(O%Zf?INg|jKwD=5Eh}@m2xtaS0G8LY@xY5l|3+KMM##?AmBToe
z*C3&e<*pxz>5$VoHQpnj9Ba#AXLc%`4I7{1wrVu1*FOk~N>#ck@>FLeVT{|FJ<L_d
zZG{Drh8J15UgugZEpWZcbrpEwI>ena^}#jB-AoU{^)i>Eg;t#xxmpEocY$jlal3mt
zF2uYDyj>X7D(IGlisL1qIVb`)cQ`~U-D1b)S6w-Ys;p<7-`(SHOC*gxc%1@cAX{q|
z60*{1Z(P$3Q?{I7BGr<mn5#>kq@zapPGgD|l|&{)>k{JQcD$M}Rmrm<a9u+5)r9zK
zRnetWFCss1<`5iaI6NVKKo4kUM<+y!65^*K2AiGus*g1K=!D1#3A)Ux!h{T7l_tc?
zN<O-){xMZh90&2P8UU5Xi`4*Uz5tfno$$_)DyU9`cTm*>j|Wo)EjY2Rc7^&WzfGmX
z;GMyiI>mI_F21-uQ|3_KWYEL4aV|PWbY8{QM2l9KWR1#Uv9EhXc~PufF6!^TdvR8U
zieR@!C&Y*nk{$uq4{%JX>So>13F9A5NY2}FCSisOJq(W4Mb0%_4+z8zB_tJ9#gsmD
z0ezo+iz`iH)Zb^{;D);Isz-t!ZiFolu=sVEFVD-q!nvT_!M1L!z(o@EyA>BXbUXWd
z4*FIf>N~U%;$f5rscF<E{FX!Sc7DTQIX4YcNcrMzJe@F?IZVl%i;J@|vY`Kvu7LOO
zDu;oWe0fGz0<R;1Q&Ih03MCdm1#@t^04CCyY0HR$y(`hM$Z2!1EN{eAb)sdYs%KUZ
zHp<jQ(fgw5>aCiVI(c>VRraB+yyplBEy{X<J28fC74#jE&uwd%d~%1rLrL@6^2AvB
zN(?<MEcWa;day~}IC)xxs%AW0y<J{6IX2j#f?9G|f;ge3`<gTrH@KQuc&7>F)-8m_
zxEiEoQgnVs0cD2OPYKG&D}S3rkWjAy%)!JbYrw=OQ<@T@R$_+r0C;a7M;LboTbdM2
zb<K?ZNpT>E6CF`vNaKAZ)9{wOnZo>FAq>XVntZ;CF=o6}VjU45+FWQN0C>JTSS#Uy
zm~&&A1^O>J++B*MW$FhhxH}|mCS4>E_;3{D0D$Cm7WRRRs{vbsX0`Ftd(Kd8N@?T_
zq-r^!IgkRe&Pfi8g%25fW<mfW5&uKb`U5`$z2W<o1M=)3Zv!mES?GgZ?c)1jhlA(B
zTR6q=<x^>;kx|Xzc>Ts+PuO19RHnHfrD6M|XYVV{KXTP?gPD}qrRgp7Kkm=-v;IQ-
z(@xb-pwS-pJgjtq-;e~1_m|j=mL%4vN(M_6%NgfF@cve@+}g-T(gCfK;B>mBRIwt{
zMGGwx={>_G3yBOmcE^H*sHB9rDW#bztltxN4%!u!Og4>8i7T;wuu0K~Az_<<tq)(v
zC4`j<T=|_&yqN~(3w#xruW4`ct8wKpN!B3rwMdM_D;7RU=EDTV=NqO@i>LBSV0$#i
zGm$Kbuh&tr7*)j~dqU*H3A(J(3<HK6zjIKhsMo;4SduoM=Zi$ebgjm2GB{0!jBhl$
zZwxxG#_)|s^G$3pRR|)>w{k(NiYuY}cR*f&E?~Iel{v1y;5HS^QsfG7#W=TFkfd8E
z9=kLO9-VQnV4b3F4BXn|cG(w7Ch^6dxOakWiUWEmcE#;>EtF2<i~Hkt1_u<UAAn+C
zT!U|+EX1$o0_Guw4(36Ka!@4_EFrhl<dr{97Gr0(n0I!IONc^}XcoAya~)c`Tt}a{
zP5Bkfm0@bb`BnvRHSlzGoBU>k>M~^cBVwyB%ln$x2I=77RrU+7Z9snVkgBE0JGqHv
zuYNZ}R?O3-U6^8ri3wvbd;L#~+6Cn#-8BUrwDrilr>N)Y3r4HGE#z&wg}^AnR*zZa
zeA0+fyYGi*0BSVoNOTY!|3$JdkHI7wwgw$yP{`XIcCoN@krb9M52|;dFn69T<aa|_
zU{qcUK;H>5a50j#ldto@la19=w<TjI|9P^6B<v)y2zF&)zF4s^V~hw1t2WjXbgiDP
z)70rh0NZ(hz)uLan{t}q)qQbv@QSHbHW0q&Wsu)4#BRqXV*3ueL|8gK%r05i^U`;*
zG&WZQQWcP9_3pR6`0i~Q>3}NIeG_Sr=Ai-ti`5j(;MDJ?U=7i)Ao`z*^gN}2U<?Jy
zM}><Y3YH}cMZ@617L5*GCyp(Mr<HalA@WhDZ$w!sEX|k+^RG+T8C<1M#xn`g`3do0
zK^3mVlvU#%uhG%$TDE$vyn-fDC_`p-FjKMX2$@PJuT@RT*U3Xdlu+OK1J9}nF31Jx
z*y2#dNpYuAX>cJ7aV_9r^1ZxM5#VjgJ==kH+Sy_7SIx6Qz5!owhudk8@Rk%s11twr
zB{v;wQlo%0?Hrv9swX8PIG{N_swbN1eK559{xj4*)&|>-#P@tR^ccK{d3;Ebt3?7>
zY5v`ov(4lZUV>Bey;F~-VhINI+A3p@1$iI5c5>d8YCW?j@|5<R0{wo&25+}KSf?4>
zu~CgyjzC_|+pX#Q^TzJU0jn$|%md(}KUhx`7KE1+$k)}>3{yt-s-|ysze(Pxa224w
z*MkPl)g-O1K$@<nUy`&q6r0zsBSj_1x9e3{B|Cmj|7b#kqER8bKsPFSj@2j7zFn_*
zj$L)ngW{Xo-M^6S(?d~(>v+61F9B<xq<mfm0e3Z}>yYax@L=^Ha(JFI@H}TKW&o2P
z&Z!YCqm)-+mDl=XSP9GZE5cpxa5qVhLh4kYI>iC4=jnycryoB#gKQ3SJzeBd$S(<Z
zKS*AZ`k#KH<S}onqD$LP=7YB(=Gvvu#rd#9(Lm8w*^D-q>@ZS;={+$_x$+L53Y#(D
z3p<R`AOQ5uKO8vEglKa~fcdbQLSN{^$)8$6U<LLV%*=!3#6tx-lU&WH#p+xnC@g@@
zm(lhP`F!!;j?>H#V8Qm{-2%Yn?gg@RAai`Mp`b;lC>=kcmQJp-OAe#){Pw%UfwQCi
zHw$zMU@O?2{jgq0Vh-vLKRm?V4GzfrA3fYfqs_@Z9(1^$9qDV6d*&U6HH|ScR{@cb
z3_H5@gJJrCQ9ySE;OK&Fs3%~O3r%XXX<P_#5k_3SS$#YO`5@`jp@tMqXb8U%+hD4a
zZM@pBl@O~$M5Urx1iLA<I@-nFC?UsXunnLF%AN@3Al`MFF?D|eRS^fvBA%?an`klT
zk2vhC-^gB;`yV@e3f14H77z4?#oBlJ*-O>_31W6WJLvFkYYj(v_MK;)d+N9U`?l#M
znp`dcr}G8y#~jt0vou-qW)Y|&<c}h1;|9pVI<E%obDTRlOgVSN5jPY?Z00na{8n61
zsknZaf>5nNS}R%HR9$0ouE^|6Axg5^JW+&SA>Z)BsR9?N2I}qJPc{o(vm<kme}VX1
z+~Tak0q@y6lm_(rhedsCv8G9`e>ufNM-s;rUT?Z@f%NFRNVZ2`mZCb-2ePq1dS#fh
zGlx+n-ZGta_+|t@*c7qtvIfSAl0B|)Salz#I5c<FT(N$FLMS7e!}M!X{B$Jn5jGGD
zq&@~_?gs2W^JN`wg{>06lkoWfa29anbVZ0&0tT6Zw=H*hWB!xBYRCR6h+>wGi7lY$
z9$hNUtFjV(eGqi|?1V^Vf=-=~0j8PIL77gWiTCo^B)-4}$t3>for;^Go1NL$c^eHv
z2(B)TW0p*C4s>)Zn!STch*T%&bfp<$Xk?Dx2~ik-Q*WGPHH<1zbG)nKHil)6e+OK7
z(1j*|b>FWBBmq@ZJiSMk5Sf&qn^Ky=$FTaH1zH-T7w0wV<dYsC!B&9K@yOL@k0N)^
z$I*}aIA9k5wmrB^h-px&6HX|N8ecw%wvS7YIbciSCQmf17GzJrkdQq#sI+r39qjQy
ztM2J-s9XaeRs|PHTGlGo>r10%xyB`AP!nXl-Fk2GjQ2g}2~d<Mku|N?!3);7dfNL6
zmwCc;iFsVY`b-)AL?MHoFzpRB23r~z1C{p7o;FpD=nV6OMUwRk3k4H)Jb-a<0$z1a
z^8~OZ#!N3b@E9pRXJlu&O_56ATa72!AZ>xYT}>|O1owI|&Lge#@iv98lltX?zprI|
ziLX@}rKq1oyT&K*s0Y^EZ#o+L{4@s{Szp~7e*sUwMFLE}g*rhr^s(Qp-xR6SPNECn
zl;|irf4VmG`H#)1*ye`qU*6DTXnrz$(Y8#*6YmT`HF%}-U4&7=oX@AUpxUP5s29|@
zPUn<p5=Y_iV}YE;HzGbqW+9SbS0VOLkTjJvV7p-8?Si3%fCw~^L@}DAt-72k)~7gk
zH8Uy?oHQg4y}<5xd<Ahdq8AB(9d=wRNg&Ly*Z9q7)#HYZK~*LmTLpMa2E%IGBO7rr
z${01PaXYNHp@}+N&48&>&+~OegT3o(51KpVmzV}2KM#$(q5a8NffCn&9~AFZQj+PU
zlNKe!2<+V>MTt0OD&+RvrskQ?CejX}adi;$lw(L7cP>rC*>&Qv!<R$E1Fp;&>y#N2
z3oa(PBB@%Lj}n5SO71z<<eV#ZMp6#=yhdoNT$<d}RA<kXGzix>xso-l(mPwW{JEKF
zoiG6AE3iYb=RyN~kix%nzo8e3iNpew2ejR!hX9QVXoMjH_PPLv3GI~Csdv(2L))%P
zW5QjusC2v-jaR<~#^?g<&Ov#4mIyUz=WQPFCZ>^^f%sP~(F9kkAN6-c51Hh_uUXhr
zoGM`l*t~($yla_a<fA=sEu9jcLP=hwhp9fmvhT94@k|O5t(bLm^Ndpk^Kz~v(fbnV
z2C{XsPa5H$$k=-9s>{dPe8;0(RsN@$)`wkEY2bIT1J6}Jg`7~G0>meDJHX(<0A7&%
z<|AG_6;3g5G7caGd^X*Qgb5Fc6LJOq?%PFQ2@e$1B+@Pvrxu&RN@tgJM5`Gv&-3Pa
zo9wko^Tn`@^6#Po-csuy;2H#ApTRmO1NpV5q|*y7zTV7qkppzA+Sj9Lea`)=V8_7*
zK|9S?ux`*pkk%{<6!F_|+iB~|`cr~ra4M9cjo_*t-+X1OAi2#WQ-;2PD^=Z_fPOpy
zzYJ_5ig`_cNtk^Z+iDY0lp#VgEwEJ;xIk-CU2Jf}O=taJ$`+*dnG=2HBu`<Cvrtu8
z;wl{PV!1#PAAF~2`lg;t!>)B;h_-$~>P>`ufk3~U(SN|`hlPP>rB>L_@d$jbg!C-Z
zgscnY4i~ti!jUwvdW4r#Cnc`BRT?8l>piXrgdom%AAIG2j8BLIZh>67YP)qVT{X8f
zk_s%x(#YfNiKJaF!S2c7A0)>B)(?UArr!xIpOWsL{KN;zYU{If#W3e`Med%g{-Eis
z-4(UztuMeuBgLQ_o%Of3z13?yL3Lh%DiOQi>PWv$d1&+XhbIO0%X`LKCyV>xX;#dA
ztgP?KJHO?Mw%h{Vzsd=};q+bND-znza%j4Jw%PyK4E>R$?5{%fyzUE2Pp0`_#?YqF
zEKO)91KzPgEw-K7G<=$ZPX>HS$0rEMgW61dnu<>k;M0TnG!37o<I_X<Gy|U=#;2M1
zGz*{p1)qL_Peyz)!3kn1SwB)ES@|&K1Qe59Cempl9AXIWAdrFtmd8YGcQ_J7%Ov10
zdPjPt6%YzC?n7_~JJiwKcG5biyhm%;GDIQR#4|tz_N4Sm2V^+0`l5bM3JU8m)7E_{
z4klygZ<-vHOp+i;*u|i>{d?p`-%~huo;~`I9F1=jB*D_f0XTSw&B(LUANYQ9qrkt@
zzyF{B4Wm2Vg24;+Qw+FAr-diq6FwxwEeL!99ticH1PTW**!eRIc8+4un9?}fHQ>Sb
z9Sx4&(dly7Tg&&24mM(Vc!>-8)_((i_uuRL_5nfP8Q4PI*W>LL9{u~iHJYi{Jt%#4
zXgX0O%qBLpJYMO%Z37<$^nYez+;@JVXoz>8c>Q4lBf*tW@fjtV1zB|YBlJr;BypN2
z+Sba~=@tnJOLTLT%8t8K@qQLImUm>+E)|2FvR{Vi1mi|G&>7Tfk<jS8CT{AsNY&cN
zaS6`FX5TgCt3r?Os`5F}Zl}CZ_yV{|1YA@LRe$nizp&$(jD#42;el;YQEQ{*30n=D
zqD%?z6z-0S(q*rV4Vr~7z;$w#Ir{}X9d`av<*?&N3=5QkGgMaRyjOOfBV3`fCfB_(
z$a#7~Wo^(YKeJd~!)e$B>|ztQLJ2$r4btZTQIg`4GLvQ}MJ3VZ*_3%UoCW6DLi23K
zJX>_HZ3+8nJtQDD249k5lCE9xY=RCYM1rSQlS8X2g(Ojv3s(=z`QY2&IiKpXg`R9u
zCniowKZuOb_(Kb98S_8O$bqSbQ${XaM}65j5KMe}h4+8DBEaq*YjeuZG`*XUG+uVP
z=ylQLr4N5<XBfZivq`n%{8>x|1MP@kE`9D(CnLh8b(B9#<dJ<^$Z}7p=C^DKVic?V
zIiGo?q*F>fp$hj+AzHr2I1KjKobx^%3L_@{hXB6jfF-8Fx$sXy;5JuSb;QXK^%A-&
z*CkyrX*~X{g79Y(cxwo3i?tf1h4<HQEpzBXA+-vUd2gl`3I*V-tQ|9Xx;Q5R)_e@<
zCh+h~cPQPs7-J@Et5HC9Y{OqwI^Io&3OE_E%1q!L?Yw^`p|!(Q2D8A-EJ&n`nZc0T
zM6D~IOUrahGh-Js+Bvl7+!Pl@J1O|8Sg^Zpl8@z%s`St?^s4)ZU4oYe9pMA_gs+(1
z7WmeT1jh%mT`>DE-l2T7064)|<y9^cd1%rfN42nw==<=Y*qA}Tx9l?P15(^bTkN4l
zbKYWnvqkOb%kBC@3Gi&ENj4ZA9P*ZN@_Yz_W|KqDP^q#xs$|quBcY!X+j9#&xeJgi
zpprHS!Mh#xZ9glVO}J)@j7?r;as*(dqZt%#^m&zEN?L`m45xA7+?z%hJlN!vt^*6K
z%ng@yD_1HIIyhvH5)*FzBeex$d&F2Ljcoik?ca{0vW>)!#@aCZ#22b-zOmJLtE<16
z*}84IcqmE&PTSA|iE^gIP9tR^f*t`pw(XO3)MvWcjDI%r&kmmxsaEeW+PzB0b$$d$
zrpsO6%PkB<NCD;8V5pXdeW`1Kj;0#Ipdnjt@*eY+^~jI5i5eF?g(`r?>K&daaetJg
z1!Bp!gpCXQ3nWkBD07apq2dVGAwNwH!NM%W#Ir$wK+fs#qD9w*XE>j9Y{*yGr7p3j
z5<|(EwsMn=^A>SG^elHuzgE>b=YHKPMC$Bz&Nn+8Mp4lZ@O<M}D!;soQ0E8m&`5SG
z^c`H6qE!e}d~j%J;z|_0`!FT+!ft(glmths3nUeXa69R!Yx1qSTDTi>T9D^UK`PTQ
z^&+g4l<*m2Q4W(|U|NxdgxB9wm*>&8jjTh=iU}uk#>IRNU+1*I=e}8=D-ZCWGUBBH
zyeFDDquj12d3>d{i`IVzRu7lE8}Qy)T!Fu#tX|IAN$Wp>*Mui}B|uZPc^+RWx*$Kg
zIn2kbD^-j7nKQBh<t#bhd}n9_X3ZVS9=$RnK2zl|Jm9U)l-nO)=^r~Dr0lzQ!d=lq
z<>DJ`jcHmECH#W(WKDF9RqYOypSi~FGfkUJ2|wcit}kn1X=)f4Pg&ptUcBA=INW-M
zggtAT_Q!}TlV~)3XkvmrYod%B%9^0OaAjIDC4{}S6m0i?A1~z`LoO!Xx<`uBtPt(P
zPEq)_0Y}1i=1fB3Bp5zFTD&6~$o0949bxO_&aBTt7V$3oCa!ZoOaflI6}llWgjGx<
z2l?{RGV34tGM-uhA@B|dRNCD}b+&Q!b7-Gb(9d!wcZmIyh{3Za{|eXw3ZL7&3myeH
z|2w&C51*ri72LUW`8-<vr{93Pv9j7}&ws+c-N7zoYakdG7d|g}Sf|lx*SI3g`dkRO
zi{n^xiC2}Gw=hHO_J|wI;@#k@5?P9tER9FJ3u?f(M=hBeW2Po!`Ji9is1xrQ62A+P
z4Z$fioJJ>Z!gU~)zpM#DB4qhlpSam0F6<ZoQ4U`)4JhDkUysJ?{l?p-@htbRnu~Lf
z7Cui<g7X=WxX5xc(IqTbT<KNb6oG<U#X>H~STKn$5{vfdhC2mxD2jnOUX>N?VWM4c
zNNh(GElqY+8+_V6cQUkhJubOkDdIm6bY?~G&z*K+gz~_;KJuAJT%G>~3fpnT(I%~*
z`RdAiI$^>%w#vI{?_6hW<|-3>TIgJoSs@{KBL%UE4Zcd<GvsHY_y6wV5c3sEN|^GE
zJvPG$H68XP8KW#90TxKLQu2~4UK(7n=}6^)Dow5>={UC%%J++FAUQ9?%VLo7?`J6^
zpT>pQX$b>~+;-AK!V+CeQ)pq%o*NwseSifX)RJg37&(wm#ON$z0M3a-dY^=z_voPC
zZkPS?RO(GhNUsfNTo~xLD7xazbJ8x+UN7UbM3vT3ovWyhN9iuKf9BI0E*+iqXuquN
ziMK&-Qg)W>TY{HH^PjdA3Su|CO?A$q`rhVq`~TsT#Lf)!E?1Pj2D0B*DnIcUeaxY9
zfNo+Piav)NcIL9B8VIhRXA1IZaO^rdNf->Qy`b(6bl4ug?gXNhj$hs)b8#A5TzMAV
z20nn)5{hvy{k<zZE-(f!Q#ME-l9I0T(K_XYXMD4@F6|iWGu*ym%D<CPo>}9I`j<T`
z&rYQKqki#S>;#9%d&Oic|EAC3wb{PebT|xZqlbMg0bv+4xhWg=ccs-7&|^15iSEc@
z;%AS+WesW7ps-$m32>z)0urvJ)oQ6PEy<adh$QelfL=$)F%a%sTGN$wLWnnF*$&A!
zRmpk|BG~~;MHomYp`5#}ypV>?E-hVKyDh%BIB4iwTI-2}{2Jj|TIY)6m#LO+cg7_^
ziF4^&U1|L^ZKu^W3urm~LW4tI^EllyKvoaPZ3FPLeqn1@PN<nnyXaV_M6f$XWc`S{
z0%M36_LncDeQA_!p~e-y4&}+VD=VLdZ=FmhifFG*;0sfqc!DlUoQ4uNRZ-c4MBhTW
zlTLsQ7Vt?Lda8U8d|B+XL^>_eNaCYKvK}Q`;uIO7mhyBlLVz0F?t7B9YZXpyv|UWY
zvL{ro5zzLo5l@m$Io(<g+vVCcP_tY>dzRVuEvAvgBV$lf^%nWIEwBS>o9tnS2#SFl
z?9XK4S2>$xi5*2WK!jaw<-eraL!_+@R#Y_r`ua?nlO?@X8e8R7yCn*(^n@SwSmZ75
zGes|p9b~KGdMl;;LQ+dQw87^T#l=@WbnJFVSzEP7C9d4(tbb{{!@1MnQs>=tV4Qu=
zA10U9?t@AP>o(UxRI#m<nGC<Oan%zZTh_+5%3w|J;Qq;N(79bJAG>U#KdPuCE(Ml@
zinn-S3WEQx*fw1Xm1G|lw^c(eAO;e`B2j<%I!|1Rvi)h8gP|$Ju)ijrwzFjQTk`6K
z8kmZjr|1phQ#FYeAj?pEg(rNSjg!mTlwag}Xn~z(u!?kO(7VMj)3x%J!<c-Yr4{?a
z@Y<(y>F<U_MyEDv=r1FhIt5U?)uiMeeDP`8zS}mW#mk<~rEgbr3V>;+V{4YsMxJ4u
z^tzx!GcSUzQv~be-r!VN(*aw4Q!BeuOIBVf|5v(Jp^SI{MXVB0<!YFvvdWDwDQa$0
zHl3!tn0881G;3i;y<A=gv@L7Wym*DO*>>7EO<A4%B@zZ!d!nptXIY&Fw9EC$;<^)P
zoPADO?Fqm~R;6271xZ1;buHb(Be)sPg-a`y%cgdnb=H4<^dXtOe$d<Hg^wRV52)wW
z2x<7BJO6hArzjPTw{72Q*G4(#q}Et~$F*JuscFKN0LwubU9uG0jOr$NOZ8M+lcv0c
zCh8QnI(a!k!%}4ZztYtM8qE$c9sq9)n9%wqboGB|;FWXf>(Fp0GNFIzj@n2cJwe6=
zgR74orh<RboLr8j*%{APkOZOG(c(-BQI_pWdv>Mb3Zh%Dxb_|f>26F5wrLJrnSP}}
zLc6q)9_^UZHTn{~L(i^_u6c&GZPwVAcfey}O~z73iFLfr8iRvK%q&UU;QP`zuBB9i
zW;B{QwP3ns$CP^>wTCNb1w(G>u5r<zm;y>H&mgNeBT(M3UnyN+huq;fNmtseptp`u
z=1y^ij}83-$hYIE>}li>t?5crew_-E30twkfNBZVJ2Z7^XMrPg=yT!8m%Gv$O=B;P
z9ikIlwEo8SaOm^CBP_I%fRhtI^1rh1Z46ZbUzRR*St5sE@yH?{`zsXO$)HBm%3?8$
z^loOZ6wvUK29mlOB(eRl)ejm2uWw)t)EOM<O0$O_?%N@+D<69<>10(xc^2)A(>cW3
z#ywUm^2KFB`qEqH?YKjE>tLx-QTJlq*-kO|xpBIVEZQM*#$i7eK1l`NtqWnvb0{ib
ztUUXjI{jR^ul}mDK74S;*1CH52o8MViPsaUiq#|k8DM{XxT8F!%J%22-SrLituOYH
z{T+<IL#)3s0>r_T>3kM`{A~!>jPojAc?(veW{<&^#gU9AgIHE3S1g0~SBmJN2yv?^
z;c0>WFSm-$9lf#`3YcJ!QBFBpUO=~+Y;~H>7><CE4^4P{+A@JX{9y2=-9efyF*?gQ
zUDOjfTDxU@b<Re6R1sLU_j5_pQkvB%U<t!yr3W3P5e90~Y8;xxE1E0?`Wo~0ztTgN
zNZ>wOmK^p1nzb=WS9IEO*^!(pN(d6B96nZirR!|<zkdTkg}3AC(F2q)jbl4Z6)C`5
z{q#g|hnFPU=`*ky>(nG9>D(|vbftNFn4*=gx{hKyqdZsdvW(TsF|R2X&*G=hr5!u$
z&n_P!JR+@Kq#4ytFW=Wr6(@lnzVO37i`@GWQ?vn6eHA-KoV4CKJE6b(j&eR4>b|c0
zL1yp1ri9#d_mDDK*57?a*(*II(+t?UQir-PDktjf-QOx(wXSZza<O)(`<(JG5_@+*
zxeR_m=&VvI@xRLrUX-6t?F<_sAmIYqR=8qh>`E*g`T(9eK=>T20w!NpCQrG?r4isd
zz({M8&@HDWQb-bL7<d?(cvvAMXrW1M2lyB@C>$8JvyiJPrIEO$a%-hUIG!I9ug4F?
z!+@$rPRWvChp+dBK>796Y*@UyB~bqU`e2o&GPU#ET>|_SC(CV%r8+zA!mhO=cV%BH
z-`4hr$2!we$_C&Iuc0_yU!C`a4*0pRPTn7vx!nQm%=5Jzd=TL36InDc_NlPSvo~Tz
zL-kj0)dR-%`tZtnk3|Wy(%n%5K}A??%xUt*`Q(1B9P`!lGC%OuWjpLD0mXSK;^tY%
ze%<&N5`~>6?==H9Kif;@o!D{~@_}6)FrOZ+Qn+Y@(C16Q`|FkNpYb%>408?c+|7vm
z*S$*dxS#oMPK!XfY;4~pJ_qxIKRoutv-Htf<NyL^%~3E@;(b9;T`DhgfOA*#7=7lx
zX9q(X_3S8EHxU4QB*Y2<9Jr2(%DX5gd*CkN1bI!OI(;Lq@WX69Q<U5SQz8Wxx(wB7
z{FX=`s1kLzNqA|5@ZJ<CfALkei?fT2rHRos;3G)XqUAFFMx5}ZGGSd5=7*0)U}kZ5
zd0>5&Ga`X|+eT_4Xh#|tyvnpm%QAdgg$HRvUOZ&zTHkWXga@0pG&QC}d#g)?^4KmD
z=BRW~)2>HJ-=h>L#1!cesM9oXjh2BwXo&{RhxMKRF&h2imMQzl2;em<2(FK^ONQ0^
zL?i_U<arO46!&gyG-dA{fiQa=$f7gqaZqxvag%<~q7Q?wGI)$=FRwZyJBy$K3O`>^
z<TwW(-@n5l4x~Q2fb&)|MLD~i^!lRn?)qgk^ufZ$ptR06MzA9W7=q$KPhD9=qlb{R
zv7^p(3%hR!-At?P084!<4V+kE7H1y|GB8%ziuWqv3CZ4k7n~GFnys8sCiYY$b0NxB
zS2N1xKi(s*z}0=LX#LO-m<f&y-b~*$5l6FV5fGts9SBRH9at+wcW2bfn-SY)h<L>z
z{I|PyS_`*T=bW^r>bzfMthzkx7nb2ZJD<Bd?5|h>C*kXN@p=)G08SnEvIj1dniJui
zm%1X$&Im7oQ+ZQ)%7CKK?bjtQQgmpWd7<76#x*~GYX78vR}M4S?(Q<eHxRAJ8K2p*
z&s6=E7i_+3(jG7@+gin*6e8pCl~BH0g}rY3r25_C#_#xb!k94$`pASoMYxt`ss+xy
zoA3sNiQrzV$8GwPtY$e~{U&@<$wEK}Ve-4yD<kmpIwIjj{Pfm&#p!fw5K4SIVV_g0
z!eybnZSo;z3}_`4#QtN>g}<a-aoHKZPI+5WzJk7)2CmtyH08t6`sZkNFL)5j0~2qi
z9sSiroCZL>Wcf-O#X_B-7x2~{t2Tl+OvRUN4e4ki<|vu%@J9DrBQ?WRtz<=AZPK>o
zGFZHLW29#WES1zy+9KM;#3}!(O2191kL$AtA8m9}YS<eBK95;lnxYUb4~NwmPxo!*
z_tC!YTgs~F6B4>`{`2s?#VzIDYj$RA$QMv98}DM2A;+R<{k5BEe7=Y{oqk@?_s-Nt
zt$WMJK3HB+Mb45|<!M|R_nW8#@9J97)0Ohw%CR*gls{(DsdUw4|C5u}UJ?z(BmzO6
zOjI6;f={GaN#M&7&rYICVQ0p)9Fi*=nEsu_NtDHpYx}o1)5iWv?Am*m<tZ`tm3YxB
zvCY&0(>@E`@jQ*)V%V|r0_Cp2yGUD2&Ljf2sedv=Q(z+4_UY>xDVq7+-|+C<Zx5JU
z?9xCisP$G8@PHE-=N(jiN&uFs`n*7SSym3lU95%}1+soQ>WV6ywD}%SbKpd1np<IS
zMWYt_uXv4rXYJz|qH{Y(^dG&e4Evs+u@#rkrL~I&AshOFNG)smKm$K!<YV+LJznL-
zbJqFj9?fAp`3**S_-kl{B8IZQJ{P{?vhZb&P|K`|1f+dnGYd>#Vb1fw$S{A91*1@#
zzI#O2!T|$XDV${BhnrS(@w9L&ceaS`4_DvY<fE>53e*YY>(hT))39aQARbV53ld_M
z+i79KqNiZ;(DA^L5x53e8Jw*P1OWSe!bQia+X54b^u@G?1{=q0lfg>iZT4L`{0t@3
z(^p}61#x)_oLVd%?pj!HV<24tO=I2H?g+o*+>6C<hG(_=!X4pX0Uewxd>eM;?9<Uo
zT2MzeMD^3t8a9W1^KDn`zbrv5>*WS3+wg7KBQ1NzpNk$m_x_iE)V~&YE*hc1L8klL
zZsvS6v;hF2M)!Vj?4<r^Em>5@)JFDG(`qa4L3{`aT5{!@2iS(c8m%omF0?9JTHpWj
zWxXx#oH7LQuie7)N@(-<;Ev&8{UdxQH>|%0{U?0){|&zD@8i2agzw~kitpswb@w3t
zgztNQgYU2J<NIC+-^u?8zK~RuX<wjG56s9PCZoA-N1T19n00v3F?%5u*c9hsH-N|D
zG>h4Hy{<x>MFk!)CBj~ac{w(_JtuxMY;dRW;GrBA@>1qy!NR-IY;T>6#vF`?g#^<J
z^u-wak-N%<|3%%q$2E0jZ{sKD<j&y^5lGMwNVuwqT9s-`0tE%^D6KcFRnbsyoht3v
zYCAI_S_Q!tVy6PdPI7D%skD&JRMgT!w0J3YFrAK<ugqZDRJ5&ywDqp}J^KVY)A|11
z&*%O3{Rd9Y*=L`9-)pb+tY^hqj{T&V6}x|z(P@ApQB~kkV<b2tXsr%|^OYN=(MgVD
z-z)CMstR1kzEcE_b|1T^2vY9fHJMNEi5*TIkJP2fYM0fg8p9nM!ic?jB&_^79HRVM
zV?IyhO{RdVz!-yzGa|@6EL5q|b1}gdn%W;NE1V6h-^HWkKGsF!1)rOy+&M5i|0=B)
zX~)P=*B#~^BWdlIed3>d9E}&X2~<-U{2`kfjK3AaTe2w(xttWfdmU^y)R(qped&N*
zof0-}Hm(zrgp-<f*w@0o=b))3ruFEst%Be#4!&Du&~Ax8BWw>_0<u-APXzqMR_0*C
ze<y{Gdu#m3jQRJ5&Ku^p43T22Wm#=3I^n;Q4#?-fcPIBJ-+$eYJ1JMFt{a?c?JK|f
z-dfM^na1M(PK@vUKK_5@jXdUmcX!)9ENq@cG;k5$qp5ZV*TXHMT_SYRRJ-uqKEg8a
zscl(LI@UsB1xB}|Y6X1%IIM$4zy6bqpGXWA3r$rB->u(${voy)p0G3GXUGp;V*~8V
z;?d4$n5Hl`5UssTSe*$sxZL<(wKtT$r+6@N`2*S;rC|-&NEX5*g}fbfDl7KOa{H78
za1e7Q%@(VVTTg!U-FKHJ!{E(mr^GLj_hho!P`|MS_C@g^0uwcb^^x9NB*gpH`CI%M
zj4&S`O6b7wSt72U+#*6jSyJ|LEYC6N`*yWUYwCH$=25NyhgjQP*xM~qjaeGU$;a-F
z5?04(58NYo0AM9q>GC@?5IyS77o2)^XW`($xFj(F#%a8Cd|^(O&zvj(nPO-SuuG{m
z)=B$Q>6#L1rXVelONeuIsgvaObE}=&rSZne@wihVpC9EryO!Y+)T|^!pgt*1e}ZUT
zi+kGB$_f>Aa)3Awr!~s7PsIbS%GkdqDe=<z2P{1;u5Ar-GPFqyVRb`sbJZnxkNWEJ
z3;MGBQFSTKo`_Qupi8PxX$%W6D=H+V8u`M|g^{Z!ES%g8pf|Z(zR+kEGpx`r8tjXD
zbcVP+yzywGK^G=3)kL%eXj9|G4Am5;?PG9q!S9rKWlmG%rtpG^n?zQt@Ia(R%v8<u
zD;0JpbhU3#Y66ZP-Z1~ITkx>rQ6#a0{HOE_MY&%SEZFkj!f9$si2?^c!uh;Uxke=+
zfcGNjB=s(9-PQSrg*|^~Ps3F@Dt@*cd=v)oQP6_6`?R&$+S+V&#0a?<(Tf41!E2%9
zd?Y8_Tzwd7?k8zX*lE~;kiWHXr28kDCJNH0PB;{AC98+9dJ-@cvGD{J;NJrZ^RYrg
z+)%f^;LuYr6+_bwV{xTf8b33^T48p*|1W~4luwO-NdvssSsH6n##DgKrEGBAdf3k)
zZxC;SrU-LMxl<^=FBk^*RGUn~^q$ss)tm|e=|oj!Ol68!KwJ#w_y&pB$?bvhb2l*k
zdqq8WU?za17&_;l>I>u9SmPgqKr|w(Iu5tH(ROe+jlT>n>r8hL5r+FMas6&#Km3=8
zAy(}!Dd*=58}Jm%*%I{mOonw`dWO0Ao#ws9NvVE>+~qPx)zRxRr&VMTx~mD+AN6;B
zyz{^te86f-*uHd(vd27jR`1<VYD^Z@V8fZp{OqiK4~q->*Z{Pe@@Q%^8<X}Dd2yG%
zVOPW37TE#oV8YEsc+ra&-wLIov#1?5oJhR?{o=K~&iwf!drrWFe8$Q3VjQQWvUHK{
z1%vGmFf_pOM5MN4TYbDaTjT%|!@6!+iJ3jPW<~KnPhx8RKHOsu8WU5o_z(G%8o2tE
z8vX$X8~(mWn`(RBf2qag3;s)ELaOa|<kD$<(;lB%4s7Q}n2p}ET=4nFyLr|zzFf;G
zmT7yD0cg;sVK(G5Yz{DpVJ_>s-Y?8Yp0$WgLw9L%a=IWH{Ly+V*saS<^+AFKFO~K4
zko`fD@;K;LPqYhp8VSWBk<<1E&i2CQj^=kyAB6)Dn+mrLkMF#Qd(Wo;kS+j1q1S4H
z<I!h>%A*9J|GAkJLy#<;8ewK*r_=@2rEOm=v0exvUIA(6Mdu#=J9K9(jS?v*0=9@^
z1>_ugcK)Or)tp%Z0qz0L<>oxB)vVlW^?CC|F0sjNeE{xDSFXt+5wdB-w3a9Iyi1{m
zsA`3vGI86tei_m~5A*;OwY|i6Kmm9V-{I)k4k3n8Z?oBDQ#ZeJu{mQ+40rlzyDz2o
zMFvkD)^)J10gWg#v10}?US^rxLLnKBIVcBjHx9(Cma(I|Ftz5q5EswPnMc;OldMKV
z&3THLlr~z%)*K!L*8}jaAK|zTcY0l>NS9BS7KeEQVw+Ou_&Nt4-}2%$dixp}QfCat
z<ul*K64rF<{Z?Ra3_>=>{x)TQnF6^4KR!gMEuea$6d#D@Z$(2F>E#4*pEM_HQeG1A
ziZBS|PV2hPNoLNb&dk94pi}u5(Ovi<82Rys=Dl_*wM7ULK_DxfR$ty*w9_E+Lm`Q4
z1d*R0u`BI_{K<bE09QHwdZa!5|H~<~r|l1I`Ha`PPL+?X1D*kZP|A4kfX9l49Rv38
zt^wob09QYbFDUrdrPP4flru=Smg`W_a9t5l3N^{E9ldzecqOGtoZsA(vPWdyFC>su
z;$xr0LkCFN(xh|qc}KMrHILK>?9U()&Y(>>YQtkfKe}(EoM!94{!fWRew7&cI)yX~
z@(xzomdF(TywP61+2snPxPbTl66?9WLf8NSv_7)o;JxkB$DWwF%pGvBW`C!$`ASN<
zTS%p#B9!U6pnqV(mA#@XWA$Y@0t*haLK0q}=9x}&4vn9<Y3h7Ixlj3`H{c-HU~i_3
zYA7lKb9KF+fOx@PA&=+Ac$qQCMvZ0F1iysWbG`gIBu;?731HXlq|M8tv|odQgZ#38
zmBMv}v~6Mv?-{>H!8C{JtxR&vB72XJ3h`R;^)F4>y`L5*Vm)UW&4~x562Y=n6VkWT
z%ogl`zJl%<Kn{d))cAwXBBT|w;81~mN=k7;${+;6Nr*M4Q<(!w&iBia=u%4YlcnKm
zr$FcuP;LQO1_b9u(}x;^`k(6TJ=&=}3P1M03YG-$le#qi&FSq6rb4X}1?=-W?Wq)$
z&r~Kr`B1Fk4K|V9b{@=aQLIW6Ksy3N>a<--4jxslDZ8o-c+(gFISu{9iVBZAX@nl2
z*u|%tm8VmiI}d(fwZ)}2YoAMI-?cVa*_aRO1syV0RXA?nyTDo(UUhx;)BV6+(+k#D
zcUgbl<uy>By^EX=jRQ$x=Yd_EL15a^xjmt<E1xOsbI?@dTc^Ku2YniFcceSztP<Na
z-Xq&=!2TJdPJ>4Kgny;ozE{R7dEYPOQ~fetZ@t!e<((t`F^KgSw(r89CSd6eybyXp
zaACrQIOq$5*rd$+8=D^Pe5$6n$ReW6BI;n}_8B^hNKh2qeQsJTJGyH59)W*Q)HGU`
zt+T!)t^mRwtUj_uVr5S!*gIHI1N6Z=qvvCHaJTZPzqHNou|auzY}EzYS;^ZdihI9&
zZP5%tmEN?5ba+*%nWh`t+Zo)iUfU$}<R*h3$kagSsh>Fj%sFSE33=edngy1>``bHW
zc_P_4O2qFKx=f`cla1W8%}*+G%%W~M1o&IwnWhA@=u?Ymq*3-o4tMK5wxM15ZtJ_G
zi@3+SXZVqq=tr!;Sf4V4tQk_xLDNKQ*2J2OV{zC%KTLsWAOc6|Xf}D{fvny$HOjuz
zPL8Ef)q~eKmNK)T@7+H&!Ma6ntx3T4ykiR(>tTX<+csFA4lhQ>Ov=Ivh&$fli!%nj
z_`r1~F_w9A*qa{<S*baPt)9$g+6g+(zuxgnrS|<4bPQAIJDbmdNfSmP_O{s?-2Z{T
zzca!8xd2Sf8=I6An`PZ$RW=i6ot+S)@fnk;4FZv=zVk+M*uh1h7QgtGMK+3h$F_S%
zRIUIP!Yo`XC#F;ZE;y$ly#^jIGogHAZ?m^<zWwLv`=?ByyLC7jP=(i~90@6uW*t>~
zX_>=75uw8%Yh4C~D=X?8Oz8YdPh6r92r8?$x2?BVcutWRFmaA4Va^BoBM!n6vC?LN
zU1?0#GAPdqs1hXIYJ*<8<Z<fRz!P@m5_W{C`$ThM3*EMvvG4R1UMsvL7E?>ufJ>$`
zgvI;CXK@m3dztZ6;Tfx%GG&XuoiO4sn%N-3`{jkV<|Z-|HZmH~d)_a6e(_QBn`0ZB
zV((m1_P7GOF+lw*XI`vSd9=CZ94Am-pD~#B`$J=SXsTEA{+01OrG$NSvS|ki)Uuru
zS-?p+>llyTgMJm8B4j5>Q02F1NKn`|>NTZxLahq@W}$^_%Kl1vTLNW&+h_dJ=K<S~
zz|-QJ0jP=Rg0ISEbo=a}tYcYu)nzQ~JFk6|a?cw)3KZu2^cg&w4#8w&OE4wNYVB>~
z(KBe#i_NU8w6XWY%oxaBZLcu)myuQ5?-}jO02>*#6!Kj{-G~o33lEgAr(Cg1_XFb<
zPT~6UM#ha;4NosI))5dC#yHAf<Ptc;mN>$m%AlQG*wf1F^ky??R*y7y2(<~xmM?wQ
z-k)5Hp1$#fGz&udEa!)*FR|mmy5dCa5Gi#9c1gI92In}f)}BY9j7Pjr>ral;YRM|8
z#rEilX|&Upb>e7JZ(*nH4@?K^8J%2scZS^bPN;EovNLR12h-ehVxpjfZMFX7A(}Uw
zqV|8RD7@R*(rIcA)vA&mVapC3kywv*c9YXD8-RrWaSq-(7wZ<InYS$CF=vKISoWnL
zYemQ<Lmo2?fOODrSZ|uPgqR-_8utJ@OG*G-d$Qx4@0F`H4I!4rOD~C$>M4Nfv-YaF
z$As)=&+9zM7Hxx$WdqSbmuY4Xy_0sjz?sxSyT{qCYFvinF2kp;q9v}Pr)--T>^Ruh
zewX5<;dRK*2qK34$Go*apTaI?18Y&%QH8~9F#DjjGl9L;Ix)_FKH^UMHa3mMyd8Yq
znqE<(^uZ=T4nc7+3=B`*>z#_<ieC8%Gqv?ceaUBc`E_-fDdCQnnqteEnC=dymaWjQ
zDZvy=zaBzuw`EnNyMF_$Gqw2cV0yyfk9yO*5Gp(isf%){J6@#6TS$sTq(JN~tk3+R
z5Jmf?VDmF?j1A=L0$EC?%ZOoPbed6(hI&D1SlGV>d}9har$u%^P++qULWrI40t0H~
zcXt)E9nh;G1SYF_HzG(vfLSs2{FIY|o`XF*{IU=sAkba~OI1M|P8oAk*xyXZXDak=
zM%cLO=4+|!8uZZg9yW0BZM7v^==q&wn~1s@6wcq*nj{<pk@PMRNufXGMX@u;5c<$I
zoOTe|CP0`b-7XLE$P(Dq05y1)N(fv4k`%p8#73cW*^O+V*ZKnq*fMx0<k>)P0XgWo
ze%r|Z-NXNVo&Wn9|959+YeMH<ee+%pLDmAYtkyQ1#rMAvcf%0eE}#@y)FoRlAPfS~
z>r<ei`Oen=qFSk`Dy^EAda&@W){|uId|@Pu56y>>=PS~)e`GG_Gqyygjb?5MyldaY
z-Lkd2@z)}6ccyMV6?C~A=nDaKWM@re$$`zY6AS3tt+@84Zo^*~IM|oS;9E<6xl;e+
zlpn$c&LNkVG3p*btwW&najyLnlzVdWRp(lQ9pTpQfKo9I&G0<V=SPe>s(Ot|jwbiy
zlNn$rsl?xml8Wv&f|p}KcZyNmMKg6go@3qCp0Cl)fElR*&s7Q20?!3V$?4wtIGL-P
za0sE-iP6@|0|I1YPJ6SG;7q(}yKl!i<y2?yzZ)`eq#^$_@kY*XnnEcFZqy=j!i#=$
z$%&Zgv-ynaj^N@YcVIV}7rZ2U^F5lI-Cb2mn%4NYB#b&VE}v~@>XzocA8zFa1l|AR
zYl@@9BtP-+xyuIJG3z)z7o51i@S&II<A6#KR24!`9u|Q!3`rG;RK`JH<2Bnx95lI$
zK1=>_ttVdf9hTP)ITu?DP2G`ZdnR7Mnqk|*v^~$TDp1w^k}sAJGq!?C<ZCqe^WDNY
zoTJ!SFo<J=YTV)Y0&d7$!Ke0r#k1cb)3Bv{rrOC8SJ+eTFML&fuBV^!%R10gh%rmn
z1<oMa8MHL^fDW2H=!s3K+S|4joEM(76zqUXc8mcyO>5G|riZLw=&hXzSUFPmq&CAL
zjQYWLMHbllmHwI=CxTY!ApRLbM1oyrnUwn4)=v(U($u4vsA~g<{WGwYYG^7$bTDxj
zzc*?gJD7W)m-itjB{Bx#L4yH|P?~Js<%8&UAO|xBXS_Ol%UJ$QioIqj@}SvpbvzCX
z<axOMRb*xmf@?dA@Z#W}{l2ep2T1B0GcinRw==eFOq+sntTE%KWsR9nqv!1|!@jl|
zFs<<_rf<T>0&d}#^}dOUD^Fqyv!RGdO3Kts4b#wysT2JoK)R;2x}<`xPU2SqG~n<$
z4Llvbp;?usjUYEsmM#&~E^Kt+u47%6Z61RMwhE?B2&+-Ouw7(@Rtcxk;m30rZ5V9>
z0D?RQT@K!ldlma{h;eN^&aiEjj4Fmra#<;tA;e_}bs553hH#f5!c~NyDwiSFWk_-v
zM!O7SdiNlnOIXd-8fE>pZ@I_8nn}#%IBt=ml5&+VWiq66X}EHOf?2+unY)cqMdVq6
zQIIktX{Qn++6l8yxWjCg%Gqc@`>Hc^4#8|0gyHJ2QU`R7thDDP{|k`*_>1!DmHfNV
zXN}~6Z%tUrBtJjgMnp}=jd06YWC^zWbWOe0T5m0=Ja`h7b+)|Dy*t_=3$bt;YTh!Z
zAKU^S8(HaEA!nP`e852`_pCLJkLL`a(&GCOVWS#jz)o9z+J<ou;K)zr<mn!AsQ1_N
zV95jpqu&OKG871$XdHLlevx=HXRI{i8WI#Ak7t49U;h45MY3YF4F;823Xrl-7Zp>K
zlU|fFu_R|gNzSCQoQ$%Z$xvEc;F(1&!t@38@%VY(mywh4AE_p5a?*8WVLEd#jK73+
zT|;u1l#w%exE+jNfc9Ao9&AOixClNwD7;t|(OAaD;GQ8n-H<)8Bzr<h_N1chjG}D3
z<zObl2gAWXVPnk9WD7INGMr+vIXlA$zHHP7bks~b_$=Xfl%0+o@H&e3Iew4mOUo%Y
z|GniRM!$oB4JjHFqcQEm!-CeG+SaEdTL;O`)jCep`g_qCNgu7z5qoS$a2b<PqB9gR
z>B~%$mMxoP{`7}?t9bf$L7&hFwr%L)&*0MD3xqpXewJ0my0Q^IZ=y4Mf-`%PBRj*9
zJy{EM0%is>L?aJvBaQ4GzfBkQ&`3_Gz(`JnNm*`z)k%q3JF+KQvNJ5%lez2(T=pb3
z2He(QiL%|H567LFaAh~t&)`{RRRi+%Q+Qt+=qWa_Ou+U2>01VyMBD#32K3s{$bwuS
z#qGvN$OT-d<mpXYz`&38Im%uFz@<U)yj(YLk<K`Of8-OoKg~H5Ia_DXKM|RCB{GM-
zy*u(z-S4LBUY({8MRK1GDw-p7kpVibR5w}V`1IcVhrO&^>;C0Co=@-{d_{$?9Ncn7
z0G><YwM%>oaHj>>6SP-{Z(xGr?Lgh{=+ak%hF%3=ExBiDiv$LeGrolY{c8LEogV^B
zk%)Pu3P+IDh0y<FNpEfcrKI)<3rafc-zDWx(gw)f;6MGPMg9uTY?M@qa=p8y12$%4
zKl0H20X$C>DyhGSXJ2Jpfyq5fND)0wbdeT81cn>d(>l_yqmj{jTR@EwJ9sNj@ku}b
zu9&=I|HP-z$;{mV<VY>u_Z6$9WLZ3jgsj~7`7c@F&aX-YFNoN|lW_|6(!aCv9Puf>
zk-Cu8PN^GNjgt<6w_^L?tze@6_j!YL^Op)+Bw8DY{83%du8$0WeIw-@9sqX#=iv!5
zlHwg-liuId_Puy$o5Of)d?G@%K2lxVNH)=^?tv{Ht3L%FCW!AQ&!2x?3(wm~!LPqq
z2Q4GyH)iRk(x_1OG^UN}DK=2sBd*0ZH%mRdR`3t(Uy8B9aWPDFj9nhjuYFxh8ReGh
z3Ja^5GL7F*F|C070Gk*qpMV8D*t^0!f!E7(E2_YfipTvIx42eR<APg3V7A<f*Bk+9
zPF53gl!#UU`Z`y<-Zey0aw`ZN7$SsYMJ2`q{8qx)3P5McBOW?yUQsbzKHE};lgHWL
z6XRJIz8m0JhYi5L{_3&M<Y+WGal>gx?i*;q@}<m&2|{*qcM1*|Oc_m;<<e$auz_Z_
zM{3aCYPdG#G9A*k1>~bVUWf>)5Yh=`=9#T#ns$nXwkl?OW2jp!a?y-IEWWZwgacIG
znC$z~+G^(PPUiA!%p8DOa$!+q9JwM0utl^GZY!|o6y=f<L$Pk12ds2R>pZn3k%+zc
z6rj^Z&uoJd5nmCP(IOM^k1U%H?@4Mb(H`@A=-k&CAiNX*%G2|Klu4|Lt~sFI*sOq<
zs6^zeTFF{j=1FA*2@IGgSH1|vsDBa0o``l?Lc4^t%K+Ue<1`2yLZQPzb3zekU@Sth
z1s;MCLbE|+h!AGY)Ef+9)~tC<@+;YBHcpalHH=DSG$(V%3DMF$V{LL;m@3MgqaI0#
zZ!NE7io)^fXZ{pXYhkj=f5PdI1bd45W7+WsyQ5GazZioul`u>ZL!02RGq31L;BAH8
z9NNu@+&PSk5xa7Pa5!-0h#ZX6kt61q01G3>`MS9tT&bU#Uu-(0k|icPGC8G&le1io
zT$!`&_ON_6cNe1xrxsYo)xPno66~&1*_I-6#);1o-dtxf1*D22pSCa}OFlE)*0ks4
zgvK4J%^=9PQN~9T&dB4I!cn~i44M3950b+M{+WFSo+++9AW!VKFxgOl?LD7y?eM%K
za^El9B^ggXGSZj-&2JG#o<KLFnw_DKAXGs4svtMw2zJ492Sj+kP$Troae!m#gPEAS
zhhjq6Ou}(MW${Nyp5%uuz)?vMqK%=z$b$1b|09~pC4{Cp3z72lzu?wWH=fTd|I;s?
zcqfJZ{~Y9*57<~&;bw<`Y7&m%7urghx|A~l_+B_T*oN5@dpk?URh_W^J->g^tz_1b
z=o2|)FV8Q4+dps18OO3%9M#qrK<>rqsit5!rZ?B$cs}v$n@sN)z`|Mssk6Ho=d73A
zvo@RYy<k(tAX!F%vF;@Z>#=O?VEMC1u-Q$X`uTO6!F>hRv<u_BvX?aiN;h6T?1Gsx
zpqWt0EO-#&H;aa_vFWd=D>a@LzNq*F8^g_dS&ZmM4!(~z)Pa<URW7e*%6Id&Ty&C*
z7||1MJg?|#U^)p`D40TB^eDf+?VH%~q|$7V+wgMf6STwdGH2L)OIEyes@6ciocN=l
zXOd~6dYX3G7NB55DzzZd;|wo544co(iUApB9m{$`*7t;%2sJPn1n7(9Xdm!F>#3Sb
zQuBr4+A++IdAf;H6<g$`@sqpWV%oJ>Ee>lr%+ClqA5<Prnam-R!jbIsQOCST-7-WY
z1XmDfhh6i23$?Um-lG=L=IW~e@cAU*6j7|g!8RBA1h|ATP;!iwvxi=^%rXe5TjDIg
zp~yEdUcZ5vGSYCNY-|=9ZoIL9ebJ&elZ3<lf`oYw;5fILrK?xlb~D!Z)CWNR-PMRv
z;=5S6|FfV7SIB=9qViZdXq)*To^$xI?VseFffJQ^5Q7o*o+%_CBci|}XZ2u~urILz
z8l(yA<M~|1rNg;x91T7f-mlFipiTngz=Lag%!QIBc^rIHo9l4Oq%cV9Q#AD0`-18)
zZS9?OeqMY}W;MR)Xd&_&h|)ligBHXaX1T<VcaRcWI-)FT&1`kPCSPjYj?qWTg8{4o
zCuYn7c5EAp#bPL<h_XF``vRgPN+SGoN$_)}&Ip_W$}6A-0tS0{4z=s9$0cwdx=Wuv
zT9@kNC}=+FQ_a$`tgJf9xc!b_>$4L>ieKCR|Jwt+G$^onaF}1G`uPei8@79uI2j6J
zG#E>F-y1p4BHe$iGh&i0sq_C@XUG%W*8^UgQ8V~NXwj1~{S!koo>Xd{j2<q_*?49)
zeLfKNRoo9e3FctXsllE6^j^1Id}&-+in=5vu1FqFXtn!|6Oy;l2u26<dg7jcbf*#+
z=6P9WU&*s^MYH2i%F3QqXZ9Eh#qBb7Oy*H<L0psU>>ehw*_*Gfkg)}s72cVe0h!nO
zT;_Gh<GPbF*VE$69!H_JNp?ArPZnJv1LGe_7jsMI9<9st1zdOkX7qWP+3L&eGtW*q
zDLeZ%liA~fr+DF)O)|$*k7hQT^Z#BaYoRkiebZ??Mq`{|=X#s*Y`fDW%!GSjyuJ25
zkWB|+{zUJNv{eS-<_=|r<!H-aWF^DQU)r)396_V&Ks&667O`&t{3~JuhcGCBpWawM
z9kzKgs{Y2YV&zd?afmK6P?s;yi=j&!B9-%Ct+cSQ%83N^@R|+oRA{iKG-%4L`$X1%
z?&=m`Q785pmVx6OgsRL>odr3UCPF$exA?rtCR`9O@M@D-M12@f^idd69DlzPzKE+$
zA7+Sj2D;QNzzS86+cP6=2XJiuz9wT^!m5l<`p33?5kIyukmYP7t7CVU|C#BsGD9{7
zCie-vQ@@^KpdfJsj(5yX!>6V)NjNsWWe{3B{}$4lBY@*c;*m%1eTJnS1{*Lp?sCh-
zFxcpxj@3O9@ZxBd?(OK($Ccfvv+R>ms{<uh<(<dXSce9ZZ(jci?yR%Z#6S3KZ!xdj
zvi>>b(%ON*_Ghg<>Y9(Y9DY_8FsfvBdeQ7O_|R28yFXY~G&>#7>H_PZwb_VZ=3MiZ
zBQT9^u%FcokJsgdyQxBqUjFDMU@Al{OnN-=%Rgc%nkBZ&1r@@S3T|e+Ruoq!OsVHq
ztBu0AcA;|O5i_?cu8Gh(?Vrd4JTWgwUi2#QT<}2MSSSL888N0mW)O;%n(D2(1hEcE
zVrXK?aDTI(YzY6C?;z#yJ9r!KVDt#*-lsKIdLtK+&T|0IsUSr5%83$i0O!mY%;G7g
z$Xq4dRKkVeQ~KyrHfjT?=~$*L5&TqfSt|#XImFxfnIf?mdXmz~AtmBZMwQAX-$-i6
z5c>%&<R=x^s6nbWQeIGVDRdQz01_EE@vnlhqI0X{P^O}BH5zN|;4)3CMiWWK&T@)<
z7)_xr!;zLyQIV-*Tzda9AR%|@<s8!<(4;&6P^p|btZNCde%1+T_f+V)=^#mjOFVe%
zQP=xoR;s6&^SQ{~wX&ve{>j`9Sqra+U0DmOIBvt!5a$m7+M7eUivp|l4Q}OYEFpDs
z@V<GDmE-{7SXpI}k%Pi5QBBnr^UCVYIB#wGUJiG?BU_B$K2WhLLMk`3f*A<qp6fdQ
zP}^PxbTj837IXw2hROU;d$93agqmI`aM+@VOuuNC*7=~i0n#AIr4}3!ERj3JLLDQV
zGFh;MnbY;P<Ff~fcjfF+l4&5B7mk%XI{Uu{-J_a1&$w5<zPWE;EUp1WR$mV#L<}qU
zTwczcC--3R>IB6g&@?L>Ik5<;0CqO}$5*7z{iYfRnY`RekivxE!kw@Ue@`Nu1dq&G
zxovY#T^cm;&#VrFzq9-OPr$W#mE5@XP-$=gl9tb5%quIgUf>#hGb@Rv+p)4D_Z=U*
z<3uJc{=(Px4n$|7_XcuD&oS76+7l|Ib(2~vI;|BUyW1lWyToFP+AmwjD^666_UTyS
z*a90m`j@>C9qq}&8i^2gMz;vWWTWq}#gI82IgBdR$f*wq4z9r_Ef=fOnl)7#B<xMX
zI%B&5`D-?t%uY>*Q=lQ(6N$CPW@qeC<UmHoGRGKTpB6Dmlk;}*5j$;n={oH~;zC<9
zuM_5;#J>vXkg%gHKfTF2ulzilNq=lh&pWn#jMEn5IIS`U#7*EB07Mmc6i0;Y8v7gI
z0f*w)w>@SC>|G2y-PoQ4TGaiF)^sbanhjhOKWifD=U^B@j_1ea)}<5%@bUug0vi24
zJYg9bvSi%HA$!^wa;N$<xnpZ$jBFe)|K;Oc2d|_I`&Xj*ryp=MV{8OSRtvpWu`1O<
zu+)sb2F;^rxcBS!`8a8$by7G(uu;f@Z`{8}-^h@oHt@#J7Ulv85%G)enS<_mL=R2M
zV;9{iKR^sF{_lXQuQDT`nKO_RBHGFP{*mpPaMi5D<RENrFEVY&6ttw|yp@3zkOyoO
z{3|haC&)-I81$4YKFZ82Y7fY&=!83rV?`8DCK#B5M?<S;a>o`K?~2ayJ~phPB>T4*
zX>hbz#2Z7#zI{6mzuja1e02i3&n$M0{ZqQJwRiVQ3mEXu>CIw6i5RZqS>2tAd!yie
zT7HLKwvT8aaDW3f6#!_J<(|q1)obiK9ze&?@!+M}4mz%xS^r{<`bDcbQLt>Ex?f6s
z8ZJN14Be-}SFvdWE446-%`2imtW-GQPpFJ`ow})*5nWmt#Y)Y;5nz`E7ju&cFCn@A
zJwx{5lI-W(YeC}U$SzYH2zCVv6dj>u@B4-Tu?iMSo(shg<WeZGuo%tv{okuw_sY*Y
z**G`~oyE933h+(Hhi{E>vFVG}xz0RL><LGm%WX`pmGLIMh3gvZ&8yzxf<%LAO3}<h
zs93!mhbTw(h7L&)Q(Tn27;R$_Q<m&vG)!$XW2&gBA<lA~m_a2iR%(7RrOBn{Xw@!e
z@fmqmUuW;BEeiHtUYOF&6mK+zrJGy5Qp!D((qtEZPmc}G8$;u;TVQLiJ-PgRxn0WG
zaf*!}r3(nH*iezg#fg#aE4M8xMxp010OSYCyFvaTXY$^Xy5wTyuUPWKFZK4A@A~VF
zcFsNIa|Bb8Z*yO{Nw`IvLBcHfs(j={G19NMx`Sxd>?<?qZQTgW7NISdzL-gGJBFB?
zUIA$RsP0Y#S~cfW-8LT<r^iLze<tXG*TnwZe=mpM9>F?rg=7Ptr$G;i3CBnmHAFK?
z+glsHhtJ~jJ9KgvSfV<Fdqj)p7U&O`*Kfcv!AXl(iBo#2(sn$A0NEFUE{wh~?!qIk
zr=@O2{48Vs9Qr+#<?}m=%2+J;wT`X`H!X3|Vp!a$J{*wTfaTG`;ix@l-(@<Tde|jT
z&2?HC`|pxkM2@Z~HVytzP@0%&IdCFG1>^J1W$n)=wMdRS*y-BmlMp4wL5JXjPCC@}
z`2+qO=A?sLTaTxMm;}<_>CR)vab!bW^Y6v3&+jQZ#NN;E%pVip+WPfCZC$yGmekbz
z-0Kqd_kZ1gv~yqs?z<kRn!3OmX{IHPxnhex$f*xDZH+MNCB_YE*ww5*9BQV!7gFcD
z5MVM8>+MDOC>q!JS6g<rvn$>H2_Y;meLMs$XJ)!r4WHOdr6wS5y}2qgO?hd?O$$u_
z67-+^9chDs?H|+59syKZgSYgE7<Q+bstCP!etQRaMli={Ve`R@pQH7zd_;4n1!zgM
zAzISkjHO8=i~5F!i}h#k(Y9Cyc3n$pvh_fS%PKJK+-0>cv$pI42eG0;G<1-0mL?6}
zR(ng6&CCglI99SM!Wmw|y>q#<xl<SYgf4kGqAn=Dm+7LP(Iv0fO`FWcv7TJ$B4Jy9
z;^FKKP=2C6#Z_1=G0~jkZKrCxxBIBG?~#mqFQ{Fm$%wW=o?V8<?YHmb@-hX+6ZhOc
zd@dK<X5?WxZmimm8>P|2LS2irt2yAyac#r(n!UM~edq||qiV8{8z-p`bj@!bu)WWC
z4ytpleEwJpxo4Y5o`2_gab5vfV`1$I1`caOZA^J96UWO?Zp~I?Is&yO*G|o=_)84g
zCFH`K+=;)f?P_etj@9Ivv(6!u&8s_&PsS_cQN~vUXNTwsiA?ziL@2ZU1so@}4#t^6
zRHUZr5Q4T|L#_w5I8t`ue=C?A0Hj?*t}Q8~e!WmxuGziOL}VgY%I+)o83gpEYX8cd
z{WHnZ!6$X{nV1<XWdGg@fqOhz%6cn8YOaS60^;Z1@{E6=Xb8g1wkpO}&6F=7f|^&e
z)h#2L;6MUtM15WGOI<JTB=?;%p-U#3(-Ufui9`BAi822*f&+k_69OWqArcQ7140<i
z#6-7Rvdx(CK+iI9+n5O-GKyxR8@9oMs`20={b)!Qu*fBQam|%%wI@DkT!YKYhZvXU
zDlU+{+Zxgj29%O_JlY414Y*ex%h=i(i{^V=<ExeuJ1)#6TRri3-nE?+(xn-~-}Jta
zEb`_)Ts!gH@2f&-pA~e!&G#|xmtzM~F+)p9_hL~isqzLBIdt&q7I#VYWnOu0DIwZz
zOUY|4X_{G@9m30g2X6r+wFUQCf=mDtMhO9AI7>*!xk@UvSr0IFaP3!b1Fe8%`XlxU
zgqVT+0j2t7m<4G@gR?>aR1RzldtcB&TE+=El>Dv2T8xYSOIuvLgzV&{W#`J*u<;l(
zAK+2f3Wi(Pr7aV&uP#5#yz)J^eRiCed2XzHaNMrM4m$TC%Jw)kq3a!TVVTvpzN%C4
zlIT$5lPv;!fi$t9kPWDv!(9FiGhK>gLw9ISF1!_N^^*$uoWZfK@oAksq2Az+@hwvi
zz~`OV9DC2|t$e4Wi|1g-uWa513?W6SYxQwz=7x-}Nmd)>53uDapn4TYDc+K)Tfb)6
zxFP!T5@rZnF|*zqoVNaAr=mq-y*LQ54Kf>4wK#ml;zJ=mLDoewsMNrYgw5$wlf`9N
z4CWCpD=VBUVt~#OJ~#u~S~OnZ<-7FI5bX|1tIjlwqYe(BR;-+4bzK0tz5lA(&A;zj
zN!~A7S>Yh>v-0k*uvvAV_d(7EZ9kEp&=*8@%4LX;qqbhe>pgVl(Prkk#Dzm}ftg?O
z!1x9O+G>h2ehgw(&zmAKiQ0~Lms92OOdMS60NH7xE2LAy6j9;ej1>3DFNAIrQ)MS|
zDnf_inE?Tb7GXY_R2h0zaPtvbY@k}e-&$B`k4a(!(yGCcKgtuG1S22Ku7sp5=kjPv
z9@7ncqU{J=CI00&9bsIgh7cUkJ3sV{NINPC9yU3dlU-jtaE$#U&M%lv&;C*I_ge~1
z7T{8hmFhIV)n(-A3<;%0A0e#lINMRCBD7Y++^VbD6=L;;zytPnojY&3Gw;!DSADGF
z@=>Ne6mn5hRqq!e{mqDIp*~RM%$wxQo3ib)4;qDW?4xZ*K_!C&NW~`W-jLRc5G-$%
zo4k2R?z~h0l3B(1P<HXOXB~NJXI?y(Q+C{{Q1&;|9`fczxbsG_x@~_W`6M-kva6@b
zEqPLNUO@M0ABE;a57|Cqx();8N=;bLymH^Qq5}6^E2<pp1n^HQ|Cp)mV6gln>Qp<K
zAC46!{N<i&<d2l@@n-xQS>VjtZxY!Qk0+5olb0W6rbg*Sj2e1e;-izXQqSL?i@EdD
z)W|GDI+z&od|KqlL;sj4oXLv851gKD?ac{YoxD2Qw8e}ds;gzmvV4Qd^wX^9^cAfd
z+Z*b5b8ji(BU+P#oqAUCj+|LyeLRC>`ZOMTN5&V%2(rR)EqS{mpfKOc!DB*0XfAD^
zFwVWNI8G1RA66p;|EMl`_#r9Ba;iiq$l7SF7zLP!1>-j@{U5FEv6w!st-`~xZjl(o
zl*QM*r|u}m%e?UV{-YSgZtIz$E@sgvi;yu31%r1(2o{A$wgWh7J_-0JL6Dkr1iO<&
zn6Z`|fhLl!daW|Bypu6$LQR?w_N3aU?vE#zuS~^`fM1B%<5RQrZ8BS(YsyiSiIyPg
z^xuHt<z{_Yg&fK?qBN?wmBh{>V=HM}ALh%2(5gouhFOK4e~n?&&WCbB9M=TEQMLXh
z;;>*wfVFADGYykk=rbZ?^#hWiU2rhJg+7Z@t9uZ^lZh7G891s#<aeeD08{cP&kLBa
zv4f3(T8Rf@JFly+#;V5L3|F+1<|w|t?Gqo>9?QlPC3`IBgl$f=@lnU=zZ<n`4A8Xp
zSl(<x`lYY{;2g9iR3QU$q6&d4e|$w!YrUCe8<JLq71434N=;u1pixmjW_2XUde2W#
zEEaI%;_O$(fL`Pc7afP!{k8<<_tW0+((!&UnA;HNCsVjN4lW~cL!HdBPvHV~xr-tF
zrh*-;|7b{NUsc})wodK}r#IKbZZ+5!!j6Yl;FTFTnXo%?l@>U7RE__KRc4t2US|HD
z1F_sJ1-ijoQcfDeKVET8HW7Zx0DTfO_YPf{>(}qXeX3oQlyGDhCsVA^u)`kz`(hHB
z!pyX$X^lTeYej2C)PjM)4%+EdLt`1_DW%#)M|L@7ztB!5H^J>%-X!-|*4o#4K6b(P
zVI6dplTW{boax#{C54Y2*#$&Sd%}(6ac2R`Ib}ukN+%l*&)ps~p>I_*Dg9%y^@8>M
zvrU=R&swjx4vb##TT&D7>5<&DOEEVv_Ko)Yiffbye|J!}!%WRJ#<E6)iUV~LhqXeN
z<tU-Fd+)Q7#%uPy_uJ{l=Cj9`)-#d4{}Xb-P<=`AZGiF1`(*|~OYP85XDgVwI6}^6
z+@h?md5jx}i?^c&!VbMgi<eN?l##JH!Nw*Jf`f>B#hYNah?2dCKD0WV|H%#dLT{60
z!kw_sjp#$GBlzpRph0yT$*N>d*l(UENA^=zlVp~JcV-L@g7s)J|E$S8FMxdX@vx!e
zOzXqyL$A}h$rLN`ym`M%#<V@4tJl<i%FGzty+vy4W^m@5BF{XrLh4e=T%a;qER#Gh
zbt_S9fqOAC>UoJ*DTJr&Vxfgy+*#jhmI=%!Zz#@(acmiP`i5e2%%~MImokkVrR;Mp
zPP_Shw40WCm1C9Hy?+yU7mo!#-))e7I1cb6!KIsQVB2w~iBtjd8&{fD7v|Ma<tG@N
zfK7i6*&aM^1B47r(ff)Rk*69hjSd+)$qd4<Uqa+?M`;%R7OiaNB#VoliCN#=%E=k~
zKYVSc7*0d-wEz6TSb_Jd^Se$nC#oc8KVuH<6c86=bWS_X^B2oO^irVPG;<&<7i<fF
zo8mX9+HcRl{+(B@Qc1VJPItHZTK9+)7rxyvkC{-x*dHU3a9JtA#CbU1Njm+bki+y8
zSWx!)!~?#8u-5zF^ts%>Q#Ajj%e`-f)RP)IOS1;T@X2zr`ExSnfWRfnvKFgL#|HV?
zByg=;&FU&;fXOiSzlzZ_m!YXZsH`uEk%<T`E_njz2z&di{e4zftdM=}O5hk>%=F7W
zO#c@lS7N0@XPChsJLkWD#jFg)Y+W2Ge%}|+F#o_e=?8_1{BK;ii(U!cb^vAI*yni;
z@)IjqH|}3|<NjXUANrin<GHWQ$}o~gnD}jCW5f1{N?77wWg}}$Ki7Cgl1)jt!NqU0
zej>WLnKVe(5ba#C{mN#die$%Lp2N6TY{#W*MY&?BRP|6<%S%`za#^Z90bKV^%*rMu
zCSFq}rru~{BI!?1?NUG6y!>nURE_(~8kZ<>)65!m&WDy0i4Vn`Ou&S8nH?<)FZRG`
z@6vrPWz^=LrZwnD)jty-8N)S4j3jApB}rV(?ac?dl%$J2O>(h^w_z;*kGhPiDff)p
zlt>C3$i-LUSn)Rz>N7te@XBVQnsQs|p*f6~hm*Khm}|C(6j1@HOh?Nb&X$F)=JW36
zR&O(zj&o^7^^@u!%aa(rhAGm%oeNsVcHJ-aY}(=cY*JQpNS_D}wNWEgy@{$4@taij
zt50jb5KY<iWK9yPdR#R%acbO2-T$tvtL2TRhKoJODi^_XNS!sL&ciAFb>=IK!ZmH?
z6N=ru%xL=?qy2Qu<srI`$o=jWJGwt3{aX8gu8?7KHm{~&<I!IC%a?j;1D10QgWa_p
zdwzXrh4iIF66Gtta8^x)dB=-0N3r775vvnc=d6CRBu`e7Cojp1EXh-p<RzEnrPRGJ
z2N2O0O7bR`<ULfebq>^XTTAk0l;k}!^$i3&o%RM+Mk1dS595ucz{Imk<8flQg)nSP
z3>{0rbGu`ralb%YG{y!=UY^yMLXvs9{K**OtTB9g0Gf=Wcy4Uu2~j#Sv_nqRw+#^p
zDr|`f1a)e0VD%S-0)V{G!kiImOAyHfa?WLNCuo+3l?mxH;yug^@JX3vROJv{@=Ej+
z9N)4Mtpj0KLluwDzObQwIU7?k1lrO$oe8J9-ff2|n^I=Ia+hkhL8D{_XJm8wfy;9~
znB-U<+8qo5x|i{^jPYs(tHTESh01fk7h?~*8VSS<wsXH+aiT@=`@pgsn*WS@xxg!=
zynnl+_(87-%1vL;dMk49RpI=Fk3rVrPWcq4r#WDS|2EhO6-QwRAwug5)GeY*SHIzo
z3xVi@+MW+I$HZRi!@Mny{XS5)I<|C?!5pZ#3}Jy6z5*)DvlZZ;90(Fiund_4NB!#2
zDE`ro>tcr5alLLF_x@dS;QcLa2@>lz1r1svbkk<(qLWLLqu~*ZK4}kax`v2z^N$Qc
z4_s1^y6w1+vYln@Z;!bZxvdL}Nz+h!sPVF|D~~xp<Ya}H^O$puUjY^JINN;#zB&%u
zEq3Rv(2C_%U8_~A*%G}J4mGzYnDsL4ZaL;O-+wgeKe{Ezn1Woz2Yqe7WtuLZ3;_N8
zfq=m`BL>_5;&__YMaS!sLrSM5l|P_eQDpO3I11+=jBazZ0?n~VfjXg2$bg6>8Afto
z-r94nVGK&{2*|4bw*Nh~!zuuem+>8mxC+BC$QVDSyMiiB32g~#A9BV?Le8qSM;?f`
zA|JFin(BPujy`jsc+eYBy2_}_RO=dIEy(rS{^&^EtT49YTy!9NYkRb`CCEN{jCdo-
z(=&C<K&UH7Y_a~(+uXT78P7bbG2-W-st>r<;vG#pt%HL-oz3q<EtiGkgv0i8K^Hq)
zyG<@G#doRdwI_$j*lzTX?PyY!XyhM7+Q#Vf&y$Z*N*@hYsSZt-o8v-f4C*T4byL-6
zAD|7Lu}Zc8aX*$Q@l_m%l%&3YlHlF>zCFREk3L<RGI504h%VifXe$OfPAFM38m(je
zQ8EzPnA!D!cBoQYg20XaRH`<Vd^gWmq7NZuz3J=<xi#d~hYmfUug-OkQL#IT+^|%o
z-7H7C89v>3x^#@n94M(T|Bi(Gw#3Ac8pNOmEEzMCz&{k^3BYCd1b+C~zX>_eHV_J(
z#~JylvxgdFcq}8|O!2jVoX<6yz8`eE_JYk5Jf@<&?rfj@WScXeYO>YT=`FJb+-%y~
zu6N7^o&Vo3l1r0<2D%XK4rlz?g73z4gFU26HT?6^)I!;y=}Dpun=NPxwKJp)A-?t@
zv>Vj_XgD+k-*Sf<q!`Z_D~>|8skZ&By;q9zh{<3*dlxm54p#hyR7z@onsx<dVTe}u
zwFKdW>9kVzKS;XoJfL*ZYTdLT=wp>2rUM!CVmZcYpWG44veVJ7OIQ@`zT7n?fK_26
zFAZo~-Vwyf1zLv>ZS?H}N-<jK2og69T|?*=(U~9|YCNCZXFod8ptZdJuYu)eAw4j9
zSY|&D^I>{L>#e9cAom4JSQHf9qX$CgUq9@O3qRO{rA3vhiyo^>9;cf&RW~bBw`hiL
zbrh?F+;MWKN#5zlpYSk;t#^S`tLnbxqq=YU;86^Gnd;&Gj$L4lQ7sn#=u@plh!jfo
z@^GwE604_8!vK7iW9W)#5w<!)4hz;3U#RuGFVuR_k`T5GAq-0+WE`_u@j?MuuI=BB
zo?~vUi&AP#8o}!Dl2r(HFSM)z(2xNKhClToZcG-Uy@k)0-&dOFI9pe<O)66o;mCkD
z61PrpNb|4tJY;7NJe?rdm&12w+T2;o5o&G-#p*#A_&n7q)lL_QE~hH%iuhh~MmFdT
zxy^%dQq??n3cxt<7kNqIKRc|iw62QkKM-2I&5yVt=Dai(r>nLvm<cZC{PHG&H<q>@
zXq_2zA*$0SNcV+gWeHpV0vnimR!m7CIen4yVa&zSs?yc+B8k8&VTK)u?VaCUQ+oWT
zx8cKFp5W#<r5+?7@nG@FBilBB|NbwJC1DDP98rtMN#@nVw@1!p<rLx?@dq+Qw^s=b
zT_K3(k|ZK0WsQc8zct>ZF=yyQQhb`fsc(%*4!!l<ZGw)1xRcHY>H$2eDO7)#b^`G5
zwSTX&Ua}^|vcV=z=X{OOB4^A!{DHonKhx(E=j7c0cH|2x1ge)!)vW_jPC>|RX_E*e
z2v+T@Q9MfOcC0rim6(H<-u1(&T6mBo_HA|#`xN^y8)1Rdc+ialZ28|AQzdL#>{Y9j
zs{NALy-N%S8&YW%e0#Kyj4>D>$4@I`VY0;Sx*|uI_*NOU1uVsC&|0+qWDa9*mo-$}
zmU_cPjw12Rqa+HT(?Ge4V4%(@V%ftM^5V22b`75cz^v^>)G@@SS065l9X$IFAPYNT
zbIB+Yv43!rq!~p*ypJLbonxjMZjC8F&)f{3xIH{wCD%^&mnWl$nR0lngQNn^Ed8Co
za76-V5&cn2THyW}V-G&Xj^lG;f8*sd!Z(3SJj@toM)U8WPW*HJ2kMz>AMei>EB`~~
zw8oZ}(WNf2O+y@IX{D?(x-z+PTIH<DMU|_~t0ig<u@coz8>Ov}`zX_LT3~JXpr$r%
zUv#vgOP#)`1}qg3l<_Lia{|M0S{D<#;Eiv=37~NbbV?EQMu{JORDJ;h8Pzzo_ArPr
zqpJ_w&cVdpb&+Y8pHPx>a@+qfhl$`s=8|ykCFXyZqjHnRMynIdDOxU!Qa1cj1obrX
z{V)N90enAIql-~Yv3%E!df}%oMxxAtlIz14x`<~C>WcC3{{*H*Po`i8p|=L~17~>x
zqTsdnyb|5AvWk<Fv!Atc3!7<PS#AIH9{UNP7+uTBVXF2HT?PzCNhrW}tg<bT0c13;
zk6B+DG9cTqf+@bvJ=3+}Nv2S4re&;rep6^gMyXU>3y6cPKBM-ZpyY#FT?9zm`zy%W
z&{P65_<Ekdz5E^x@)j4b+XtU~UCH?}Byg>)-4nQnZVJP-sX1h4Ah+@jXnbkJV6JWm
zxTbhyRGE#ZPZ;I7;!_1HcbHx@BkB6}Z<MWk?Ipw5;IWbyKMD2>0QfRiG7Nl4-etUU
ze}9HxtlU$3Zv+67cm%%*`UUryvw@7d?du75NINt!j+L($H=j(wH9`QWdqQD0b*|il
z_Gl;fprq;qm><V`KwadcjaP_8jZGe40C6e4-afA8O?7LxP?07F3B33HPoQGFJ<e3G
z&P^cQfE^32DZyTzyxYsG-@Pkeb3MMPNq+WUOmXu7`GOx{)5-&Ee*H<PyZm4E{EK|G
z>j{G7#djTaM4b$ndz7lU9_MyEYi$;+2RV4Nnmvj?+{zsm*``7{c+eqZ*jNUogdqy)
zU@(xs!a5SR;To^AuMlndO7e^2Z3LE;Fw>M-O}XUUjWKUPBn4;%O9m?>1c-&>mUu!R
zPg44llw)LUWX}=I%sN@#YHd+A4m?2jAumg^fxYVh{c)AVaq5;LRia||PnRo;L6}(c
zg>XJV-r*t$x#uUg2Xtu|KPF@UyAxQp^<w9RY-hI2^O?_WTe$x<Iu}JI?oX;lEhY4v
zx_={c1Dj8Nf2Z|fon~WlA*QC-dl`<2(0*~#ZYQvo4fk_HDPw;^<3*IEPEt-YYwFEO
zZx_vqFqwY#3n8$6n-^gSYtJx70zF|<Z%N!t#2TObH>&dzcKVt==WMaocH2Ng+KkNq
zd}FtaO*Y$Zn~NF9|2-dIZWRkP`EsKRRo7U3rQrg08gAv@AvUh%Xecov3HcV(Dd1qW
z@c!@R3u0IppSo@$tYC}8Q+l85*6`0-hk=6luu!Q0q1|lXtm~kaHg>valP(VQs<yU%
z#;(7?rWkUi(-dX7)JfVapv(%<E4SG|SFWu7p~_ruZUo^+D-7z#UXj)zQGI7`gb>5)
z_t9Y*hV*0}0s;9ySb>4`Z@)n{#S9?fJ4|T`{|cJY`0-6ZY@WK0>XWw74*H0Uh4Dc0
zdSV!lgM~p8#$PYT+Ni+-=?~ZO9}&7|2r>i|8YVG3Yc4`##Sd19NI)Snj7q1DZDF(%
zZXrPTjye%5O#zry!p#!17qyKHiOkDrkKOSD{}J~OHSu3}@X-zZ>u~@|kjA2*8+GNu
ze$WtQ28|MyYf{!~cLxm;RO?=|Cq!!{aKjN<L{AZIh7biK&F@cRzn#FR@xQzLG8Qtr
z?xBUb4HcCS8E68KE6$mfYoLJ^9fp=qoEmSSh3V-+MYiN*Y5SY`J*P@JT2$A4r1`*`
z@N-#s1MhZc&=RjMta#$I8&EsCbdh(iyGz5Iw5)w2oHI%zIa*$~4=-#q(*X<rffx2=
z(5zP%f*1bbrUPBNaPmTk6UYpmg1iyV(ZNTWxl)9;J3s&Aw*0;e^Fhhf^x^5Fhqqa1
zam6<X*7#u&Ey>U!V(Fr9ytLG<i^%kOOG90>3_$wQh>`Yz`F1P@p8A)Fs;>N*uKZcf
z`~qkG<Ieoq&iq1W{!8p)M}B^r8x75!Ug(*l!`m3!wy$7+b6R_iOLZjLUfctko$f;H
zX)q$`1?I3MOIV^sPn-3O=SnaTyG4oaq9p%!;R6zcC50ssMF9($7211duw6n#v7?9i
zAd@M}c!s8BCDc>_TtqaCc&D((yo{Hd??X^BtO(TzLJZk2os?jgA~U9^A`Kq3pr9QP
znb`u#fTS^>!~bi++_6dQJyv-bzC89Pb!@aD`|*>K;+}yt7h8a3S20dhb6-6W>Mbnj
zdECs*y0LI6z-M(5Xl#q?E%h?LlY32FoL|)5pBw;AN80#1szWY@Oo(7ao=v#M3{e^X
zKs9bQWan=KLJOSS!(3y91%~XIb^-P8!jlZ_8}Sl3mtc&hXT8uuV`}^x1Yh*&Ozjdy
z`Pa;jtq^=%B5M1QU|oz{mzhvnEM#-YdY6zF8}53HHav!JbqJjzfqe>(MJ2<VokUJT
z{P?f^&pB?9&E(*I8?DkMr|PCnFP#;SgUfzpY+CW5BT*>w!`hpe3=Sc+Un#rsuo!nz
zwZyXP5DHYP{mP#YO;?dro}c)8v}(zI<>f;&6r{5DA8~K`xI-WJ;+N9y#jnCo4t?Sz
zdGOvuz&}kpJA~4xUzlDn9T8F|Il3mnu?2pGSPXo(1;htv>@OjHfVvg<M_aPaKj{l>
zunec|6dI@M3ToL3wu+sdmgctl+<KvNE^|`g(u-Qyjql35@`cJ~?<}FRzJ*1?og0Cd
zmoEd$&n(t|%ge6v>Z9E3YPUXmV~flzU!!b>1xZ<7&_=8UdQDo2B`wyXkGFq>)67FQ
z5WC48bbubZ6<RtKtdP75&%|k=RT<L+_M<*dFXd>kD+a@LlGDpLIuQ6NExCpe11wdj
z@i49tt2WF*N7~zQ&2n_OgH|A*7N-y7=m-ZrN=vRmZ%CeZg^+1=+>@-EfGKs&Vm)q|
zE93Mbj_@QdJP~fBu>6+L(uKlhr6ly&nt96sb{35;(uXda*IJ~FELuJed!Bc^)w_JW
zo0hrt5inJ`^pQ?Fz^PX_P*(jY3ms_DN15p$vp(7!o>WE$m+525!V^mnlu55F37=R*
zhvGz96rSOw!@T-fZ+N<!4tMKEyTix3XhZ-W;|d?=q$8brwKIGSD&x?{Il@O<=usBE
z#ynS9HaEsSH_|mXqGWEgcdmld#}~~-EQkrtx#3tbG;>Ee=7!Dvis8Ec$eo_oAtHVz
zI`!bBn>ylWVwdY$Kvai>_Gq1&pY&YUOJ``uS%KrTm1(S9s^hw*rm_6*1dl{V*yLUS
z-9=I;GIZ0iV3h+a9CtdO(875{I?j5$+`~A-<D7F#9AQb0xhpKR)}lX&W-=#Pz))t|
zG0(g_-MA+htEa9q^<ZU_06u7SLhBJ8M_ccb6^!~mqCHu%R>~@?y6l8ej9hq5VW5*a
zT>CZC081amDs<6-95kV8q@|05>_ed4sr`m&c!NBO9DXF1kVlirqbtLYg#4oiie^zM
zs5%qy2zo0H6otk-+3)2aZHBu}>!+c;e}`%;;4603;0+S>rvKYrKt!othoKbEAh&fH
zkVgc7l@GTNV>=KP+F1}uSY7u&eXJHRFgBw5DsMC4mzv?2pBc<7C)R}c(YlFBU3QfD
z*j>ed$Z`xALlJlEwju@nz{<s-vl9wjLi$95nEWOSkn%(<)7+vw>Jl<1_Jm^1`;R-~
z;b%P$W4&ROH@3*T27Ylj197QP=n{%fH1xnbBLIsaRxrjXq_B5*BxqRUn+fDMKqD=L
zxXUiaJ?)?Pd!pfcMiK6LcJcRw!}qj8+_PKwd(7}Xp1H_a%ip6%@*}jp+8X|zU?e{t
z6or07Tl{J}bex`9a(dy3H$rBMPW*|Nj0!(m@DZ(x|B;Oxx<_BW$~YTjF8Sk~C*%D3
zh;tvv*+2s}&H|xpvGD9=#^zyeWKS~(O8r9Ti6#P`XJzKV085Ic=cS_A0W}zWv*m+}
zLd=20XJA<cPEH{RpH#HQ0{t8AAfY)>j*G$ikm08U`etEcKu#rcD}}BAfvZ65701B#
zn)fJ(>r}!0&1&#HArkAx_rpL_Wi|O}sz5fjgSbR+0rZ;Z!9P{^u(H1X;TzBAxg}u>
z9?_r6OsIJH*2e9R#&Q87i#QaaC-*0Zx&wqRG2n89p|JnE&MPgje_#)kQ(g&nv73J(
zyB})|q6o9fjd*(7UwLnCEkmt&-Yk)J$n&N~StMay*O&#<f=?56p3|SffA<8C{O_Xg
z5m#Hzze?uOvp}}1-qJ1$SG_x%FcK{dUxI(e?;=0cCAEFSRDBkp!47f+1RB(7%l1sb
z@1V5|D@_*k950>5REw&gEDiggv5*j+rMHdnp!oCj6c6WVEavmnUWvT1QOD=0{8gU8
ze4ZgB&v#0v33}$0mi7HRN1|gW?hs(RF2T@VmA?LkG9u#;!wh_Bmc6iS8^1lwGmB;!
z^g?XpME+S2j18KVzt~7Cz804~CU8DR*M7?!nB1_Nll{>mGo6v_Kb${386$5|oGL&C
zi$jPi(A5>95|?y^oC)j*G+})lXX15WrV<J~WN1HVL5ETPmi$R3ewADpS0bkHsTQ$A
zMA<)tfBApPyXBboBR*eA8FYdEJ4UiXrlDu$L-~d|p`mB$zh}Dd^1h4G@3xd3zppqa
zvmC#tm?r0r-%u1w9mjuG+?6<wdli?&uH!?B--|27m5{Y>{N={w>rDUG)`1{v5ao4F
zE^|J#Npu_CV0J!gaT@AHmAK}d)4+dySabl_PUj;or~ZQI6t3OQsb1&9w?$WRUFMu&
zc4k$IHsRXhoWeOX4~Xh<?Ql+WI;Wo!9mciGIo0ia_^Rjvu7CZlDHdm@|661%O}I;E
zFj+lcE&qX8sAGRZ=#0Ebq3%`a=Vm@sKFDNcPrC6JnQ1H0=0!l8#|jmb9wdbwD*30n
zFhZ9=mqvWaMxdX~V$ni4tNXk4N{Phqm^yY4%4Jr#4RBM)!5e-csG0Ia=%Xs4N+by7
zB{FRn*7!H)wexQUbmcQ?!7h-yB=6oycWWs(%@$s}l37wgn@p4DH;HcUTu?XVd>DaE
z_x@~Z5%@(-fPr?$JTm8Jo)r10<1JZh`*0)|?`PlLOc9wsi`d^Z`t-+^fbL=0^Z@ND
z=x*D{aH^*q|KlSH{HL1I&JHm;c>>ld>sOsX0%C=@(h&&`Hrrjy*~`-E9iDHbwO}p0
zRhe9u2!W%fX3~wrtj)_<4_KQJ9?vSr&}g5+Hnx5+>4Z|;Gl?hkZPKuT*3<JE3$53*
z?$7V`@7Z#5v&<VF$I5`hcp^@5;9iTkPf&2V?GEjffCqk9VSlte_2d+yPB}ISbT4(G
z)mL3I3buq<lv6wjW{liP17UT7{&$6ku7_5y_Trh(JBu=ht6?j9LVa>d?N^A=__Ked
zefXo!k3ML147Ul~IS}oxr@@8L8-1=tN!<d<9X*o-<d|s|Px4w<Y=4v%pYfsMoJhrb
z&Pp}ilV->p5d@UIhYqvkOW$hNZqc?do-aYAg-!0Br&fzG8$Jf@_{12D!0^$qfjlwV
zzu#BSBVxBlMqw3rCSsf}T%_AVm+sOw(J-ySA99DXMR@i{rakOrU~B*HT3dgHao}3d
zsX%ah+mGFv`vX|6IFZmH5|uV+Ar-e){hMGTq5M8Q=(C!9R__=gTe1Chkexsvct)wx
z{eRTGd0dlM+CQA!_nrL!2}?i-ngkMd%VMii?XVRUmjWs(9cKUyRl2F|jJ0E*LYxQD
z>J;L11eZ>TrXnp*A)P8h8AGN6Na>7Zo?ol2bd*l&($-?!a3jC(xr3dV=kxi!@B4Y*
zzurFx_j2yDpX*%bTE17L$hZ@}mLZUvv@xBE5e^P5a5#o?dDxf!B$x9fkW89yuo`0j
zCF)Ms0A^)24&8jr^!Z#}#J;@Em%<xk;cYFs98{S}P~Ur2>x|=(oN*@>#xNpWh_2ma
zd*i7Hr)C3<nEAEY9KUTKxw<;<%Frc^i^v-TTc%<N#$ek#kXBEzyaz~oV>aSUj14I(
zTfz@4bcE_%p)r7R9da#;aV*nA?kyHWt@~t&RMa>fyV%}+lF`^1A1yiZb~@4)FMe`P
z*KuqIf9J;s(GESwr77|Qa>vJcWKnv7^xanbdIMVdk+gWNDtb)4|Gv8F{*jOVH2Ces
zu0J9JUb2pIP{IRI_1$gWwKL!bPus7}4wY2MjG+<6*Z|^<9y5jp8)GG86m-#nKO6pX
z@R#mCmu3r$=^A5Bw9zt^d@wUOn*0NijxnIY{LY{3M#>8RR~j=^EcjA`XM8{3`qzHO
z?zAtjq*2^}ljM~8y<Ev<QA;caO>(8gp~yRyRH)BGyqPJ$o$SHx=K0GlY;ufY^6t}H
zbLDL!9K}-TyIa1vE*+YfeD3&1DqCob%evOtYBu~3V{L!ARv>V2uO#n24*5wi>c#l$
z;;^o@1&h<}GC4S}uvxzbfPvW&EP^$_&J6pvG0D5EICbZ~^7%&*4mNU>opS9Sb9^cR
zROGQo#BH4Y`Yj#@s#&1vBD=_Fy46>M=_+fAZ<>`pU!<SU=|<V~`Jp|GL8H|ScHCyk
zE>o0N^F_xv@YOt#TFsS?I}~XRS9d$^;;ns(Hd)?rkG_r2CP#MMXUQTHt`a*Q(6`~*
z<jjr<Tp4gx(BVTmlUkcx+9ANi_k?Mat2%@n-s0-j4&b$E?4jD^ogIjUy~q=yP2ShR
z;h70ntsNrzHdxyRXyfE$&vHXLHN1c};7#&Iax(P$*+N&55NE_uxge@_ls_Zl^{|+O
zrC-3a?trRazK`>ul%5B1SUf0nWrw-5L&?rxw#r5o!BO3#^q82O*n5HP5qjYS1leEm
z6PE00=IlxPMi;r|%AV@Y)_Tqa@^ZI-+jDam@qw3%nT3@hG7^*es5U)kA=Ee42dR%L
z^Y7yzf%)3T=)Pug@Bw?3X~2J1u3*<PN{>AA>59ggz8q<Q`ql$*DNj>ujwt9gxga!4
zaHx5)!qXT#SCJyOiIj$>*yr&-cD2IP7&|QCdZnC)qIirbdPHqv`}LS%8FZZXIsQjf
zUTTVs7xM2ZxX<IUixrrJ3^?q`XRKjO?64f)m}bY?cg6mQp|>#(m@DRRBVl;(>8N!Z
zEbSIqp?^bKaa6{$R&l?(ltQfz(LNkiS2KFGk!RypIE1U2GDEwbDTF>18d933Sy=uD
zRtMnVdrS`Cae~u>11_!$1~sx7YshTtp+DQ^<yz)p=~*N>MG8)RG+%K-{i`QkrzT2B
zf-N}Ev?F#HTP^WSk43;#Te%8{a6=ugA#e+_A(Uz)1=VeB_SEuibLbEwEX0sJd835=
zg((TCLv7`d%PH-@#x)H}XJcYL+a|lxkT98Ajc{L{ul$|qiHjW$pdA!9`I3)k`BbcZ
zODtw1A<?#SKtU7x&v8&f04;ZLpshTDKKPlS_^<%*)t-(RM{wY4@+`a4dc^E$kFgDE
zO<M&>LZUw9klyf9!BOG!@*c6Hd|E1>2<c7#MbkkB<xj^Voqd(SR<1j$vVP`tLFh32
z;CuOKx!&=~>yA%e`#hPceHuvE&$KQW5xUFck%Nl~u^kpTGn}cdv|!UwKEs#)B}3CP
zfm;_JwftzxLIg{We<pF@-!pChvo*;xS|008HoKB*%0`^dJ|_wiuLrb9Nc&am==9f7
zfiE)p)(SAHX$mg;4{Wh6(x!_gN3Bgxn=YzwmD$>4wprwbtH#PsIM1(F6@s^IHJ?7A
z0vqBepJK4aK$6n_p?S5u>m7$~isAP$4S}5dec?3^&>mgPR7{ZS_k`e?T#vks>#o-G
zT~v$Xw%+$k@L)qs)f_LrUD&=1@6C_!_@O!tlv52soO|Sc{r9SeCiC=_D_C(s$-&<Z
zhiZJ->tnp{J4cgi@CsZMB<uiWqRC=wY&i?uISZYC`m<|ZuH7PPVKJiir2@|?0cL1a
zlX#i0><hj-Vgai$s?&MPlb)HL_k7T9p}9N;osS_H%<~Vry@B?<VfDWZx_yoys&Z5p
z<JRepPG5L+v^?fW+o_83qz7_u`82Z*$mmI~;Rmjv*Ih%eIR~wlWOGuhtvnXvP~GHo
z);agKOv4~}haY(V`ugb%r}wX~ja~5%$TYD~03CgKtoe{Lb8Y(Jtf>65{12SZsIszk
zIpvzNva+lUC!A)@<<aTo+KTe2M4UR)ob$1>jYX9``}z4<{4Z5CqziIBR$6q?W}UXG
zs-heNJk>lf)|z21*Y0f`aOh&qI=v;BROqJF*O%?AeCG`&AJE7FWLNrO!Kg0Qrqk?S
z(z>d?%jqajEX;tXz0*~0K$-2wF$<iwFE~eeTzh+&quglSY<8C?@D(xb;pgju$%=@u
z089yjs;XOmh;Eahq9(piJ@fqUUAjb?APxzV@{0egb?FRdJklk2b#bFQ<K4|yGLlBj
z1Lw`<iTx@2YnS>QOklH$Za-2%{u@4fGChyOzP957)?(a=>-HudI;(PLvfQ36@T3U%
z)YpQ!nh>rdlp7A?;1`T^qs9jO*2Cqjl3rMh_4qyA#D{yXq}QWNpxa2DbE=^$^*ilA
zS6cZdDqsi@92NCFOZ7>gay_8d_TPg!m~+>ZDKLcz=E{lOGh1K}6~tvqq0O4j`vc5O
zmm<L|!5nY&m^Ihg!&z-kYpcp$9b<nic34db)t(s7BeAc^4UY*tN|^Z&F$syw6mGq)
zJ!C%pf%(;?N4fzVoHdZWSdt$k(6%{K^Uc=gvVwWqPn;>7v$yQXd$QD6Cm5G>oDks4
zC^Dr9Ot7QX4XC0j3vx@Bjti|{n@8lg|JZv<h410xs6z(*UH@Hsm7X#EZSh!uyPYgI
zBnj+NhyfPK?TG@2fwZMg?IEW<89Nd9Akid&?g$6ay!~#><gNsd{Fvbgw8dT<V~B}e
zEKiZ!jRFXQR?DMahH}jyFtGx~T1XPa27|!P2vUFTO#KjU;APb{Wyf2%6iF?f(Fn3-
z$KMmCK;rGuqb;bL?iy26NXHGNim1z{aOtshYzmiZi`TwcmZ8+fXmOjq_RTc7*#c9-
z?^YH27Lgb3$u8W+%`{!DiR4yM`(u6Vo2hyw-Mle=2Sq)cI!Chc1D0kiCZgsjZr>aA
zpEyqmcOXPOaD;`{A$Srgcch)t9axIbZLxHkH6j!>Khf6i#IkJ>dLjk(n?7r$lTYK~
z({!e7;As^=9B3L9EP74XeXW&I%j4eqfQszIZDQ~hWifR3MjO*2xteIMLBr|(K-*BP
zx8fI|ZB+DBL9cW4zg-Z5|9bsf36uCj**dO9%k@s<${p;5sa!`Sm-YwtOcdmgXQPnP
zz2>+0wZ+gW-l!;p7J5yC6QDp8)xomnE&LY8(B=RGp$w()X2$v$I{gvlSHGs7uUB>~
zSB@2?=Pq=zz5W6;@P#`|Q7Qhd0D`Ju{dL4}O$1i;w5<R8Vw8L_lovtbYz<dq<QfdL
z6&=x>ErvFmD$m!@i(>wEvPbwQdj1I_7wgwp`MQ?JaU0{gqDan~qnah!kf+4l$jZ=S
zaA%8<L;Bjc{CrP^^*$1vN20K@JY~iE>_5{{--z_JleWj%aqKN~WaTD_X_1Jmv&Qey
z+Ui>mTja@ldE(v=Hsb(ei6h;|gY{XCdYfW~L-8oKH=Hf8@c|wlr^`z76V@ZT)^}mh
zK75bKa@9M?qb@ST9gvGucn|9#|M3|PD3z8ZCr#_$Aw5QsUqO1HKbY%kg)gl&R+pHh
z)kA5jmnQ*X^bpM#@ea{<w4OGSmcXT^TW8_)VP$!$6A#uLeqQ)D-TyD%|1Sam_{WL<
z`y~A1^;6|Ia6-b8o1MtPlR7Pl+j@I72%P7R@4G7qf+x<kU-ga1Tj>1kgeyr|<DU?g
zZo?@Wh7FJ0c>=+w%}$<*HUSzhYWc#9D1D`^2W!tF&K(z9=1a$}W#5^_k5$J##;nMx
zoK<2uG!0JO7>^dkz@vafKn!WH3jHVMV%U&tPHYX4Wo`R&R_-s}`)vbEbrrce3tk>-
zfmrovg90iy@UllA?Tup{BB_fo?SG&IrT<+VpVJbdrAF<)_nj-{<pZNWH!C<24I=~1
z(<TW66T~RKf?tSl_-!jdx)}!MvFHSO?#4)NsL>*kS_*Pa)Z#t8Us;sIWlu2ABSa+t
zR_?!wE|ExqjqP9sw!C#mqT;q9f)c8HDZnf)8~8IY=Ev@*f<M6{TdqKGw;3n$^MGRu
zh^kz;97X5R-f>L!eMcncP)N^xg4t#_h{$u+<UJj6EG8UO%kre^L_bH4l0Wl7DCj?X
z5INQH0~-uxc_cnnJ0mWhf|hw^+=48>dpMHoy~n@=bAXI4mIC_n)LhSPB&Bh9MtGAt
zI(Kj~g{pH>{}3N@aa1hv@&{~sh{gMIsI&f`VfR25n>o9v9Qn1s3~-zUmflcTuhNmN
zggj-Xm>zhSuR<6gSSl8xrZF^zkRj{dV%~^<pQ4bj7c@;MHePJqIW|j(PaN!)o%+hC
z$84@>kK<-9?+E4P`M%vj2ZP#zdV*ZZ)!sD;j=u@p*n_NVP5cP?o`z)!K=f=zU~_43
z(9GFlI&_n&HOO-nLM2X$IRh0reL1;(hSjlc;?5#hh!~Nv-4z+GVzI$`tB2Dp!Unw0
zUNafA=zAWh1+wO%y9{C?DFD$11t74fpsQM}fB^;dEi_B}%+MaAc?qe!=_&>yM}d%4
zo~T=7pF=3HZx^-!5IgH*9<>Wbxm!GsA-#Vz{%Hq+GGN>T{57geOkZA+BkCvWvOEMu
z>gUI!7w_F;kn!+Xk}zgsZY`RMIqNt)>W-9J->bJpN?nI9z;Jx9)dLe43duyL7`4Z1
z(6AkT6Ery;rcHEMHmgc!0>c4w6jD_izjN|K1xO@1Z`ba2D5zCd`@U_KwY$hZD9fL|
zi+gyI!;Rd`!fGVQ#`cjf?a$mM1-4wV?MZChrZ0TEN(~|R>0k~oV=pXaudQY~%BhR2
zi|ua|J9`naJ&=f9Y~OB?*$_V|kUTX&!M|YiWnNovHY8Nw#dE^;V@lY7;rSMRGw#-!
z*ET#atzi4wq;1kk0sjsFkcgro=lw`}Dh=|}6HrBnwg_QkZ}`>iPSrr#kCni8NV(BL
z4Y$_o8f9XkVB<Ah&Cae6u~|D+V|9pVE%b^sD|M$Um83`MQ`Ik5oku9OO6}=Nt@}vz
z>E+5ZLalbjzJsvn!tSitQ4%3{vl<{2!q{iI*4nMT@D+QW_sGW=VjXs_c=M6!eS2ZW
zN0@<x>Pkux(8^-8GA7>nQz6>d{-F{dg4?jgB;c)WZ3A*gd{i^5Su7`<vQCw?Ts6jT
z)D<iXl@w};3RYKYNhf|_>juk0)MmF_v7?Rl^HAd=IRbNAmusuLwP@m2dF7M{@*l|C
z9b1cEoaJ~;rF(5H#g%>^kNnV3c<~S#3eRA8hu?9P7sht%RNy<~4hC=d)vu+25h{55
z!A-oWTJhStJ~QPdvoX1#+W<SD+84ho*T#q|3jlS}PZGl~8#_(_#cSTPxrA7OrIFL`
z${B!2o3jr7xGs2oVzY=+e_LV>c>s~<=aI9GJ0Ei}1CaXW3;@OMR<{y<?k+qSLIwy@
zbL^u*l3{-WWWcjdXk+?H4&8MyTkL!^6jluXc+?9F9%`0D&ARebt$7x1i-YT{-{zbI
zXv#z=%gQNI8>cZnb2DEEEo-!A!_AsFxEHysFOtZHgRGa0u3)!}vYOF6jW;j4B5zB1
zGB+OUj!7u<0edT9Q%w9KahXqBoEK$TCN9pKX3Nvt^0c-*ohvWWl{dwaXK>^hsX*KI
z@eFf>ansuPJF&&fWW{-*#d%@yyvdsi)){hD>|1{X8Wu1F9m}M4^UdOA&mp?D8L?XO
zoSt3d0Odm{Wm;K8H~uMKSvJ~Gc@q$$k5lB@JV_f<oZDZV*Ke49+r}c8vf+(!8`oza
zzdO0#kb)ZjC`tKI@)Su3KqIB8kVckrE`(h!Wh_jer9f^eP}o<)n~L_||4-~~4dcF!
z6wVCDF{vD0z4{~P!q>+{kIl3wDV?o3#HQ+<)N26e0JB0pwnr7d?s7ea0Mj42>Zg^>
z0`kd5^iRcD3vXsgeH%Q#9PgA=b(<B@=cKkzqCE?4?%D}UPD219F-DJJ`PpEoYf%-Y
z(BK9xQAAUA$$gP2TX<AgDVIA$>hNbdSD5&e&VJ!e$(1RWbWvAJ{$q+QOl%1gSv#_C
zbu(g{p#HA2<dF#Uv!qGYd<duqHPbnZNKHib4V<E>e&se(oxW2AS&X&$9{^Z-T>$Co
zoC}X|brKR#Rp*|+rBi|vZdG?((zS9H>SgB{Aq*0<bt*_!=&_)D$42}2F^fbUu=gUT
zYC08LNmX}x67|wd2Q^Ac@FvAyTS`~nE7_p4>546*3XMe(?N+c^O)8iXE3c}o87lba
zfv>r?j9;R$wSJoiI9riFq7d?)vsHVxh_2qXwau&9A_6QHWt+5qv-Y5LLx#3617T!|
zWVM2bY>KJCogretoq$yV;)#nS1MEZzea1K2E~kMHbS~E#&QB7Z8gOP)QYZc~c4rTf
zdFQ93{w5oRT-pd6Jp4aX4(vPpAE<HhyI2LkfmQIP)}3j<^y{Jf*e0H8wG_c1mlWW>
zc<m1R)jPQ8z=rm0FD}y8)&cv+7ACvj<vHzB7pN42>hFTxgA?kJU_7OCAxvyrE^~yz
zCgRBB!Vv|@>|v76ZT%tYdvpq%ukA~ONVr?RqhV&IzC*^^6dN6ijg69aKafe2MHanl
z!LbY`{ZA9A&Ksv1W;K|ccQDG1Fxf-v=$T!@x$@L*XKL?1PSrS;%Lp63K4^G4uqNxj
z=79OXdK*1LiqMa<$g5ik9nPRm1>j7oy4{Lsw89cwo5h2o;QG!+Fy#Z;us61>t%Xer
zInh+)%+L-bRbwQiJIbGVF5m)T-S3|~eNK5kLwhzUzsXlW=u|)Vd6TL>ExX3Vp8u7w
zdb6_TXF#e@Rc9z`SE7ITdE4YHN%+Cg3(bkGIpX+ECco3CNvstLk_%A3IaTPU{0}K_
zT`nMBu4d=}N-Cr&o93s`#igf<3-)GoaT&75vr{-S$HqlCtiE${-iDb(*8exBeobM^
zivS<NZwT&`95ONb={5BeiqTKU)nCE5;>gK$W-dH@U3?2rOB{I-G{0z5*iBdslSEhz
zN83V0>V2FeRBZaA&*X+k!E{d0BH@#Hf^XWmP}7mSeNfeN;gm0VF3|MFkFS;dYx`Z)
z$&m*;&8SxKIXW8~7}k<tCW`u&U(`2-?K)+gBCkx4GzYS#A><FL;Q0jq<JPy@LS+ZZ
zu}tAXxn&u(|B)Mf6!LSOc$H3_FIp)fY^iyND)pr?%7`7Yz=LmgaHk47x7L`Uo$zG+
z(%`-YMwXAiIP-U(iKTE&HT)M<akt1{MMGmfZwjGUp$1CqrwF^?5lPUsD|Lpy0GN&>
zQOjxC2V(oDx6lpf0|S8WqaZ_$9^3o%-O*54$r4|Q8rIyV7@>tzhp(5DH^=Uzdh^sX
zfB15;lk9?<1L)dBz~s`t+_ewc*pK?`J;(%oG0d>;6!Ymzzc_s+tTKh56EsQoBR+e#
zzb7<Fo_BnnF5K{EOfqQrR=ik_8S84kOH$mW3^toi1%M!Vi_>!-kmq2(4GYy$uDjJ^
zivjL?2l`=-$rb|?oHtsrcMcgkV#rUt%MjYqa~);}$hTRro7vG}zarSGSUia=YSB|R
zXF)b(669BaT?FWpXLWQkOsL9JxT8gl^lh8?@pmj0^#i}Ft9^iT!wA7MS4G1Dq38CE
z&TN-jdhQAd91*v?gXgvi%lNUzcXkIY4#J(cVo!D|M;9U2fLXoHB1<Ha`d9XBD13Qv
zbEQIN6RRavZ0ScQgm&|tl1%QBurlxon_7ZAH9u_r3Daj4^zTa{OR@gaEMoOhon*bF
zV>)+K*Pf@{2qXy5ew{r*KcI6Cnw=m58^uO}O)a}WXy5KTkf``V-4izolJsA3c!)gv
zgaZ7!N@Q(hMBd*e93iB%vjarwQq%(&r+G_cCXo<HOJAKiGr~`LUSnrI8Zfg<YF+At
z2@+3E46oclT^#Bk$<XF5;cIeKGH^q;a|5kK*N2W08R{olFO6F-0zo>Rr@fqJkt9``
z(pFv^zfB@{2UYLfQ~mQj-^mVmY~nBk)%)OH%f(#<N5UBUhA1)x9}~r@izjYd<|VD`
zz&!TbO;%1xS$UB}wTbM%h$2yDIcDz;m8mw$6~;8G$OA=F$(;aAWPcaaw+6>d;7Gw5
zLP0({)qJ9%3UlH_O=IG}A($qfrnK!E4m{TwK#18S$pCXz0^6lk+1X*u)7Fn~yHgG%
zp5NT*T?3uPFxE^OhV@K<<GJ3dHu#lzUZLw89{&|q5|#S)KkE1IvCN~^Vs$m<3Z5r!
z@Kzj1otWH$D&8a%w#;2YPfd;G14ZtN-NR{I8Gmx2`xu>o6jrvlg0jtZ&1N2!>&L)h
zDL~ZIboFOekOJC6NsE>YbR<iM<Js}FGbwOatEph`z}(ARKco`eRiWFij9^@A%2_zB
zw#b3NS_O3R6V3IfIp_D2@MxDCF2JpZ-vrLq(1QzVk)ee>80qp_kN5xN(LR9D?F1~#
z=hn3B1{1rXCi{Gy5RAf(v>z!wS&2PDyuwEfU(X{<q4<oiEuil+-$VLdBJ2CP&t~1y
zpLve7_MM)zb0(7P6BN&6K35@1F^iHmJ(*G&!GWcH<$jB&?&hx2U9&t-MQ!ouQaISC
z(zw;9B%iNMb2Lvh^Cx^;;=8V3Y?n&M5nun~fav)TTyH9txfr$EdJpYz<)}Ts;7Qoh
z(O_B0S6s<E2(%0$tvTTNOkiQu640@yC>_gD$Nlg~POv0BSZXiv@hqXfA)SMbY;y(&
z+n4sEduoZm@GB@J!aVtRVR7in0TS`d-$JyVFNVrYEqPu#c1UGC>;xGG#Bb_hgbGG=
zJkO(i$`dDgGVWdgw`uj+mV|EK=U4s*VM0MbP#3_<2E6m59aF`YsUq)^2ybAhIWY80
zK(#-<I*|Go1&vXR{^L!-l_5cnz)+G2vw{)EzD3Z-2>AOs$s_1HUZ%&>&@}9nnGQD8
zZibBhJ2_?pZg8lXv_PZVpZx}$Mm)3m2IXSo^3&c|4GDL@mtXVO_NlPR+S2Ti$N4|f
zgAoE<V<tTWstpPwrG|}s$!IIa3z)nN4%LF8R@z}1cj<|Qb{L;O-rJZd7}D^n5XpLx
z=e`fuc!F?`JGADUa7k4NeYsu)19e;^%dJPXwj2P4`t!CiNFkqBCBZIv(}%m{g!-Mz
zy#PSRTBlBlOt{1P*Y+-@WAYoK&Q9TqtrHF|{6Mhe+o|)ueTv9U*PxEU6ETA0Ju9-`
z@Zq`;-eP&-z%MgYSRWiXwBil*if>^#3q}6d{=`Gx!u?uH9;&iJA@W?N-<0iF_TBXn
zrtl4AS+`c(xd%A_M4X-@n^Rz;0DR8bF*u>k;5>rs&5v>iSO}QrcxJ``2KX_~?(^0P
z1onm-q;yUaA)enq-2d<e<#SAr(sYmF%02@}6Dps{7EtnlC^3w%f?;r;5LBwtW4Bdr
zR&7|W#jB0)vSrJ)<ukbr5Cdc=!A7UA-G;uSHV8e!hIiQ-e(}IQh|Hm@SZH{J=8X5v
zvuJ&vGfa;GRxu6?IgBVB(4={)tPCwYY3#`{ZNfJ?OgFs4Gr5l0T=gN<C0%3M14__#
z2ND42Dmxg~dRRO9Y&9NPo~^;JE6I#sti=%-*!@pswr9;0X4^lOvmjAMdoVhdP_a2w
zM8`1G!G+FA_8h>mTAjX39A2du`#^QvCK}VL;8?0(CYovCNB~TiA<Jk8WaBy|aj?El
zp&JurXfI@Ps6=&}a2V#ueA(v#1P77^4?BXwN#>j+`wst_q_ZMaR9q~`2^Hro^*_U;
zAGJQP1*t28;izz%q?o6P9n(Z(b*k;}ipKV<EI${W{z6N0A>{n`i1(?s|C*ooBl5n7
zF<!9l(pfbL4qpTDGCfM7jl)<>0rU(hStr_SW6&D?YDxNPsejx})epy=uaktYll0%}
zH1V)b_eivPn$$5(@-KCg&^qxm$X_SZul`SUlKfbwavDQI@CQ|UAtJ*mvg&V`tz&yT
z8F7MOwyL;@%f|Ks`DkUNq$j{-J-;GZ*aMv<`A-Mzv#9h^`!ERU8%4!$;e2_{<jza<
z*TMc0l2C!=ZivXE$69XeiZor1B&AWNvi2K>OObP79RI24C<WZlOSH+wka}jeItru}
zOPT$xohpMEa~{|%(x}PoUYN}8QwGq~{+vgcNxAb!IUmJ*#5Kbw@$P#EEzyjb6F8uC
znKiXCD#{TcZezdbb}6L$yInZ~R{-bA6Bq<Bv{LkQUap-2cxxJ90%N4ZH8XjQ)i)Pl
z9$_F{+oPs{?15@dl0EGD_P;!UsGjE2jJUv&Mnx;4446KBfGOb52cNYu=A2LvJ<rk`
zSoZd%H!xel@e_q683JTivD8t_I&$!f$j@q!DqFG0Qq05A(7Ifcu`uEq%W1d83P=CC
z>R9F+$KZrxt<V*;YNjT5>|FambpPXOgcf!M2)+-PdEh(!5<z;N-~>;@+YdOKqEBE0
z5t#D?ctH;oM?<wX?LTAvHsHKz^%cuXH=Qay5|&W!Xg4dEdQ*G4m_d}=nX|}i;v;We
z)#nRr3-P&GA}}u$=;z^5zn~O}`KNsU$yf*bbZR&K+&u6%^(AqV>lC1&pB{dkOZ{Ve
zOO)Q~JC^y3YjEOJl$U+l!LCYuzr7_gE-E<n6Br>L&x{1<i-QP8NZkJKyo&{?ziHRc
z7aWby=ROS`_<m=T#*FOi+K)!y>(Kx~s;_<YDG0Tmwk!tXG}6pTb}hudMypVJ9)<~L
zqipQc@Lu9y`srnwj72T*jhS7U3Y@V8f*khgoZOXs5`SMi{xpHUK9=zW`uapDIvJh+
z|Dm6;HBe#=S-Q*WgW3utX(K9;twa!|oa~5I8#R3zxn_Z;&P)L#LT$auie60_menI=
zh}-fAQ&vHVyk4?uG%muC)a-aB0;tTehJnFsf3URqan6)PbGAuV_DAMy*x3%-Mf1Fs
zwroLvq|q!4jo+9qjM%WRJx8d_Ss+Ybz$8pDFJKYxv5iapK&y3WO|vIm+YXBL)U(27
z_4Uy`t483p`YvGV`C~mvp`UpYnvo(wF|VZAO{iW*UkICan159WY=KY1rhP2YsotbG
z-`Y;jY}ZIFa-kE){Vg)RFch%f+HR-%ae4L}#3iiw*taV~u}wWo>If_y;co9I@b-l@
zq#Sk(x1%0E|86_JHOtxlrf=gKFKv<wHZ2z14wpAZp8vePE_!EEQ}nH0DZK><N8&CJ
zS^`&E3IvWND}jLu(!Xlx^7kT3k-)DW;sZ`aWtjgoQPMfy_CKDZUin}8z%i{F5sSa_
z;kNd3%8=T_Z}`97Eus+rm=~Il)Bkk8Xc}9?OF#**QF%74F5YrjfSt42ux;K4%7(d|
z%@$w3$J!`!HNR+u%MhqSTxQHqACK$4PN_`XoTxd^$MsyK*Q3_saZe~UC*w|@p|`Z0
zhkq!K&Ql&29oKaF&^;N?Fj<S?iyW#+{X@G=Ay^R^l1fKhNc6kvEDF|=yMZPK2_yhR
zw6Lp;a@0Ujc*3cE7H0pqQWM%M7&bmwy-3m~G}vw)Nf%iWDn}?#Hf!ylF-Ow56glqN
zgr>g>9^M>FpSdCwm=hEO53_1TWc&)X0e)4zIEQ^k<8eW;1P<^chawuTtt7fXN>Y)#
zLGMD4E&Rui)u(^o=l=LsN!z&n_cx2P1pr{>c^4Zaz{_VMlZYr=#`bZ7_6(<)2+TQx
zRT?-y;Po?+L0N;8G<@)NDqa6*3vD0zgj4`r_BG8@TPM&fBs3=%6aY}2WF^TYNse5p
zEmvvIMOf>I(KX@j+^4;{1+LsoS8kC7P9JjeE-`Bw&AG+;+y#!@97k@pEqA3Y_eERo
zY)fvcC3h7d@GZGnmfT!R?tDw`LQ8I;C3mSMca|mh@m`)|awRvr)<D9<*9A2IVM5M(
zBa#f;$JJc|keyTt8Yrx6jr08H_<>UY1FQi|>$v?Q<CF;F4zR!-6eKET40!yXJTQ%2
zr}+syKk)zkbKqgVh4z~Nk#B~ndc6D|^IjwnGom=;k6p@NCOOyN72W#;2Wv7uJeWY>
z7V~AyePFoaFT;Kr|Bb<s2LJyj?3d_sqlKx|f8)8xr?EvzJ!3jRnkH&(>M4dX-3auM
zTKii%-gJkm`2VK+CbB30dyJ(mN^H3LV_MVq{<I#;k7*6VNZXV@O2@sNQY#_@Wy#5w
z>azvu*&O*#GJj!Bajz64CEd#WsOtqyIVkLp47UgcASq_K&@JTlHcHWrfE!SE%WQ$A
zx;b2b<WJl}gtg-G8FU|3MT(+7GWmQLwjm+b#OICQ-k!qr|K8&gO5F;98=L<^#$NC9
zFYxbqMXfDx6|(4$48&Jng%EjsJ}t0+-<Us53a?>C0cHi%+_xiw`lo^TQKklO==uVc
z*zrb#MJTl_Wc)ASl8#qo*BiYk)m8B0Q+~c|y#+u*%y<%(&b=sD-dwgk73%;3@?tI%
zfqv5SUQ8|7R-Bi~PY28cq;5uPh&VDW@)rf&%~Uj1@Z$CiS~d^d{V8j|;=@@&4lF3s
zIsbkG`z(wSVG_W|<7jx69}J?f**1F4=tw|s4r};Ica%#IC5Q*O^uw<mdr#T_L8$rg
zh5lJeGNnmGO+HB1QEKP`+b{xUu_r=zROCK9daO%?P$KtEfcrHMaHofyr^Njqh-ZuG
z7Xtc&Iz!ue%R$n9@;~fL_;+cbq5oI*1LQXOf^?Rn$(OY;Gxi2YZ4QnwT1s<VH`Tuu
zJ6tzF%Z^x-#o`z8g#v`hd?9Li)Q67z7Y?jRH%>`SeROX~$mS5GaZl>@kZj|j;v*p;
z`uykMaxQ)W|C91^@?W4GYvym^mO^i7URQkri~m`Z<>52n^4t8+T5S)X{R8`j|5-N*
zrCCvWWGoIaR>+N;Bt|n2bRgL3<=aX=Q>P1!Yl!iX%=nV{nGoJig1$4pBr+aip4oGi
z-uUyF^Yu&zsmbE1&D5o-7%okE3U1(cQqXL|{|XF=8-FhR;hz7)GwjvSQ$BzTJKz=l
zoQ0;=0nx_%1?3u<rB|5^FR0#7u<I4Q5nwH_#>#km3h)+%k6Nu6R!aycxlF(=w3Mso
zONR#Y4FWy}bfw{|z9|BSQ0d4GZBv|yTeM`HgP{f4*-j%*Ks`VbElauf{bSys7;K2=
ze=vJ<L#~VfAkD^x#K$d~U%k`p$PL`7FU}E;b0gw?zT&51M?*O50zf(*UCNd5>xgGO
z1pm&5pisnj+|R=>Q*pm7H>3}t5nBz~JGR_V(2)MfzaR~24)>Zf)V6Yjy`?XM^Nlv$
zTAg9Fg>bHBfuw3lPHvDpS6Q4J*1waf{RynMiOeRPr7jJImgas4)zU<VjSfCgFHw^`
z64oSalblc)F8VrE_}p#v&H3T>vA~*auDTYZf-#}KCZnKWVQy8#HS{YRIQ}p!B#riD
zQAH|z>Nn-KT$N?1Xf!w2y;N+0Bi<^x`eTLSu(~S1{V`(m29hbLpe6vg<hG@p*E&}H
zrOJ6(WnlxIBUDjF-h^5VU?yXCl~8Msy}bu+U5J;Ut`LJ6v{XHbUl^e~601kqU}v|s
z@@J8wA!5>Yu_qXB9*Fes`m{+(eN{CdnH7&5Rn@yi^oANDDeSkyt;aZPV`$$;zR_Hj
zd#T8l8*EuB?gPrX4D}L!NhO(<s=R!UkHivDld$iEuTiMpal;0v$U(W{Y{|%V(o_p0
zC=yCvBSOk0q57&+F;ViAmn^_yf(bu;{+_Q+sE&|Y1|~{QjFDA<u_ZJ3{OmsRv(r#r
zzW#0PdjMHIz0+ATaHa34PxBwA_c=?ZToE7fX<ncSUc5}>M)3(cFV!Mu%U@^$*(C%&
zApb!V{QRQ$0KG&GE#E*7MP8r@?s#f{=OYPyC}&44VA;uR@gd6EVV>ZudkltN7)Khm
zAP~6DXf#L`_}O^s!yXSMF7TrS2Zh!_EAXBz8t!{xeKjXpukxe({gm^cJSp*akU-B$
zK)ccHfZij2BE}hU(W2~lmQKb^)`JYt%r;vcl92ha&Tg~W>g&n_T)9IM_)h_xxgZt-
zr1;PTReZYN(C?k7nRCT`Lcbp8_@TtCrB<6kj4-Yy-xTe(_Na`;i1nuRQiwvEBJe3T
z4*z$@WB$8E<@k8U`qK3U6?tJ5d1_mt)K2b!>gGTt6;4-0{~H^~?$6)Y)IuxaStP7j
z!Bxx)s+gy&SRtxdAqM7Z&b+{!c`98Dn=>!ip%>)L3w=+KV})g?AnUjMlH7;D8OBvW
z?o=5U1X7r-mygf*+7o@75;G`S_FeB}CZ7)0^1=|qe>0d(0-Ge%eto>}JU<rMShLya
zBeOLt-pYe503;>IuDOoNx|qOD_MzKhFJ+XXo!wR*Y^b#xIQalRA}4|YG)Ug1YRWu;
z%__G)=gW>^JGu7|5E4~|MG587{Z$P!&JH#%2m&q{9FUKvkJ^L%b!80o*AZz?&p$oI
z*A?`fyp^qIFWh5#0cDNt%01Sp0IS<RQtb|i2Fk?wxz_X;fpK4gG16$<8M7i10BPL$
zHfl+QjdHNnHu$>7u1!s>PtwEKlqc|B^3s@JfP2pow8a=ToA_+xd1F-hZJI@tIdJ;i
zv65Hr8Fxxoz)i4#sVsfhb*O{7!67Q+b92Wkr+i88zrlUwK9?<sx*1wqt<|koi(J_f
ziKy}Qt<J1gWorw5QujHt;H5Wf-&{F5{dT0tF*siG?oC&7R^R{P&vp<#hzPex-Xq-j
zfZ2NMAd}2ArL});P5qm7!-&-t&8-iNBU6v;3bOuGOCGrsSiG7eVK5<qF42R)_QFMS
zOigD!qQ%$G-@~gKD`QToV_}B?cwcbX<W$koatNdS)Av{mlV2=A@PQ3^R)lbtth;36
z0_~TPPl|k9XpN4w{?1uQ>$@EN?dAe)r1bR2n3Kod<|(}aosR<t;(Fk;(TcdJ{87U#
zkM56_Lj!tLXPmvtxS*tL)Tv&g7%#u;Erj{iEvNc*x%d$*`ZCBBIOU0rg#dTWHto`O
zZakB1{lxtFN5a8RP?L@v?%D)1SX)@99G#}z5el!<pDR5KLYb@!?fb$fz&ya%o*$}r
zX{7!UcD6cUF$Z(G*R(xCtMi7}y0-tM!F+gY|Ey_^I*aV@$7YLcR-vt2^h~fe$yEsJ
z)ZgWhl(Xe9oVuhN4g5QqcIycy|8KrKMTmn(;&+r=YyvZ<bcJ$N>k2EC>qGbM;u?$8
zTe$W=S+(ytX~jwYdp?qUsvJQ8;sGUkDJ`x`mLhjc^oY(BJyw_Il>~a{<7$_IvJ_jr
z773Qb1nej*R8~WFI=DcRa{8Q>cJVUKu_za^?6C=OsZ&Si2_NzxMIeT(StNL#k*v$x
zs7LfWj9Ouy)q+vGET0_cZ;_e~Alz}2k_iU%OsEs#Ge(>gChki_ZTT!EV3Z3S%@-h0
z%tQW02nYIx2h5_yi-l>qTt_^M&9gIUJZNRex|mlo>T-AFZJDt?c2(#sb~dM31CuKl
zT;-I9+|6@wF~wZ$s%wSIL5$7A_n7+S*3mH0CK1qvT%s^@K$dF(<V_Rm@x`#gl$y&`
zXFJ?s@Vu=aQL5XPX<jq;-%$_br|xyC*XNu2FRP{b2=*Wf-c%lDK6OVuKhJ#XiuzLS
z=^fB(<u*Y6JVmCST|(wyU&x$8hzoIMV+a2P8<|a_VCM^}(J=9b>KV?fstqr5+Rdu^
z&C1jDT=iycO&+HOori(lRpo}OTIFlP;X=0N8Ur5@7(zfqx}ix67+B{<9h9@sot@t-
z#J3hvD85}Jtv@?P^Z1Ibr#3UHP357$@cY8&7AZG0DL4L%MZ_BD<<P&II1TuK<N$n*
z|89|*T3IY*m56;c0+>GS*_tztY|@3DuH|+OKrEjA{>jw2%Gr-pH)&4{U%t@PYqp|?
zf*scAH2*<%&6_q+h$;Ej1)$RDLK*|l)F5=ZYzui)Et>&!iY_Qh%a0Z{ZR{;$t<{IC
zN3_~ER2XcRF0^_`Tk|C6Dh~y#Q13j9Ti2T1Ak^j~J{QR%QuT8)&9T%>$h@ZB5}V+P
zjqjoG7;Q3*+_I*@tP2?kB#ItxCxS_Kh~cfS9NVD;+;vSQVi(@tAsKp=$e?Evs9&7}
zOyuTb_MoDA-yU;p44-48EjAVxwlz)WSOfoLpDotNKiS``VfE$e8iea)Ko#+<+P00V
zjn?d{OV;buo7YW)y(cX7VDNclisEdI;oOZgHE2KFOd}hXvtl7&p%6&KEK&|o+y3ey
zCx8!O3|&2>tchjEh7d(f={yC?OEh>#?=nOsp+-&Zbwcz@^=_?s%}$pnxbmj~u)cFx
zgY0VBx8%*r6-jN3vO{ayC&0Z0R>f}~ONiL8;bpS8Mdb?PtcOEwgA=f)IsN(`b><v5
z?Vm4(&Lp4S&6UibGD^0npGdltCV4H)9LC+Q3&QkoSc#aBRs;-5tFP2v`zgCsK1a5)
z168RT9$nLFmeN|eby%9zlnWz=_%nE7iK%syEg%bu5%q3uO+M%1I2$J#MTOcBs%!&7
zWwol%HcaF5m0D<{$Ix1eM(JKti~p`Qzp?3p?Qh>+q-c1AyC9~8)U06(?`k(#XL#53
z0vcL?@6XW4q8BRJ_5tDfA?1Z~7DhxH{(Caw=!FV)!;NexV=lz8V1S{IadA_vFqNHZ
zL`xc{Dn{xLazKvh?-70)pgzH&h-S!GVyw6@uc5ycYpC7Uncnyd`ZWi2tJzU5+RJUp
zf~A>Hg%|CJ@d6$?81On^qY-_lqH4-OnyU&Slg=M#w<OSEwXCr=@UV*y^QyaGUURT!
zHS6V~^~lSovg-M~^h&7BwTKoIOu;Xa*ZL_fX}0yq>rxt-UrqbJw#he1I8KD%Gy<v`
z()Y~-gb~~{_0CV=?0k;_9Iyj|+Sm-Z{6kca7?-2H2y;ZmxGn@K6!|8nU}t$tk*oQ}
zkvYO$?_#8}El}*}<y_;&+NnN2hPD~uan=R80m>K<2p}yPf-_NqXDO#7pw=}3kY1N4
z1QfP<$lRGU*j@K*$^8C-UzObNbA*YIr$)B7j>*pvoUIvqR|Sxnqs_HhG~S7u=v+jL
z$Su_1>oxz#V@CA74(?e(=AP{!;uFK8oCcQ3^<EW_=VatHcX@Er1<(LO&`D6*B2-Q<
ztN~&3heOQe8nI_$w0~T^<oio$wS_*Lj$hp}YvUeq0Qi{U5!M|b06)AvdMTMBJ~UA?
zLV;p=Nm>c|@ojXWg{S0amD_hn$rLm(UkDK|CGvb<XvqBSJA%~T-_*PY4HZn=c65mA
zCdlljj@s%8!LSYav&g?1p(J<9$ejG06E!vz!J>%zIwy>Gi6;L)C(siI6-~{gtFzhg
zlPQw}(IY?6pdS1HW@>WrKyw!Y8UldsIo<FC({jxfE$M848S!d~>D=|n^lEuWON0H%
zho9#=C$J9PQeE|kkOK3MSkD}EM>Ds88a;nIVe%zDGLx*gln3{5J~OxFOsu+7)Bv1s
zS-$#|*enXG5Ggb3epR>qolI1l1}B5*u{)Oe=xhxrtTbPJ21cHIqNb;t_P!HIG?{Zg
zl|Q>}yHQAzvCU#j6c<lCp3zr05tUK<)Pz9tniX9v#Qz?m0qe+bZS$GF`AAedZvuRp
zI3L|j<^CfSC=sUq^H~~1D9_9xDpRa^U|hW}v$=|O90vH`wG%7^q2-8(v&z~qk1Jbl
z#k?vPu^=>P1g0yYgulX=gI`zj+v7oHWiv2A$oSX`doGl)w~htW%>VI3jZz_~de>fg
z1K-+YSpzHxp}IhiQw?GLhZ^<cv4a<(&?y?9Zsye0brc=C<Puk_q+fn(;lj?Q0UJFp
z%v5osnUCo}b4WB07M{_KX(R{~_f8SOZJLy?UiD6A)OR8~s#s8oJJZ!?@Af{+I$`ki
z0<-r;DHLO#|AoS*yG1JZr}xx7Q%f?0#$!rsk`C)s&xxBCWNgKf=b<JMg=p@1I&WUX
z{ZqIXoYI|5a~_&;w8-#xe6K}DApWLRH-<s{Ljb>!-Km3_czb&+lw2ip#Q->@u<<nW
zVH%?Fj!ONNaqwbe8mfClHfwx(_>1DLU-I<}e_bnieM%bxEZgDdS?6E1P+*^$?h)QX
zzH`S00tPRRPp?_UR==q<zrff6w~#4BVLh>}MQ8eC0!capUZs8`jjEETxdGkg=dxfX
zm-lyZAm8QRnx49G?H=O|%JTkoLVYqEHjx99L7CJoQ*cC((cGJg5D`^?ZbaqKfnF{Q
zpe}h~mjYhBikGVX7h|X?A^B8T^BhZ}{T0z?3ry7<di_#hBjQk@%lT=W1vafjda1Vr
zR=ZN;b0YW9cuDj{b%>rUMj)fQB9~l)c?R<1D$tbFdCXQ}^)9U$*LVJ5<HG%JZY6_%
z@1Uo_=_T)eE#B($=j9%{tA3zFcIt!5QN9&C*p>PTHCiF1t=Li2x4}1fv1PhLHvNHI
zjngB0tqLeEr-~qAxih_XJ(?(JDKh<GV(5zT7~%JBrDxyGd{95!Xg)FEdaF<1FVBqf
zA_8c6J!Eo{(M?{u<KZM5pDwP%hoa!lBI{w!baJ9(@GIp0Ux-y1&QA@QeI`FOAlE&S
zo&U<ev}3M}<~t(&*LF-rDL=O33A6*V9Dy|C(;vvxgD~}_O;MaE8oPt0^gRZBv;End
zP}Tm+c#b30kK;MrCm6ig_Y%^1&fKoe^Wl~JXi;rEF8BpQ+k)&S7Yy2x;q&r&`GjNR
zY3d)O|Ex`Z6wT{lw>~~umxtZj7eez!x74csz0z`I@voJxmGOgP<_G5tqQ23WvL^rF
z<TE}&UAFp_k2^|W8Le?y?>SqQF6#t-Z3{Jh3Vb?D`@<c8{`hFO|6>%&cZc};gue>d
zmO(7K4O-goVhED>0`d{}09R;!-zAz5&90?eH<bY-fgTa+_XM#jU`qM0JHRS^C2qdh
zwqSZGDB~9A=4$n&&^E@+>D_rcgJoi<z{?rDdBy=TnLYSnT@opfyrQ<`DvxG#fL$Z7
zT|dj73OT_W@Qf->UMpe4uRdz#rlF|!1}w5HA~z<4U~i2cRcs+**lj<*t&bjI1>PWy
z<VBC412C><DtDZ<DSnK9Mlh#LJ0}LjgCDBDP`NpYF<N#hY3|th%ba?GcopIP007@i
zWAbO<oT*i}C<uYA-<hNe&IlIiY*Gg#F7sejTi9LQk`#Ugw7`glZ2x^AydnH(Am2=3
z#F+w8;6iRgLO=(7qcNb{5sQKkH;rgZUcSn{u@|=00$LSLUF2Dl>;{zv5ZN)K@>EDu
z%+ZXBTqRCLJ6MoR7+PLH4<l~N^dH}yzzZ{{_i{jFajKuXV#^B~5SQYN&<;1`<i5k0
zZ68_`C&Smj?N)3tMlU2{2sn_-Xkb?5^iXss-%pB%{lo{pV(hP=Yt#kz2R{@$eZcZ4
zAdg)OVlO3;6mW=_liUbR`5D%K++~iaYlnTv^R&;pgDa6<gGt|?{A`zo8XY!W^JnY=
z3%1qkIyGLhb*#3Zk`BoIB-cf$yEygA5S!I!wK&zMf-!ZV=~%~mGFDo|vBTZ06}s5R
zRg321pk2R!o~(=F*-c!?!n~CR;G(Bii(XwGABKZBylGp~FBK2uoWJ*^v-`>0QR#(m
zTI<%GP`y{zBXa#2f#s~e_Qq*sDir`u^Sp8g;V!#bh%qh|+olB$<N)>R=Ybn0l!b2y
zPlNmSX*cXro<{sLFlfc82RQW|I4uR*2Je+rNn6b6qQ^G0DyuVusk71wzqVewYRza@
ze<eOD)XXP`HN-291xo=;t9qZ+F^%(16FK)QA@}K5NXJg901gGUdr#1K$k>@b6nxtM
z_#@CV1&TlAuC%tcA>PbcZG)2?4{7dY5y8ZYD*U>-+J7YRX}xQN_-O189|8i2iXd8q
z(3@c<x!(V~^RJjNu0PK(JbR}G5s1v*h#(w)vGuGB8WlZut(*1Z85TZ-S~zQ_8Sv{C
z+fe{Xwg+)TaFhr1W_p3l9_rUi<yd`b5OFXGY(hvvOhQINZo<-pH3=^zY)jaaa407?
zFeg`)lN+3q3zf1yC)bdZYs|@|sK=lOetjCRO^el1HK<>k7NhlR(-O3GTx;Eqe`?fj
zy(c0Lst@b`V1@;Hwb^142^@&KKEF0?&9wisHf><GxNq#C9<TWDXhriYV`f#g_D0p3
ztmV#UK2#$=$9uoaJe&l%<&Cb^BPTfiiq|<!>fRRoztX+I3%KYWlPzQE+)W>A&rl7B
zbGR2WscL^LPgTeZ!R)tu@#0LN4o27L*+RWFo+;S3&+i?De!6g<>E&gnlP;%@<m6#J
z+kVJ-x>b4Pk7}#6jK2uj3Kin6SZu)@#qesqj_J8;#!(K*Z|{$CkUt*j7J*lyCLQu~
zcg>m-9KdKSL&)4UCD!5W<2@>(KfT{MhLD7KNSLGe)oYfylT%!p74VaX%mjzf&*uaJ
zfs3S{{tobYs>?`o#6bXlwS1b@Vr~-UpQme8{J?iYM2hJ+mkVCw5`>8Q4vJ_Fglfh&
zw$iEovm7V3wxBJ#?0ZbS!jH$6*wmydmPK0<lCzduSBfAoE^MM=R}jVOOJnT__BrYZ
zjNUXo`81VVlYsWk&aBPKy&uVo3OEwA`BA1;CD{BCM-(W%Q{|po;)p7Fbwn|;uUpZ*
zcP6vBTeNw$X7Ai7n`f(z&ka1IatE9wQE}gMBpPlF_(8`6AfMSl%Q~0TCN&2-QPYx}
zw{b*j3nBqqbg$^pjCDfVko<_-`$XwWI57)che^lDrt}5QU2UY|c7(7^YU723P+<7i
z5P~T;++~X896g<dO?^f7ymSSOErV+z8Wa_NIM)8Os&qxM$hrNki>Sx*Qo>XQPkTjH
zxSWD{zq*{h`5jkWfXP4UZ@ayCzLRE7_f>^%3E;xOr0j*{AI88)Mf)Ax$mcXt0Xh;V
z^XKJe*{0QUgn=w+5j$ir4M^I*q~<1H4B5yQMQcf^s7>J|u@`v4gh4b1DaWTF+%&e0
zET8i3)ugLgIDzWyZeOFWLq=6G4#i852LZ4MW3+dcs!aiBt(Cgc66<nj)^a7zMtJg9
z9~}5-rLqNZrxq(=UKY|B<JyC02Lc@Umdd+YAznWk^WORaN!5^poLup2^rZ}Ui1hpw
zC(66nBY`u_J*{`qNi?ripuTbsmbM~777m;K;wzEggIe^XDrDE+ng%Ms279JVGqWMM
z5DcoE&NN!UfxYozZZ@QAh(3igfdA=t7uznku|3SELeKy59jF4!-FzSL!oBRSR#3Q6
zpd}W_41GKi_4g$aBZ?7v6Oz=G639{umS;X%@#G&X49SL3Fn&Gksx&|n6baZ)iS8a#
z04K#Qy>V<wrvx@?;|$jIr8Ic)Ig*lXQ<rI*VA3=?J)^$cSq;uv+I4bVvqK0;2JFy&
zv_?D94YSbOKLmN1<l|jr==YYxqfNqEFfL5;!r?bAxS9iP%{Rv0+w-Z=@UE{#bw<}I
zT(k)A&K*8muDVl#!V9`vG;YO7jUw**Y1qj|rzKEHe8P&IMjP|Uyer!FyIOC~Ble%&
zh9Y9cP5^^FGOtQuw*FAPQ)$k5#IX7{IKxH>3@Zzo>Jl8XlL+Vx35#RF$sGytF=R@a
z-l<L4<DY9qOV~};7D}dooKFpyTA#IuPrmv~sQJ|KVwd;}HzKK>Rl4&}4*e8-%;TP|
z*9q4bNL2xV;=B}SHfEf^kX?P1LUMW~A)qW59~Ul`AA5u&($n*|RfG$gpJ98%_OYpD
zUFM|jdELUriUmM{=wS_x>lD9b-unL<j$?6pJQJNG;%+~$b_bP?T74Iz=Zx)!MHh21
zB7?-zB@UM*^^E(38zAI2T|*Xf(xF*){;cxi4hDW@qok|-k7f$bc-FV|2K2Efg!3#n
zvu^O1qj$YQPVbYP>A-_dAzGUAB)3@J_br$eobfeck^;ACP&4!dk>mA2HciC7LXL{e
zT#79(1^h0B<=?zmf+KvBE<GlvQ<0iF0|QPTv_G~7R*V(ama1pe@d~`Jf%_4Ih|spg
z_o{2Mw?_tO!1SBvO`A__&t#P5p#upz&cQ{)#hubZ`#~Q{oKH&g)QOS~9N4+&0pqE(
z_EsR4cIa7XSK8spp%$FTwqKiyly%wTY1TSG5$*J0VvdSK=$YC0(F?ZU$sOY0FIr9G
zG?haf;uZ%BuBgtRPa7?fe=%`8Da<Pl`Qj>ldiCMc-)w*XvR5KDb0-lj5Aq6g-pR^0
z!K<1Y0edi?l*`!CJR5gX6A^wT0BblCWT{i<DZ|U{AIKXPa=dvTZ2QotcTG=UZ>DZ_
zrL8TAd#e;6U^{$6naGR1ZIi^1`~7<)nosP<Zh*FE6oz9r((@rHK!0U3Y)<UkS%1sU
zIyA%cYu^GDI*{xzM+94EZ`(BsrNVOQPuEIjQ!mX<h1+_&wA-dQ=~6^v<HYU)o%8^4
zJ(FTvcv3tA6~QAH7frr>_}o);oygYdsBEE9X_JIyBLGROZC=>9V-88UU!XGdY%e|{
z(}#B9<$SI*4_nH74&t5Cyt-H`TmfQT+?Js}vqX&!@ylC=Iy;_aTVipK!8sZ`bZ+x{
zY-;X#f1k_&J&IV_5LV`$gtY*==UdZ)>*8@N_03lld_zj9DB|3=Hschl^-<F=e2Dso
zaBu|GFQx3o!|J2n>vV2O7%Hz`%r)w8Bt0UV({L97iuOI(85{nrc<UF|Zsm#C@Lx@p
z{3;ynFK2t7hfNq=?I&UlV>f<G+q{akzKhC|d&l=+c*uTJ*7ZhJeiyA?xBVyd`Z({O
zVX?Lp@w9T5h|<c8x|n?#pI=g9D4z2T?Ti-{=*`T@nU{E1o#H+695xu?bU9DY)Ndjw
z0WWxKZ~WIbX7W7tP2}eeX0oHdiTZ@M5ySrWZv_Ac!#r?Ly^hxEOS00OE4Dv&9YW-e
z7#bt1Q}N!81K$pah#W3KREK?ls@rD=8G&m_?aPns{|0l4$dBx2?4R6+w1tXb6udX*
zI(9%*fbQJl2$7U%xP`rLp73J*0lh9T`Ht#*+nzUuKe^y3_O<BFq;;w^Aj0-lJ|rg~
z+zM;A6ZFKfR6+|#axIm#DGd4tmqgb<R<E9!4jK5_>9z1F1yOY5icLw^$uw{7G(-RW
zMiKltDdh#(-H~8O-~;2({r(|O(QuFHKp(rt>J-#*v(77x#(`oys6o$W`syJalv(C?
zV<0Xmyz7z&uet+Idad{1DDGZzvQx2d)*!zIthf17Kiyt`!Ea-xtq=KRth<+iMTR*A
zq7IVYLNr5NtqyBT7eu!nCD?RQoSK3S0Q7I;U1sZeLYhv-?#SLD>|Mg96V8DX6=JhR
zE8EzWlGJTu)W&JK+1j#mxoL?Hpfk*-=jE1Dw@PFZ2lMajNM+>eHpMkPYv%cp>N@NB
zI;%yhtcw6Y0y*<oopLAm5h@Ya*%!d`xkZQb6nI<EI`|k;TF1O}WHv0UJo9|(bRcn6
zYXJ?0`Oh;Y_I!%RE?(F>A~Y1BBI=#tX4orrN)-Flr({&pStT>(F_p{aw6UgYpEy8Z
zdkg3R!G_;X9m<3PbGiJCB=u{aAsrbFIC(6V$zLeY5a(aCWFMk5EItVwQ<L(68$jWU
ze;EDvp8D$5_-t4Tv7RS<gp6QUr&y#BrW}-Qj0`m<s*IU|UQq;P4W~s`&Irf8lP-$*
zAALq6vCe2oqms|`0zqvM6n~h5FzC7z=uM%U=h#&zwo*)P^b6fTGnv}2eBOZQeFx04
zXnOen>n(oLi)^Rvm&k89L?LLFI_dg1k&O5gA5?5-B>ns1{-t3nu1=xLAdqNarZa(H
zoF`3>u)7L?KWv}DTEe6)kD|Y=@6f&F$cgZO>l5<kiWfxwZ{RF_(pS>;Z5wNU)<@=B
z=kMw3^tr4*IRB!||G;-CZCseXL~urUC;Ql3Cf@;k!O{VVw!7V-;1vyTIMpk^P5m2X
zR0nBiTcVep|C&=z9kT^=)dPdUdZVw0+Nz=N<}zS|x8AWa9Mr~es=Ork#QCx*<7?wK
ztrjEfdC3=IOlAl75)M+6yf0LDijk7l;C(k@BP6lI518{;t*5VAy@AS0Q{4d!dUeB9
z<&}}75uBFKsyuo)roD9S0aK>}N`ke{xuH(E{U_jk4LaXS70>&^H;kWV2Cc70gxb&{
zx5xM_+|#?djFB>9qS#nKWq3le@5mHMr*J3<RtUgL;o$ZX&l?V4jYE7(6v@Q?#Wc!a
zH4Cy!*z$XfK3hAxAvq{n;W{iObCVG@Cf1!T0ERCj3O)dS6C%bGI%o8!PzM5l;#<U7
z@R-w|n)ps{<D|waz;H)4|GT?Qtmn`J`1+O6wDIuD)R?Ug054#+-otNto+cfh5RBkl
z!puk|EMrwdh@Ju#UN9YmPoV(%qx`IykxM%k!RJsE^@;nF`$^xLUV?ZxVt||Z5Kju+
zdT{jEx#wU2hVKn;hacsJ_B}Kf&L8((D}{)Os|%I9C?9%-lxm_p`@@d{O}Tk7MVaiL
z=1+RiZyC(<T4~UTuqnGDOu^T5=%z#q1M~E(p#-`w*ch3E0sg7Neht^s9IG#@3j!iB
zxM3R;;Ud%KRWbAS!DE85f+2pn+eey?QoPlsFO>R4;)Zzw@B1vEQqK=k%+z5IRmzU0
zP#jgPt@9A4KmRs7A;EjDxP~BR^WnKFrTMY%R7t*hwHR?lrV75n^81P4or08aN}2pD
z!8=t<AB26Ofaqi*2r(4ln{ZruW?yULO#c|G%@8QAl)O!V=J+)#PG1>jU29?Naqut2
zVf^>E6C>W)cRmY7dGqBc^8(zCJXr$6EP>b{_+}?{Eh9UQ9A#>C;BYIN1sfkQ>C6-d
z6N$XO>xNmL#$Nou`o*L%Qi{9`jabbYK7;+@_bh?K9hpmlJUwIiN@~!lflX=yj;q0v
zcp0VIde4#v01LWn-Qcs10)%~T8H`PT&OKlW;`wM+saEM`3(uyV$|lJq!0_iWwCHo*
zIq#c9ruLNYn@n&1DPLv5cYXc7%2&Su-`~UY2x(AJuogBdu2G_BvgAh5Rl}HS!<)g{
zvQnEo%Z2E1iBtRci|h#k82Svuq=F4U6JWjKr@ig~v2kt$9d$rriM=WEUFaz<8wHtG
zZWJtnqg2MEK;z>I<3cHE+#bc73R_t9@hN|8VGY52zw+nj8pvl#pvBChizFVfJ%;}X
zM{rvU91!-&Jvvm%@LD*^FPdQ9`@mSLGQJvUtWv<R414CU;L=KsKoRk2Pq-_Xv4z6-
z|7ZB()o?_I<CokS(q*cL+w4|9CqTM9&xg;ItL68R+yTTHxj3;q6Y9`6x(&OgwJ~_=
zTFMxH8BXLqtV!Wj58iQy!PyQd{>#Pom&3(h`$*=(kHAxy*3*1;Lf}y>7n4P;%imZI
z%+bBm7TS?5vPtYlmfNSfMZ!_*Um>|k4y4NaCxv*`#w^6)o3Xzb4n0s0YxiEGv&<Wo
zh`w8%C_crHPZ6{OVRExb>JF2bpHv^2i|8<?Q*RIjaJ$K(#Jo51+Bkdtw1s;R3x|3I
zw<?nr6e}`MXenlFA}I+_>{JhM#>Ahwu)TgK9v!@|{z`(W94TvF!r4Cyr-WhG^_~E7
zH>%r~$3^9#Q8OR+x<pauG&WH<gi4pMmF#@r7Db`)Pe#$6R<jeI21E_HX=<nQ#>_e1
z+Uq{`2ls7OU(^Vn$LZ5I{x@6S9uP&j{y#f2J9`_D<+5^F6<1f~VkufGVX>={qLxr@
zX<AARsacs>UMpD7K~ySSJBgP%%fK7~rF1JV7zL}L5}tIeyd<StlXt__V`{?wKJP4a
z?0kR!!0znK`@ZwM&->gj!$t<UD?!s^e@vVDmy1p3f+ptn<uJaR2kr{=a>#zkm&GPr
zNeH&JUElUMc3T5W#bqX}FD<<eU3^sus`pSW<p`&MeHA6Vu(};9k0G`-3z_NJFAaOB
zvFKYRC(%Lt-%d~=I$>Q|+NIl7bV<BCrF&ImNxU?rJ8B3X3DUa~8mBUvi<$#Ufr}Sc
zN#(@K&X4pxlBraO1I-^il>r{6F<Q&$#7lh!_h+0RH>5GW{^g|$EQujwa&n&n3n@eR
zFR$8+ptK%sbJb6XH%S~au>*muIX?=*Z45${+phqBQCHMiP8Iw;G4aW@x%maBEX($k
z&m%v(k_+({g*jYv3cKV<`1^<CJWGDHTN{@(%@`dqXlP>MsI}yR&`9`@je2D&gKTfR
zhUKI1<D}6MiKCX=A11conS@8xBMzv$bfv9cmC%@SWc-;_?I8Eif>ntH1q%|Z)=Ea4
zrFzC^RJo!NDRB6MwXVnYg3@Y;*jU!|XIh>sjw^7&QJ~9@)>Os0%UQ=%?YQ2^X(2MX
z0nr(c^5K_N<FBqRtXKL!4@^|}9RiF!5U+XDABX|x^=T>;5ZoUXWv*Hg6>dJiE=p&9
zVJE`FTlTM2@$rogv>);CX21KV(-%q4XZIJ&kFAb6ygKn_Z|4N_sb|nfC_!kwQ-lP%
z3Fc5J^4q{YlsT5C{mzB@!7M3sFoT1%MQbK%uO-4V)(kjV`m7RuAjSEPOkx`!WlQUf
z4c-Xo_y{TYJiCej8ZhkbU@Wvbl~JnT;(HhT6aThAF*QfMlEcoM?_Q*FYbcX82C?3z
z>S&$@jseSE$jq9IVwY%c*DsdsH(bTj$RzF2<~Xjklt0GbLOoJI&*DDKpU25CR5{{x
z(`e*>oPhn?u*>lP`PR%IM4pjj5pLVb??w|WM-@IU=Bv50!IH6F_>}M5H2e7VSw9CI
z=d`>FM`a~<Cg`}SHTzNCY%x;%FrC>BIL$_AyCe1nFXEmlC{5uQt2KN0aR_|(VVJkC
zTPoVkx3Z1|{rL9LHH)~}e7@;WFmRyV@lC)YnlnzCPav9nKECh2YAJ`BVm?^Z6eQv8
z2iq*-0Q2rFZ&1Xy3%^;)Up7}aeG&BFo8h-<Y37whdxH6~7A$E=*2$n3Lu|U7;Z2=m
zp3Uu0X0N@Jk!K!<P<lUp`|;v5F=L5&G52xM9LbMBki4=NC{}Pdr0*0`;71eb;wYXr
z&C>FQB$Zh`&Zcx6n#fJM07hjV%kf1ssw1A)ji?&smKv<@cORf?%w=6HR~+Surgt0X
zYq{)kt4FU|xO(B{jHFt&UUR@G^y{_DcnCbZA$d9MYy(uqQS(_2w`V_$+e0^-%{wzx
zhYYnEsK6=Ef6Y@y&4A)R3JH3^56C;nl=MUypV$~#j2xtb!e5+^8HHoFaY=kEYAoZ5
zLjKb)+eSBJX8y8ns5$pB)UJcQ=&?xacep3&kiP9(Bgi5ohC`(70Cj&OHSWxaBT0=@
zu4X)(!DSR@9CS5iI2(uOH4d8JIFygc&7tPIgJ|SLV)*+e4jMYFFNxvLQ_)FlYB}rK
zwy|p<GWCXw)4=k{n@i%sD)@;fUO84`<I}Bw{O3jeybBHO`dc=~)2zoxZTexMDWR6*
zzZOOYs^}Rzlpb=(K`~orx7Biz=0>Ix?th3?l1qm-`cTbPtzFo|zA*kF)D-+0VT*jv
zV!E^WT(N)b;+ypF#ya$+)f}h23|oitN<FLS-Gfo6wb?9BYpd6rmhhe&3Ssei>h9<0
z88_MvTs@exEoi(o^EQ<3z{hVv4?b~^i&2$qa*gQ$V2x5?maVtSA7lBgyUy%33Q^d$
z^2hN_j_d_2xpeL3%yTq47b(xX3lzP5{seT7sAuFc&_PSG$%K1@@??C$M@M#B;Z&yV
z6{nV6r$uuc?e4;b@z3opG~I?3f;U)O{y3h)r|x>Cc;-#Id@8dlc<$Z_S`z(suS?G!
z{(L$7v#xBm=;Ppl!BzCGBfEPy*PwoczE>4&cjr)^<~9`i@A-R44BaE&%l!lL9~6RA
zPW(}{H;64NySb|{t2~6`Xhd501iNN3JJ`Xd%?_>{lGI1Rt9qKBW0g$<^)0K)pJb)!
ziYU`bqwrh0@N?+5DXjd||NOQ@IurVBDr=qkKfi5|e+vEf6e~P=_iqrF8nsR+xuFUz
z5T9RA#129eAu;XHLf%=1D<v1oJ7`xthX|yp5PSp~ZC%Md<<lVQ@GXL_m!#?5dpcX~
zwQ9Oo`w*0yYnHg~X?8PT;;HDU4)9|U36{$`bJe2zRZlLx{TWuYbLCI7)*GZ<5gCj8
zBmWC$u!xW=c@n0^A2AJ&{zpOu$&1BrPFgcfw=OoWd<HA(sg_lwxv5lchRX-5J!MkF
zRp|#)<4hJw_C8*P{ywd~2`bM7GCH2e`<@_6ziS@YB8B5!*9?{$zUaYEvx%c@*+bG8
zDlxO~!$<$yxkh;|5xr0$rqgJSTsR#|HJf0>S|aqN>-FYUuy{ZLmVbqj#)LkoOZZrC
zxtb3*KjdS$%raYgt7W3WHIWZY)cPlednf9g6ZOuCVRA2e=>`8|G`~dt)kOO3NZ*?Z
z^Vs46wajU)0vN2_yb3MgN9wmWW7OfEa+QnW%>0J6-f>#bIGtsj-U$))=g`x>zdVg+
zTb$-qsL4EC4|2yZk>apcu^c5#$YQOhaNQ*E+mZjkBev>_sOGLd%O07@wgnmxyg0RH
z^_-1M{P4hJ>k`k|OqX>B4XA)=$zuFj>{I#Zw)J=s82xi;S!e@cdP`gQ9J@wfS47^o
z&XvKZ%O^}rNBb)}_|;ypGxULGeOa70i}qwO?kf$5pXbxXEcNMgHh-3CX?_+>xeS(s
z(JnF;za-%9xP3kFFeQi4*{k>^&dIbj3}HKmNU?l>PkxE@Tk^hYX>aHIsugIhH+;Y&
z*uiBmH(gTV7Hky6<1|R$ebe@~-*}bDfaKt;XrDP9N;2=F4TuJ=Arhv`LFdw8xmlc#
z?uOhPgoz>t!-29$@WVtD>@o6@N%w=EIZ%6P{<`5{@;#n-0DpTDDVX5y8I+wKi5vi)
zHIGG4*Fn48)dnKEE`X*2pqj@6lr_SU;Gn;`r)ZVbAz<xE({#P#b~{gUdx4(cnv@>~
zeF`6f;|FAzV_ews@>!%<<>c<)m2VkbtZ8|&>MNi~wFdP{pJ($>4eYD+gJDY>pD)~0
z@ndTG!DC*Y$MRWKdZehZRQW7cj>Wl0LJT*1@RXV4f2|tjG2;qWu3gz%{*S8K1~6V%
zmG!RIpNg)^$xjX|sV<+6P7YPg(%0k^hVhS>;`o;5%4f6I=<Yq*4Er3s;eckh%Efa5
zGu^yCO{aD040fF!lKHC9E}bqj^Lhcyx<dvHx}H7c_X;{IgR14Fa#Ph{xfx40#cR$?
zXOF86*z8c19<3Q27_CL3EsE9xOGfK_Pe*v-Y5asp;+oN0M)%*M8fdVLMg=tBpntSV
zKCdd)*tOiM(b?G-N7t(5b1FEwYt=K>Hy}~UdQMe56W^;e_>RuVuF)z5H6WB#2Cq(M
z?F@IomOgr$GM|66mQ46egcwER2e@X^$%Hkkf%?#d$8A1L=vU##^sed7sN7C69h#3|
zx-+T~8fC&-=C2c?EyU?R7dmRj=mz)bhOfzTTU7@%E;Bu7eZz+LH*8pEi2?ji;hG26
z_B7P(K(B3M6GgSsCyW-dS<RN!7U2h#dpRaW`2gvp3jW0DtQ#=^$9wzissYBdX%V7<
zODwb1!CguU)I#$-j)Iw(?3k)d<J55*ir36xSAni+SFLhtb+u?2h<;mz;Y{feM8+fv
z->I_e236T+>}g0Fk4h*i4DhWofc2;<dx+ah-gijDjFtxPC|W-9KM)?(MXCsGb<rG7
zSMvJetUXDlS$a`t;F*c~&zo~m50+LrX%+^4GWlewkRESQa&9*1^W)=p<$F!)O)2n|
zIMhuvb==`Mu_Ys?UhzBFhu1bbxgIVPyXoep6A*b}KOv&fJ&8)oNr*zo)d?vE?Woq@
z(}i)!jp_gQM!ET}8+%kWwLDp-@14iCpiC2nH!TjzZj;x<*6Uj~9e0#WuWFJjZ~}_y
zS_5#XstNb((xdDwp%<*<;+-P2$R_U$8k2)}9&Kk0Jep`h8HkSW*Eg}>P=($kjY*oE
zBoIn5kefXQrYUk^AeVJJID2x^n1LL;NTD$bJIBbNcl3qnk*DoriOe~(lZNqDev!+4
zlh5|JXYl-lFrSU_**LF_^4L_Ojds~sr%jz}(}2<ubHI(|%Iv+LW~Zz8cV7R<7*JDb
zEJOMb3_@&@ol3AM)C=P$schf?>M5V5(dfaEJjBW9fGG-!;0VK1{suLrl8;<7limIT
zE9z8E9c8FNab~o&8K>IWCwy4S^HnO8rL9s4e~0{DK9}9xr^m1wn(K?0Cu;yD#n2OE
zc@SpAxugf$`{bS%*~XV}Thy@R$w`&cxOhl7znUQ0t^5rkMQev*s5a#}*!=O_OL)$@
zmOLlmp{Fr+(?E<Zycxs=vd_XA{KzMp|KKMcQb|n!-;rn8V{0#A{$;`PXO(-b?~(yt
zX0N`2F-8wd{syc1Ahfu}WRjOLiCjYNna4IhhkG6zmb?W6EDGYnIRv8k!a3f2q16{=
z@Qt=uSK-dKYe@3FS*4PG3N7|EGR`X)M<~Xx4SO3Ln{Hr)1;O&?lqJYTWcc|Q+d|-T
zG$>#0j^F18x4+8nGI+l3aE!ms$6FWwCfTs{jSE;Z#N2>1EFN>b94ud;j3POMNuPGg
zGC8lYlPslqkyJ^3W>JGP7czr~VSNk=%hL)Q^D*j%hEK`IJs_y#_ju41iP1oW=;D3(
zaRdB}mjCki4-<2lFeEq@z%@=HuktP3Tue9QfD>X~Tu^Ym1PY7DM7Z70p#n)Ke{$ly
zzs@EXuYS^{)j74=(7l7M7rYZ)vI|@-FF2zj!a5hPy=EZ`K?D73cWvyKr0zEbQJz{6
zM!Mz>F_(7yp&^~-Ss{~lY%t8HxzyC;g<Dpvv^h0~`5J|@ESxv*`u^^0>hKlol517l
z7qRG+nbWgYwaaGa>vnp+zABCF*>W2KTC^6n%Kh<bbnp`_H;*i4A<DG84b!(C#y0s9
ziUZZt@}oi1Z5Hc$QdwUf)(15$K|)M*wkMJnQcV-}Epy73uvQ5a!0;KKL~waFx4K5k
z?pccnCuyRomL0Th0s8sCsq!?ub@F3m5Hj|7d<e;$XtvS0PvG}=f6jr|OP;FSS4b&u
zE)AkVM2L}&D?xt_`5w&ciZP>%<Gzbj0%-~diEZ;rZPkA;Lk@m~^@g>sruaUuEM;eX
z#b=M5%$qYOtd$qSr-j+lh-Ada7mux{LA=&1CXl}~1;hQ<9C<3pp^VRvEw9b`j&B|-
zD34nggdV@A^YJH@$E(Jm*Xp?C`F%!u)IC05YSt&&(jb=_(DC7~Egl9M1{nD9m_FH5
zPs7W=^U|xqK_QJ2@jJ&ke|Kur$W77teY8rypE1gd$i48dCH&NT`F#vnbuo;&3ezT^
zV>>^0Jz)<$Va7iK<J99TJW*?wv866V@sO%SQ0LG-YEl>6MVd38ORn+gc~NhGBv%Iy
z^YzWchw<j#(^+5hMXE=pC(^vE9k#{8Eu?dcC)W&HlWa0od99fyM|O~Wi!oLCtPhcI
zWIKt@j$+-RkzIOzK1Rk7Aqct<h2>JI7gZj;9^*UyfZa8tnCSQOb0TtW77-mg6TJH`
zW{h(+4kfMrQ11jr+FWxf7}~w1N=>ZNJgO=H{r`Y|{TfpSJN(GlGr20ud}D-lnCbI)
zr=F`pa}6zwcq`ULdRS`E9>|)=6elSn6x5*^e|J}FmHHN#uPT5J=4ES2l?|xXVVq6K
z8>tG+_=E(i3^XbH_ldQaL$Cz-=a(c8S^a9B!T_ue)pR}dn;zIobg5#5fmHru<jkN_
z#S*KT2;d0jFx4{IMc{y|{+?3o%%utIv8Dup%A1nQ)Fq2M_hT3ih@`@v@i+Jjo7Wnk
z?{qh1*QM-%fc*U02#nX=1ogy(YY*%Jk3{sThT<<hAK!g{d^ACW0SX#m#1YVuPGcKP
zOFN+K@j4Xd;^Rx^qEOp<b<_2rYdrOVUg>>Y4xt+OiMRo+6V1<l3A%ue^rl;Bz*!No
zI37R}F&kQRPmuNpVX;gA(L?h58ATsQv^<^j2Fr7kM!Boll2!75VrGXD=|g$K%YP*>
zn@RPHjP7Si%uh?;(^FIUiQ^kb7^SBP_fAhWbbg(Vuk{Q$jr!uTBaFc8mZ?=nIRY=i
zr%M{Z5$&+FCS3X)mw?mI_h`7IKfmqMb5PN1TAdTMCB7}S2#{lBx+kcP0wHKgESGXI
zJLq{-=YO1*X|f}%5QquEi&c&gS)+9E+NN~trE4V@EH)JiUZ%L*B`zef+#=Xaem{S0
zYaPlbZJks8CTdQ4nq!^uC@tN;EY4M_S{IojR;o8gMtLd+?2HWaR>tj*MD@O%8%{R0
z!*yH;0R*i}$*970jOTS1Acs4o&wKWsL2T4pY-;V{Q_hn=qO1IhjT2y})D;%64R_pr
z_uu?>YS1~Grw0NX-P=4Yx~iCOyX>k7I!`x^$4-lOpc}u@WoMk-7^htw=*9)?T$-Ko
z+f@P~rwI__7nn}nBJWX1S!^ii#)@tfA_v%9?hcnt?X+=_k32S7gbhH&FST9>l7GC}
zYoi5Hy$=4|#7PT;6W2_7t&G1l8s5Zf@M3;<L2oBpUdY<LnZD*3PCb=+{)w^?>pq*Z
zeL1`BGaMkdf$}gM|6BT=-~Ykx*$7=YV9<ZPanqv#oywy_?vwHMo<O_`u8NX>?(C&m
zU2|;1t|GJ=u2dDkm3|=ERY{j_Y%q;T27ujL8cfYesJ?<aHl5)739G~SK3IQH+fl#g
z0mr3wQ+>N=FdVKg&D^ui%Thj8wRsb&5US385L2siGPHAabbw)y!Q_de<g*ySzAtv?
zd*5>BQ5KL(UoYzPTc$Xc+!Ec(F)To0s=v8sMDM?`hhHo`j1D__#3g`g>qmQ>YUam_
zEE4lnPPN84nn4$Nmkl-2P%srSn##BqZ|w7~Ls`BcP@r?o)^9^=Ru;VFDaWY*rt!L+
zxC8!x>6%*B-?jRHo=VfJe*bWQQ%w&mv*g+6fK8od;|w2wcKY><Q%^eA`)!QJ#;(f<
zYvK{2DmKUN-0)SFftt=2{+(^eD9s$T?eGw2GGM!mxx{*;2VOUAZ!9KFm~41^#eKgT
zK5*H2vf)xQR)%HF4*^#?82Z||Zt1|E@NsN7yJv*>RlCRS^w=mzT{qtB(?#+6!&{e|
ze}xrRw5hy|%EKUa8aevg4qx}>L>#-HE_#5tMCS565sM4k!c{nI51m0F@tfV;HKoYz
zFPQAkRflKRY@76*66pJrFKqGn8bj;hAJ;;Vm%r@+mFsJbOT~ClOQ4<)4<M{CmS5(z
zS=?1?MH|}|EX@pV^D~s+ruH!^BKb3v_fg8psKiJ0&PP?AM`_oi4B;d9lq!l5_y`u_
zp;1$!6!R`l4{-q}%^%VwK%86PwDUWv=&U>(2#?Al><apf<V`pTGphP9c`qOo`0887
zKfkZ#iW-84!vDL?(r5T>8!Camp-Dl3dOmKt-cR#|s9|xk4aEZ?YZjmWh)n9#l9w!o
zt-)zytUG%&eHFwxMb$-KYaVZNvgR@KBkB1{*+tjB%zE`e?L53dGHMX4NT%oIQMqc$
z&hkzp_4<3UiFu_7meTxfB1eHvKe0hwb^ofG>ib8w%~QDBND!s_ZK{E)!9~zz-d0a(
z%*`?9=Jd$T>6x3;D>o-GH>Y=QjwLsz&-}d&1WYNV?xCAgXn@JC;axM$TPt~HR%2li
zJLuKYf`!|vhIuw0K3rq8K4G3RY|flSWZ7#K(*N+<lOVsd8d1S_^I<X>j{&Vzckv0$
z_7&`nerlJ2GF9^!)Y~}R-<auZ%;a^V8?VqU@irpD+BTrx(E=sXEwS2Nte>KHPNPy<
zOpElT)upI%7tpI<;UvVP2G32WQd)Wa*-Z_-SFmE^By)n(X!aWW_>8^$MoYlhGtJoB
zZtOANnCNo<-DR6J-}ac@HaX4qM8G!1Z+psTo9?we<Fw@z6x$jO*bX1J!QR$((>7?h
zEpx1G-Xhz4+v9edBhB_?z&6!yo944U?X}Ht+H$3J!BZxYrb?P~?dbn&-lo793@ZjM
zw^}u+No9i`!KK&a+k1QT2oNyjKM-rav^gWnJaKb<IJECAhZyOK>5P*VpVqD^W*b)$
z33U5vwq#1ag{k7Vt}0(eOt~df^V68)hD{%o%+9y4=lFg-!%ODmr?EE;{d%zwI^IMn
zL4_)rt=|x%80IZ3A$H>Y*ceG?>KAY9mmJ<NJ&WJHE}pg4;ua`Qli4G0BiG{2v5mdY
zyn_$zXA?|U-(`PKNGU93S0p5_S;MZ|$nmQPADxOW8FTM==C%vfco>SQqEBwcXMPSs
zV)!N8@16Xt9PbjZmadxkRY;ef30qi*&*5u=Jfl0fg&3)pelr0x5W|`ZBes|eZ?Iw`
z5MGGm=g41BC@wt5x-<p?kMenmup|bmZ#}u5E-jAXv!&0;=WKaV41yE(kk55id~UWX
zpPPk+F<1s42RYD{t#wqPAX{2F#m^CTQ|?bla3eoQnh}Gi;-z~N6p1F^a=P~$ti4j3
z=0!bcc?ac2Pe9z4Zhac}RnvU3bzs7H%P`j&;R22|<N@p7VtfCc*%WWCsYk-K@NjI&
z9LP>CJ9JA_A#GRU5v2Cey+UCu-g{GgYBRZ48r^j-P9q=Jd9Pee$;&#V--5!OAc~+%
z&q5MWP7kz$7E>X>_9Si(!Ll(AKx9%=b|&}VoHB~n54RLgt0xAglG}Wpv;ZrH;`CY!
zgurB?bCEt8|7uQ4)gj!b$wJ}oxr*i7ksXFxmUX}b>k(BulhZeEp__VBRcRhtD-Q@3
zwFS*j?Suwyp*E-N9B$!LFzVAW3POvJ1K#X#)afw5BSF+8nr7IU{MzP}(!oyF6Ulj_
zwEH)*RTg<l(CWBm+VH!Czv;jGqcpxq?sRK|<Bc2A&S2K@V4(RY$Cv+6-e7|A1`fR%
zL%z}h53Eb1OHs$`;I+_#dIqyvf{qIT1W%b(1`O4X^Z<(3W<e@#KH*q;RUQ_Hu$6CP
zICzs7`Iio^5&xwLG2EAkJ`tW(U?M$7U=kbT>WEFM5H_6=#&Nx;44!RUoYMu{uK!Ta
zVm0vZ{P^4d_3u24<3?iKV6{`#($g7*<OwgwWd6flt#j0M)T@x~!)!uiuQWSG`7x8|
z5+Q>%a0glu4tsJ9&id-Qmf5hqPc$@X!0PpOz1FEWc=S3LmWU!YdKEDc!&aP~y?XSe
zBnW!rrK}jlY(fi}nB3x<p!H19VYoqMw&a>L#jcstj==n2>Wjys*wi=AuC>Ap;DQ-I
z%IQ(7GV|G=c)tEk7~7+z8G?%(rFlM{tyc?{-_05O5pFQ?*jlUj@sjMdHS7JlH$A$y
z@~_04O7ZFn@|U5Q3Azk--rwtY#qZ>gKQe<D4oXG>TKC7CS;-boV-ejMOP4%oK%Smr
z_y;Xovx<<lmT`E|CWe9rMa*Z0G)6I53<<rKFd_!=dP<zm9`AUqI9}(%YZcp)k))(|
zj#C;Y2|vU)&S0U;lw=U)Kjz44_UbhDc$mKzQ!>(kOc9d(g8872jV2pT3u8bmU<x=E
z-|03Rj%z7o_d+(wNW`3Rh&O>gH{{`6>hiU$P!`kaMGF%d`hl9w(dzQ|So!@J68b~N
zwnxzxL~d7V(_wNZ&-{b6{v*akGftZBvH^`RUV+EnXQj2F$H;TGb!@JCnUmoxQFMCo
z>f!xA<DrMFiRu3tX-QKW<HBs~*F~z!%UEk^=VRo#!Rt|zd~|5;u66V3S2nN-LdL$#
zG0qv27Gytcc|0cV@o1CON&CC*OQY{E+3SpqbVbILj4er0stkASN$(9rOKlIfBohl~
z`FgOK_l2HN2L*K~(2Tq*P3`E*@vNOtwS>`xQYmnIk<O*>x6{M<v`wt$Sv5@L1(OrI
zKdWBTjVVP_;4I2xikVbp6SGvFuiHIY%9KQhdXa{`U}Ovm)~;vY(4T5{s;42@fwdL_
zenWZ2v75xgr^vV9$7@P~PbeZSGP<PBJ|@BwX&QGQ+W6&~0_thNtTEHPk&!-nX!BWr
zxb}SSQ^?b(4;RqeFETQDj(bQ0&WumP;i)C9+e#W>m0JnR-s(NWhA*w<pdKdna7CKZ
z*Sm5}7@KFdcE_D!WaQ2b`dW>oi?QdLiWsWOTdx69d)3pB_BCeO@%u#Y(Dc?5_Z>dW
z`o=_9ub>;neLIo>oBIHpaez&_h;tbk?YEi+wKO1aNifMtJ)DuzgN9>03(y7vb8D?}
zXlgDnWR7AZW}h>wKv}No+25<YK+QMwm*$l9zA?fe(nDKd;zHulIXvjGnhr4lfM7yb
zi@rTDUeggoKu<G}rFkMF5A;^l^lH`4&vk%H3l5|p2M?$`aE@@zc=bb!VC?Y$gWweG
zYY0CeW9I11thefOY)8hS#I^-y#OFp^8Y2R>h{HcQJzvc@xu<#0ZdE1`H#19zu1lsf
z^H3FOY?%sWQ^$<8=<es45@#qD;xa<2u5M(Vs3H{aG3t?EtG0~cEMqj5$*g6vI_W;k
zm<S8jIwjIGB}yDO%reDf8F!y$+)(GZ`vcvmz_{U6uURJ3CF#P|=%m*yV`8O~@m*0C
zUF+qw{;JQ9Y+%hy#y1deQRuWS;Do8-cI$=K6RJU2X6m4ALwBZ<hPGu$X~Y7Z<A$|3
z2PuNt+n^4jDnh0@JE(>djtO3F-@s=4JMr*>)2&WG<Nx>4!&MgMeqLLWhv21A_rrn|
zT3S0^TKF}(YOmBS26ivNu}Y0MkfZVPqwcqU6Yo-weH%^qTw}(D9>ALb{#zr<H?bLC
zZyVyQsgS-3p2`OK^rKk6IM7~C1KS>%X5~Pnj(otLJR0cn=9%?ua?t*$)*C);N5;v(
zJyEqZ&cI7i@{f3?lSX8GWr<Q(Ar;q|yLU#i)kzPt&;v}v4Ln;i#}3!`spxS`*<(&`
zJ9L`T0n1GRt&fSVdi7GaCrX{sf})gs9r`pSL|MOyu70&;L)l{q>vxQpH|{Y=C}F-)
zvB~ur-$0u3N2zP7+O9ZP*TCu2GwNi`*_3;D!{L`2X3SV{h?8%dMU3_}S`F@cwMG*4
z_Y13o<6h;%NZwuI0t^FZEBw>6fM6{qHo29jQR4}h9roYJgf~XKGf{^c(TaR!11uMm
zG$VW9ao6Zr>)~irXjtH4IZ(bkNuKD?qP;X#w^KCSf96Bh-O}LL8ttQ1r!SyuVT0px
zlrteFK%*`knprhCf{~xU+VvE#uiN?h+CDAoy$R7ZTgB#f1V;Gqu~zX$yGC<6&_qOs
z|0CPn+gQbnl+kiZC$jI0kF#R)85l>!$JIrs?i8(VsBzY87UQE^)<0lLYi<YO!Tlrk
zB~K+-41{%~n?_zVyNk_bxsnH7G!*HnKUYx)gFFDfEBaJ=zLh`n&rVLtNf+Bue*ihP
zdeaWgY;+}|MUM01jlTip=fFpP;VfW3wPw<lhSR67pH~fgFp?O(grnwkOZwzVlddCH
zT#a&Fhr$J)xmcAv02F2wxsK(yFif+1y>r7lS6o!?<Mb2j!x2MV&&l(GknkU;ce9S4
zua~=7E2%q-|I$D4U!nQs3yC5kzaK0tXSe^0ZIsv}mF$@c_NvJCUQfVfALFuT-SV9G
zp70+Gc=94vio)?|F|Tju^Zo2fI5SD~R>s3a7JAH|_?vGJSJ;t-8B;?{j7a2W$glss
zH!E~682=sc2hg{UU`-$8PUW8I^x(~q^Yix38p{xtVy;&s5Q3F=m`j!<SXK{te(kTM
za&l<A&1{-?R&gXB51Dy2r21>Up(7;aRKt`x68^`$$p+V$So>EIX_NKEk+sA~xEgNQ
z{Iyr|CL`)t8N-H~nGums4sEd}4MpByOv&TZ*|E`%zXg*z<%^jpQ&nEg60(#s2-Gu0
zAxp{YRV|ClYgpMB(?n4RbO)0|)TxyTrBV=j^vV`?W-n%8WLob2wj@<vE}fT)E~==N
zr<$lxxnwe2G8yh|W~}N(W|nm}JI)#!Cj_%X3Nu@Bw4m^?B8;{-Mw_+H#t1^m`(!GW
zpFzpXy4GUVk+tm7?M^-f8PFUaqE!P_{>BJjW3;aa<?l)Pb7>!X3xnRwq-LUOI4s6E
zoAh6K!*sUH^tP&4wNkgz)J5<hXOEjX<(1H4%uT!otuFLRvkS2?!qpi4N;TWr@1oC)
zuA0<k{X3x~1f#LCV%^IAXq7U-95zFt<W(wPV+4w(dCe3S7itH%TW?-{h%>i%8e>=2
z>@s*8%?EfvG@mBWKdl%sPUlhW;bq;G)pbAJsjG+Zp_(1gB^Lp|h)EFFXHs%q^!BZ6
zZ-N%JTvFt0+8G(X%dqJ{V=pG5=A7lc!TS{LeTwl#cH3>KtM^5QuikSk{TJY&?HV)N
z*>-`s#oG7ILV%{8V9=0<*It`#&&xIB*<&HWRk5}$>_~L?(HBRBP;5xT<othJ8L2`1
zNu0|b`+t5ZbLQph9V<DEo>R+8{Y}I|Gq6;NCx(TFH&oHps**Y9^ylf8@TAC6<rPQj
z5OLe>^HI(ydNwn!cpH30L{ltd)7P(Oi`0}f*+jiUS)Ve6(B}|Sg%F}mQ;$1MhhQ=0
zbp;ogo9sDyRqz(;c&B4{TFLTa^8D~9$7AqW{e|PARE}fuAIH^>4{l4-O&k)9Lo(!a
zdedm0PPDi)Eu|LkVY^zDFxl}-2S^+dJ#kOrN3d1=yZ6WJB{;RVZ)5poQjr;-wzJax
z<iCftD*r!WrTg$*7-e=73Zd*BL?naP{i$`WSsudiC25E`&W#qm(_jEcoSj{jX2)MP
z%?_KbTxw3sGZucpq^>Ogl;xj-ecR4^>|tVV3`9X^?w_`b&>13iAkbPXgDaS<n)Kx0
z=l>CHr&R@`RheT4JNFfvjvI3KRheEx4G^5L$5Ve>tU`G*rU@>R;!wJ5@}l_~s$ijN
z-lD-J5C7hsUQzkWwz7tT^QzP51{>BFtRyAO7M>q$_&2XF_^`pSzHZUH`2~MIGJpT!
z{Z-o6tJU)sy4w~SYc?mWHx%b<PY|f->;9cklJGeac|$X8+ch|UBv+=Y)-|cA1C0Ch
zg2OKw&3~UUxq*twq^^`B0q7voF+zptT!-#Bl5X^9JM$TPzEfY?zJo2_$&UY8ZVPVT
z#g^~JN2^kNgy^{AGt!;z4_)rnE}P1!xCqeR4fXyEgX`GFJ;eI7)GWkuupb+w!MDmk
zCs~yIR$iSuN|ieb4W%hzv6<JQ0|-Jgj?}YW_gmhH^IzW*218!L`aw0Nmh87->dT#o
zeH;uo$W{#ax|uiF3J?(wEPo9Td*Dn*y2Odn^X}BG4F{c>SKQ(w)Zx+v&3kjF(c%QX
zIKd!JK<s;8)5`YpFWBvWV-N-ViWw_;<x2#_)@rP;m<KnownjG3{V7ZUr-E~E8vkQ`
zjv8FgmU}^3z2yVsmoTl@ee=j(*0zr|hx<pV#C@?KFoADTwEkl5qnC3ZJ(v6FdH=pP
z-_w+Ju35nK$FUo0cCc5!Vx9Ol_D=5Dj@+^Bxlb+)Jh{YmBA7e-At87PgiZm9Jj-le
zh0Hg;MCjXnNAg>N#zc@<zK6G)%F~U4lOK{rN)S0-p%iUYSlXF7WZT9>=rGO$s@JRf
zm+tLdTF{q@%?#y%C9J33E>A2Tgz`+y|3*k>Y1!ZcIA<qNH<Gv1YCITvt2NgQorb+a
zT#Q13-urFP)91lut%&gV%zaS!Q78SVlZg){L<j4@lZi17v=6%r8<R(5cP58#PPq>W
zV;)*3Z)UUlQl9ePcP2l$Ipq;P>}J|6qrV$s0Ci$F&P!`=Lp+gQ;;W3-`=UwT01;-P
zSuiVQp;9ZYB}WeVR?8_aih{wYhAv8iX{q08(b`v?6^?Ol<66^T3J-90O04v(_IPPM
z8q_|^!X@M>zd;^(5|7YXQ>g7ttTW-Q&9Suj)LRf8NKA@H)RH>}k^!2AVSrCN2auj&
z6(d(T`FR-mx#&^YA++@>#3d}zH>%Liv+AVFP>Iyy>L0q#{-_mY&<3scAU*6s`G6to
zY|z|(3`@(Ver+x~U^!@nUWMAjXxVDeZrMYe9K>TT@oHallj+4?c>RalxsyRp`7KPy
z*~o+_^(?K8H(iM1H{kN>Mt-87)(0ZlKo0A->7}=W+`nOk)8PK5hm`yG2Um;oW2&qJ
zxXh4sXDaJ%M0%svx{`$^=MnYf_R-4qJ><IJWV2AvUkp2o>%*zdAJIjh1#80z6m$UN
z6(0775Xo><T|(yJ1KWi;@bT(f^{%gPI(A1x!jqP>MO(1)|7@#kaBMu!^Wbwv4}y9I
zUVs`YKd-Ga3f-fdM9gj^t4b!bqy9c-PuMO9dQUtgbvZ|!wIS%Jkpr~W(d}1hPY|{E
zo#i)?<?49y7lJgtZdwIzv<lwn2;K-Ifj5#dx@mRLDRSi2sxz)W521^><HQ-jVl0*Q
zcP#7<S(xGUYEfWyTw%~F@(s-mjypdR{CWT(x?$Go6t^_!6Lp7A!qC`?>p)LI&o#XU
z$V8w_i{qYCxR|nCnySBfa-@FYTPd(SMMVqa)bN_E_Bi1)qV@d|msh!+50l1di=GcE
zAB6|lrst5-vK}Nq)wg$mus~hDpDjCznuzO<W<4Dwp;hCtu@I)4rUuJSmhNLs8Q+(l
zV@*GP=T$L$eCX85=PB;7P(I-Swu(Un%|TY47hQ$gF2b)!0}RQ$HvGm8KFGodz*t|7
zt|BorKP4daJssa)g5n3hY5uwYCx3=t<GZU*>Z#civaNT5;<Kr|VZsEdw;9(8n_1@+
zs$V4E&l1@$ExI4PF5tTZ5zuEj2+`GY5TjWR5<wkfKr*RgCkdtV@=Mc9V-qI#UyIT{
z%WgWe-tN%`S6%*R{;qo7xR-O%sx@_N2&HDcURt`aRMfnkkRQrQU9lm-qbY%d#HV?8
z=LW<KGsiaR_(*^Ev3}BE5jtc3j)PtCb!j%0#YW}Y=sX+B@|D-Ir6)?=t)<Sew-eTf
z#?RMAz<fS8&0Uf{5;UAOXE78wNB-__%fDvjY0*4WkK7JF!}t)@bwx$B8ZWfM>kAiP
z!4>0$mXj^kCu2lJkrSC?CY4amXMjoBD40LH!3Rc%7GSqAwW=4kBOq^6wrFJJD?#!X
zc4J%wdvt6-y>tckUHgQ3_jN4KTHN&OV%VVN?t~$eic9Td7r{iM+{deD0-m3_XY46O
zfgP`5QU9_&`Q}8QVTtGKWy3z`o^LTARBD;^w}h4&PL0k9{9NHmLP<?$_mzEQx{&R0
zCe>n>Zw8B^DKcYso^!m4x<WJlg%V2i>s3A6b?$_kNqb6NhQ$aU?Y~~{Gc3yQ!RC!$
z#G6O9ooeBArPc09HKiW?qJ;IQ5-iz^)3TS$&t8P^7*F<6G7W&aBk2U<LPE}@L#*|B
zuwVQyT@O~n<%UNu#n-b{*atj{0Wgf%yiB^7uuGM1q4QWSZ~Rj3QcxLcKR>_d60tY&
z2CO(CZKEAhpvygJeW_EoSkx`bkL{Zu-&@oz*;MB_xGX=O03t*B5rBaHims1y<<^9f
zI=;(8v$r2IVqt~t!oQi+3wh9rVqU3ZGrvWiaH%J3u|I54eo9V$&qu_tC9bfgrg(LJ
zTxx#&L&)XH@Elr(&f3QlP!b`AGf=x=y65Lg#}fEn)MVqNNrT<bEXTb4MriYsx;gt8
z&z{qH4z{CGpmp2S<x13fe&6>=;v#9%7CNJdWBh{T+x(EAuvZBuO5vlS-)B;OcQB`g
zH7`P#;gLGl!>BCoPeZIdF~#W;Gm{5yu&gl023pRUo-sOG&YEtj&AZoangnyuQ(Ba)
z!O`*3s<ZJA^_!OLvlyRf?@Q*9Kh*iHFZX{b+((1Oq1GPZQo;`gj2{{tIq7dSLX&&5
z;cGN3c+1)xMCi8Q4U#>!{hRfKQM@y8OGJOebAhk`uj~IZhFy9cLNxk@C)6~5<Kzo~
zLHSSWo%~y8W8p_DA{{4wyc6dMQ(f9f4vt40URN))B#3UIUgc#AeXP^ZF7n$D<)Zf5
zAmau3fmXHFqi(=FrrW<;*up^c$ii>f{$FaH$AfLK-Hk28GC#zcZ~GDs9X|9)XzAt;
z8X9{yw79`ir7wbT0$DExo4z6S5@6v~NkQF<`ZV<Wi;s5Y(9ZZ+yNv_INGW&bu+qn@
z*w6UHoM;aRzn&MzpX(&IF3=hur^+AM4_<MPsk^W);8#&M-VAT0#Y(fM=^h1sjG>k@
z8-&5I=+$y^g_3qg=ppt1Oa*3MRC|#=yNn!XdK}}W)j}MKIjwn-aaxT0cv3|u&nOLq
zNnObfMXrO>l2S5DbZ@N@h4P@sl3MbD=-yT%N&rodGl$t-zKj;HojHwqH9pN!ozG5+
zWg4vav0jT2hozyNHFeV=-Gtem&m2M39Us#Ay?MrlLKa!eC=z5UX8kd&=8Bz9ucr^+
zi3sEw<$ngvJiHz%*^?lzx>*k;8AS?3?_9xjQS>hJH1_3NtlJX^)>K?0QfTUBMz|OD
z3^IguQ_xe}Fi}5AY#<d=KDADbuScRi@yowU>?jB!lKLrzW55LB)()T^Y|-F@fX{=%
zCPT5W`z&a0@R;q!ZG3X$5!OdD<_8NtQ9(VC%Y)_&yf01$o}amn$+Z{@b4YLE+&trs
zSJef7PXqwF&ee1pnM<tfLPs;RS(XwkeN)i{H^bTWd%;@O_E#7YL(~BriDI77sl8M>
ze6XST&P~NJ^==T=mNw!&e^V9+@LyJYzK#}HWT<y74K+vu7Nhwc6vQOJTNgC1L=06Y
zG*%-<*<113Wwu@2N}~GmadgO;FQ*#o*sD3r%(;v`heyNCmBt&d4s`4fck!3<<0b>7
z8cb?l?a5JzsF+Z35xYQBlF?vZ1sH#T`gsVHJ?7}a`T0wRD~>O;$}Qxv03IuL=BNTW
zXdq4r;mQ*-RP+E!1Bw+Fa1p3+Su;by19+S}^yF0~gnp~x-CLV*hG#${NWy#`$|Ck?
zQ=SU#Pq+)9dWC7bl{iBw0E+h&ZigOU7JB^MgsjealqW80gq!#s6V}tA39U<%8?A3A
zaB{G7(PySG&WhhKY3f6P9F;SNLdyPS4W=hAKpVOMZGHy;!wN!}&_<ft8|8waxdiy2
z^k7nGCLfh%=hN(HX;0u>NEIJ7FDY1&xbmn_cBfzgQKIec;_OkI;G#h@XOMgLvbvqK
z#$#jnWH_EcvFlNN9L*Pu!pqn_GcPz3YT4~R!cZ3{oT^z`zWpftpw_~K&<HQLs+18-
z7=eUF38#_$8d@{Mn4gwk51OZnqX@<->vQ!n?p$mdb_<qA$cpk-78eS?Wed=<;#mc8
zfg6W3JVI&0cf1Ny067Zi3lU&xNH0_n&C;B#%Fj|HW8li|D?$u~#HOh_ek$-HQfI0|
z^Ji-}ohe-lNR__FA_YjK)rK0BN89mgxL6qn*+w~Q;nG$;&>{5YK~JMu0)oP8=4a72
z=f83f3$olL_Z$q!XOLJz6%Jwp7UQl!2;;3<IB`R#^fDLP8|nFAo}EFld1ZqGUmZ_<
zC$)#y81BuX_|&!^m-7$$auj_21^yiZ7@Xz&_YG?%5h_SvPtNk)i|r|w>+4yu;&$h9
z<v(=)JEt&%%!$E3;}wK{3};t(2DxJODzo<Ws<^s?3Fk#i>IR=LZ0-i+;6|S=U2wQ&
z5cGYZnOK3$eL}ybZwT|ndYq9_nscgCljULRQ`x)=F|dzoT{P0pTnF1t2i2)KfGv~3
zMwh~_h*ZHXJL~Q-e2v^^AAII<jo-2Eiwz#cA$=GVaDUo%8~pJ0oj^Cj4-W?$+BPnS
z`6V^3B#8*m{kRGMwVt!OFW*QnOLZco2KI|B+v@O8-RDjNg@=ZfseJ~O<Bgl9Y(;P+
zxP<rAfQioaxQpvN)+ZBgylUXLkXTC%zYO7#;5JL=+cdstYGycdXW(M>NPg$%3yw6f
z4Hp~0SUradU;i-P?*24$l(VifpnvP+=>7jxJM{(m19Fs5gRDr<XLwQfkxfaB+q`I~
z7)`B<S7l5UA&JG^0CMVFHcgdp=bRY8u0(W~fh|3nu*-**^}E3+5dv!ck{w7$Azag-
zgYHkIi3yNN4tCVC!dF3WUt|Bd9Avc==?iAQjXM7A&KLh2snR+=Vb`~0q;HF^AVyBA
zV?#1vYMu3r*09PkT%8JbBm1@a@#6qKcwP~SKIrmxh_rF8@pHu&;t3;^B6KYm#LC{=
zzYn4PWlkRXCqdzV>_pd$Ab$!(1YRYqvhv;#NhqjLxvK_SXQR$Q=<F6McxAl@cqNZe
zJ_`ebUhgte*9zQGZn}WjKG>6KowfY}SyE$!HSID!fW1XIY2zVg5K!B0l<vEnX6F?C
zk`x5)5wyby6*r}Wow$didv>w$`SWTg9c3B|j*dbl9Jt|{I>bNx)-Ub>0CCh`7^ghI
zQ041BM`4`un7bG!-w}F8;hrFWE5w(Q%@YVm4G;Ywrv}YBRBTaLF7eL;_c4D4`}}zp
z({H_rd%Yij8M?XQAQ2vJyc!OgUVi;Di|8J^!t0W~73VIq)&apRM6A)$0*L<P45^jA
zys`JCjnR9`sj~0HkAi5=g9Puy4a?Vmm+4+0{~U2@&Zaz~aCzO&`P59tN2nN;QSBN7
zw1FcN0qgNSJyzrXrE2M$8~7?+x=Q};zJB04pSu7B{ttd9#+W>tAA_^dQ*qAv1qd7&
z=0o(-;*;f`!Ho4#Bd``sp|9qo*IBdP%P?g}oh|#_C<J~K-7+$^>_koA<N`Y}$wE3q
zr7Jb69;iH{^!elZ+?cNs8Po<6hF%ttU`s?5h5}>z0WnM9n;SJ*9F;#M416P17vdWn
z_B8$w+seqlp}KJ=eFHX*x0a%a0RSPrizpA(j^U`dBhL(Gu@uqDC6pJ6PkrhT(@G1M
zg4lx1vr)f`U?i=UUxzpu;vc83rPe^f|3tgBIkiUErrkOf$b{lKH0f^t4@I%Td0jZG
z+kY<$?=e}o6sa9>Ku(|9S!pU*j{0KiHOE-b-uKo;JwduUS6tb@b^;8m93w>rr)XT9
zs^17*zi}KyRZfm!0b|i*;xoKist~M&%>>pQlktTDYpXVxQSZybzMcEtjcoq!ry$PE
zBnDHHt2F^m75Jvz^r*U?6O8OGjRGD{ZUve+ITioqjp1C`_m|b(XWzqrab8o)v~63!
z&-J;BPkt}uvF9|7NB+QZAuE%$K|bF60)WfOC-8K;I_nxbmV<f<s}SBGPr$VhoHl)8
z7{xO}Q?zKOtWDAGVp|IQsEET=rC5f2ii85tPq1Fzq&eTaQx4%DwC7OfDhN;5VR;GU
zwR(DdqxBbzS-y_(s40{w1kSjgHU4Y9wlRlkIEcPYMktu$g?S8k>FVv|DElgI_;QdG
zMoF{ueugvkWPhEXEPd3m@e>7e_y@&NI<ew+p;(7f0}A70n2bk+>mA5bA!5Q^S09uE
z9T_9gNifjIh!P2;%DM5^`8`qii-C|b14|iYw8|Zw;}RNjOI~sJurJA1Ix=Qwq5G`D
zV?EF@CiK5J0(6AbWr4V>qeOQ*s&ta{LI_(P7EX`G3V4Iek6fjgK<*@eZjLW^oHsX{
z{QSvPKo@XB;J@Eu?0*ILE8Py_<Jk@^p-pjbxN;FxAPq&R9IlFX)#jH_*eis>+2onC
z9fSTN@3$iQ5~yFK-IR@J%;nmWlVT-Y0-bDL`c98$ykO7LDSqVDCz$cuQHIP9u`lmW
zy$Ti{7o6elc2d$O`)+mV-yL_UONTl<IB~G+={=FrFw3>l*1@ds4+I%T?~GR?yjt2q
zl&)twpiM3d5j(3NZ5{-I(Bz%*{`D$30gduLZ?@I3PL}FFs~@o<6{n|{Hxjw;Sp2DM
zMJ+ha%0b9%sH63VQWh344gw2t^i`Bh@-~Qkk#m9tn@3Sd(fj_2y0A4T+0qTjs&cyD
zLShv$O?aYIFiiOw+6R3chNsrUh$BT6@lV^XJ8%Cd(Ce|Cz3vT}6W%+|T|=AHzuuZ!
z<F0fjjIP-l&>Kik&3_^$kSgd)YAE4YUT-hD7)*GUXJ4sf>p6a|C>}_2e>!L=f)Hvd
z<mUL6+f$c2wQssm39Rg(%e{DA<lfG?4x`qM`N|5HI<!96$cVjwWIQ6ybthU8evhU6
zpUKsjyy>T)X><qd&<ZX(rBf?hdQjGa<j|U&mD^XiwAfBj&vLhep33z852(ErXZvTw
z`6@p>78ym%(UD<SkFmeI`iqQ;y9!A1`t9EVh@YZ6@T%2LZNbB_A1lG$`5VqJ3uOJS
za5d|B<co%EXmmzX&JQek(==y-CH=lMrU0J*=hrG^Gv6f>R!`(Aomd$Qy=y%Os=jVf
zJkB<e4soWTqNeB@;~7sMBS~L-)_7xnxKd18-O63oSYOAI{`*x}-nrKb6TqIApJHWG
zREQ-22ULN^S$t1kf25Vgc!y~3OjBm!b$dm?l0(WPWAr0+?8BD16M1JvpnnxzbU&<F
z4T%dN=|=>8eT;zB;Wfyl9xBEo)0=f%7=p5kjS**FV9Y#JDBrV2X-B;L&hHRJe2s&k
z!tb4HjlUr7g$h5EZ;?NZ#|tSc{2-z@T8HS!>tiyvZ-qz~S%JU4{wS<BhSIz+9aITI
zoJ6zsQK(G9C#3T7Jq*xJtQ@-8^^m6ryKNh5`g&MKIz*LmT2nGUNm*J`&HWiT6Vh0%
zNsmvkftyy{SIcB>TX0!}>X2N(ICP52`f~&UiMQhRe#=bH%$WYE%W9cJ>Q<WnH#7pi
zSLy0RJV5lZdz6jzx?kUq^$n-`Z>708SX@K-J*;~R+VX)GTQh@1m>~KHw6B-s4?B3h
zd9HU9<1r4EZ!jpa1VL*vB3(yN{ozu{f}ymYIYhUrFLUi0sf^A-ou$elJ2C$KRDXC|
z_6IRHhP~BMi!5K1rbLsGQJl3G!+na8e#1ybBgsfjd1P;p-FBmcPre$?_=y^co*@2b
zjq<7vqFT!z#1keKS{eV2@Q)7j9KP5&ijhD1gRr`zrm3l9F<$q4vKD!~Dr+Nrov&dn
zS(#)lO`iq*jM}1RETg!@D-D)P%5fzIuSMh<>v>cl^CF%U98I67Xs^;WhFcwURop0b
zA^7=x*LzB(LE`?XOxxyZa6ENRc{|}E-VU$Edq;72Nx{ezEerZ8ZXNbDI0pV&-z}sk
zDpJoMMC##WUkA4!=&!hP+TY*^|3!?tO9Jahqyn(CkW?TSb!6-YU(1?>{Iz!*ybTWX
znN)K%=Td8aU7$9d=>4w+tl^gFnchxDjrxn-3jSFB>jJode_u_u=pdI0^O5ia)AV}K
z<t=ecL3#$hpJdESq>X=A+{MX#OwDm2sLgAo3EZS>RMy0xv!boQ2_MnPBR{f@>p~Ts
zQHad=uLasOIn3#cWM8@<LY@+4tC}7{u7!dNILZ8@!kvz+2jGeU_L{XORKHD@;<TnZ
zg9320n&9Lk3~E|3oRl9loHPw=sU>^Pk55$gT=<O^D{j2d#qtGC7eI0u!<f2-b)siR
zPwQ(P8F5*=f`vb^mL6~LJz&s0ZAr8|`9@~qf`0)92&%`aGcW6~c1LI*6nqBR)}~c@
zDELO4Cp{l`XFXP9j>q;NWU}tTSsdVLoOD^^tsI&$-;$H$%^9E&Eh$l-#AVC}OEC^j
zom$NaO-z#|cw`0R#e(6Uj>2`)D(hKe6({Y(TOqyhXF9;BO+SS}*kmNM;H=Z7)<`-4
z0{f4B+RCGF6enMyiz2$toB1Q_tPbq#--5Ma*6$haQU|X?eHg`X;_71*MfCh4vJ+(9
z=i=|^x5JQ~z-lfISSp3=DRbjP`}lI`ELx9ISwD1iBETM|=mwZEmeQ;^XF8AfBl3(6
z^EkNGuo2~~^>_&8gtU-T8U<_)z5f;MT{PhfX?lnG3;!sl=?t(Q;caRk&d^8l?;S<0
zO5Zxj$Qr_oqDQ*+y=Pj<eV{3VKu^e+!0>U4x%{|9uq`;^cgA<KUcGkUXs04_6fqmM
zOd@E&>x$U#kD(kd-4QGGFb5I2P)++rQSuyEF6!w{D)6BEIH1Ho6d1)IYmoea<0nn+
z5aesni;?1{5C*{mV<V=Y&MfAT=kb%`^K({QSP}h@tKwqmdkv;39Bd<-qY;Q!&nm=>
zY3HmqWfh%+3X}1&SR3dn%YVUllTLIHrdX@?RH7=Yyi$t{{jT|Qq2=u6aPzP8A5thW
z4uqf$X6dQU+pR0KTNSe(Rx3Z+A*xjfig^qYGHMKBdPYc8v<==%xFKf5^H3>Jgaf?Q
zSsAt>x~Ho$c3pI)SaD@@bmHBMmhV#*E$*F$5&|W1c06H8o$IoWBeeVhGJ!QdXi+O#
zZU|xzgXsPV)HkJvI<}u?6Gb<?I?F)%$8pHYt4A-ux@whmW|s=bKUi(V=Eym^<Hr0R
z;e}^d{$6A{T@EYwZS8p@pDj%Oqhv{$aoO#DNvdk&F5>}Xzl5pBkNPWNo=iM(w4Zrm
zekw}F6N3F>2xa+L=NOIfI92rTVE%*{`xuDFcl|2mQjmSfg_k;SzfjGI<R;X_ZE8e8
z4|y2V^d-?%ot1_af89)>@7<dz4ezk-2T~~lNlKkq$y<$}i(PDwe@VEPv}2yF=oA0{
z@p}DbydfP{?_b9wboS5j9ubnscp?1+<MB^m7ZJ6`75uHi6w8T~$(!FB+qp~fJ$LWL
z({jI#`J)g75vvIGM1ZpP(Kq_pT}L55?LNvOkT<k*{3F)B9sES!DEPPki^OvD-Rra_
zb#!8eH7WkwQP9)P9ba}m|Fkvnf2Wenp*9sne#d#K)$p1X(Mi=tSLLVV)FeR<ySO=e
z==Njm&S)#FxqqG=AxxPT=w5OAkjDBX$ZZ%;FNTy-{xd5riEM&o8Tw6dXieF$C@FYo
z?bWfE1FeHhxqmSs62iX!5EA28t1_k^3O{{lc`FAS=pmJLUk7e0{hc+v3~8#KPK|Yr
zij+Kb)0r+JAjD&+t`o~y8#|8t!ulcSHj{p7r(2wsLvxc;Pqw&HQ{96WES!y?*Lo(k
zhi}50!bdcEjwytVC3tqzi2D3ZUn`O@)aKBY9Fp%uj%P?ObXI=4BDyz>0qcNuFtq+j
zLfSisWQKPZUWkN0xAQfnh(BowC++NLlvx*6cAIqcEB&XlUf-M~S_UE0zyAeOeYX%2
z(QoljTe%LjC$PVjbs;FWEUT&h^({juZSZ!W^;+n&^>7Cwx3OP<d@J^A8!&7DF;u%N
z8%%TbCyd^Ti~FNvj~ru<Mfdy5mIaix)~c~zBekYEFi|OcBCA7tvVU=JvLRcrA%qO7
zS~(|n<(bRcg5Q?=b13T;vLg#;cT;{&jdNi?*3(57f@g0<Cb}0uF6e}v^}!%K7lcPz
zU!@&2H)|PbOh?h_F4)K&?Jy&fRY*gDHHw*!h*a(Ei#g1{>zZu4bm{^>5h`J7iGm9r
z@DdUZ2O5vKBPoYGk2}u{Vtsv#yRH#O3}nbPs6_JTdHh1S+RlForcnfEEZIe(vm|4h
z0uOPLp@!p)_N%`lS@s|YnZ&2ogalE?8=5sgv4|#f#zEXT3@LHS8$0H!T6uykJddow
z(hf(unn)VL+ZxjbmY*uDLIp8)k#Wa-#T>5=(VU+003B2f#T>63>E+rguAY@Mng4n|
z_z$gT+xZRRD2AZWuA{qEn=k4KatRMI2aX<u)11JxU2|OJ-x4GaAMV7_Ry8b$ojRCv
z-`bQlh$YXVJX0vsSQaD%lyiUdqh#yf8^gc5n}dedX}N*h$X^+YZ3IPxCi9F=G=e2b
z7vTRx>2-x;?CfY_sJnI&lH#SiX^Zf4d)d*==e5cbhr&P@sEl=P3BoV4@+f?10kwwv
zCB(mauZX_)|DF}0S;0S?!sKdBMuv9$E{;qrecZvp_|}Pxr`lm5fV`fXEiBZ)f|o5U
z&}^N`$K}TXzV~!0nc%j^bqeo*Ejpx_P*l^|Ao4-~6XN}q_x>+`@G7%+9nkOFfjjVX
z?SF9`oLY0C8<c(!0olvyZTIv^HS?aY`&z$4kApvX<~u@5JJgX9a7$UfoqZJb8I%Qt
zbP+__0V&VE5&isS<ikgq-bQXE4w3MI;)^&_$NIy6OKez>-?Nu_iPe7_6K9Vy&4E3I
za695*gM@8Or<$$>kG&XG&k%V)?32pBD>nC)$8?}#H4u=Odv?Gkp$sga=s?Bl+Aw)A
z)ATD!2!)()jd7>yx`f4pXk<$U?-CY=QbngotszDlKybNB|9eFKqTM{+1L^8J!dDBA
z!G{zeOiQaF^kjq9Q}Nr*ztTLp_HIbZjqQLEBYo7asBn#cfthu87tAEzZADTmxqTPZ
zq?ak;1PK$YO2&eDiEuasnynZ90vTZdg{<c;45@1;S_q&?poGfwLpqv}@zn`}?RSA-
z_y2&PFI5D(L<~`}e*pp3ZXW9d2z~_aG(xs85df5hyD9?fqSK+n5=iKEo{Ad;5_j=l
z>j!s3LfGC;R!zvDuvOXjE@b<dARCb2a3gElWbpT7PoHKT;f8v3t?DW<MYOd?1b})U
z#aWAPbOjUaohup7E0zcZ69`-5x-1bSm_Q>XYf+E63n0~@9e7{a0jc^gJ0QEs4iF_;
zstfIasiqU{6eU`Cf<mS8&XKHAJCL@PId>GrV_~2^DtyurI*ryUx~W;w{<`4)u3+xq
znt+0mj^XwZ+?me3K?8qydPOvo1d6r=x*h)@AD_g*7>nf-<z^Hd>{qO}iNC;_*M<Vg
zL@};7huj`%Xl%WPXvHDFgz%5{j1M5{3_uuA2rpN>2jUnKZiTrDcth8xb1S05c+ORE
zWnFYKYTDs})Rf&^)zMVTiaFgek(ZR;3YP|4gJ|k5P()KQY8UkW(N664QKmEo&6X4o
zNop(_PcoO8kb|V8ou^R;o5%rYDCfR4Vq+xSdO2DbTFw=--hHK}45LDElfX&Vz0@bb
zsCGOA3%&4tJJE{bQ&SY`3aOfKjXN}HeR#JBAuqZciR6;@rJtF37^1|PM!6*Jz|kk>
zcDqZ{k$$ER91VQ@Q`?=0TSo(ZjOO>+E~Dp31fO2`0*DxC2@PKOTDv$iLYR5O(;Idz
z5}MN6C|x@DCpN8!>xxTJxPheB;$aMiR$suww)fPg#XzDpvj|oEC!vb+ymq+smJzv?
zvCeB(c-&<TF{cNF|7h+aCm+g-+wBlg|ErV8Z?*sLI|#?fJM=NSKK`k669PKP8+@pN
z*}o!y{^0xzXh#Z7n@{!R=)@cnw?WKv3?*OFUOmemI0`T~_*i1*e%5GuktEiC+1}(2
z{%bzX4J5KMBMW4;uY^`B{AIP$g}<!U`f_{G(clC<HYP&zdCdg96sGw+otWr^Zknw%
zu+Z_Et?9%-CxmM@)xbVy&}>Sdf>>sp6GDF4NpZdEZb*d(NhcWfr}1ib*SWJUC){EK
zNLHuas_bY;(_eoSj(}bi%wz<B#JLB1Tu-w2=&X-|4WF>4@i&x-mc2n5ksq~w+0Iof
zQmR*K4RJl;O)9GrXHYmoqj5N)UHjIgloRx%2zplOeeQY3qVGF%j6M5T8ZPB1NY{m{
z(w4h%Rk*){AZhN$KXslF>Dm9Yht@sV!%3Y;NH*}EuuymaKfC+|1giwxA4iDK;<R6M
zVl5$m(J}2AvVWk34IVaRel@*7_OGJ7sgI)N5N&yyasUuS0}R12s6G<%>R6}!pR*u)
zu!gZm$d-rj*Z=WPr!PgEKN`YgX-s={qde%wu0|i~ZjoA4pNEb>GzjVwp(7B{sUk|>
zg;dclz{<0fjG6!0RO<w?sViL&0R(L7)(f3GT6NSTQV5T#XR5KM0!?vk!C`Y7|FU^_
zN7Q->lXlQx+@K}paQ<&Uhs+D<kvMVRyQXBVXWu)fjbV+)*!}Ot14ip!j8-gKyJ>{h
z?s)KVm{`}eH^m?e;x6^$zAoCqNcRKjCA)(3@_lzB{cpmSyOI7K`Js06yAX|)LmJON
zMaYxTUD@)k{T|(ZH_6#V6Wfkmt+9{NS_ieS{_GGdjEW=IgnQc$p+0G?O0dV_SO&_`
z1cw+7PhVn9?}U)|5Z9^^HnunY95nyEYxoD-olN%~W7#Pj2@RROo+~@LZZ<F064!V2
z(J36fI{%NaZx4v7O#eS~ZotgpHVh*&qXK$F1x>NmR5S(@6~z@yD!Xj@-9u&OmbsPY
z1;;}3QaaYxOIE|cNhN7@EH#W>7z-7l)p5%*DVz0p!Am+BsLU|G&wFM--0%1M`$w6X
zbKcAIKJW8B?{oP)-TQx+w)KrY{9G?p65#yvl>d5*_ZGx@3W!*MHtP(>1Dl@XReF7l
z3P7som=Txy>yHMYcQaxpv`sigiMAQuQTi3m`Q?<m{MRg0Un^jbPp&oIgng)mpk6J~
zxymos9;-EG#uKUjz77c$9@PE%Fv=MV2RWMHuEKUC_3EO$*as@>lW@~Xz5R3cx|r~*
zECPi%rSc*UfusIz(s7<R0EdZcY!9A4$YUbrWO=aPg*)-?1-1X?iaJ<VEOLE9YVA9I
z-RYv{HkAc%sE98GH)?Rzly*Ovvhv^Rp#rTa5)mGM3Nz+)UhU8yFTmt>V=hCY(tM;Q
zH6*;W)W2pA<{OgZ;`(s1hh%+Ffe?FQFxiLZ?w>n|d@aWMU(m|F--B}$WAISt9C>*g
z<|rQYLlKy5U)8oaOMM}#lOB=x&|}L*WK7gVRw0yHoDufroe(!Dz5GG*STbGub)fbn
zXI$5!4krTriob{YmBYLDE53Izcc*%>`-4W~EWb|fz_-F|<u^7NW`IkGzBV&%4>4Mp
z@7XSN=b{lSqGTjg-!xZc8`(;{i2KHX#>&j@G?o>=dSVB!Ct{rc0|bV=@@cd+VlE(T
zO*0TP9~kPL^gP(4b3%kf1ObHDf8>~+LPV3stbL`@V7lG#!`6R$qUItl`1<+<XAcf_
z=2MVzBbH&k<&RY@PQ2sG*UHN8uDT@bD^^){u}b5r%W@)uX|J;M;s*@ENgZ`rX5p1x
zv8F9<9p%wdrb^Snv&}=@lb%Oo*MH-RmJvfGBmeG0e3vFD5pJS_EjCLqj>ao4>MjvJ
zlskOpEs$zNBB;wVI;?2*RdR3c#=N~HpU>R0l-#dy&IB(BJ4k%QCIf=9@5&_QvR^fc
zJj-A=;|L%_QLbPp%B|oGuLOtEsXx4Q&rlQ$`h6!%&xu{+Z1+{6RQWH@Gj6CmA-A2>
zo*<q4{jRR8Jk_P$$hQ;j(QcGi!^&P_ARvOq_4PNoqCTza^`cAI1E&)+56x?(!GuW>
z>sLfr_jyS_sq+dgvgG|=My1?HP>yyRl{BMkRO0n}M<va>_rQ@g>KKCK`YE{i5#S6r
zFV2ct8mzyyywy=>6nc7LLl$88dBjzqwOL|ZGbyaytUfFIJ%zZ634^0>!Qq-1G21^F
zx9DEiJ@QW%DoBpj1f(cgsj9Grd}B-93wQmqJNRvj!20eczi}{5FzFIZ)WM6n^0^;z
z+*rM7G+9yitln7mmHl3Wo;IP9&Yju0Lh>&@!s_3j#AW9A0nYeiI`Oh5nT6#E#N$)a
zjGBW)S^MFn@^gZ+|97x3qMcQ5tCSO@&^QE4{}iN9mddD}<lfQ~VX8o%L}Pa(`%AY`
z-dRaObAHhm5F^fVFT`C;SkcyW!m19r8T-B{5hk7L93dX|r!^v=!&&)c6c}gEC3c!>
zC)&S`y?FA}yh#X_ta}<+3Ew3+>WZC*<|1D8y96QHYkB4SlemK~M*u?t+v6g4{6p5*
zGe;OP-|`AxkjK#YSNtMwZ65h_C=N~U_lF%hS=+=K=f)mC#}!4z9>*5^IT`Lc-KwHT
zlZk%_8X4+$&f$%f;}DYc3~wAXjyQ?nBA%kzanfGJ8s|i+q?Sg}^%?gZ@yb4b{YP*l
z{&wNr3nAW<8+>F_3DLKCX}=Gogqi|f{LtLI9AuIV>7uA|Bmq>a%Mzw2|41-u2g6*-
z;*gR59<_t#mj-ZGTlwxr8>49*N#{O<Q$p1F`7FxOH#T)nG;u!Ze(i4}uIx4PA2gO(
zOpq7Gle_GMb#(nu>i8k9=#1{Jh*)lBZk;rLh%@H)N$CrpExAufrg-|MZ~Mv78y3sf
z{afP+k3%D?YhYbZQLge<`3pZP1*tZY8yHP-@B90Y97ZN6KEfOC;0zKU=8cO6WwKsa
z>KKLyxPJ~&NudVVIeoZr;BvbB1*T*jx&7=LNnG=o&LO`e6gf`>pRyx-^GT$*85bfi
zn~>pae{Kz|DN4JqbUb3FYQj|YpwtfnY?`AU3R1Fqu%0MjaJeWQN);3!i0Lv|v+gk_
zeT);QWP#RQpo3h6sUG*0|B7|i8Ki;XcS(XFn?IZuJal*XN>L1#QEvKjKf?dgO&=(E
zd<|#3NOBz*X{aAp0WvSLnaKIH%ZH)Zl9Rw6MRTHp?m!YmFgjknp^WE^TMe0`q-@@p
zXdrhKaUAFrmzgJ8KsSBpmV(ieOA4aFeu^rMBxNU&3QGj(@t=}V=*Eo@h>sKGrQJ8B
z5^<M>5amHq7`is4k`jhdLmVBy$r=B2R2a0J+!BL?m)<4^&eotcVqH+mqkHw5sOawz
z^YSKN?yKr#LypR^(trER_m{2>IF5d21TNRnX5%N?g&>2*)#x{V8ABw2{85)^lIHqz
zlPN;KbDS}%?#8oB(1rr$Fup^a4UGII1|x4!2cx`k?_fmjy@Pq%$3NU{Fv8pNI$y|Y
zB5uEp-GylQL8@rB&nLDzZ*p%XCqPVBtbALugU^NV2KvKWJaHJBE6v;ak6|lMvqgMb
z+>@@q-cgJV_G?G+V|4x1jtwn{P_>fpTh#9_so!7d5GItK@3_l2<{=U$Fvu~hPwrrK
zXf8E;^bKEq4tPgC?koKT|BJ_c{5<vESKe9z9cWe1W|dcVirxP1u=*5Oe_LUKF_E~1
zxTA2dQ{d7Z{`tLfGy?EDZ>yQT<)yw%_=911y?c&Jf4S$pTcMtJknk$=1O>WcO;Bcb
zKkv?8=(I72%m3rN3-CmwhTqVwGOlX1F>%O@CtNRH)&vhD2crqb3-up00h?oGx4jDu
z|Ap}HPxg3Wgt~FX)qY;9o;^2SAfv%n2@XeG=p&1y8sHWXs2LFG?>=(0ccbfA<u5+-
zgT&f*Teay}h~I0aAqNM`CPTbRxZ!Zg^2COOxVs{MJqj@6tZ4;0;7$l`qAIJ}<9wg$
zmwMtT-^7a#tF#I|CvJzJ=R(h+yAzv896>OC;Qai7ggb=<1X*|)T$GZCN}dyo<58a3
zT`{^X`O$x;oi=lx^k>W@Gw84+$6d%T_5T^WlGknQ$_J1Qonx1ayNz9%*nRBM`;Z--
zV;BGI`$Zl5lt=&@+%o|rnpl}wp(o;bulvZI!kQB+O}%#lH@Z*YZRt@mfz=KY!5N$Y
z>}hFbgtEk50TrH@EFMHaTTAU%wZ=1%?()m0481+&-m~Xwjc<qFKv>(m!&J8&pFZF%
zUdi+$e?nDP*Yn2HM9(DaqCBe3tqJin8mQl+)XANnKkRDQp2v_$M2@%gOq9h{_X0A!
zYBbPMA=Q<pFf0iqO3<B@YwXl+l<8eug;J*|f=WbaOwiz97J{Y*sW3qr1QFU5MW%cn
z+zE&xlcy!1FI9@FQDn+De5al*zrh>xx*TBnzOqe3Pu)|%1Xb1Z^Y7pN1&PTyKR-?O
zwf|>$?04PCJ5|c|so}BwMb(@X6swtIl`LQ8ND|u&mia?6?n-T$k7fZ?sUY1tD`t0I
zt+Ag<@P=CBu5d!|M3vwzwZ^4dLh!9ayAfRU^C5yS#JJ(N3=-TDB6#{^pm*QyLPN~*
z-9WS=M|q>U?f;<bMUWwQ=@gJp^QgQ-6~n~n`;?2LTsaXKweo<kG}wzWpEtI2vaB@P
z*KIdEB@g$xVcW#PAC2`;&FJ0ak~A_witQ$slx<ydNgmO)8n7f>4O2c>SHqh_B96N#
zEZ26Y?N~Y8m-!&*1;49GM{@sZU1=DiIta3e%(&MtAe(|)s!NQBdVl?$pcn^-4!O%v
z1O1^1{KxfXaDv2jpTPRN6G;1y3G7rSfP1jFZX%XfUEF?TWk2JHWJ{b#BpXr$%DqVE
zH$EO-2LsdA`$Ee)_y=AJ_X81=>?8Sceiym&tKzL+=c+z+i5K~hh=9KR7=Nak5Fr%v
zhSLS-9vEC%6K3NmTaFsML$sG9G@$&{ebwfP3BJrZ5CH${oW<S=V(ZPjS2}rl*PJEu
zy>phg2Ist-QfJF%m*1X{XtI^x+LSnD4{rTivsKZYPDHbG$A{{Dp;?JNd>_w`>Tdgx
zO2Y6gFFxwK$Gjs4eB{a#dQFb=A#xC|1o+@|ErbsV&o0Gxt{e_LD{F~pTLN|r%H?~;
z6|n(V<ixSvn~U-ZT1O7|A49=Kl?+AtBM1lm6j4|9cZ5$RyLy6ko6uFCny-QIH+A;+
zXP4iakeC8q1cs~eXfz=}qUut<`;OS+3-Mpj-o&dH2<f+WHKUPFz&ugtx7~GUF>Vv;
zRYF{Q0cHjS%ej~c(RBfH$KO)hCHw(o5tB2AliDvi>z?i0(AY`OWB4a7v#z)pVKT{~
zogO2;j3bz2bIeDSwr2SSqQToLsPzFHdc@OEJa#O2BnQOhAeNn<1c*FlAdi7-@t6je
zs$;D23{MPr@_dbY{ScS>ei_eve-hT?A5P{Ps9Ps{{AF5DoevMn<|@sG=b0aPD^YPt
zY&p)=TRr6C-55)JqKmPV)*hX*S(OIjUscAsD`|ud<x0D72RsXP0sbcJD57T_;QkMF
z;iNC5F5E)MSbyF)6H$@D{q$?Qx*S1u;e^Uvce^o<mCm=D#}Ew++6qx4@cvO=PT`TJ
z*xAD6b`alNK|#<3Ij=?tT3cn$r7DIbNcRmTNMp{A2PrQ;jz|ej@u(h9sRsL;ePg#j
zzYUHEM3QQi91V=J&?T=U0xy_gOs+}NcjPt;N2M<q2O|FF1HOuSU}OGQ!<zXf<Y(Vn
zzWfS{{I3$LeN{M;z<^VQ^Q8_k3*r%KCol^H{=^RmJAZC|)6$i;<T5n{VbfY-fyn2D
zZx^>YzW%KUSkqdlSodl88I-5ONg`!GjIQAkrJs$YyUEtmNV;3PXxxR5#t5G;ZW~=L
z*F@^JnqLDp#`;HB6o)a5obaCVHw``mV0tUC0~$GBKL<lA&)qokuTaS0ze)#CAHS~k
zYL{EJ%NqL_k3^ad1{2_I$6AXXyS=!rbQm=nsPPW_s>%xG+aAeRaa(%v5j(Cph}?IN
zqh^oesz19vBi1!e;~Ez>NOZVfN1p4+9ztf>HP*?ZFvJ^`^80&5caP4{4wgZD+0k}@
zi_LY7BT1fBBwmOC#r#}JDF}9z6oGqETd$$Yer1)^7~uheb`aEECCZ<#E!MJv2;0xB
zA5lNzGo&eG{xE0GY`$bs^)n-nx$JWe+de^R7-{sXMtDf9@I9$T4j?inm*@np{xjmJ
zrNu-|BX{OqEQQHYx9rDCr$uMls~ql8#ZBHL9-~S<ffLoN3kU^6pxe3fsX``d?R(yS
zv1T=m=FhPv5G5I>H=)b?Y*zfLhs_X&<jHXwcN_~!xF3#p(l?yAbBd8SBB9ZG`o)%P
zNg^!y=UCgraqc+2?dkv_a`troYz;V8tF|OrZh$T(C+Ok|i0^6|PYdq}EKp>QKYgy5
z=WhlC&h&53tRc?iA;Mg+jobd&@o%l!j;zy_d3kQfk<*pp-X6e}_?%~8d=27-6~A{}
z;ELWmEpQutQ0XOGw{EpYEMJs&WiybKuT1{sI*Ylsw77dMaX+=p#Y8RP8h70&XFP^D
za&ve%PT=^*16|GibwBdcmX|XnTVnX8fbd>v5JQHn4-UZdz70PDdFwMci>(Y(xy2Sy
zvS~9CgUOG=VELZ}0z!1Os}@Byk3-O%P}E_4Vm;kp6&9y%jz*5D%{=vV<%H*=WfKzD
zOh^q`Q2hQ6nA9WB8Qp@lu|^q%9aVONRXEhPLM|f?Bc0eA{}Fp2GG%HslEMwvA}AGg
zje;mJ%4*7q+;zCSP4^4y+}T?EqWmfHN&_-;<OgqfXw5CR)m}pEGw%Lldu$-Nl2q!Y
zC}DLC4N!D+=Vg_S=-?Tq<}f)bA_$78c*@tL?XOJ}D)$6e<c!sY6#-<eIELFcN~jb^
zacdiz>B)P@3vl|2#PUdTc!1gR8_A$iron{y+3vm8nUk%CX)gB7?Fq@L=H3oR)}rSt
zKNiPxZuT|uqGQ~fPDg(AK1YRK{EAnzY>PM6k+u-OMcQhjkH#YKzq2v7VcPayPt0fE
z1gFjh%tsn(hVWt*O7A)i1p_tW`x-0z=3wos32|tV^fC5;#^uOwI4Goxf9JoC^{{W8
zGMZC+_w@El+Z2ey6OM|w;6qc$LyD_&5O1k*2;g1X3am4vAAkHb(%xsxc_xF`LISOf
z)7p&m;Y-1yJn0`BfA<IJXrW|;1%?ZH`+yZenplw-_H3L@AJe#yEX>Sn_;Y<Z$}W*2
zW|(Jj-w3NdrpHC~EGUjcw1yJH7WdWK=&0hJ_$0=#E`7|ab7RVGvi4mucn?oRk?+vl
z;`ZHphwlCob)#^zQJ%PVM6))Xl!JHcV~U#ZAXhAP9x^g0<*{p}7ee>n6q?EGyU!Yy
zx;H#?LF)Z#w*)<btX~F_Ch7jeNd+PDjmpn8Gy>gwacj5YzeH~BAo7dK?RY*rTff=u
z(8uf%7}&_xPDf52Qb^sn#*koE_aiL`no8FJdmr{%ni9Vu=|7|&E3LQDT>s7CYaa_e
zu!FPNONv@JC(RYD;atdi-$vjJ4!DtOtG2a+YfOCgQuO}k1)L$*fnkkAP|?@!q4nv#
z`hS>ls&{VYSN*@4KB4yr<maC1eV=-j4(6@Ne`$BodKbydMHZ>!Z_9uyg?m$Q535?2
z7~vxVS*&iye+U+GAv`zoD(C0L-RcjJVA(`1i6Ao$&B6S2NseZf8yT|CJe%UE$WY^X
z5dkt*`6ELAf;V|&6@Q~V(_TorZhaY8Z%9H%;<I4dttLK;#g~ww*!805$5Gq$;!onA
z+s)tRUPl(g-L}QNd)gLfw__r~b;4*cme!Y%<}LO2b!(_Y{!_a-nCk4P7~a*JG`V|I
z*Q6)gQIH+(9^xx~lFzEW=_*h)ZF91%B4howTH_^_Tz$5|lube*h`|JEtN8Cg?p=NR
z>GuCna;2jroR<^Jpbp__xH{qM2m>%)w~!q9iT3mJ#}G|ZaKpx6+6}`!tP2l!(MHX)
zxr{Te(>!ASNh*ZIMSbI+y*bP!a+s3Vk?0Z2rsw~_HFNS0fztD2E+|l0etW+mC#1=}
z#uN4Y-JwL`X4PpRI1x(ecY%5y2wj~Qfa&dz;oGi<lz#;SBe6KDb|)7Q?T(i>ws#+s
zI0<7i|L7#~^%xPkVZF%}t-hn)A&D+|3*hx?_h!O+#BOz!WZGmyE9>eCdxTsaFz(Jh
zroK1KR^GD7po8H8xcNloe|N||ZOrK2hH^AeN~n1h_SE1tMt<lLX;q~MihoRuhW~nz
zvh2>xz17viqBN4JD2mZzv}b0f`wr_P`=@Br2cH6D{_m`^Et(9(gTURi%4;c8!?UMG
z$m632gP}3Tx>mN<Wp{0ZB3QfoCZKEpF;9%5gzkkEy&g&FpDGs>w6Tw*Je4Zv7u;eW
zLGD&6l`2~bZj-;^r%II{;G^+y>?0|Osq(<Wik^?8%t@7#3M<Tbpfnv17_c^l6%mi5
z3`v#43oD`@Nm-aG0`IKX^^6M52>tJ5fQ1!<9!W_`l`j_DL2oam%0HLh4ir{!kEEPV
zl}~0@@DpsOfcR2aG2oGufvIwxwPN5(+t-M+EUbuEU;LY`qQ@rN-qK5ff_AjfH&y-s
z87Pj5KHF^{=AJ`-SloWwd%P#$s?gRVX=~dp{^!66A4@XAn%np@fnWSA(P(?O@jnE-
z6(-cMF8Wg||6O2M2Rk&QwrJz;sJ99FBX71WT<*~>2p;?X69Gh1?9?2evfFCVm>N?z
zi;o(b7ywFFamvl87XV513&puu>g<oZt&x=J;Ni`Y6ML1iRBi3e!+$>lyfUntux@|N
zPXgOGu1v#;*67CbRonr1428jGS-@pO!>C~hD~3Mzj|=Z#&h_t07Y_%JimU`s?GgJ^
zdIjMrlF*(Dwn2WGxDX#@UAqt$T4%Q&5VXHkv-XDdXB*dB%@a+Pr#7c}g>@wX66D@L
z+PHz{tVjr^*ApOI$O&k?gc0n3yQ)4C1Qt`z^!fI+1=Z}(ob}Vjt+%r4f&g@>o6~2r
zYpXPiJ`<+M<{mEg9Vff4iVrI8N@DwRnnRN%rD(c_=+Z$&VebKTix6I$ZU3*-eGwV<
zw^D~QnGSFRvSj!1sSogE@1=eokzMgOoOJ2gIJq*&Hc<78MCByvurz6e{131Q0AUwK
zZC#ZzF<hE+C%E@!QRY1P1ng_g_}!)D&3UIA*EA~4s4o<JPkAQzB-&d}rQcD$36Lin
z)xr;x%LH9YByXN_8s#jM-aTrV$z_QCiRv+_ApOqdJxw%}gq~{ITtWW6t3`SC9YnXP
z?SV{!!OC3~n8pKeiX9E?)cDly(g#UL@WGfE$j+uRvcoTGTv5E6yV`=mHLeo|P2K|^
zXsL!uhp<xIT}_Km-YNYx@OYWYiTe!S196SV0K+MBJua8M?-Vjcu17`z@1?`M7G1W5
zMF=EWuROW#?)-(|{F}O(R37P?KXg>h9^5l`$y5)7#{8XFCFkxO1~v*9pLaeFXfrW@
z>Zach6QYG7Lx0`qu|&8c`5FzOsC-0i@fZ*u<-#u73!{`T0z&Vdnrtn6&6TL^81@1$
zDp6!@)|8!XO2U<`dhgMbDHZ?`iMLU{*Uf~vEm00j^clx5zp&mogO?cHIZqVjwM4J|
z2H+>3{|4X9@>f`E0V9mUBCtwr*JQ-WcXESgDds&&bOt8lMx^oudZ-+*CS^^T;x%I3
zv`$9rv_wJswL}Y}Y;hV}0V93c)sCDSA`0P&2DvJr0@AG0t|@y<Q@uAMoJVu3Q5HqK
zW*l9<W{=mPakDxg<=PBkRzr9ptM{;4k0r`&iFR3HYy}b40&Stih^eIHP@Y%@;JNNt
zK=`4WmOF=*FQML(`Ei>j3Z^)#Cfb^#^=e|gIXX{lgeOOE$08U-eKOJ(tF`4sSy4bD
zALY2LIniE?(VG(^k5)&EwN5{+IItgfYHV8G%TkqFypzH`290M@gxjDAwlWF$8?0lJ
z&dPGuNrKnFcqc`A42+PEx?Y}1Q4RxsjJ6tBVHD|NQjGFIH~zqZvkh4IJ2iz`-jzsK
z&R8>}iW9FIQ^rF?nPh+xo<UJt@qHtFQrg#L@r*h%vOT3?cZAI=^``#w6P)(;6LrYr
zz*X^RBw!9)Ptrk{gP<rN``Vl+{dZ_zqsq-yY)DK<7}bJuH{sSv5psIBF=cL*H~xQ~
zRR(r@*4&`14?UZ;%7Vg?{?4ZFY)P3Eo-rxHGfA5b;!F~x{@vaawo2>%*FJ(TStn_w
zzUt#-zg5etN&4toGHi#IANswe1y$9<Gx8$bdD?@Os9@hId&Hz}eWW*tEAQ^p^air4
zq>WuHDfR01tk5965lH(?NLLAi9xAu2dF<HE;Aq?^3B*#U3M77Id|sZ6r{qIjT`CEk
z<4hkVmXJ2q2HUuZHhv7X03x_i8j>)H2BeVxarbpYa1@wl=4lkh-l?gfQ?N91D<L7F
zeAgJCci>jNR{HYpE3u)0lXX3<yoPr?T7K2HmDj>9@=}E=3!sx^OpVB%ib6&~sf<<6
zx@GZB6|7Sc;CqK}4W7H^YGpy_{eK1Dx8Hpq_0NJYCy_S+YI_I8*FxvSOzEZ2`k9|I
zN0XJYVr6z%TF7CMF)_k1QG4-QVH8XYXD4mUo~V=fJ2xPHqN%liLb*|sH1D_2IfeDT
zBhL*GmKG9fg4|Qaa@B-=z?t^)-Hya%j!9bk0SgM0P12bkS2TC$FWga{4UI!c_+Qvh
z>mj@sA$Q!qyBCC($zMS$s}TSOCiMA*<#uY^TK=qOx2N~A%I1uGoi{(+lOI90Z@zZz
zf@4*PC1NF*2RjeA+o8q?Z?0CJ4$^P)$;xZ{FNtB#rF1@rHL%7RtWzT(bg>es@#meY
zRerx+N>So!mC8X{B1`=V^<+qoZq{Brsq(m*d2kvq#mcs>ekE_Weosq}-Q{iJw0dGl
zUA!&-+HJn(IdW0xS?nHRE@@WY)YYtVrTeq1Q8WAQ*}j^zD?Z)TuGrG;S=g9iZ4KI&
zH$6K5Mf9erOR-bqMK}4Cfs{Y01VAa=ID;^X(DRR4MG3Y*cz2MP->t7f>i&GJt1s!_
z-TE@ml=ARw9S49!l|Zg-%g8*$HC^+N&USk~Q!7mf4TcE1{7S-3jyQv3QUul{B#O0S
z^X(lc56_8p0F<m;X${oPWkMOJDz}h5nW$v{C+(CKU44o_bnkPJnDsyQ?{Xs$ma?<M
z3bVsI`9k?N^b%=*l#=<M?<h;iJE3j6!!mT$Ux%*$-Ig70&5m#YOnH=YqTBm<%7g!7
zd<*Z6@1NbrS1tbGKl>72{r~qR9_!XugP8F@-hY|A-#Ih!i25{{*J<g#|9n<@F(k|6
zzuX<**WKEmBc|UwmyEpd_bZjTcb|53wLeoDc<-}oDy2DH56b@tHLKn&0Oo%vxZ#rn
zM8aSfG%?kcHEf~UesR}p;+MhpEuniR&i@uACDe~g%cr-f`{BMW9u>dn)=%bYF)6T|
z2Ztg-e5YpLL{kk-Hry1#sM6D2y(pg(5ui*`MF42EoWz9uCiDmkTDznuYBtUagJJU5
z>Y$Ie)Si7|qr)DM<3UkKs;6<XG|$fuPsxv%ov-!e>y9<AEw73s=%wOJBh0o{ktknc
zR-WzZQU3IHDYQ8Bg=U2Jg>9&GJ?(%c>xcy>ohrGfZT@TJDu``J>cWYUwuv#*?7zDw
zYF!fr=ftQWD>^1Zv2#xhS9W&I8Fl8uIDuLGyD(5ldBwryt#~Ya^6(Q8TwZzMOv)0D
z-wI(=&)1-^MBd)Vbd!hYp@c%veruspNYx+QQ_L4f90>pT5Lc$<r0r2_v&(dx@^KVK
zS`f)u1a9VZ8@DVkd;1m+hw%0Ut}KdEDxy-xFS8x`1@+Z~_v&E+H!1~|qzrpt#Mbb#
zXij!S;p6fM4wX4pug;hldTtE8&&8F+aEd)DS>OisO`)k2S07|zhwK1jX!FHXj0O+I
za?*!U$&u<q%YyeK@P+nX)I}Zca;cly6dkU0#+e;udQN;lxULpzpN%Vv<HW5|AW~j7
z22Tcu@f$d0a}*j1=NhVk+c;u#c*<nTflBeH7!P3o1;ty>m&J4Pe-jd<G{gr72Rd0@
zmrIfskXDVH@@~}faBg)9#*e4A>tUQ!O$_ATmro~$afAA)QwzO~yHoe~dvMD7s14!V
z)@~$A;N*7*$@YX1l2un{OzvE#Y<pk=I_=3x>!K!X<jN8`Wo^_;VceqGg*-LkJ+92e
zDQlt@^|jK}1WeD&DXU52*|}6<HnsJ=j7cHd!^SFX9HEcuZ_^2%P0;iG9e2&FWPHF;
zrs<Lunvw^H!K#>k$5DQ9PcM>7OjB1`>1E_B3W+47gQkTc3bez4wrt#bf_6Rx!*|Ue
zXivR4R|sFadaX5KnYu`0rf6Xxw>q*`rwmGmxwMYi)i6a1P|0005lTqQwam5#Bs<kG
z+h!t=ke2_!tZhKD)0fQJnZ&A6y!8`uC}5l>>uj2uokP9FWzd?z;f?>5OH+gTX3(fs
zk192(2f|7+YIVcmh(bk}aTG-o{Q;&GJnLbf(wOQdpOD)Fa7-MCb!jwWbVwB<Gzjy=
zn+>U-#Q==c%%%Pze8lJ6h(FLH0PTUk$uJ0=2rOVmHeEbmsEuZ@WLFjjVMgT2Uyry$
zK0h}sB2_e86|SmUVECXcwsV1WUwcL&&|}d?_wlH>^o16UJdMrQ0>Z^QD0aj}fCb8P
zE+LX{Pz|em${6#)g{{gbjIkli#>N!))auHOTXoJue&c9e@j%XXsKdBRE83x`rd5~q
z;b8G9OX8egJt3?WZwHFwCS^j}%9VIMJhM{XPMUL6j54W6cmQFsXqsv17x;k4W8x0x
z%a+VaQD(ke)C|mQ^4M4*-DS~;KjV?&zCWmq$;__RnU#uz*_DW~cRmRBiE;){k<V<f
zedW8*XD;|z`W~M#yC*QaZjVX-!q?a*v#7~8Mj{(t-L1Vw3OU;{NSMbpA>GQw3S)<^
zO0tfRm7Zcr-X<U=)x1q{i-F)t(!x}dE}5v@zMU~X$ScGi34ht}c6jCfPk))%pC<mY
zyE>bNQs#E_PaL=>8TO;7visP^M@MM;kQ9u%Cz;xfF^9K!N38zUQ%;>d8FS%-h!Jae
z!WtuVw}OTo!XpIntlJ(4Cz!ISn+Kb>cHaZi1~9jItMoS0*kY~(WYT)@ytz_Z*TwS(
zLp*PJk{LtWXdy)(kI-U1joM&f%Ho*ywix@sq@<*qB#cpBOJ38;Z!wLFmZxwfDKX@S
zM8wXoCO;&KtC+^bq@;hDx8kd})Si`6@@!u`OB%rt7(9d_RZ4G?ANqxUNMD53OYuYc
zB6$UVu$EK7H_}(*jW@{;t3@l*n3tutvs~nCOjL<A38gqueX!T{eTX{!E|9eTUsWs$
zqo}e*D?|xqRPcxpcwt=Sib}U9KPY`)spwr8PEp1z%2!6cUY1sj!V%LRiD`R}TfZsE
zmQRgAl`8U1@zx_DenGN<MlrK5XoEJc^zGJ)Q7iQ$Y!#!0^rNwx^iP2m?G9vBg*z)a
z>_y}AI(G#R8>w+gl&2!>g6)VaHwKLe@~DgT*8<>fUU`)<&Jn=g3m9XI&Rm#c(cJp(
zdK+65h=NO?sFGyErU_<o;KkhG)L=XayE`5o6@lIL5(9W=JY_F=*m|U{C_F+)OCjwm
z_g}1HrNNhAeigRjc|13YHxH8M;dySyclPaoh9h`FCZ*3sXT$9x({BhvsQ@+-qJ24e
z7t0?}-xKFCyQ-nOKhNySJMvxaVYX;30Ih)qWxnWcxK&j1D|rhjG3r~Nun6}yJFwr-
zt}{1APQRGDFYsbZ%&Q-QWd#$8mc#Wz^QVxKj>RyG=8IPvybSdL?fqxR^-U{m7LB7~
zG}*Umb7gG($ARKRH)#zyr#&wME1-B0`#~80JL)puvS~D#w{~w{QF?={F*~c8o$tuP
zVjvQLb<SGonDv?}>QWy><jRHAkxLz}jmFhsPM6J?M!=vV-LqbI%~~w16aFGh6;cHQ
zP9GeuHv7K1zp+-=`_@^DT#e^89f)(!dU->C&N1uN^{Wub;F-0+9!?2y06vo5jm_3T
zJ~zQbIdt~|1o(?RQNhKtUC%koqW1&0@J+^nvWEX?BPL`b8(hf?<r{Y#vljQ)MhCZR
zL;a#g*R0n|n*%~$BpPMIck1vuEGQg{rt2>T=JQ^B_d!@Q>z=ig=P7)!@mH_1o>@yv
z>ENdue%3o{X?F5bq{h_$7_i#+uhb(|g?T}T)B;;B2M$0$jI2iu6TTT9KQi}x6m+1R
zvzDOXLu8<E99=jrvT$5{ChbgKA_&_i_czhGGZ+t}x!|Pv=}cqq`T}Nf6xh-{1;G%2
zoBEtlzKF@NuWL*!eS}S~Mu_zZl;a(!ERJbR<fnrkSm#LB2~Eb70dN6@1%%O#6B<Xu
z0I{+SQxydRyalFmDaycqjsF#VK7{`<M!qiKWN3_+6sRWZ5%AVs$*&&XO7oHI=)KaC
zUrP@J5R8gFxbZS7`F>8C*>Ks@;5QE*qdhxjMed%^&q-Hc`u{ZeLF$JO^_6%Q0jpy4
zl@GLIv@k3m^_%Z2d1wV_n)`OZ#h{1=gR&0P!Ptg_uHYa@@g-MXOm*esd&LCxwcHy4
za}EZ8T4t`~1?GNa#meFxb%s5u9I{UA_%i_|&x9!w`O~~-0KSz!iqEhl&9@{2AFnov
z`lXC<mr?F{CG~Fx!2PZ7(Dh3gH|WD?9Qo-shPLGovofp~qXC|Kz+14z0}F2cU=jkA
zKg7X=Ir4|vm~dPEeZ*n-{q_Tbqv?JGa?TaE#N!+D;_aDq?sBGmudqv{`Y3r*e0>RE
z>AKPNrugawXBn-W?<ieJ*hB1hBX_pSCmF5$)7YO)(WaBca1$eBj^XT?D{>zvzk)(;
z2FZ{t%DqvIv8NjmFocyNaS<5Z+C=_Snrwrskyo`Y4TV3!2@mCSXaBe&ONFSs&|zgX
zjR$~win*YK*chc>U<{i(A^@BNlUcwE(laq;Rv3vsN3N*fjDeU=l3x@lrv3~Wft1G7
zCkNbTy0gg>?RLcXKKc6g(RArjl8?UqOFDNktkj4f*%KwqBo)}w&Fjo>OUvMC&V7Z@
zp)oP{FkOt?qpwNqCul<oZ4oD6|Cw|t0N}zf7Wt`|tJ?ZQ<Z&ezws7QcA(r)Pu2d87
zoC#niUj8?my(8=Ar1dC$@be1y)Zgmwbb#idQ6csogK4sen1K_ALdo?lv0G<UuUb8$
zhI8kQb2LmroS~NqCma`uZ2<p;c~C$LqX2@xXI7z`iF7f-T{`PXNpnD|4sRF^#*-Gs
zyOO61k&fiT#qH@)*1rXY{+2ZK){0j?O`v*ZQRm7`%_x6+Av*kmHlg;LB-gCzW8jX(
zj&wFoaS7w3SK@PzckF(9Xh~xXe=DF4nFSs0c88${5nP+2$l7vlcr#}ey2!vM%Jae6
zF~SsVdSM(kfb-Zy>81GkFFQaed&NfakJ0=W<Zn<_gwWa7A@97iHZivkZ7LTJpU*wg
z;bt^0Bip|hUD}U+5kU?`EPtp2TaNUpF2mWIo`M}2fJWT76fnHveSy+j@UKEGSa-(+
zT*c=+cICuCPI%C(;^<o~)SYH;ulrG2nwZ@zu^04o=>*ylnI$z{_y8$``rJ=CycSA&
z$Scf6tS7jvI6ilMM<J23rGXA%f!7jOXfe1gF&;~-!=m?E;^A+=%<5NmK>Q1p4v1Yw
zQ)r2WjLoRi7fo6!U8jY$$X8|34$8CQb2oOll3#W~le>nmfxd<=o{lelwS&+}H$@=7
z%p*kGGl(-kAwLz*uk0u|z-~z6@*_|1oVTauQO+Gn6&CF9S_}wLvRUFVlWAvvp9Uv_
zrN`MF79i|`qQR&qY0nk@)eZ~~4Jwa&>z@P$-kx+$dO|mBFlW{w@Uh^Id97s#r*8j;
zp^HBfU&ET$svqadMe#5m2<nGrk5?));_+u;UWKz^ne*5%N5jL)r1NMPfIvj1lkeo|
zWa!8(nyy0;7$&1G30)K--w?S^g}QXXr5-;R51$!YT3vHd^V})g8aC@nlBbAOF4Lv=
zlL6a|0E~6aTDpEcTVL2=DtBS8G%j;Bj&n9y+)d-ffdNOs4*T_+9{csSv2<wzo%vt<
z7(zs6U2Ky^p5U!d>9CQ#uW|H$XmRt4tCNmb#_V3b(fZs&r5U6HK<7qy`#-dfwa!}l
zVj$-Fhb!tIB&?_m@bZQZAYI{afL%EzU6nUqsTavl(ok=1Bzaf7-&>m0VcI(koV6?C
zP;cbYjKd_Q*7HP?NRdo^Pa?k3%8}$a;ORa0aZ<RqzQaG?662^NX>h_q8<tt?btb>+
z&;UW2u8-_+Y2x>r=~7*XM`PUIo6e0unFDL`0xMXH3xZcZedkH7X{+(lXj9JlMKqs6
z&nLL_m@?wEGLbnb91BWPX=6uyR7VwjdnCS9@dM%8w08_)W_ctTW$YCp9mG=?Z5lkA
z(u47(r~D^|LRxDO>sa5SLiNax-7&Qodp~dka~x?^F_JOp)d5FzmbcH{4Wz8bzTt-j
zx)IDP5BHY-;K!au_v-2Fgg}0LQR%<@ZsVe>VbDmhe~6>a5?lH@j#{PtMro6uOynW#
zJ-OpX{a!!T4ivObx>3K|PhQ75PX4vN$`9(>_+M2er@qmTuRBlU;86^*OymNogQ&!M
z`2&8;(s68>^H`x2=T${e_N=A0*d6ZJoo<VM{Sk{gj5wDiHusC}BPPd0!H#ZiqhV*k
zPAM#)YbaX#kRx`7Gj^xszft-T>7gmg1zM}!$c&fhV@hC;%0bQ_1CGhpU#yM+!m@n!
zM*YU%1g@(SDBboSUCN(c%UuIDp_EUrLA8@Uy=FgR!Px5m;`iJ|^2Ukcerj?39P*&e
zxOiO{IC#A(&2m@yhy9I}Hr@g)38cy`3`<Ik=b!eYlIh=Y@4E$ce?UBr%DwnoNr*3f
z%-<AU=4MSfLfHI*9W}VDC{gjy%y`<ygpou%hBo&F-@f>$MIags1Y3Q+KW%TpNu2wR
zuWx40q#a-15e@NG+?u^802CMh0nzAZEp>u#|LiyIMdMA;OSE!Cym8RWIJtC<#$EGC
zQqzulUgNf3A|WAHQwuFIXuOFn{ebeG33wQd=Z{xPGlI0bqHfXB0<zfPsnLg&9=D;R
zS^R=l`U}es#P=911YT_A7RQ-@ZRV2PQ9;ryX%2%fy#9d22}ZN1TrH&&uKs%%xpP-r
z%LZ~@`-bYuHd~~d37%@uR9rKMgR&m`dT-)gJ|_o7Kff(;xHEYH=C+<l+c^GZb!RI5
z@ATIW5PH^OtBiFcDEGA0W1-NH`F?n%Yt<$EcoALt4A5G0i#wpd>;2|m0WOLI@$M$E
zm)x`#?66wEDho=~F|T}xE)_K5z7FM!j%F?R)lnA*b$N;`#OGdC^JJtxcSt}qoqGpa
z6R=H9>A+#<v43{<oVBId9hr500jh;+0EPDX`R<42?wd`(i;~5Tde-kwe!VdHHFqR~
zdyBj2c9Gv0ynnpj%((<gHu&q?edeoPhQ_Lt1Y+-8L$&t{HFWMp5@$>9DemOgkis)Y
zn|s{nOkNBC{B2gAvf0~+11Oi0Z`>;V&WHR2oQ@;r(4{ARH4MluG&&kG<m-mAVVqO@
zh0DI?@cTNqw%TL=@N9FfG5?87ru3-K%Tw2XV~akz|87sx08RZVpLr&-q)%vEO%vTs
zg`%AtLh8jrcmrJIJT^_dY=B%-)efR@wBVC5bn_^bE*a{#`OInLdeh9vSsnF<e2|;?
zXd;T-Lml=1@Ck?bN}tRAZxXw-3(To6w8XiS7r0@Qjw>zqy?#=*KyT#>{2L~)Kxu-o
zLngScDN_8+ko&%GiuOb~K9V$#B352X=a%?zDcEr%cd5@~-v>tG7yB?yua5ItV)%tV
z`3=rEbL2f#-^S&B=rfNg%iui6ZWg^A1AWiNL?DzRsO=LSF+i>#D7lMrC<t1%G8}Ay
zxCNA4BT?pFMrUQhuw2&<;&09RgLtO4=$&k6kv4|Dz6FrpmJ0{zQciRBaxGa+Mngi{
zO>bMrX{1wzvf<q8_$Ys85PH`8v6$yo6!2?APa00-{pWs&#>Y>Je}jh?cTEuPUey@C
zN>%u+iUw(gF=wA#fk&ogEvR9ofgRYa#<xa!PzY(rsN%;+xy3XW7I3gq+%bl$AM1l|
z0|^aX3|CuAj4IjURMB1kbBFcVZ$;lj{ncE^c-1&HEQJYkGLc?JurVA+Lv4vAF;eQZ
zk$h=mc%n9MiCv$9zjZJTSs88c8TD6ONRmK{D@UzFzh+i`)Gu{(a#C7t>KK#9qDdnJ
zvDrY7dP0yjgdkrVa`SxTVjGcSf4lK^iX~<~)IbbAP5eh|=`h0Q_Hwo;5%K&IOt_h2
zgr~gr53Tk!I3x-ui`L00-pPGElat(&lU<Yh1viiLSdwywYD}z8_H}Qsy0x^I&t^Zj
z$)<%g;%5cSed}4D!+v2q7>M>^DTE&(h@5qC@;@)ZWEEjQzChP}eA^1hXL%{)1^=5W
zoPwRmuX2!?7utmeSo5?U^?difq`j@Bv=6r8u4`bu0qPOCmV3)|2+ngfraK$&cQuYe
z^)30G-+$@FxucjdTKm6nkzsOwZpQ#aiio_|05L7U(vgokIpmt00nLFZ>O&u}7CN%j
zQ*_77qM6eX%`%RLusS__m)6Ui^DvedNv`j?;;DLT-(GDO1+WDm<%LKgN;!7k##s7K
z0_2M`c89X!ay_aeB`<I=1*Ga;P65g%HnYN57tUm&hfZ@%AAv}WYl!5-;{c_=akj7B
zjTZ9h`n~NQv_6k6-P7I-P|%_1gM{P{XLGCCh2f>U+8yOrLf_q@b8Fgd$%_GEvyc>i
zLov~k+a!SR{6~K_<sj~4E>bQW$Uxa{b<BEYPNiekUy*?EzQI?y2bmVhufQ0A8iv}X
zhfRZA+U3QI`!zFu4yggo<i9$S7kf@<Jl_xpgy)+{4F{WOdHbC)+R|n1rdNZt+CSd3
zO*mBgdb`zVH6HmUyI=>lLQNRdN5rFjVA#NO(ES~CJ@!q?flp76KQSQrmXOPl{3@uB
zF?oPv@<7LAB<2gFC9l8Js-nEx%CBm7CclKGbqKY%-^r_Pl+J5cG1Qe!kdra8wxhI9
zAjsnuP40MHtZ_G0H>jN6QEx=VO%;L#q_w2b%3Q)G_McX`3wBiTQn_J%?2a2hv+(Zy
ziLM98>`dVxpxewJ*pgqynPC19yN(<QZ{4adXb<{53gF0z1jLcm{<g6p(rTfK^n#6}
zw*wSlIKtK=om{+^i?IW8>Ix6r2KM;%Yp9&8vvILrPPcwlZPBw@T#7xM*2M`Zw+mjY
zZ3s$02B|yHnuwsh7OToc*i9%R94eE}RwixFe8IyZWH8Rl>4WkVWl{j`4`GUjFO2#l
zybr{hVxgfLxGl&FV_X)Hf_7Rs;e9Z<!-8t_HU>Aauxv}XxUAL7(WZcx82F3zvF`C2
z_jtNW19NPG)uNG>pw>Nn2*2FVl|8@#AHGRNlYYSV)k@=Y;fUA#K!p@N9hv#b7kn;D
zo!*NuzdY$994yl8jv#J40YaLkf;3$PcHJslJY{*7x$@Rgjg_NsowVjq*8w~6vrc_=
zko-OXX;CYK6onR_LJRz_f#QMNcbuHC$Ps#Ci~j(5f&giYPjv9-;m?MvjiKdNZb_PJ
z?jSg1uO#?5J^@;#d8{W#i>-1TT0JFm*U)1yUFM{)sO|wSg;Y~Gf^-A%-4H%nGc7mx
zf0?BwBm(h#A<u^)L=tg`O;Pjb8t_W>-Xnsv0W(ZTrmZp^$`PQlGEXbZe_vaT5brAH
zh(^TmtR+Mf4B7Jxa(ibP6&1By8IQVGLDwHc3%$iZ-^$JbK1l9oYAlk4;I*pwmn!<D
zA=8n$a|?ps)72PuF~5TZ)q}cI0GBC5l#&1@_($*#g2z`HqBa?F)cEl}nGS;2nVy!8
zj9Dz5Gmo8I3FNXWMwzIt1*A+xG)$LU=r1cn1e9jq0+>D4@i&6=O@382(c2(-gXDes
z7R0p<0K_n?#u-J2a)5{ZR?Q+*$3S9oNsMd|jyV}cwk%XqzuGUYu8PRRhA>Q|>IV!-
zZA^Lm7E<mH!Jj5XUE<}(4K*56J905pbC~=uKrzZ=)j>8huDEz-oPkVU{1Af|#}HiM
zppR4t!@OJ-y2JhMo3M+nPeNd_+O}A93kf}Ou?zVUD{FjBr<Nyg;^eo<`y<tMUFDY!
zSCAm}3F*s7EHvSs!dsR<aKaA@`7#_6oW`l8JRG$jmiF<QX5HDQ+QS3s+$<D8xO5>c
zD(};@&xI@EGy|T+Q<wjaR4->9l{*&Y=>~1@_X?nt_(5Ic$-f2Alek!c?lE^zXfVLL
zz+i@Uz?|(azjo@~F`Y}0N1(L<Ca=P-d+ZA@yqf|RZPFe=(&?bSP?ewSVpGXZRx_;w
zI60v0_Ihu?T@iWeU2o@ljYqd3;COkw!4nq?gj!?AuQ=;L(I!rMl?-7(2Y)bdgTOFU
z6Lz*Dv2?%_RgqwGa6I93dA7e3W=|a5Q6EQn?QN$X5(ovvEHZ!4%AH5mMB@Kb2S*Yg
zL;1xJE}8fyO$GyL29srTl=Q$Yz#iG+V#A*Muc}CO5CH4MeEW3NZwa8BlrXp84_r2Z
zW~pIkuA4uRl7|@@D+$PU6DQ8}<NQP=nFqM^K}Q7fF~1vQ9jx~-Oyf5gVX#8Nu#Vi7
zB>y$B1La;)pA$meDD(WlTJO>IS)A|B{UxyeH`W+v0~5K)=8!k}bI%08zk`wE`WZ5U
zv+bW7Z?O~fQ%>-V&Aw%mUhlA<-mX`xCLKBX%;KJe_3?+V6+7bimq}loges!cwUlzO
zUr;9=S9R&6qbHTx7IMh}Kp$~FR%uM1<Csr}zClf}#k)8bW%q(MLF8u~1e5~AsQ6`z
zliUpem6}$j3^WK+a3JcMHR5tVvKcT&VTjPnQ5IW=008^zHME}*nA<OXVOiO4@Ze~#
z{q+g=6~Y0>DHCtQV-8hj=qRhTs<wJ>$(q`t@701l(qH{T3W6-6o%V(M`;DD|qCXE%
zRZ*ZWMD*$VREd}aRx_swb0HBI`g5P4w)ZQXFo@30L}KqAg5S{*FSvw%-o~Ex+FxtK
ze!8EUaNp%3N3<2mLi1L>P1o;4#xjg^^ZcgIH&m0Q!|8uSupR9v!uh`yXdm?p5bv>W
zdj(xOlbSH-Z%AEVE4)osL?1i3lAv}J#wtAxBS|$rR+{7AG2T>NH2T5xchcXo6&i*6
zk5~{)aegt)U#GkUT((7UR78IQ@7mQcfM^Rd9ocm05X$>iY0)2%_-xh3*09HMlo!U1
z<R!^3Ifz&$$y};fmaZ@e$?S^AkhLg=4ELq&t93=s-5}J&ah1Ypa93Fkuk1~6`0W?8
z0}D)BizdaApaSV>zZnEYUe-^36rP<UVwvYI#|iMqjAsp=@7vr_l;g<6>zLA1N)|#>
z5}$;HV?!?vRt<!eIF2UCiH0irfTbx60!8^zMQBJNDUiqp{NAryZM@Yd^9}<39U5cH
zpv*hUM;hatL3?m59aKHs7KbX11Y~6TFx-(J@uwxbI2`>{(G^zSh)Sg}<<e;f71mI%
zr(9pXQDi<x)&_(YrUnT;l0e=#Dztmjf<Y?6SSk7*l1R5v^Omm+i0^bYCsGDCljW!w
z2%y-pqzWrYD(zLHI}n*NteQ=+f0i`Jx_bDi4D8BAGKC{?183RFP^A|IT>2~@$T_}R
zw>qV$C2mK7O@F@~SG<vNq+DHwkWQ-g6=r~c^89YB!jc#_$6`+K5fGQV@XqNg(0DwB
z4=5Wn7Lg;Kf8}k>87*<UE9*7J>S%MNvQA?h6>Zf&khLl%YgMiBwI~}sRky`>8xXaE
z>1pILEuaKL>1e8M1P2_(#${x@1Fa1Xhqk0TrE%txh><+fYoJSS(X8J*ta#y1i`z`w
zjd=zjjTu|wAnnM~A>8R$5;6}u;%Z1zvM?1X*xu%djK3IyY1k+*G}bT7#a?vSS5-RZ
zPi9S@OIP9`@xUZzVX!+}<3c3lT=8<8JDzL1I!K7jn8A?@Yc5QELwf!ytW()Ea;nKG
z>*m7o3+TYt1db0q*UXgS#0H1D=&a^2se&b;LmtfeTFitG^<H{vaUT>r5OkQXSWM*}
zLa91HIOrdc&ik$Ol<fzy<d@W)kR|k1cY=Hnd2gYekS)x!>4yn@Na5+iVbTw6!n4-w
zY<^|H>3B(AqxWk+(3YA5j_fH|-WGq2_DQXS&XN`?MHN3g^(fNS#5FTgiobqQARSv+
z9O6%h48*FhPJwR_myxX~8<4K@dFKX>Qa3QG+@Lo+z-3HgC+}3ozy>DO_)AflYLR@~
zhtfwRt_3kKe}`43iQNg$iKx9zEK2cK*UF;J2=;+f4U!A}31PYM)T|%a`S#CVTx6Z|
zjEyg8eJhhB+50&x2rf3{8dJR=<s<BYCEDV|0S8c&j@)^!YBoH`S^1Kk8r3geMbe#?
zs0scfIc1<Aj2MhkpAP$L+x4uF%KL~*5$_4Qt4QBhWV8i*d!n0J?Uz>uPYt>DcOg-}
z59LsUcSNxt03Fr%rQ|edb$Av##tp>i2TvV{sERaCR+j2<JqG8D;*M9XC-r=2<w#r#
z!<Zm~7Nm4ylc2^P3Rvh|_SfX^;?#DCRR-6p!3sqo6i3?ErpCQ2M=V|Dh}rfvh4v3W
zV73e^w9vCH8r*_~uvw$If@(JHV-Kg<S!8@Wtho0}R@YYJs<>g9oUQD4*iljr-7;<o
zbC$L4f4AtsFmt+88@IX05fSZb@Egq$Zoui*gzH+0u)8dR*7U^}u{)D@#2!el8^!HD
zxW4w_dYB<Ti$j)w&-zEHBgy7`)0MNe3yvnA+V(yFFk%6>8ZYX|fjWOY4qIuH?TY-4
z9|(B}?En;upZ^1HRac7#J>sOPVpGBVY-;q!M}{5MD^~&sip=Sb$v9}F{iw2VM32yF
z*_W%M=Hn(qQ(G*>y?WyD9hQZ9Q>AhVkK^GZdN_z?Dh?lF_i<ZCOsqg7hSi?50NN2m
z%=XN%wRwua1#PT#B6e!TRUQ@yR;2x)Ptn`I3tHgBTJ0SK@?<<EZSg4=5c>(Dt8o`H
zPr%HS+bx~80GacnB|zyo>>Wr;wvDHhb3i8~U5h5Q^oNt9!Y*f3X$}k%GEE2N%D4l=
zoI18jGwookc&()<ul2|<yzUY>S1vW;QiOUO-uB@uM4OG*9KV$08BgVY6Ci_B+I&3n
zks^wAdUsgFFWYo?ilV)ni;!dnS`1(v5iw^5?XZ|C#UFySsM1NBe5E?d1<INegLINk
zb<&BLET#3nBQU&G;V>|#qr+@Uw#OYP60|N|6p%L>NpT)IDv<kW@GgQV!W5eApA*qP
zgYRG173rtm5rT1gFuTwj#&AfQ2WCz-s;}ya(G>+wKZJEy?m&Jv**C#wXMtzM030dQ
zfq%Q=668NCgSBfL@R7vVG}EHH4V#dmtZ{nbEpktvu2<%@IHvb7&grnlCDio+nnP<(
zO;ZF?S6x5~LouA^TO6?zo@ib06)uag!URFi#Z!<>YD_WAG^nd>Ru(BcW1aehogU*S
ztW{s&(ob7Cdffg@3#zlUz8o#!C;>njIdQXNNpxgyM|nGG3S6h80$y8<?PP_eq5SkW
z+u%OSMo=EwAtOPm{GVG~vDAq^OpVrFv*PeUO%ptuxQrA~E?|#c4-~bqLT`c}hH9{S
zy^s&EHqsj@MI8=6F@hsDJJwaGCq>Dl9Ob^w&imf&{Ow@p%91wWEmR^^Wkc7<rUri$
z7q<yhTx4XSdlfSqvC3n)mjD;qiSNKJdM3e;GOpC&$U?2uPn0zf^$vEClBnR35TwJu
zNCQ~6jO=I#IFo#>-BFR&j`Twi1YwN8!RaK)kdn_x#U5!v8{!~?9g|pYwbty^mQ@;o
zDNcAO+y3X^H~B3iK1)S6WoqyzBF`Es#b`agko)S>)0*jEbtoZGns^JS8^gcX3>|v2
ze=iqacG6LbNrCQELWYZFiB{Ax&I12g^%|R=-je)Q?4}1v*-L>b`+@x;1VT|=?b0nP
zp3=)^dhST_eAApKg~R(bPlmntE%JcFpN$<H@meyU63S5BcntekUsuBJo@}ojXZIl1
z-5xmAdu9g9d@=0I@Un+ErCzs6gO9cZ&6Zee0{vEU4YN7<wOA`lZ-v>cwkk}D)E^i&
zo8<)#4vxgynJc!H?(1(9`ekjeMM!{7Z!cVtHV*Y{C+xd&VAz#!RcI08C%ESJx;`NG
zg$TirwcT37ReqdQSu30LYa2pUYcFC-_1^}P`ye_iw6-YaQ80qbuxno_@2OsMP%U@$
zo2Vg+){7?wkuJud207LdXKo+l_u?4QdF+7`C2Z|3yQ%SbrQNEf5XpZbfp%&c<JykK
z(MicSiS(0ykG;M+wj`w%>T!t9eimf+#If!;+~jE#&$TktTN?Rs1?oc2P#pCcl!+Jm
zCkPI`p$UBB%oe0_A_t`4qRBVUVFkYo@h)#I%R=m_Q1MDdpZPe_U$L5s7cF#zEkjsi
zah`U5k2x#%YnFt+SaNgBbxS$3GJ_w?tlW#RX5qiG)Bw(Xvo&LA60QbbB|3z3Bap9^
zt_AjFaaKK3z1OLuP_*f@F!=fk$(aBq+5Lre@p;FwKD$5JYnPKvl}}d!phL6mL8T?I
zw#B1o+<Hw*v#I%MAg>l`OfL&;K_5o<+ilc*lzs?ITV0EoMW<eKB8yuU>kqrAap-Av
zea^O6hu+$F{rUpeH+}BF>qVXYW^e7+$;T_LrpBimW03!CYv^O&x_AA1$)+t&Z;4sI
z{^sE?`q++jSn>7hz4&M=)RerLY+Cj7su+ZZZhEjcaEa26x$*Pqy?EVKs5$;^vO2Ki
z$8Vncl52gKCb&<L?m}ApIdCTN7gEEBhxzgB#bJ$O0hC;bxO;UE3*1XTup2B~ik`Oi
zMCh<K^#ENmfCRO^Qr>5_{j(5Gii2M^Z5pBbY~!3~oSGNtr;|YUm3lhmF)S|OAx8Fw
zX9M{u$6B0-K#{U+L>^RDh*RQ{%hixUgi{OLo*d4h*Hn+Qu_Z5Pw~g%IGq(T0$z|g>
zX`@c%-N8Ck@zm2U!!oyF>Hf??r$(oGj&*Dwg5y7SZG-F%G%k|L+Z)xCY@+!{o&X;A
z>NRI{h2u(ck^eug1PoQH!WKO9(cj3IH&xw?T!9eJ{B1xO0DA-?VW+rqG`1Y0a|ZGj
z9dT(ms;%Q$#|)GQ72kzbOzcGfepfCrc$kW?c~Ld0Ej}H`2rf(2z_gZZK|XaHDn!G(
z#36A)o{(8msG0WYuo_NEZ)=^8s+>^9&A@;_u}4)RGOX~F+_w#7;&M7;w&81Po!_r`
zQW!btOk$?e_2j&uc}-4g0}>T^KJ<`I8L6OG)F>Sz=)5E?TH}dJ^As?|*<xYcIU42u
zIC8wmFpy~E7(kw2eL~}u`{L%}C=XSb;1pypl3}N4P&XSYXHpx?IGsZsEB0&?0Jhq7
zUUbS99Ko9n4g-$Xgf0Ib@hnHq+MDN44*Gz>g>M;3xp=NwyDbrjWns??WMU*jwx|u+
z+V~*0;XW!Y1^HB+nP!VuA<9x(Lg+b*68fNWb`@;T1gUL+;IzND`?Ff3X%J#Z>}zVj
zsx>Z-ciY#VG8B01tBGkMsxJ;>`x~`IuZ16ohsD`8J>iRge-R5z()06m>NyF#k!Yz(
zBaz_1plTuh40jIItTis;s-no)q$zE@fpRf`EA|y_>$Q;IIqdv=c-%F``D9&cqU99D
zQQlcu^Wre+sD>zJ%AW{8Vkfz#ihP?e)sw>#Y>uiZ`Qo{dZ7)v05au?)nxpG+?E$ct
zllrl<aIPaK63|A{Fj^oH<P{Xk#8--C6e$xQj>9I%Z!+w^TKw#wj4gcxt@sgToYRMd
zr{hWEpajIHe@GcCdk9asa&Y@|#>LBF2-^_$S0kj0eB%9%9N0_Zj&=5m{<@93w|u8n
z=*^!%*q&zRFaS0eT@i#uX#IW4n1{c_&6KeLFxiZ|>8qkKx+MF8oyp4HaNQl_U$m}x
z8c1A+|G|1^&`r@{bHhxHL>$eag?X)WY0nJW9nYNl2j`u^z~dbDLKq3<yXl_6w7$T4
zW-!7Fc>mOwtQ#*!y5rf#Cxu=@Z_f<2_J-xuKWOg^)*H`wr%!TC&x3(8o_5AF(uaWq
z$&Tr1c-l@L(lkfAr>7UjbA{6f7al6C;-s>GH7>1aB6h49wq$v{4`rr>V}fgmuKxYN
zU|p_1fGt-%^0F`o#)Gw#F|k9Kqr62Kx1xffs%>ZcJRD30UJm80^zg>OhiBFyj&b@l
zH^;j;4!3c~bbS?r@QLXK%2VyRD*{4hF6te^RH3W{&Div<${W;|4Z;`#fn5PhD*@ll
zsc>Qj)2BP)8OQX8ZSkya`i$a<aTiavU5kQ+9G<?AbXfqre(V&p-rVPQ5cA!AXaK;h
z9`e;c3yUY%0@XAHaZP}i2uCZTvV4<TZYQS@t|0(3o}Uj4W{4cKTpCzj5G)Oqgf2q6
zeuJ60h(eZ0HdKaM2jSPnz+=VJt&nA-969U`Ud-_E`2nEr?heGDAdY%gsJ@4Gl;+!H
zh$c)fS7Rs37WH03+JQq=In#=~)6R`1?Kn3Wfu@wQ{~Z1`x_v=aUXE`=b^D;6(&^8b
z0Q_d+&v+L>@6K``{1s6e-yCvJ6bzl;L~4u;1ZA6aBz@OPTolCyB7KxS7>GDB1nUE@
zM(1cw5{s=|c@8FP{6TtGBHJK+{tzI?f_eu)qO%GM=_t_Ha10bM#vQz~{IV)__&QS0
z=aF2fwRyyMz$)Lgc1Z=q(fxvM;Rq7$1Ku3cGDg~RG#(3Uot_7#y~KME+jJj9uyg?U
zLih`=tvLu*hu%lb2g>_xs-VDZJ8&@#P(@pBlj%YRE}=0boKm<|vd+$7txSw}p|%aM
ze$D&|xZ~JUiIc%7YSH3y6!MYVAq04gGmKE@tJW9osOsrDR0v!0`oJV0V+s-57N%IJ
z7m4Fa5iu?lW>^0r!+--RCELQL54nUA%t%TgBuArCE46KAs7(YAcsb2&9*+&+0WC!a
zOV*H#7pq8elnWphgG5|u5S-;L`wc@r&<@~BX(~NM=;=WF@KN0zh1`o!=VL;hUh3LG
zZjyclwux1)Q8?zw@`q-$zuSxyYiLFUOZETgKW%3+MnIPF6P^s>ZnvTl-HIQP$;XGf
zO-~_%8^lMEg;oi;yA|TFc#3)~>txqCa^mX9nM=;szv~5hNAfRN^!u>Vp6Pjb8%VxA
z;i4oH=s1$Bc&MU5?dp2ME>w|9YFSqdP^<D1XDX?6F%yWZ1a?dQ+*hMjw~0Is{Dk|I
zsXgdC0+&cvF-%z(sE;K$<`pD$rkMh)C}Hp*Bor&lsMX|VqTM-B%I?mll!w%&6yx2d
z<cnm+ygK7hThjN`my1YKaBW?JtYQ^A+LCv5wjzxV4oH8u73myVE;>+pHN*hWEx@fS
z4PybSO6Ipvi}`JTH!U=|tUx{Ri5Y3TPn{y%uYWjqcXmIM*#)cck|D)GL;EL%3IdoM
zHa7+YEoM_I4l@^{+iwm7k2Nvk*>++T7Kc%43fK@TXb2XEQpTCL&6VO{%6R(LFCyoT
ziwDpwiPpM`3QSSDYsPul`bo75pk^5YxgOQ^i5`J@`eh52omROUeah=waa;?AeG}8~
zo|;#~$o3ZGn(h*_w^G`gox|q-Q>8_Ajz9(`r>X;!`%!9c8YB0owyic-%6+MAi4G>J
ze<BWPbrcGgwH6Zn051*+<o-P<V}tfQ<zU+e<^RsR3mW_6S6j)wFt`VyLCtONw2><N
z+lsXear?ZautbTUV_lS+&6c#jYwEOkE+5Z14=*lx19?Ez`$F(eWx1SkTHA@K1Y@DD
zt~Xa!%M!JIvbEt2B&1f3OWhn^l19`;NW~EH<xh*f{ps|Kaj0Gc?!9^k)_}{v8Ub(!
z-0?YGx(56ID0}ySsLK3*{LGniW?<$3GXo9^gEHs=RJ>tjnI%Jn*Gi0NGix2U18G@l
zZWptHvG5Xo7RT0Gx;u=VR8}^bT1|}>rVTH_F3wh_N$J$dL`|FuM46fI>p5pY-2D7L
z`}>C(<~--Qyr1{;e%|*tgYeg9JD~~414{|K$#@Sz71+r!#^yB|6+-`9M4TME`{%vc
z0Zv!5ZU1|4$Jy)o1sTxg`)7|&)-k2tzce*x7?qGS=l<EyizQIQs-PoH<qfIB)}h}r
zYTOhg6|b8L6O*{qL=rPWh3z((y`}`Dj=yc(ZB}IeblTX}1v_oED)9@Vg_8TXPE&NV
z*6ESY(@Yv2kzL2(JIUjz@T{uhsi~dMY9aC>>a6s;Ufz(z`-&N|dq4j}NM7TX@$*e1
zbLoWH^niJJj(HC_CRA%Ci2ZeCL^iEg3Dp#F!I#uj#b$g^RK>N_jAYDOdXFzEwP|Up
ztB|OmxTDk9h7Vn>2P#J%fJ{r2%gP%5v)$MacY8ja%b%B<pr7TJxrD{jSkhV1($rMB
zGj^8X>L@lYD^7iODgHb&j7rQ|qM@n0s?yiSK9iSP`n+N6loh%8GP0qMs*x=Gdzw95
zcG@&5Z8~xekQ>s(O?6D89MdT<LbT8wM(G?{x*VQFETZ_Bh@+1WoHMa2JZTR8!^cAW
z*BPF)22JpR_oQDUase^clXBWIVgOmqxFqRf7%Ju4oVhVz(uge2#p7op&o?J!=f*%~
zgp37BOhE<tLHNg&^dxLw4ARQs9YmQb@BtBzh0oR`5(&9~#eSH7C?q|Q5&605(Ik3u
zxe_|*+F;nQ!BE;|=t|U%giq;GWK-Las3SjYU`CRVlsh`)aLTv$cHX1u9NlkA$(;yg
zN*sKT?ijAZ&5N-<P#swZo9K}PP&;^`NNrg9T=h6I+$&Yoo63m0cNn&BFjP)8Ou>jm
z?T-<+C+f%#7%>d}L1e@&b)ENVI@7L=2%N7amWEw#($Mx7thS1U@J-}ucB*bOa^uTB
zXEq{J$osBMjy0>H077V>3l_4+^+#dB`U`Fm`##%=<HyILgZmurs6+N0*35B7YL29p
zrj`12)N}97#{vd$i4MAyO3tDFT~!)1oVv$=?<?Qb94g=jH7r;`9jxNCQ!LSE-egu4
zqz_baY;)l%JSu&01((oeiE5s_u^@eriepH2!lf0%n(uDT*!BIcn@?>?tvt2V4;)ek
z|I&WQmV80qeAsrXb?I??5!Y3Y6H!z#VQVb7l2cn#VE|iYysS#zs1J9mDodBHHWqzz
ziEQpIDmXLM&4AWHxY<;(!tI?3!^kf2Cio;9a7Zs8d@gD3!`v<@*R&SK^x=~ee~7C3
z2oW6VV75JtNgjJT7q_Hw*di4$8E<;+8QJy`+<2f1>$avlts`<94a-(9+~={6bl9_I
zPo<_$%Vns7nJhPT&O@`=QX~_$4|lt$=XN}d&5xmya;W#JX1#6L@V3EW9S$U;oK>Z7
z7&dHFaVZtSoVN|6g|F(^AbQFhD$ZiIV2|;W*E$jnVOYn0?}nOtCgrhaRsNVdl7tZY
zXCSSm&pN_u%^*<1904XDrWsqb<rk39t@@^)!j?NA#cNd919*1<DWvfxf8($~<7h5w
z?M&8b=N<N80sG(}a?o=#z_3}<9oAvFR^ELt%oY@`iON-_4tv^jf4PI>lvU)sVOaUL
z!D&qc22+lz%C`+GH<2kn$#~<akq?kY&MN4Kc0<m&j~ZE1DI33G@W22L>)_-c-PU1F
zE00olfD!Mu594$z|5R?d{lNo>pe0qLG4D&*pt10)u*{S)O&mjlT8GXIR?TE{0!wpF
zC3O5~ta%rwkQ$r=i!JqWm8-%~S^@7mz1My-mf*ABwE54G>76(D?c-Peseqf2T<x|e
z^Lq?l>&-svO@1q!<I@Ay<c`foI7?E4a&G@a#~<D+bu3*&jwQ9NYWIG_-pzyD)}hJ!
z5v=955A|Ay`Wwe0OJZOqrO{JowhTX6=(G;SRFn7Zu3YN04|Q#-%$-JoS}H%|Ur)3u
z`G9AdO5cXrLjiay0ZXWP7b{TaU)1tb{wHuZziE5LSKN#l|Bxr?I`UqF*Xp$o;{Rg6
zR4>hBz1Be;?U7eNF0S+h;!3G+t2#o4u0L%HSkuW5l>FZxv81NY!XE2T%k)__4Q~6u
zjsr&FZ9~1zW4EB5Bo<+=7|W$3pZD7nefA*%tHo;_;%nU9+Fa?io1I*#(>}mFB>Iu)
zH=}c{=FNZ3Wy+lP%r$vPH96z<*Jr&B5Lq4eQDT+BV;$9T#d!N$Id8p34avcD7JgOf
zv^wphVF+J#z^$hgJ2>U7YJlr2jCBk*ga4C3pXab<CO?4nxUHkHg{7}IfQ~FY;^C-e
zHAwu{3I~9h6y>Rcv$%6QRW$Xo(~77-bHJMD;L1GKA#STB`K!(C{+Xp9U9IrJvJY|0
zEZYsA@wlG?)*%7gEVp$a03d8IByT3F)U{UgLwc`jma<9@_lkLSw9`J$V;}3ak9kDD
ze|0YRs>7bLUs>ZHXZ`U#c^#?3Iv`6bwA;5=Qv-9TpQ>`I-&=SdJ{>N%bs4Ta%5AsS
zGKzNxPOma?Zie&+tkGk&I;|;K<`pA=Q~AdR89x6DWQwL?jpIDlv0m$#{W~4ptL~Yv
zz+Kca^Hr>b8!4?Zn3EWXYL>Hccjc-|XVj~Xs8_fdn^)CF-Ts@>-@G?#wsqm%!YTup
ztYv>w1_aQt0T`2bdE`;b28{a<LH^*sE5n|~VYYkNQE*b`*N3+pf!A!~Fc3(;5s^{c
zbjR_qBXct1$y}g03ntt4GteQZ@cfj~$vl^4&#tU|%$fI`c?nx^FUx7tT<<S&g{!_`
z#=(`?o|OCXD{l2G&nJy<{@xS+0EG8XzOBRMVs<}~l(nB<iqQ8#Sref!`#rwJxvQ-n
zYZ6g+yaH>HPc<TM#P|o-eUxU+hRMu2v}o?X6}lz-U_3e#CGdtpNr|*G+<hFAJA=xN
zDNSyB?%g3EIwNby{`|qP^3Um@mmonMGQ9+`1f5K7?tRG#3Upw@+g=nf-5S@_g}8CI
zeMr+{g{PD`19E?|^{U~vY2$9Qx1dVGaqD3tucuzHFVb=9xp~(6*wk-#I|ftFZydbC
z=t(yo8hp5b?+I62*<t%&TnoFZ;7e<ShbAVnpC`QkFN;&*6*+cp=Hgl4uqvM^c4eDY
z$q!_#W75oEr9dxN{_*>?>UU*6aXwAWeW+{}+kDeKL|)FNRi$~x>G?T1KXY{IlFHKO
zU9%Ha$!Sym7|RWGCej=|c2k3#A_9EE2Iomd5CCt+X>i>u_L4PIK+7}Uibcj3>wYHJ
zoijacL<S6JBr!zs`V+mf1K!cD{akj1TL}hXc2wzvKN{C=P-kb3+n|o$LTjH*AWf5>
zf99E`#T$;n|Dp4Fjk!8RAXju#2nsdApVre=1uRz~)+0@eY;OTP!Qr*(5+5_xYU^nW
zVp%S*LI*SiO)SWQXOyu;17o`Rgd7CW!hYF!N<&d2jQw)XBtA9>%pS?S{7V>@9~eRl
z>4ZP8Djz^eqkqBWcHV7MrKu_CHAY(D8}f;f`_hf;T&40=S+*Zg)#_c9ODjKZ05Uoe
z@N{7RzJoiW!782S-!tOcfvLcQ@=<4ro|vR>7Qk5(CYSJUWMB*bV|al|N$z}lHXDRv
z6>eod(8q7vslGW1=lai4I<3MoPlCGekAK_Sy&J~hZ5JYg0A{`KTEsK`-{rqnHEF1m
zuhp{RQ&+ue3K}Pr$dDtZiFTF$OwJ-m_Bx3GNBUNIxkXJ<O$aAo*}?n?KEw1=b{Z+V
z;LK8-$)mKm9$9VPGmfkS2S~Ejs@*mkgB-iW|8S}CGzp8Fi8+yau;^C!y8oP{&#-aj
zTFR$|D<*Oc114;nhHoOpc6<Mm4s>6?e`F5G#r?9bu|Qq7L7n*6IOhmsVz-eH`GrP@
zifY)I+W7+QE-@-Afir@<%?hrFEh>Zz^nAxntk;UKp^`A72sRk2V%5$JW8((7%2o+_
zOK3oEB}R{m+VfJ>(E@er@l;<4EON>WMNePOF9jx2OL(najZ8trg<zqPY=I0#lzvc9
zY$ic5=@S*4!J6Od?S}uWl3xvYp|ozkh8Oqu;)U4S4=-f+AH>?ZELiYyoDv_K?jB(z
zM7e~N=!A*m4gP939^kP%!<cvlDV3<s<tzyqDKS=_AghRM@F)Gj!hfjJn5m*dmZz>X
zkC2lf696qy0Q9=CE{=4!@tD$2;*~^ndwPR<&vF?!a_6VyzuINy)5YpjXH(A}>s_Y!
zXL*^YH{xdlq;BBYo^-uD3yV-6cFkLw_?T&)d=h0a3GV?bAf*&71yPLv{Ox{7K+cf@
zuYEUySA9QtDed^ZH)zKn=xaylH2h_SIylu3B<0_~QTq@2+V_oLcY}7~-+tAOfA<FM
z`1gL*PTX~acH-{7c9D5X?*IW3AIrw16A|Ah6n;x4y|cifHSX-<lE_s%#VBp>#XMhQ
z0;t=cATdJisjTmv8;rx(^o>L4k5SnWnKTNU`@Jl<uf1H@i=@Ikk(Wsgdz{a-f+%qd
zeu5k<-Sz{Stp)vEV7>9wm+{B_@K5m=qX^v<-;%pV9g^ZZ?}71z=DS1Yi42lwc7{IO
zA27w+hNu&t9`A{#9Hv=LQ^DR_M{c-1vsU{|^@_a{5u-s$#}W4sY#;v#1tMKfLzf3f
z^RsfE9r(RKo04(<7TF_5w0*lX9_};ftxfyPXDjyJLGS%Aqn0~Zk62On{YWv4zTgN0
z2VjlxQyAHJgsgAjJTNho1=zVw1=|mNmH$il+8Txb!5VSW7L$WGTp>fx$YcmJ*?l;*
za~bWOPaqjt?FCkRT~$7W^6E$l)1oa}Sj1?)J!HP3fko_0$h-^{1weBIL#Rkcs?T3r
zT>#EPnZy#4YZUfSZtrX&hw?LxktK_kP&u+9q!H3ZW&p<?kS^tPf^^OAZP%s|haoxu
ziOk$79jAw=VP`wD83j1R8rie5Yx4o59#KKhAbo)wRM;6rhWvi(eHH8FG7=w4irk=O
z1j+gqCq1vqk0pyMo;g&Wmyj3&M6owmikCKC&^!ZCF4qX0t)ZIKRErjmE@*r@0KJ{x
zsoau~xe5MRBlpEi*RZXRBno62$`X3-R1SH6e|@J)%jJedM}sq~TtLs=pq;SnSM8){
zueIw#bLshCwL{+DzH$573BUhUJL#!w?H=eoHqw$`wG*DaK|A4@U$v7K+@PJb=s(+8
zgpwPy6Q1~0JL$0-v_mrCUL9ZreimW=4cZCC{oBbjM*8iwc6}Qs{jRTFgqHDh!Z<eM
z8t)#8>M*#&8#WnmvEwH9s0@jZ={sN2HvoYb8sSUR`O;4j0ygIco%4@II>%lU8YC8m
zn_pX7pk8$Xm-6Zp@>L?2(}2RTj~`R$;R847?xDW9V(p}zMVx(uc1R}N4@OFVvu@Ci
zFZ@+I@tzyB6ASvclW~@xaf5dJeSPf+%_aBO-C-mfBSqFl9inq#Ulw)R2*9SGhZd~f
z)0let+ICEryMUZR-a|qYUQ42SEqY!Xc~88n?>)n{_mE4NEcx1dqFQ-RRQHaTbEEfA
zAX$Dd0#8o7;|A-3<@Z<cy!{64_{sg+$@_hCxR>?i_*)~lpCTWORyEPo+PAMUXubO{
z^HbSj$YU8`i4z|iL%_xF`qq(d%y<ED5cRB6W8^qOQS*&rcBE59UKp-|5|K3FcYX`_
z!(P13-@jim3-cMQP#q-bxkD%LK?oa9USQjFW0A9mS0U2J0oT*%iPBKG&Ja-nZidzR
zK6xQ>Mx+en1R>4%$GeM@Qso{k((oI=L>d*&N3<b98Vla)BTRilhBQ(^{a#s0NW<Fu
zpe7ExZh^@vgc5NaZcEP`GenLIf2~G%TE0D~Yj*-a82iw7BM7P2-w0+Ee9Er%A*K1R
zyVay=;Pd%~kv{*E?~qIi-yt6YDe2mJiuwpB8C=%W_R;r&H)tkU{sUJeQ~!1I1NyI9
z)RSARUXupbMIHZ4sA4}10*gWw(}g^Me;88jCAssty(TlD@y!*OS6JaGzuTPP(Qqvq
zF<BO)fDN_!auiCs1}B(X37qay5CU1{`rn)aqdGtRbc*^*AG9pTeHsmJ#B(!9o<AUk
z!x)tnhuRK~0$R$GFG=CqkUKZV3Dd#EFO=I=X(`=A<#)+7Ib@I_uUsDr^c{M69t32{
zJv$7d+V9Uph7|vNf#iNdyjYU~9E&U#tH7{ap~{gum4)3Ji|P$D6Q4ORqdIj<BNb>&
zO)D^@54#0O3MZK6fqQNn1pW{6QYK}oaTlPH?m7N83QT>ZMl4yEG+bUx1Ry=3zPS=~
zbsG&3iY2Ode^F;r(}u+Js8mCXm*rnUe`LBR{Stav=lDm+{H3Org<nh><{62yf=#FL
zOxlBqL|1?;AzO|(wJNu^nj1;vm?_o8(>N$2d*kgt^VhP{@++2^+doXjrY^tYw!uk6
zdg)4<&5ZnYTudrbw%ZbYwgJ3Sfkc_PaOwJ)E7JTgAsI0NA1+IQP~vyvVeSKvPQC!}
z03d)60Yla_6!73P<We}^yA%MC-}!;^PZ996UmN7XYvB1&83lXUsK5d{!AtltXDw5-
zS_kpl%~4tRxsQa3Hfyneb04ZaFczi~kIfW7evI%~<n=;$W#x}!{mAa6R#&!-#q!*0
zrm|+N+h%sCHJ5(FR<0V06kEg#*A?zS%L4A$+YJ2pXUapG_~RWXui#$6!M>mYm&d&c
z$D}q^=JO=Iyaw17Ef)g?$Qz4ATL@bCjRt=~>;;XO*l&^I$r~+FJQZ0a(M=>n^}r>i
zj#!sAm6GOM=)>dh)P$i`V8wrVt(!i|$DfpYA-rY3wie;@8?+UU_qNR`V-R9cfEwi5
zqqEq#k6wQYQ0b_(*%h$R$u)cbJk4iO`3ex*Xh3ce^Vd;<YGcRM1~YR0S7(*Jf%>po
zXZ5Jcw;RmEweISH+moj$JcZB_0wL%<ZPLdS0>AOYnax$@=iy5*vW`C#+I7UMGh+89
zJee_R>#?`f{I0H3utrQb@;<rB9^TeLn8In5{!XE&FPhdu3?fJrWW>E8RJZ7VqU$M`
zMU?Z8mRO?sH*ii-Aqi;j@!q@d_rB_hd+&I9?xUOz3%_omIZlfTYA;_k(zDQho2vDz
z2GnH1a=ViAu-28ycVeL%l5dTy@9&ZIWy$mV8<o#0>#IR<<h5DywelUXRgc8%%3PK9
z9!fUT_wnx*VgHRb?4t;Z5S^jhbic<0vtqT=6(n&Xxz!af?VZTFKkY<zE01ZUFf0!0
zJ9y?cKg11!cIs}*nLEI1D)c^}>U<W7VTq_XNqW@3bAWq3$}c+83>CvS4FGaQmj?-L
zB|L-l*HBQ0I_+hY`iB#c{*Zp=?1{w3GF#XgN1ypq>ZTKrp@c3ZZIsms@Ahu-jH4i^
zBH3cMPL-9LJ{^kFJufmJ#Cx7LxU0v_sDm&B&D?znI6m<z?{8z_pa<y|;+hj$oEN`H
ze5KW0o%t#51%LI}tXmxgT7Q8CxtHQ7aR3F$6m)>lM9dG0)X|G{briVYwTslS_^k#P
zY*>vsX0@;ZopHv|Qx{W#L6|3EpyYX4#OnU@grjDYfpW<6oH`i+f#z6$QS6!hs@hl=
z$v&uenhTu;x*}Q&QE$((g&)N4vwAfU{o-(0XcByy0phFvPpiZpS^1Nb%5brM8|O<(
z@D*sa-$i+mXJL8*n0l`+0kJi1%>d!MV8A@m6?Ozb9W}U42k_qp9r$IH!+{IL{6LYr
z%O9_5Y72YP4Vv$8x7rEvUVkJ%JS3k}IDPa#n?sbd8NtZ){V`Ik=)=fQ5pdTJBVSXv
z62R0>LCcBUU6gYU7&g@s<$igdoSYxn$av4}{`tBg@8}~3$RP!1>NCkx9o5E_$+^zz
ztPRPN+|{GDC*Pt>h<~#e?&OGwD=1w5G6|?fEv{M`J@=kvX_-8y{)f4gD!)SZUBOG?
z_0WZW{M^b&#}%@I`xS~LOEEd&q)c}XSG7fte2=SW%~^V?dbj(?Tw#hK%|_?iRJT_(
zPGfW4cOm9(<N>Zix*MoDLe4o1deX<6M#g&uS8p%>Xc0>z<L#2id!9n*By^%&MT4vr
z%~ew)-*e^d&i%*ST1Ln*z+mo<raZ?r84I&LBR|{qsT{&j@&+K9Qo7l2a{mrQTpvXY
zH0NEEAidIEs|C8YX!ux}$MPi_6BiBeBqpHh+!Uroed>b2|DaKLp<6b_L{!PYxh%V6
z_T$6&XF)5j@vFZlQ@*Cbc!J6wLc!mP7F&bn>Cu+WVoMNN+PMTo1=GU6g626<$j03q
zG@sCNgDR_2w<6-x#Bszi%rs!DPH_!GHX^tm6c0`gAU@1w2;|0|KZ0PjjK?#eTyd33
zuFFl)R4;euHbz-?!a>wsfE?|ah^iyU-Qz0Ty9WO2qNj)OchwmY{;oA#4ywW+?E|RM
zH_E<87=*{K(Zy@*@soXYv5!A4zCk--VZU}V{g@Z(-BnKbU4JYRAELm~*Ar2ycVB@#
z;!sR7rVh3mnPU|r7LPu>lpgMnCrHc!pySq(@lq_L%7^}{M`5r5q3T-xgCLjk;eH>|
z(Gbk6dx%(rEEsG!!AKv3ojZlraMeon#$$+W+jPv6h~R*``_#s^o+ge0o_V7wAMotS
zZ+xRZGj9!ELo^}IP_(&6Myy^$1A_e^)2zN;#$V3As=&GrC{jUW35tL@mD0fcq)M(6
zSiie^K(A@09~^9uE>V7tNM`)Kk$1DmF%cD(Ub&A6?D=USZVc`c-w5L+O5Jr~Jh?+U
z-XwMf2qM#a$0fCAr5vh>p-zG+Zecf`Xw!561W<H{nQ~|sXo5^&IDX2tJ@1nP_!<AP
z=b{aJK8y_J&>4Z;IJ48qh<7O?M$9L-AulIxFJ$mz4ylm}ZTIP3FbP(9)V@6zC!xQH
zqL7~)nf8-M=dds*-ApwNrixyJ>!nJVA9wU&3@T~kj?N{Y^|8X7ILmSzbvW*EbCd#)
zV$V<b0hfmI?}txvb6RN2%a&L8pML_2(!xO9NpjCsrp<j-{6~;PCXJq)@l>L_dJOn`
z87X-cRgOk;EX$=Xxx~aR%3aB4hZgAwEuYFISJmA^$`f|Rje}`#=;X?^jQK_F0hqY>
zcZ12q(zQ!qkP<g}F?SP!eWt>n;=s`>KP~&#gYtoKrLF%iMHp80$A}<Y`rHmHJVB`H
zs*#)E6w-0TP&_H6b&a8TU?P`9)l|9Qns6@_>7#hv2at>^W|HT(p4q)W6?Mfh0p(x|
zBO{>Ol}xw?E4BQ<(PFhX-B|Sv14i3hY{W#}C&Hw}-NMOOVe?J(YVmzJS%|V1Bp?4!
zoWEu{zzO<r<os||E!}=AgVbB75d)*}c;m#0urR~KQ}zh^;Ii12>-1|ksw+1eU;_iQ
zIBD7TbtDa0Vxn;1`=$%wtaE$U#ce#c;YD3zlDgrr;qWoAZCUpmTNh12mWAr}rtiX*
zE8F7-q<?HOzkV4Qf+#621tK3qX}(6JyL9unPOX8XiwDIOf6S##0ow(Vd%GV$`jOq^
z(O&`|pDqgjEI$D7C;H1<<@+8zsrbZDnhp+l)Gb!HAmD#<s6}UfpCPt!i_@~%;XPx%
zH8yM722+gXFMCZ<>1k|wHeKw^ba@-hyEu0O?JgLbRxr-zdg;MC=%(Qa;m!0k&I6LD
zFKGEPcnYR;090wRwS;cd%(f?q&vnn8TQ`fHP0Gu>H0v2=R>9H-Cu+EqMXW|m&8Jn|
zsM2ENLSf!KRDN(xuiTyIBE?#3N;Zxq<U4^r;e`(loQ9-L+B9qO<zZfUDhzBmwC>~@
z+z1c@G4iQ6NJ8bZz3|}X{Y}ld`90P_eNQxp!?N_$JI_4KvsP2yOz2W?tTXT#)iQZD
z1g`BKo#W6|^D3^2h%H>qL)PKrT3aez%`PXzm9`0+*ffg@NJnyDZ<RP&c?L%mZqCbk
z@g40Wy5>2;l`tvF8eohaZevHsO@X_ke2mfWx{O=SmxtsM8h~(4^Bd>S+A`|Ru2W0h
zGo!dssYnqzGdk^H2rdNBx?RwbUsLoM_!mye*307#*$C@76Ny3(8-+Kt6*cdeqDZ8F
z3(fyMj?*D~3Dc$(e%p<;u+kL2BY{g^<tXGL`UV?jn7aFCVGE{M;f3B3#jEH!q@vUT
zRDq}mIhB=gL{^;WWmToGsY<6Jv5EM>PxVX-jfzdI>VjI@{Zsbc{bCibE8VV#3kC6}
z(17_jKM-L8(I266z~WKD5|R^v7Zn;}r|gQCgTt|=xN}LYTeE|IuA2{>cHgCP=W*O1
z@Bjg%RYh)Bo64uA_0p-c>&SJcDV0;Jsga-)*&J;+q!7E^Hr8Ej5dIaaLfCftxH^q&
zkS-qAxr9w0!0uTRg})?jyO>na0sXpeYzxK~p6V9bPeYA}FvJA9ic)*>I1=<-NPDWY
zK*CX*Krbp&Lhek5O$9YTz(zaNw8N$jsMP@*G!z<#jSZ+#<P`yCQ4X6n5YGl|s9ndp
zcCI5uJ8dZ8rwP~)l%er!N-H<ooHpd$WE?gwppFgLVqkIqujX&3Qs@0#tC4O8=BIye
zbhs9+H0zzNvJGa|?RskadU}4fVZM#Zwb4L*a;NGg2i(rdc&gGBj&Ywe+#o=6&3K=>
zl#dTLE>gRPjzhJ3&)5bey+)Mn?+BO(Z!C|4TjzfrCo3{eb>{yy&gB1d9BH&X4olV}
zuK|-L(|wfXlGco`_`Os8I@yxDUY}1qH;9c-jpzaWcc;#+gVo}4==37Bcj)Nl!B!t!
z1Pvsg>hDJPUx$==eg9eiU;Pu-@w)y4|9k)Nw}Ey|I)*rS8Q<X(6b}dBN++Y=RQbUQ
zX$2k-KE*~6O<XGYX0={CB>#xt>eUswq-^f}Dm;<i>}%Ts_5{BOYsoKY7x|xmTmJtv
zNglGFB%d+Sv)zZzJUIsbw!dX9Glf^;P#*coY=oa8i@^I1AFcNlsP^xfb3j}kx5Ngo
zb^<I=!K!(zPj~x=FOw1zcDyJpi$jSC@@7K6H}&LA{zbfrwB^V}F8v&CoX0Mid3#C+
z;+`C?vSV*2bS{l*IF*n-+O}sY+t87aKIGP8$rDy4-{f>XwIO-5+x6=9<jnMQyl-3k
zvE(8C>WnkVg96otuH<-G?Gb}el?};I?qqIH25reWKXt;Bce@)i>*f>h;l**aYHwp^
z**rGemZ{9kN$Z^j1AGH5{(;GXsG9?}QT~F&{d;@`1AXqC69*hoH#uxskj`OxZoH}P
zcUT&~2ur(_EDdvdzw#}Iht_+LL#lYr9^r{NBpP+ogQa#*k$eP+bE7iaQ+>8Oy)=ph
z=OCAX$2PfhX^P(z?Jux8O;OH*G>G3zY<JGtL#B3<AYr6{DJnpoMnle!_nBZsPQy~M
zu5Uld-jjMRKlAm$UVIpLjG17Xl<vPR*R^PhX*|HW(lm;I&6ELpw%ud}_1SAm_PQ1x
zG$oOYb*2P=HL4KA2C7GOnW6}7w`vg3Z8hT$#)YGxJy|{5_5Q5cjyZV+kFnXqs%DKh
z%o}gO--1PI<xBQsRr0w2t*33E;oHV$JCf5T-juCY;kGFrFQ-~FBabAySMZi&?Q*-D
z9mx+&yd_($(0Zkv(63#wNu7n4($iwHU8T9+o-|iDXXuKQj+vw<%&$33er!@6hpu}}
zo<Bcdj*}_D2mIL{#0OqPtKNBlM?Vh>#Nz!75Q1#wI>)N0&Ch!>s?KL7zLW}%!PT0O
zu~1L$oUC0!ZCIl?L}l%Q+Xz~f=%YKI9aki=q~FeGCl@^s_9W1|TN8GB81utg`L#*X
z&c4?siSLGG&$`chya{vz`hGG`X(VnBYkmxyAGqpIpiklVr&5*Q`FFy|2pCA9JMiPv
z`yxG7lL)QIi#6f$_Q-dPgyJKS7k7rszmt6ih#UgRgh4zE%`g4=9$hjLkYzv`Bj~^1
z;YLQeO-R^f-j~kBR+Tc2ZSC`qw609M3tuuaX-yVk%(lDfrr%Q;NE??)5w#-zov4EH
zB%_9Ix`$XKa-LaQs})V`PCLB3ckgc~dgC4f6SwPGyqb?_pb>P_Q<T?LcF;|i|A^cg
zWf`OB@*FDQjzNasqNfMd$7bzn_|$QvX$hw)&d3a^A2OasGLElYWdd8vIU5a|R67^v
zAUF9+*QqwdHC>?LlUbgw1b3K|d-89kyojJADYKCpHqw`mqnw=T*jrKQgDmN{4N4zw
zerIVEIIqgqg!EA{O8$+JL2N4d?IdH~nhvM-*t3g^UXJbSBfwFZQrBA(KAhsW(5KEb
zMPF<GyV>ouaVdyASBANICEtkkFT(l(4xejLMlI|2I*a}p{i~4-`eWud2l@{pL-oMG
z!I1f1iAonw1Tj1A@ZzGaFaaz&W}4)8J$1%(OS*r2z*W{|8s%_3yV8{5bS>Oqvbw8{
zNU>r*G1yZ*iWK*nG1%)ZD|*s^P;^?_6o!0)Y<IM<DV%9TBC=}ZG3@Ab(3%@FM$`Fk
zgag$X*cS7B=Pckn9j=8do$$wWt5p%WIyuV6={LMJdi&Oq$v>?XSY@kfIR~eD$SCg<
zHVOH*<b8{5R{nvovW_>dYFfgCv3I+k*q-Lf7_kX+Gw(|FsKI+dvXl!d{cJvhL=)Hc
z@z`6FeVh(Ev3=_;#Se}LCZKPi2R8%=VxPwXFZ@l<bZdfYjJyf6h>S`$fs0zLX&MvR
zh`(GZ&!W85hJ&UkUv(BK08o4JhsFNEG*B2P@06c0KN^oSq{VIVR5*WcILLJ`PWO+H
ziRrMQ8YA~ZO?iRW<78Pl`KSM@QT_|zpt=ukF!n2eQ{g=YaF{)JcCn1)WCcxg5N=VF
zBH?nyH0!m}*C@Om)O9Z|S~wUAoSL0Bae25YExc+m64T`DURv6kK(eMr!Kc-7Ub2VF
zUk^L04LG)%Tf(>r$gy38P<g6o0o&K*adcU)+qbx=W(=3|&Qb)B07~RQWo1Xe@km&s
z3%}#nqnIO3ucjbe{(Lw9wE9CE6bPDigz^xm*~3i>P(W={S!DO%zKwlbiBp)Els+Lb
zJtINEgL6TR0qnfxyzpo^{}BKLz~qvEO4w2CtO8a4KPz{}0xbWrrI+ThIH+;3XaO!;
z|GlHE4_7c6;tN;4W!(PfSPbhpc-8!yWaq&ib9a(5?8CvLH(PsGEgZqB+jPel7fnow
ztlAILk-wqnm1Jc({Jr7w=1`zIi_ocy|7@xwJ6B9FzFwEL!&}pSq^Wd`1M|hkc|JW2
ztDe91ts{rp+b+<x+~!r-<eiHhQLjEkTr+xe&}j+n>I$tr#*obRn-2FUe){bn9!Z}t
zF+F2K`jnfL8S6uEiSET0k17FjB|3Y^s0@l@hSYi52);L+4*mDkDPINfadAMSMSt%D
zAb{rQ^u-U3-u2Oc-&2z+a=hNST2#Bge_!VhqPJbI{C8dDdqT>Rzq(rf2^K;y!i;4C
zBLHw<g!`YBfb#;~|B4ZsRS`5q#(?riL&_P$?GCVUL(o%qR8S50p_2>rul5A_=KlY^
zPzN-O-lQ*ojrh3(_r-DHd|OE7&25X+*=fd{@rLaA#A_bEHByU9kbK*?GJT-4+E}tP
zmRKL&A?b)qa2{<G$qDIj$E-}h$LWqK8U7$7XGT>zUp4RXarGMhlK|lY-oT;e$34z=
zIGOo~B+>2En0KaiE}=DUxLkHLB;as!Dbkp*BY_?Zqgx>j*`M49=Bla%tdyjcFXe6R
z+t*)IdiTf~y#6lt{V8MKHL&wlT4Sd=d`z}=puGW^F5h>#9d$o33m5LMaVO0}<hI)7
zT51k*Lg{5<vKJpm$vO|Cm!7=rW(MEZDBKQpRxQI%X4=#qCf3Wu1Q_muZbzf|?{6w5
zBBiNG>t>_)$B;F$P18c^fQ%34-v)x5(a_XjuISAFJPbjg^^1n0mY>Oj&oSm#;@t@x
ziX;UJX>ooSZwvGAHkh^+9TB-4j;s-Do_C;v?(=P0aWvFgbqm?7U6Kb8%TPqz&eUoV
zZ3Qa%h%Zki*^rY;m@VhoY(eVp3v^H;{7B{R3k%O)hEEA6K71alxu83HRQxUK)ri^5
z&eK>9J}zN>!YIbW&|W6i$He%VxXYKiA>T(K9auv2YU|E%JC0(p-8KZMx5|r^pi+oO
zJVXl(VMQDscCuvg717Ph+>9Q1y2az)K)s^O%$Go8n$JL|gJn+WX?iP6R;VUxfQ}i{
zl)gnOYi+hWr{c~48`b<O>EhAL!sp-MHSS?$qda+tV6WLeu|^o*lmFUvtK?5nO|OQ5
zDota1Q3Y85A+P5z4R?HA*l`b3f3>7w0=ReUPcRdX80w{8;HNNU2&jzGkjfUT#x>u{
z&Eb1G&5wQMp&cz6KSZ6hkw^D4t{qH!+lhaRPyW<Y9IpC_QM#$w=GM8SM`S$V^Up6L
zcp^+Ec(R~O8i;B?fUgB;&>v6A_&OPMe1`_0f)`pngHbR9!4)#b9WjC-tQkyQKZ@|6
zvU`)s?!Bp7T_xQ`stuW$ooj0u0Uvc3RWvd|%;DPpZLHg*awJ5pHo6m{yT>8ZW!2@i
zPKMiL<KI{I?~KM{?%ThZaAN~=WW0~nR@~vo4!nXL;PWr@_1{1UCY#4S0`C3N6YMiT
z8ajS7TzZ@Z!r_a*kQS19%2O2`p?-D`&)uDt5H(-T%+HIOpQoLbmI@BqlZX6C&{ZL+
zKkdweDoE|fQ_okk^YfUr!l;yv`Ot9YQS;TR`FZSYH7a4M3Q8E{5KYUY(OE#v1oG6g
z(%=lh`txAE*81{b+|_vVfPsvskafqi?m~?dwMz1!T8eSx#iAc1eg|Drk=vy1NeH$}
z>;pJ0|7xteaai3VqJe)Umb-6>ZS2u`L?5=~9%g&`y(KlV;G2%ULpMD{mDJMt&r(i^
zNqZWK-Zpl?L$nY&Or~gyf#7uu<Fi_Qc7rfHT(m5X+^gR=6#baSC3&m^T3G&KxM>a1
zybv0A8=-;aM7t*r49~Zw=4)g{A9Rqc-&GcXw0)~1PxYd4fr@XXNKO;~w#KX|w{^hU
zr&zBJDeRPje2qiYo`PtPYo1%D_7=qYY^j?HHrYJ|aiwbv&TS3O0%Pf)*5Pl-LM=C{
z722Ny<MRvI4kX?zFrJQ42O14Hh5>s539>7s70l<pR&f9OfvOAIR;bVq*T(MNxz24*
z1XY$oeruxnYs0DCKi4u|YeJjGYf*Xg^ewd19)hEeFAs%eq1z~7T8|r=_M+_StJ~Ar
zcfOC(L{Wa%6KB>Zp^>W``Md)d8F7(LdjfKrL(#U~91D^y{#{dkAnd8m+`GQRZ%u`W
zb8!7sv~*YpAWYE_rCJ?}i5|PK$#0KutxO;}xp%U}<0N1m;I<+ZFMdfLoKn1ba64Uc
zH*(_bl%r?(d!f5R2Hz3}?Z}ej=+ZVrcPvt_Alu8z^{)}K(?=h-P)=(q@?Ay4B05+;
z4s9CgWC-s~xS*|7i&2cGDO~jg>#8-lk(=&g+`yhjgg(MoD`3$C3JpQV&l&uA!?@Vv
zs^i9eR>+84jO0;Y(3$6?BO@<N>(KB!tO-jB4UT~-N1mSey{maO(*%K8C!>qd9InD`
zJIFbGV&{_Q5#|NMTadvx5Q$WWBb{<$t-3{5v@o%jIX#aJsK)wYC)Tqa$51I|qI5!C
z_cRM77iV#PJVd!U;C|x0JJy+}bLQ#OZ~znNHO2GoMqDP)TdpaV9n|U>EUH!`oKZIo
zm64L;f{YL2#-3H3H6FK;iSX~JgSvp-RJ6=UAm?CNM;<NxTMhmI#zSnD4<kk)2^|H5
zz(AlAjyxU7dtHbcMPuFii4EIVxMxfRNU@9Q!(-My4J~EmR)eB6#-x?`)-%2HTT@)C
z;lGBz@Gy_n=ye}DasZim@50F)A^-nR{69&|ja_0Jg(meH;gLYSZqE`O8K5<xcoeA&
zGTmc0OS3OJt>%h}>BCjayK(OHXN$g$uL6w5yOWmlRWY(nP|S}JH^so+WX}>h-;Mn8
z-0j#ehIgRi;jnrp8wXP({4JC}C``IPm0<pQP%9K5=d^?fw8cuBLYh0_M1>I1BWk5Z
z`e?%?tZ;A#$>AasjZ+C3i(*N8uhrBRE3OZLaq0V4*b-U`g;9-bn*)LP(W>-8Z2E0<
z@o-Z;i_2Agf%aKVK@GBxiHoTvc_e|~H|l(ASQ%c}7|I_UUXnM2?2NcyeR2-+;h$@v
z{p7Uz2dn&fdVY6ElMoJA6R`5^kB1P&h{utAH<g{I%a->GrF7gm`)dM2w1Gk-9}}C@
z0EK1}<xQY7o+RQClyO{&_<X2IPx){L>vb<`uu=lAJgOBU<={9>6$BA>i{FQksJ!<T
zetD?sD1!4^=(4BTKmwqOWW?M+5@AwE^G}A#O}$M=2``46)&%z;t-BC_at?}i7V4aZ
zdLf_!LSdS1Oykq62WGWG&RrOTUK<X;^%L3GTWC)qGIH`L0EaZgu^KL%v8af^h8x9~
zhVqYvmRJp0_xf#jV!BOLO2no@cTo{hA-W*I;tQ0fDm0(ff}ntsI1*@C!t9K!WRz5b
zu4Is7jb)+o#!&ByrA57KY-6NHL*;)6IR``mO)?f3GZsy20UK<<TvCMBLhzaf7LZ@E
z<X=`0EV%aXs!-K4EH{$io-ij={xYgeDwrrf6e^z^?(0c<J=F9w(S7;1oeOMhM}{VN
z584bX(;vgvk{z!^`0g3Fb4rK|wjMHA%n~c9PXe8tup6~6J&6<{Ny7hxuqhoY81q05
zxY1a`D!9?`FN3#`mazhv`SMizp;qx)2k=|2YSO7Q>E@ErbknU+oEdSqX>d=DST<>w
zCY9<+f3jrE(;Z-L-_+J>J>b<j{>~m$`{pKMcrI2+3VBuwzMt0wYH4YEh`<@c?_deL
z_xCR0yK{t#<{#CN|3B&y_jR?<b+KwUK^=J0aw9>k03~5+s9a5Xo7S6WUdA=TKdiw3
zhqR+Om@6@G7NRI_=_y)xnQP9!5>~iOUm``=Oz{rN0S;%XlZ`4m+=Ee&Z-^iB4bsG6
zSGK1|l|Yl1PHEclZ|3&(?lbG-BP$Wc^_bhQB=6m~SOZUGWe|RBkGZCM<iW#>v6#&v
zd6{1>R+b4H{c*BVq3aT0ylQdBw<MZ%wcQ-jaQ7D=L|xg0wIzr}t^BjW3AXt6A<!DY
zIl}BBi?K)`FTQp){}3)o!)~x4S3CMiHsYmA<e+9!WEZ`Rd3kilzZn_SXSGG-?vl2s
z%lCyzN)IkJ2vh$mI}thc9-Cnk()+HKuS;R7dZ*UBCf<kpZV^w2<6H#`u<@8ogf`UE
z{PL@~i;z3KTm<L+fn7$Rg#>{nT*OfPdUbwR_~;XC>o<hQheOoqC)iUL347Rt0@5<S
z^kSLMI^cMLus-xb8K${K$3@}w)!GRcedxfcF8?1{kF!1+Y38u0M2|<3^NVxBZbnBm
zuQd(k>2cRCM<AGTITD+xbUW_G!&-D`J{jAA^Y^q~p^(z#kVc`lpuBg7I+y6NR9qA3
zDe<s%`k|2~<`^w>E`d0v;@!T}A<iY}IpOi?*TdvcK_5t@g;(?U%VG%sJ9X95tP`x_
zCPU|vR4$p=PYdacC$f4;p*S>@|1PQevO=9-8wPuJI2C6s<H<ov1IZdH-%ezEh18<r
zO?BiyDI=t*!gu9fHuS%j#Vjm2-y3$S3>g>G&JQA2fG|f55Mcc<shi&=;m+t0w^TAH
zQ@CPU=MuW>=`Tn_C(9B>9MK_pI{ra57O8A|@9G%7nDpeWHlVYE>k}X}n-^*NsE{xr
z)HIOFc)A}wyXAU%c6$i0o$%CT95S)2OMFK@+F~j>+G1&!^io%Z+^vmO1I}#>@dd&u
zKmk4O8nNRigcOnpWq=khNKv5R{9~aebp$+E+JI2gZ%DnFHe!-sTQs~aRP;KF>JXf5
zKePM@k|WP{y-yM{sb&>9NNW4pv>S)3x<-`ly^5z*gW1aW81tvv#wS?#nRsW@PE%~<
zm$s8F4=zaZK(e6qNJ@fyUQ$g*J`O)4l*kqr<&n4(9^pq{WxTF%0QRuhj*jmFvuQ{v
zS$~23A-QIMy+f~qQsLl0T|loY{w<UIqx{f(1vQI=0Z0Yu$<53^7p@WANw1<^#)8|0
z7rKb@L7I0CLM5%|g)W%f#PRA!pzstXz~vftHZL6$prLxG)kvRyZ9W2*5DC>HkA_9$
zD~F)ZKXUG6@~&X-0=#ZgLmH(e(gS+p$EZCt?WJRVbc~;ldq@R49fW+7EacZ}(QUU4
z0{PLe&2uioHH+0iw=MgAs&fmddKJG$rLb$({Y+N-nl!MJYtrgz>8`64bF$i{oU6@q
zCM|>6bh#?)L_IC!lAlkAlks!bLcINw%5nwN#D<?OSNJ>eGvZTK(u=AzqnxAcGzEP>
z(LBL~icC5-L$>Rwok#sMn6C5*C1YsKO>hby1py7Fn-ZvL$51j$KQh~D!SS<jm8TL8
zt1}i5iy-07cq*icMvsdoq>n2ZiZZiQ`uC&Bm2sKH8|CmaBbPDSF(3@Y7xK=~j-$df
z^&vI6OuEv4Q!=JC+qI}4(G@md8r#%>my0Ipxo9%cB=?NlH>u%BrQuB>OoGtl0jf$6
z<e7K%aS7iB^Enkv5k&XXM$!rUo7NZI+l7l$3is<>eCrbFNQ?=!X(z0YK8o%w-g|CO
zKK8;<3`x#oj0WcsOY9?Wmxzf+A$4L`P+kSR&BzgN(fZ=$TMv1haS24NRyQ3cZrB=V
z_0)nk<YQp%)_b+l9&HpVB%tQ$kpo_>)~(eLAN`vBH9PG-ZH!mTmA1j-3)OplTD?ar
zXLC4k<iNhgK5d*=8;hi}$R}H1NJiX?(V;bzZZd9O<**wZ1xBCN<g*P6XcPR}c%-A1
z>)ZP6Mt?#4>8IG{xo7R17Os<y0a2v^CgXAX%w~RP-M%UxB#rw*?u01MI}lVH(4PoN
z9C%>7bExivs)I>~xWr;Tb9OOY+^@a+c8dJw$yfWoD4DrKRe1Gal8Q?VSPgz=a7RZ%
z*Wd)am+`pTa(t88ry9m3x{dK}yAfB+-jp$3JUTzX$;36sG_NjBQB~YlJSw_*0hg%J
zQuvh{jASB}muwxuhK^U(0rU=5Q(6Xpm0@d#sC`zWht*bYMS-B$T6$8C*o;!@@vhy4
z&2Ml)SCj477R&>hAK?KtG;XX`DuiT(;tCF<VRhrNfg_Ra?@MUnpjeE%QgfpDNR4;f
z83KZBKcJp~jzh~I8c~?N>mzjIFd7|&v50XwHaN;(XmH}org228bf0?XY4pwCr$%=_
zoQ4Zko6gOu+nZ0+T;CzfxeE+H*h(LharO?!wuXQ)K43@rTLY<RI|d@F5!_kPMiz&v
z(#=>bht=k!I0e;&BPewP?!6^O_$Ukk`H;HEf>97`oz72H)zXUiYCz?nnB%el`@vCf
zBSdDQ5j1)y6o1l1S~Cb8M1J>!F&V-|IaR})dBaw#x{YV8qzmyQnl$Erpo^Cwkq-D=
zcV1k@%^;e0YYwSTHv3ctb4oN4mXmw@B8*#6@;yG${4Z_M2CaM{o~5zGLuxG2yv2Z(
z6sJTO1L31<Cx`zB>WI}N@g~m83rB;R7Ok{7T&tC$)J<a}l9tpM#A#*@9gQ3+X=4~2
zPdKXu!O*BR8R4=g*wWQRE3FwOGX;?5^M(kgX*bvc@FNSaUB>Q6?h)l`-WiMtNo|a@
zIaq$GPqg57TzkTA3TjS-JOiSzf{Z5;2z8mH?YoV|kAg(HSkUh_t|z7F`lJid8|;%V
z#J7U^2SM%zb)7Ynodsa-P_9le3S=A$6;Q@`I<+`udfy<z2SMZ!yY_E=Fuy%qoN{eU
ze$RDd3J0!@DZCjh|2ow7uDCA<_tReHMBH?3o#L8c{%6F-V220k!j<dC%+}I=MtAgc
z2Ed*V$E^7dxC)*4!WUC&KCboKsM$7{>WyF$RN~2C(-4Z7Aj}*w<C~EbTO?&Eu>rHS
zDp!N->_8;L81XN?TMtdmZd5ymUKLtc$0zNU$t}>yy?@H@DE-%p_BOver@c-5oKzwF
z0h(16H&J2l`H7dHr6Z%mp?(yyGjm>>szoJy7HnaAdz0Ti@r860ZwudD_x3G#8*8jW
zdfC9XbACmNBbVJuXbXqIUXVp(xlFozWaPHXFCe!aT-YJeJyb_zy49w}Me4=4f?*kd
z{|<JxH37DQ<LnyZ-vNsP#A8oMmDmQf_6(4vJ@MTjOb4|Lj0dA*fb42%FOlk?TqpHX
zJVduH)n5UJ@z3DV64nbI8BSq^^dVNc2?ycwMe#guwecV>Ux6ywMQesrlXk&}=M2=P
z!>E$KlD}ux=k-cVk6uMW@qTxklzs`l9}0p2Jk1eRiFaGOq8~Z9-YR_4DKh7F%>l#l
z3R|x26S3x8EvmW7HN&A-XzLVcMLt|E%Zn#F#bcc}WFm#)Am9OaUI#?P9lwzK{zU>I
zO>_7lWV|doe*)Fi9d=Y_u3Ue5XIa;J<atu$)%&lSb=}F&L%NK}cv8Vtb9>iFsN^21
z6F&^zTE|U9M^0^|g6JleNV9`3LAugI&wRRs#kvl$a9-tz>XM5&tlDYaXZ)ayF!17H
zdM9hX5{>Nvy;<DAIN_AzbT|@FVkP78c(*!AYzV?~q;1jdV5L8h!*p%;*7fclAFu4*
z+jK1gPRR}u(+}^yQvOyrqJ{ov$Ii0OCB^{sH&5#^UHS57HE;IkG^ChIid05qvbAut
z+SSf+1ZqDM;-!}UNMl~Gv}ZgnI|#KfDA%V^{BrR9(I8}GKl=Z1rW3J7>+``@Xj@q6
z)zCwAMBXH{8}NWZO+|`qfy|dlcKX&j4A7zj5cVf3y%R0V<0di@6gzC1iX7Iizoxni
zX#f}jt8OhLyc={E=<r4QYtYwdB693QbsqGLy9*Oj<i8Kfz%4(F?#mh&vO6+Zce0yT
zt*$Z?l&@Fws|guC#JaGch0*eOj|L%M%HJOA1+5T7X>2qur*~8-XMlSc2LlHIf^B{8
zfmkcNaizRQhLX4fEn&maGXA@?{=1?iCk+(eOi+9+N5q;ywLy_<y4J@Db)CW&?OTX~
zV-|7g7It?EpSQ~jkNaeVez#MsAqagmR_#roxsfEqmBA5gp@rLm8e|+NV0x%`vSL7<
ztnd<zsrHF)cyWJ?GGSS%*E?%jk#lIR^y-zSm%@JBnvZI6Yl5a$h8gp}G-TPtS2vFq
zo}>FZ>yrhA*J(d4*pC@=4||kTV|lG#6U8Q9-N_%8mmuYmCGguig+KM4$+B1?KoXsw
ztnM2X<TyA&kRh=N3nEy>X9vq4BsYP&h2d`tmKTPr7PI`FZ2oM>9FPU7Gr57X7(h5m
zVqG2$3WO6}J{tZ!S)e?cIiNfftB|-G-!o)G%WAL{Qdto1Y95d?e1oXUUNO#X?IpwM
zrnwYISkuddgq6QS;Q+gPkMqt(ZlZ7!KJSWoC*}BQ;SE%HyXolD5rPQbK0j8)jYh7>
z07GGKGXAXF*a#^a`47#9W`Rd{Lkc+uG=nAC&6st$q%X^PaY9hD0C&@<QdmPC9|#~E
zJj+(rGUkP2h`6wts`N1CzYHghQ8Yb9v<1uU5L=$@dWSBbN0q!w=f94+vVJXPU&scu
zs#=ZAPWuZCKCRlTg?U5f!HwPm6TJ71as-|n=W9$Q=f#2361@p!ose92IK2q9LvF(r
z<$6|_5}bz!DN+qmx$(S4W8}u;r}knQ-%PNK<sYE)?|_DHET&RE4nRGJg_sXzcCF9q
zN8!ao9Uc<<-sk4j1TCFx`!32tt-vOdHUhiSwI0q%qgqci6phkBiFsx{!k3Mus6ljV
zG<Imi`uKhqt?+RN`a?7r`Z>5hx!)71@jnLhR%aeu&l2fy^9;FLmc$Eho?NT8Jb_dd
zkHP?Dxg#2Ul6%`Z*E<d7b_*^BA(04z5edqYB@PWLqMy7IU|uCuXXFs>EHfkj#J)MS
zs@Yf|V*ekQHS6btXHOkF+qUNuTJsuZIs4!~Z7nPPHfToHC`SL_=D0fO^>;OV>>#<5
zRpzfqq7Ds)15b>q3PCV60Y<05K42Ri(9-Q~0oxcy0uAm))<47J0j!O;akO-AF#kTP
z64Y{PXYbU6A;J7F!_KC%qK6QkRId?61gjRp4uK1PcYhM>P1JY`4K3PUQVaqYO>--W
z7l1j*QVSC`cyKs&?*5r%P9o$6)h-Vmh5pWmGcTL$%c16qpr(`(Y>NDcb?_-cLKu3O
zqE|1RdXp&{cmWF+wq1n#vsQ&0ZwgJa-VwbR2@l{nYymVm(dF+%RDwQhits?NXgahy
z9xWv-r~R(*nWQfQjNSzi<lV7l0N_qIu0o=WQki#*!C>UP{DV4$!!=@j@1(@oV18Tw
z+l_Y-w9z~UJ?<zOfa1iULRLXk$!RVm)O^np<aPJk4Uh~m?T#Kor^F2xQT6a)qK21F
z_iV*6YVv_T5#t7bv4?Q#Gg@dEu&_%+XJz1qD+HeZrl(eeQzaRJFj!{(Ct;-buv$>c
zg|>_k4Z*E+({IBYPrI!K<k+f6bv36}9$MFQAw<>yH@2%iO>q1mIz(=b0<Bs`Od({q
zv6LD6p6e8m&dJ(&D&r}brin>L__~M4P&l99Kl6r&Nu>ERKc=2c^24Yn+kx6Nydh{g
z-}FYfkE-KYA7Pg=WO&N9o(3;to~w^&EK<ZTd*Di_j3a(S7Jm9^f)LycpoHIQXaQ=F
zE1-=L|J7685Iz-P%uioX0406a)AW8gf{gqsq&RU@8vv6{mq0b#g$DNn(M3}^Y&gu>
zxZ3$~L69p@DlaHi4DNN@__Z`KrXIEuDrQ1j$rjxYmk!5bdFEXSr{Ktl(caY%&|#CB
z22s7U=0EQt`_slKI|N{3i;%2tEv3c^A}Ypz^pvj;R{^vBvim&;9Dm?&b_9H14DOjc
zoexG+@HJ1~qev&%^+P?xPKBYw(>=ZJH_Nz<mvEiUB<d9KJwgXoKv+C3#*a0`b@vId
zf)7*AZ;i-0D0X_J#{p|8OiXzsE-o_fQQ~2F-ii{r4JDEdO4UY~JB~8KzMlMrVbBc^
z?v||Gtx*5$#&vPveHnGKq@z6=U+5HQ!wXI17b0_uZNLn2*JdnuyKjsGJ*3J9X@M(7
zINeijAmzQ*C>$3g@=g^7=v-ojrHvca@F}7~2st2Vu`9Z_6Mk<`6A!dlb($N4a|A?a
z{mM{!ah-w;sDg?u%J^|0RMIDhlQUYQ?cEyjy`H8N3g@hmQ-j%V_$TRn@A^1tNT-x1
zvqj=Z4A>%RaHn*a%u|T<%%xa0IwXfvwkGo_ox;Fg{sISddr$sWtU<v#;cvaivyBnn
z>1kTu`y>TJM-DEqwYn$2Qr2g>U18AYUF);nnfE)#!Y8&5$Z(ixzeYzW??w%TyR<&h
zvW*oxd%!M6n!<jwrGym1(0MfQ7k$6=GY5pd6Q8%Y@jvyrHG0w1Dbq1pj3Gry7}V#$
zg{|tiJWd~0J_C1ankRE}gukI`gglZWMz*NhSPs!pD(PZR6AJ4<MkH|uoZ2>+<(W=M
zdJyuG)7FrB7KlFBK9EuBS}r+lMRwz7S&o^Hl9Q@Vhw0UYY2;}hN+v$&JU{WZcW#w+
z*2G<-U!PLwm;bI$q34(X?6Y&2x+1S)DDn80dzI%}F+NSLP3fq}PBTG&dhPe(cr)t0
z;skY@+he&S;@90~)Xg1aUL8|B)XYIoEPc~$-W<c7kWO}+lVb4XtiJeJGf@=_Xgi&=
zToJzNMlmlunWoEneC0Yb(JqT<eL@HI^6_r-93AN|YSN1v@T?s@p1>H<&`2M{n5d*-
zKCCI;X3iqYXS7a=%DTdTfiV$cZ$@$Q6WiAfAkPG}uF+&&5kBiSk3e0V4;N&8x>tE5
zeU6E+Syv<<CW5H2E&C>&Jh(1i?(wtkElKF`Xm>>oH>hGbS-8bZ(s>}~Fc*!x0HO3p
z@TUp&R-(&M$}c)!4zE8&zI{&~oC8iGXK8k3`Vt=NGo@l7rsQ<D1yeI6ViG13hBL)f
zEoJ!%h72G>K3mz(=Ipd>ji|F{V$!x@+~PER{sW&&@OcQIZhW@lm48og;@c_IOnPhz
z`BsW=hgRa7yCJ0mBa+{8@C{=s;Urb~oy4MeQ429Qo=P2NNV}gR1F_aA4EUnrG}c<e
zlwS@PFJY}uu=$<gVz=J<d)9%rnFh_zVea?_Cu==N+GZ`>?$pghg-t4TWNJPle47tC
z*|aK>O=i-|$DH~!SE(P*MyCQIlfLOPsSwWMrt(SZ2?86i2p<nbVrKH0BzDT53B2-Y
zMxJFHoVzk*y^4+M2_Pz6EnxT&kY#^DO>V?1<KqaJAAFp^e*w$~|KS5aN+kXmFW>{u
zqz(kp6q{}%FY_JB%NOOB1$>YOKgutogopg{1^HzWA9%)JATOt7lOYA9Jt4iHlixy~
zWqC+^;774tev8Kk-V)D}x0Z~QoByE95aG@X(H}lY^D|0we2@uzPnx@jk;(Ai%k4x-
zZpTZ?WWJNz3E!a|_vK1w3h7GtR++C~X@U>(x*tul7Hn{u$uRtB`I&S|dHoc5c4WIV
zPKM4m$_wA%$4M{kbw<gre~tfS9GTRanp4=EFhL_zn$#jhYG(ZLr?KU>jExs$N<i?)
zlZ$+Ij?ULo<dQVSCY=NSFX?<CMsqdH6&I&z;kUnM!FYs4Eg8+3)7^T4{+g^O_Bu7(
zEu%E$mk8FFej)gx;WVQ(K%+@tpK<=PyeB+L1DyoMFwc*(J;#2KR`nD+C7Is-w)O+l
zlw{5JWVHpP3a3@gZ|a6k>WZ+wySWBtFXuK$Z>f&i(V#YJVFR97u842pncEcY+15p3
zJZDE|0aD^0$$KXxC!Tpt(Y|dt<c7qvc5KKx@~oX-i)VgQbYNR4xv^$P%NyjxGwy`&
z2RvI_!eB@+B^ZzFwNMFq!*EB0H$iV0#Kcv)3eo$vhK7BHh64@ew|{of2INrnnKVwY
z##>n=Qw_}4e2}(bBXU%^a}9?~#d_7Wv|>&*4W+#hsW^r7BAYp*NsTe+C|%3Vo&>Ln
z-7?8TtKIM9xOO>&*L8JIu_Tn~FFeR`=0%^0b$!xsY!{vHq`3WJ#>D`BkQ%!FN^Aay
zLW}f^PLsy<dc%etbkl0I5crE8{2(^$g=gdI6u`<zD+ma#NTuC9)19=|d-!Mb$sxYO
zKbc=1;y?VEdGL_H;g8LKAMB)~9C(yDm^^ApA&;I)A&=rxumOzlDtZC6U*3IE=b*KY
zL*3>VlJSo7aJTtv61IU6UMAz55SF2Zo7TFIoG{NB<e{THpPn#(IuM(|@Gp@T?feU9
z;l)gv51S_?`sgTM%VBdZxo#N#MYP~fAd32=&QELo{|uQ24+zjvfq#X}e@MW_Fw%3R
z#S!V*?&fyPL%+%#6_07?H<?$P%qZl2L>O?<6Cb5OKyx<%Ny0@RevqNqlmnpg@fQQ}
z(FzpHC!qyzy6D6YG87TgMSvzeL#BE~T-1GXqBmaWj@Ns(QE+wH4a~Y<=e}Q0V8TCz
zMzEGXfkuINoiASR-_`{-{1n{A@7MY6*AuWvPmrEYNROkDJ6`9A*E_f60I@5Ph3<Zx
z1C0O~aRF)6E*7JaFJ9+~*L$~>!i%Z_y!`z-&;2-V7_J13fUl3CQCSJ&k4LRmUFnao
z3X$RbXhh)i7-@7wvZK-3DNG<<?}*n`h6%szxL+4QBOoI=af+T>Rrfq=$wGO8wfsSS
zt(KpmTBLKJ7{H*6AMSorm72DDP1^9X5ku3EiRuZMVPC{$zH9%U`NK2IWDckAiS)d#
zXmcogTLZ+%sx8@j+>fBL(%lp|ba=GYM$e6If^V&+UMp=0Z(O^h%8{sZPs^Mz(B{6I
za_3QVr){qL05d~*50crSUMp@6e~D&ZG`lBrf+b057J$lhu>U>^<rsHX?V0~Mw}9Ny
zK6x#$=QO6)y@18cwoh+U`|P<KJKJWMZ8M7dpaRaRdl8SM5A@=KaNRO^9lPy!x*O+7
zd+}^(-Ai!Y=lAMo+g!Db)1AW&%$7aU9k!}6_~zMf-@Izgc+i>m!YA9|LTf%|MZE-=
zJBp@R-PW1r_Ee8*o#)d~(Zi{erV|fWvVs=1)EF+h5^6*O8V-hAQt192OSI3LTX6?h
zgY=Nu_K9is+bR-gPZ`3kv(979d2q#x4iw}E3Z?`K@&W~S!{8{5Qsvt3ciZ#530g<h
z(luppR%&QS@Y<Z71eIs@Aa`Pvd$z@yh=S9}ML#^4X1(7@8`1~S<(J{x=Cj{hK3C<i
zP7iErF#j;kH&EpqNV^kh^q8^GJc?=k+*T>sKo3dnk%D}G!IXTO8pSvZrd)`||2|B@
zI^ADzw}<#Q=emb5?t;7A+QH5^ozqt4h|@c4jzAn2u&oe=sxU>4@oEPXmnOe`n$JE{
znI;#HqE)xT<Yu4hu-_A~-&^5#o3ySS3C#<+kskZ48u$`fy!Kmt)_nN>`0SHUws7qp
z>qOz!?&hSXuV}7axEbH_j{_x}2bKQ-2g=FCgHyOGXv5!vCz{V_?g~F1-^!0FZN8xc
zXfr0o0vFzi5_yu}Oj~r)SbS?bthD(8zRZ)0Z%wgGL>qA&dHWx<WuiD5-;l>p9;=1^
z(1~O&0BGgSD?W6apC90?TDo~HDgv1gCje`Nfhvzii~No*+y}Sc=RI<`=))q*D8#5*
zlFDBWoAd7>Z)-G2<mIzY=Qf*zcL%gFK4X5sW+2{~AI;*P;I?>d4wNR!Bni@7&+Qn=
z#pJxU8-1<`pCGk|_HNSoY(^lx&DDfpCsHHq;MVV&@010IZ2Ro;J1D1Z#XZrmaXU;J
zqU;=~H@^iH|571VB|MI8xe4FJ7?oI}g4Nk;y~(F?OmD8Kz0Tq+rRZ>v!PWN69c->`
z1+;Ft{|G@sDJr~*x20&6^gHAf!B;*S=y;zrpY)ZhTH&?c2NO2w@IOr0(!kyh>$!@z
zke-tpQ+nSzbe*%-#_5oE&pyp<zo&GQs&eBvr~O_m#Ak};mLKCX@s$g=esAmgQ%c4n
z9r^EZhs_9mCBC-SG2Ak4_3q8<oPbG%*FGbkrJ56({zBuF%V)ieyzr*aKErRlGut}5
z;!bWjP@3n%+?cJb>(A>*IW1$p$2diNDr{c(F<IPIN?w_8mBKW)>QHyceA$G*`uEK*
zkxz31`RhFrGFKSM&nL_=<kMVZz~A(xuzwr<*4sK?(WAmw99Uf$$?HlOw{eow`u`Yv
z_xL8N^nZM2GL!4{l2QUR0h-YC8nhI&6hWJ`q)@=6MT)ZM(qbxCR}t^*+6J~1C|ZIF
zh2kcGaH&+=sFYjXG_r+4>!(ClE`p0$qkt`9L2lCK_db&paX+8e_x1au)6C47bDr~@
z=RD^*&v`DBiI7q-zWrj=QjpR0EXLdg?VGoF8d|noqb%cs&f*8~+jW(4Wx?shS^S_A
zw4WF(nk~Z*xAs1lK3KF_iXw<oqrXo1X#3f}_-RM&eK>(?QCgr#)82<42(Dddbo6Ma
zSZSrTICs?}IX>-!ZtXN=sZtzt7iYi{q&U;B%>`v4?{K8dUz}5Q8HTKjEE>7$cHZ?d
zjCmMs(;}zR6!mTrA+b1j<G#;H8_NR5AYoF;z_GX?*dC*5Y80MZvV+1?2hLoYS$FY$
zr3pO0m|p^V#mIo&m*RZuulyT5Mx`J34As7pujE(Ti~w*7KLz+9n0S-~V=Wlpx<3f6
zq`Dq4l7+So2>A)C1^(-QqWogkCk9V3mrfY%6if9FfvE3yiY2abv}xN9AVk0RelNX3
zAjFU@MaVKEzs_<+<}8?oqVASAzCMVs(D)obe?4f)#82{c%Rv`hQ-!Ao59-NJHgJma
z4q}`}8}uth<4aVMr+tzH(0Wn*Jk_#!U}upS=E3}An{k7+cxq4aG(Vx=NxZ1Fh6ejZ
zuH)iIF`)+#OEECRVIgMdEuQ2qo+kG6jbv3#19jRtDjVX`>c6BCGbSW19hYd$%#0b6
zXd9L2ybrsAn3P0!q9zL-)tV_yF&fRBBQb+Ce>oWwqv`u0Cc^LsL`|?tlCO_ta59G_
zHHi!aA1gLf%kOCZt=c=pr=3&Oq2jS}74nfiVg?Kc48(^GfXLbspM9-iO>i9HE+=ae
zpxX1bD7(SNmN{GAa39k;kLmU!KMg!K*Z`Q=YfrZ3_wlvDVt-`A(Tb(CD(OSQ*CbID
z`}=$nc)M63FZd-9Nf*q1W3<rd?YC_**~yw=CZiIsAr7N)qZKm%bFyeMv?1UG6}~=x
zi@?U3-u@hi)tv~!RXL2GQgNUU$~t2-ESPR@MKwo49FWvu{)K!(cwp03zqqH*dh87U
zIlrXrn-z!)SvthRCx|a1Kpp~X$(_YhZCH^MU^MW@#L6^C?%U=$Su3t*T2;8mNEI44
zU|Kax5Mm)yfn`nKghX6s_aKFTki17StjB2c7nt1zdC0q-7F5+akt4f!Y6UEi+xpP?
zqJ_Kor}sX=AP5tmYd#)ytE5Et_qx>I@m<j{X%DRw(kp`a_rArLAEm*bFdD5V`cykV
z5qLe2W-1;DomSDlj|8OIv~z65Ms%ADQZ^=P_LmK}d)J&B_YWkJYpR9FAsx34%m2nr
zDx215Yx}Nf_hj`)ZllsBiLe=?D}ofiNf@S88;+Yr^o^|<XwXN$)<fI)VI;HKWryc-
zI;2zJ&u4s1^<+LT%6t+|P;^LFmGiT?4ww;W2Gr6I1v&;m&^H20sXD?c7LEHKFHd=}
z)=YZ%?CbsaM>a*+RGa`IS%x-^7i!(P;W%00H~VRO(Wl#m;Vw<sCa&)5tY+P`l~1nT
zw?X`HALP|1F8j1&-P&AlOZKsY9dfrq<}RM-v@iG6c{&eT-NmD@p=tf9590i+%YH2a
zcrCY|^ZbC}JkjSre5>e#Y^!#n=BHKvU@AJ`vGAx<JFOWt<n7$enA`fihi|FIC-@Fu
zQ=J>(KYUg7*AYF3&!~ovupa(WwNGa|+@^X$=REwG>bBOc&D)`7#LFq4Hm66M=htSc
z5%<`NoWF;3zT)XfyXY@YT~*IiynyJAVsIb*KOoah_iA(8+Ejb>HRrYqNQ&vyrW`wX
zpl;`Gsau=URL_X#Q$1Sn-#panrK7#Y**@buRO>gE9y@o^z=-EkHf^>QONOx|=|Y^7
zcAU+xO>~PROVc8%cKWs1UP;9Hc6h4Bg5B$X1fh<{Da0lGpKyq<Kqo!VrycL5Oa01e
zFbC95@D~^S*OKh|JK!uJMrzGW(YmOrm#xZtYjJwfP3};MW4H*rNL%sfokP+>^`Jtb
z9@PC`_2{?Ako1t$^YCL3pxs&%j+2%mQSt<UUuJ{7V3F!U&W$DU^=Vj=%p-tF0@?qg
z#&=O;x=<q{J{z>s4pk**(@rXa`Y(=u$c=egJQZ;)x^8)C$DTbt?bNQ3{5L<uv6_F}
z*v#|ER^tXDUrvRNT64S!io>a1<A#dcWI^;P$0jY|{o4GhVd5dZRjSrOy?$*DjMH$S
zr_D}#tL)0Mp5pA2I6M7&(5B6EYBLo3NsvJzmE<8jNzvr9tyz6#ZA5s-s$HS%t9rqw
z%~K8SE&AddhO_9+JK`6SH#Q{WLb4$YN8mkSX_sfkIlWjt_MF5jvS*#w9y~I1gx~)3
z4?~BZ-44UL!H7Z}$4?3M@ve+qA*Qlhj6{^?qk4*``im#|AT0@72&|ZB4y<Uh8QQ3E
z)vgs-Z^ZNZGK>i4y8=fHL{#(^Pi|;5hN309iyy_xgZ_WiD@;G{;l84({S_bfVoFvG
ztEdk>h3r#wYOA=e7g|s~E@oH-$ixre(mKA^CuXeeeXHtU^@7>ZE7F>UM%>2eYDjZL
zmb)v+*@~x`xuE7uYx5ni*63{ysJbHjTBHB-cGXi6R;|%pY_J~vPf@b;9=^0Z2+oAi
z;&(YyRWlgVxj%%t(l!2!x$e&O7jD$E!YTzu>TP*LjXciFeC=9qyY4iN1*}bpg$#lH
zRjK=1-@D^Ke68pyDHuYJ{gqXZFy>$T%tw1O@`l+Y$-Ep1L-Ud=-nj$jub)Hh9R~>x
zXNU;O>W0GNkEz~c*Hm{>e8;Y;wx;-xeW`jlrRUgZs(&Zjj<xag`H|J9RyegIRjCk%
z%C~Z@9MYFX2&sF0WXXy;)7}L8tJ<KNh^SjRaSfQ$)uPWsuzXBlIn`%&Asszovnl*q
zckz^$b}#xrnEqSf^hY*5;s(>lDu{i+7%Z{w_P(YM<Z17L-DA8fMAY>cr0NY5WLr6q
zdt$6a7#Enr^Q#5vxb<c*%!EJ0NRJDRbj8?SsIlLUaB3%xZ`+y0h(GQVm-o8C2w&gh
zJ=|8L+2hwvoKycpGh=?ew{;Jk?dB4BtcX(GQ1vLsYeWbFko407R!s0$?spDi@-C&g
zB}~^tjl(#n_91d=*BAKPwX`P7FJBj>euo0-5b$O(HsyG1nD4ZKG3<Rk6Wiy!i=)oA
zdbRmo?Ojfv_E9fgUOH0mr&sjQ)?=4%+!tq-Q!uDV{F5Smb-Yu|IrA9nEJoFO2L;{Q
zN4p;K(JTBYdM@qU4<q4tDF}0cH~R!}_zehiZ}y?2PdPrR8}j+o_D>PdOgo2<s=m3R
z$GE|!o#<5NVF4nwD08jYlPM?m%u@Jg$$fcI?z~8EUW9cP@0=B3n+1Pgvu&0PE&%#W
z%B>vl%o~>UBj=?zc=Lu=eFee6HJWmoA*0g1Jl+o$K8PXVTq2Qu7$I40vzSBARF_>#
zx-bex<LG_iwDcZ{yywXweo3T%+8EG`ciIEk#$yk^_jRTso>~{-d|U&kQ`>B{8?124
zmtL^K@n8D2Phm&@C<S$ad0LR4R`Db_WqA+1;!LI07+qGjY)#OrHTa6tR(;5{{t7$u
z{@LQz!cgIj&|CpmI6y=OOdewW8xsCp|L#-89TK1TwdEPsQxjd`3)-I4Y?Yh85%l}T
zRIjA_ZuSK$J!Vr&4ZT{K{B4TXbs-c*mc*KkoDBYx{wnP~9{c{+^^upZUV8Dl7s_sY
zpnPdVWZgU8x5?CXskhvJpn%5b?8`2Ff0Lx4eJyw;ds*Ir;rx*2R(e)zt6z=ZF_<ZP
zCH|$I{Pkn9)HS|Il$zuyeuchbUv`^hi+uTG^_4siKe$)ABbM%EU;0oecpE8#g@SuO
zN1QIfCjz1C47_Ex+(<%f1+8qpGgc?aC7fy=mvJ~dX<;&KM>Ukbqz~>JBA1$S75DK`
ze)drxI}M(ZIOv8L%vpM%MaSzQl<QAI!N6cj|0h@i_ppBmm({f4BpIr)pHMP%E-2=u
z2KJ@xk*P1iB1K)A36s4%Y66t;<h-Pqf=X#CgWv`xMilb#?mEhgw5Qn`+H3!q7^Qe^
z{2Qf{A8KZ8nuV40Qq2OZ6qbl(FMH|{X+qYXs&Nm!GM_FHi)%~wJ_wt|={r5p`x#`a
z{Ju08zbt#^fvynq+)y9V?-x@gEK|sema_2jk?3di?WUcq)K%Db0r7U~j-0uErD56a
zH`lZudH><-$48Ib(j%kxyk(7rDgJO0WB^Apdml(o+tJLq5@pyNZr*^<-DfX3W%Sw2
z1Qy-oP#BgYX`VCxf^@mJqmHz@ccy9zzOjr5edCu=?T_LcRoxwO1Q$9xijR*)xHVF`
z6v@Y-m8^<M%n-t-@frPP+I8dwDW)S)*%(p)AA|}B=TE#MFskq6OQP{hhhEu;f4-qt
zR$USq(8{cZBBCG6!#~_TgNG$UuVms5C6n+^H}uLN{EI<#On-aRU@Pdl9dzcvPF+v_
z!-!q#p8+EanQw;J%gT|c!_D&U93U~mnZwxFNL!A`%0^jp#5Q(V=@1Fx#pkf#!=))W
zjx^s1wrBAvghOYkaq@4QA+@rMHHXv1;>=FQ$MmqndvYQHK^9I?(4T3Hlac7h_c>?q
zWRxDlj|hJ(=bs_<#fp71WL}o?=D;$VcITh~<IIV$u_9Yeq?Hw0bE0f43#W)7wwz%V
z0AL6U4al7!0YqjFLm;)yV5}@>%|QqUnQlfjfgrLcXE=etOp-$Y28|rn2$kqiAb6uz
zu953|Z&Yn|ip21s13S+V^Ek-0^x+lsbHC!153lYcwgz~G(^}UZ^6Iwh7G5EwC_kAT
z<m4cL0;xM>J7lwNPKF1UWym$Sci_N7rIzq25(g3~`xf(-2^aR<hCyZ%BbHN^@fV0S
zre!a233J0u`V+xAq|Y+^+VvOVbj4WS`Wm_f6T_##w$UHMG+b38DFYOnKf@BDkU=zz
z>n{$heJo^?%$;NAz84Q?GuPJJL$74NyJCq93nkzR8HIUa6lPV>d*(Y83d{8Fs_Sqe
zC;2p3ei%Poe;rW|?>>mcgJ19f-;RRSiVN`y`Ej#H7s9wsM3;R+g52l}E+f1u&(`j{
z{-Wyl(7Og)bBh?)imy#M@Es??i!4t;fYeMaFJt3z<f^m7Wc5k8X$E7;p<yIsvp)??
zxlNQCgAWSKQP^@4oN=!?XMlDHUjIA3Atl7J6^L8)TYN+CY7s9hc!PbuKXh$zlxWS%
zhV9uo*8GWXmWn^<DSBN2LUpoqbrsx9<a2A{-AN;1C)Ti!RsAZ_jQ6q7N>W}UowOjU
zbatFz4A(*XBxQkfxBHE>T&r$ZsHxKYNEnIef4v&AyU<_13a;CYb9M1RO8631V8WOB
zGk3q#ue>de2!H9iaka-Dyb;G(dhn&?VzA;$FmZNdX}%uSx_-H8wFg(l4S^*gEd4EK
zkb>5*U0{8xt34xS(3qmN?}HWp5m<8wN6%xVcFeUP2IRtLOkx^1N_<S3n82xCByN&c
zu_9^HRh=rbm4bZ-vJpFj+5@aE<~3ar!E%VdbNAMfA=FWdlN|CXs}qBlsD2S5aFa2S
zw+Qx32doDUSrsUdh|#sDlF{`s65kBUt7iBCNsHB3q_7KfK1SitgfuKHXR2{`2#0bq
zQsmNELJrj|3JOj~Ugz^ZMvUmnjA-GxOLb@JJatxhBps`>v`9%6j2Ik8h8!}9DeT^?
z5BU*WMdpiw9RqSX1D>7Fy<~mu6%%Z^CGw=V<(UXf-8vk0E8$Ges@7f|30DdDw=%*P
zOYK2}Gd|I(E=^4~F>+*kemRyiF;r&kFqOHF7Yi>_F`wlxZ)Qs-;}Azk39TyXBYi<V
zdoy&2ONSfgWyZvfUzQg$Fwv<ZdM>4*ZDR~itQv$EQFkpTLU<MxEayBq%KV8|R#G}R
z74~$<pr((NpS|RXr*@55&xk4$Y$=YqN-XTW?EAq8pcfbz!X8p)FDsqVBECbc5m>Q>
z<h}@vUok@UW0vu*BsniZ1I2&g_{U$`HPEwDS?99JC2qO6bO@8DW`*q3*3bG>uSgOH
zj4Ij&Hh?b|yJF=yr*dRBG9o}><MP~Tj{T!dM)7WK>5$jdIud-e@S0hTW;DE~NqOKC
zmr_1bQoGaZxbAd{J#OWJy>;&&JBWmP(Q*YTUIec|g#Op?fk^o#J@$4JCFg6DHTt1f
z{?E@`{5_wMp6Jy$a^g)Y>#zT-iGb{GS)7y!Ji-W^x|DU>t#aTrLcnNH);^9`Ls70K
z(nIOYZ+IAicZe+A!F>sizj96Eko0<Yf-sIe3zU(MJY$sO9>9$JRffX^1~Gs5G|MH>
zOi0D^*w+NvXwMoW!r^TDuJ+ZA<w&+QhjbcjZL*NO3Ge&oRH2<pHyU4hJ8t?5p4qk%
z8TH!IrANvHc&w5)tdpsdyf^yG!ll-6W>1e#mu8KqFCCn8yuQ)EX{z+U${O$E5E)8S
z<vf<4zb$KgqyKKa<rbpIG{Tiy%??@=(^$r-N<#0B*ST)UD&$n{Qu5*2<8_vwE_-!p
zZk}&wNN`W(aqs}<vQ~fjvR8zIw*)NxRelsWzQ^63;B6o8dh-mC4`Be~{Vd(JPPoxj
zS$bqb{x_P2r3$0}rdy*3T)bRQy9sda;|WAD-7+|Q_n7M^87b!ax?96H<CG=ca#?0F
zPOpdfssGQJW&}Y>5K_T*i(MCP@~JH+SRW(mmXv)&7MQ?)x|f<r+}v^sVEOEC6UZJr
zbJp9w*s|sfI_0%j`sMYFmsrJR)qMkc6y=Jb>cbeD{DZ_H%EYY5#3vLsg*6=7<cT<&
zd{1eL)T$`69_=lv9GsXXwJFLF-$&Ip2r@-JRhpGtHkx)S%G1Y=Qq&bKj6CKHynGc_
zqG7NM-vrKd8@?(bAXyQTWUK_=A2X2}Rtvq<cXabp^rwMjLt{DT<YRsOAU{74o~&h;
zm0n(TsZQ`{JysX6Nt@*u<0bOlBcY0Z`l?lz25rbB)*lmf{yeLCn7HjBg@)lD2n;#b
z!=7pPc$S@`T^B%vC?dHmgdFOI1+K3p+VF<{2Ry$E<+CB=={vg(rQ$E)GNPYz6)&wE
zFl+cc^wRQqx1klG`1vexOVAb*W%ypQV6-rvEo3~~FO%OEPj_f+IE>tOz5Y0Y-rjBH
zvi?|i#i8Ic3sgur&bXSp;TE)A-_7<S31qzpXKMGBwH)cLKo07DAU+L4*xGH_Tk(F7
zPig(TFn<+Jdu5%|T^Pmx(e>n2em2N!>{TyAmyVazGy3SuPzu1piap1aeMXd4fz6jk
zvi)-r$dt6-blMwSjor?YG+yDgH|S5wtlP&R2P<MWa7ZESC?I)QkwUmMR^^L<S1l3h
z3Zt&Sps?SH?<o;7vA%G1)w_}V$_3)ubF7XZZ~07CXs?`I*nSNIR?oR3_IM-eeGwm6
z9=Tf2S;iC83PfwTFVrj7zHWoTOK61TacEq@naIRgdiXIMiR_h?v<xn6Nq5IYnTiLS
zTC&^MI3h%we6YQ)@kthq$1Ktg7G{zDkPK%;p(*v4{-8i!mYu>Rs^|0vWCZD!9ie+x
zzh7pKz+nlva+PJ@ZyzSOnuLO`ZQ&1HdqcC)8UE1qi40A)Ob_fogCQo!w><D$hu#c#
z=>2X(mCzydN0{ec``h60Re?sKw!l`QHcWa~gV0={HvAyj^&w*MYIsx2*m~CTsSF6T
zMNkEoSi~7x+g#7`Q(g5)tbuf{^}$vM^jXn<uDt34JmKB;l?R$#@5{WL)yI|lxiY^o
z-)EfcHBNF_zbEM&3tOhtbFSSoezB>gz>U;OZYYg+$?7?NQD7H{9;bi!htACnxX$<(
z_}nK7xiGp#uFXPx_TTqK?-D@QukY_mU|VQPSNHcN;QXyGuEua*NKTJol2Bg)cA+l;
zgeb#o23S)7mM>zD&zO(teZXy%)?1B}dq6~NPt*rJ#z}##vcQW%XLKzESl(+%l95F)
zB7sr&A`AWr(AU5S40<XJZ?VasGmWv|w*ec*tgSr}^{O{+!8Uv(hh?%x*7|J_zDrXa
z7@VylpS{FyU)Ez^Y_%^U`45aFpB=<nP?W8BfG~LPfK87_PJpSFcVrnYnx!p<!j^1P
zi@C&J>C_HbSaSWfOu_^LZwLs$lt%L)y1-vU_maSRSzv(xJqU8WtQqcH5Fn~$5N`$I
zTps?;@>Ym=Uk`t0d6Sgo_{D*BvVbL20jpmpjGTU*FmkS{;1q|>yBK_BC9?j2KGuT4
zVa+A}xz<&&!)*4|)o*)L7bS4Pa&NnA-wwwbzTsn!>T8ZfvO^aL=tx5msOYX|7k+{B
z%Ef_idK&-D_HdG(DU_d+`lrx7PUf4!cn3uJ$nwV)ofSK`KY$eJ63eqUAqEKZS|l<&
z<$Ar_@C0_j6|fVMYe=9jk$%QyBK)DtsM%+)Jo821R1bKKwSXcm6wv+w;L?b?BxGGc
z{oN9M%B^})e8Vy?yyP2&G@s7xV@PZIh4;4huxnYjAq!HyP?(=%`5=@il=OZ31FK?l
z;EaoEN%v)uq~pirz(CX62*?xy%`!OzS_C@$TQB%G^?&Y$;xtD@5Y&&IW!+eTM_?Hh
zI9*_w%r_#9uz_uNxt#vz9<qP4yacBfUAJVs!Z#p_*9ewd2)<8yK~hGft|6%yDA&?^
zIsybhM+kGo8BvBuEzfitCRuYtNIVY?if(HH+ioBgjrT4nmc`v(j)5_-1{)q=N&k1D
z+hHW=-xKZtwkS|U7O0ZTnuV6-mjukKQsLs;Eb`iyc8hx@`XN^;TFE}&A$Z}%4kY;6
zc3B`70bd8?1Ox5?QAvxU2rxRhac;iRewzS8?nmIh=7#E0A3@T$&#>q)2nh;&-;Ah0
zaW^lUMr+=B=|hcsL|Xpt&G4~GaOYFj5ozlEn=2ctmszFbt@(q&iPs{gDtMx1EfR(o
ztmJw)%5dk#_zC&{aH0u<u5L+S&RvAz?W4YqXgGo(S*hi*Zsbn=J;51-QH78&ks`G9
z?110K*6@_202GR-_5!*(#OEY|#X;DS^^?$=5D5{SG_FLvTwQkdwaHpj0lzAC=p?Om
z`-oMsbALmVYzQH%HBy2m^n99vPlU}Eqc7}sbCj2(OVx@}jnv06zK%}S&_Qr)BjevK
z=~42UUDg7+rvQDRTt{y9H*XCOo=_R)^t5i<fT%$iA0!_+@zMM40vf4Eg^KW{{&4@7
zuD^!93{!SME#Sc2GT0ePE&>!<KDudRsiG|Sz#+T$WO!eIo;5r&w*~TK{U~B7!&3yg
zxdgechk+|`6hvRh2u9Xx<i^AKL3|Iry7CCIlQee1DCsBO9VKvsM_uDWgJV7$EZuJa
zBU=k25`OJkOFe=Bh1%yKq(2sT1bhy_kelWDM`TEC=WaV+v;{gBFtmq%gLJWFf(#m-
zTnaSFYZ@9@RT>;PFbBv$TBZlZ-u{7fEfMe$LO{2KxDHWXfql&-mYY$$!Q#9Z)~5pZ
zcZ&}Tdt>YNgjM&>h23H@$g>4@8RiE1G5y?N<*_<!*hUk+EeZ@L^DT`Cgd+WLA`lYF
z4GDy)_cr!deM-0CFTUSVt&0lrBGMav4x*+L1H#bWX?x<T*mSQGhQgIT`-+pX6a4m-
z=fCqHm`2a`2XDk`%TKblZI{bddSJ06FuN#1kIv5)H<RTqRfaJh5aofs4&4SP4)-CD
z)Ll3rYC3SJkU!Ueyi9>*#2TL=A{qwogTSzE!*0y1dl<LnFFhFhjnD4uC)ZhFat$pY
zIxHZwLkq}jJ*e9tl~^>+?GJ+Shsi_MPp*L(!k1+;;|pg*O~1yfeu9%wv&i?^V(<3E
zZt?mTxn4>2JJB}qkzrKpiC~@uIK?Xz=oUN3Te~Y7{edW;p(?(Dn^%~lcXgXv@9oBW
zmY8lsjkzP(PvGd<dwONJVT&8+KiE$$f&6}am(%X;`fU3(XF+aLTn_wQt2cX8PegbT
z`!p`*#7WkV#3gY<&tLMWhA9Y|LDjr#@(tC(h%jE!U_W{${ti9S-B|2JuHG&(EUswe
zPl~#7g;fogLwLbN#D?%OOO&u74BaJIB8eCwa^3Fg-w;L!GU!}P0ps)leTJOLktJy*
z;%!dVi)2KJ5GVU>#zUw&&=`0DNQW>oIe5>a95^kQ{1e~<6K>RQ4#VyecVm)By8J>9
zT;^aa+%~}M|Eo&Zv)F%v-mi4sOXGoGVN!5c6!>f4c9&r}7E!2<!LHmb&%vwhDW5Xe
zS1{IJkku_A?CTW)G?05n82yCrW>;Uc74W9*iP@7qs;9AnKWN|WQKc#xPqN-^mmBtb
zREy-EHjhdp6UaQoQ%Ti4NxfV^BNwiSvMlW<HT}pSUwD`5EjPP>4K7d^ERFjNBQWcy
z<`9p-H!VNnu#5y(6xhSuo5HNH<b-G>Fy|f;D*qeTGeT+TBd+uFl=`kN!>!-1L4nUg
z_zlnI1fhHAn;X3ny4QfdeTUWdN76TWq<i~=q+?SeTTZe_jYGO;i0nM=Q7sXOOyKvt
z!LQ``KM{$k04XmC{+=fILqx#9uzM*@e@W=0D>oRQy{t5@g;%VP5<ym}{Gx6f6!5FR
zu)NmuyOqIJAk^b}l*}BF>x(Xp!t(EKVTgVA4Dq%e{p0rxvF5!H8gR-nBPxUm*VkQ|
z&CcKPHT_3-DNR4<_kxV;-+(j3?qcqaKXgUgE)ltP+mD2o-Qs?eTQ`e|-1<jJXxagl
zh@%#BLnRmYQ}3BBUU4Eybo2{BFoW|)+ZV1y_ege{VK6zH5v4!T#WNZ;7{Fv<0t+=+
zB5u?!3|FN8svj_mEQDAhef7(;JA@7q9dJ3Vc^KTHUJN0@RFG@fYbqYvw4JFy7#8i&
zBkwa6<EZ``(IlpFpjnvwflevefAWJ(So4Os4?pH(*+~i1&}^#4QJou|J!wPWbJ%(g
z4zq=XK!;TLdVfD72(+UD?9sgTvSWwA3-m3g!3+4Q{t;=|4f-P41D~qT`5t8hEz+Xf
zvHvxD0~t3l$ptBXAQ@xV$M=l!c0J;J-ZPCqwS3xDf=Mi)OxmH=ZI@Ri%)(lex0?|s
zK*Dd1Bocn$Z2=?h?O9ERXPm{uj-;jZk4Q@w1R-HG^wWfa@QXxPU=S5>Uzbxm%uG|5
z)lHfa$yn?Ni`~wMbyS|=C&HL4*RB)C!0_(mQ2&tVuk?|n(YHPGWbKiD`nfDT^KVc1
z;q8z5zt}I}8e)adzVb|+Yrhn07tt6EizL0)yMEW}z=yx<wf@7dik2Y4w_dsCDT;y|
z0&sr3UUXX$;)Wr12C?D^E35_z#@Y(9$aGBW=Q)9Z08inFG!w^a#^sGm696^*gCBNO
zPsL{QL#cBPIJiS)<@tO=w?t4{`C8^$n)@pD1VgLwuYLCn!v_IZmtjY1Et#NXv!>tE
z)iWXu0WmcX-*`CZo`RoRwsnb-428@q@Yt5QhJSbok-@n9sDT;`mj<fRQPv)9Mayj)
z)(~Zxes7=ot)Oo}RA(n!H0?k4RQ8_hy)MJM<~PV5p%_Bv<(&!2ywr*PGr{trFz#M^
z#gT;kygf|o82Gy1-Q~G%|LokJd3Wu1{q;t8u=HOF$id5<32)@Vn(sjfm;xKH_(H>I
z|Jx657l(Ul+1hnarIufQCUYjr#>uUm4E9D;C8F6OT5KV<lDRC2Z8vkxOxu8{ClabL
z)KAI6h!C`c)9-2r13UT<eTeW8fn<ImD{?=f=r<BV;ok~v$XZ(wTH@<fZ~OYedHZ+Z
zbp8DLC(i9z{qoJ<1S0CEao3tIaZ~Wylk5*~Z|LvgVWEea3kC}Nu<Z$CA4cf&OZ~xM
z>-+aCF@{eA6<vl;{g`_@1pLD)pwenzwJLU`2Ym5Wq(2@@<kI}1;6MUjj0vwDhdrw0
zLp#6psG0|n9)<xARNf1C;QY_^^y{BMJgk(u|2fFn5)F}L6?jfG1nyOR;7$ttD%kwQ
zhgr~LuD{{s*#5h~O59CHm>*O?e#XP>h6p9ksSjFSIZe(mU_`903%n`?J34WV1;6RB
zmvx?vzS16V?^pp;V~y4D2y@U9tuG^UT%=!&RY(6yH<5}ka+i7XFtG4<lhpO%y_58^
zYgt#Trk}$GUh5*Cmce=$BE#6bbZ1%6Pj{|80`B|q@v^{?T~CKN^2<_uE%|e5c$@;e
zg|hd|h08VvRsHvPEOnM8U51NdG4fc1Mdfd%%IzNt(sin9QJ3NL??nN9jxbA}`STD#
zn0vB|2(o%I?$G`+0TFWX+&k=-EzfkBe+Y)5bS>#;doH^GQ9pct7w&|;dv?P$H<6dd
z=BY=Tw(IlMj}WPK3v@nWB451kQPs)Aq;cG%x})m++N0VkY+1vN=%49t#Ijkaw!d*p
z7h#z{u&QsQVF{#Lf*7NM3_|$b*?!ap-VFhV=q3;-H(f^<;BXz5;w~%Mc8SW$*rMdf
zFhULQ1s?A*)chV%u5<xWI0Hi^mbb5~Zp-@teDW@U)gb_}mg*-9Bd4Dubz<Zeru|-`
zIebIlqOP64<D#yDF2nAMZ-c8AMhX)i)Onx|Dw}8E4{*;;+2y%`mPG**NHXxKAPDJA
zzoSI`wBJ#pekw?!;<z9y_jmDfARiC08wn4YYh`%I$a$Dkgx%Z~)wl@$lutyj8pl-J
zPpz-usyEv=$?P&JwI12Eow<}cw<3i~ZT2ffUIkNjnZ}vOrFOr9h9x+TNiHGEXZu0I
z9liD|`aep^IX8=+fqd!gT%0_n61{PiK3}>vw{=kHZjXMl^!;3OZ0N4bGD-SlZfmq~
z2d!zI)O0u+N=f0v@h-FUq1*}pL#kQqnkZeA3#u3HrUr7QQ*yDN5bg|t9BEoEf66Ih
z(nc4Z=?U*!!+qQ=@9!f*qpV-`TOXU9EIJ5RKk;yMxS2q1c_a)uZuu(9!(qtD-5%G3
zFy!Q}%QZd>Iqt9lf2bdF@^XA&To`h4w^%<e3^}=*s?Q2TPVNkrvG+j!+AqS{=7~zK
zv4XP>rII%B^`f-q4wks2W8>`Wh;Q2ZJxPZw?92amIg9`QDp$UmgX5pIp>l9~j=e0`
zZbkf{SkaEbnLPK9t+Pg1Jvx4EM>0k+RS$!sho$P$43oqu6sjC^X6D+N?PF8Mzz$(k
zZi*}=cW2^>uzuIEnzK6_b}JDdrL2y&?;5ouZV@ke2xpdU+RlT@{dBUD=aOS8wXf-X
zG0c2=$I$Gu(s-Wr#fa8+jD=y`xH0u2SEf`wvm{62jA8J+GUH6{+T8ZBSsA1~Q<f~t
zv{Qd#*KbYi(=I)N1Zw-WJJak03_{EG;^NiZ+>(a*D$Uepv3`W~Y^+-)a;liM2jPLU
z_9It^*gpMQtv;hjR9FO?D!^xMd(dl^!r^};!atH6#_7*p<He1uIj6T5c76?Y4K_K=
zGa-B89YYpB9;caV<)rR`qQZa1mL2rGoc2dVD_vS3Uw|0tDcbDsMSNOz^_Y!mOm+!1
zU->v)NzYf6&9tBYn{w_<d-4N3f5^m3QnV9T%^yxNryuBPiS1F!+aq3`_$ou9L5rn+
zlQ{eP0nzbPvQ{u!*pFE5H!JQ0Lk~Mx^DXFx%3(8;VubHBP+wh^P`v@}7rn^rZm((B
zG^DK3j$~-7>A3(VX>RtIyd-9B3H1tA(&S7mbG3z!8)w;MbA?9MVO>sUihO-$ihA6*
zPMn;_%i1%Z$i(dv%oBMvT&Nhqjgcy0#MT%lbFX0SmTvZ}Sz#??;FV`GiBogehR)-4
z3~D6s$u-lE^Y-V}oZs6E%gQU48!pn-fXGnYFs8}CRF_bX!%jNZ$`SMmS(SDSR=+Z^
zgpPeu;v6JW>vldUSPGR)lmgXBn=Vxg05{9X1Q7N-NLa6V)MOltW(rnwJ>Fi;I$z7+
zD_53H4>sJQ?W8Tc(3TxTLHp5`_@1`3HahkdRS7-#Nr`)qs43LgMjI1qPpwPZ^n+b!
z5gC_Ai|GHT)tt`T3*AP#t|2)_#~>Y%KzC0vrWghtPtWz3W-{Z5359N=c(!h>F7%y_
zkpRH>(Z-C=@O1)gsbCB;eRRXv0qHusE{2>s3iW_`d1h(r<Aq{+5{QPL{`jaJ17lut
zMcHCWh`_Zq)s<G$;n+30wWTk=dpcCNaSc+h*>X86%cdmk7(AF4jl_}Ht^~d+wa&#z
z*XrCXLccVPxD<x9U=63^xUqV*$uyBeKSFI6Qz>+ol9%v^h0afz(%3;Sq4~Ti&zAv-
zsb!$&RHm$i+A5t-^YX`Ge^T|&SGiYJyCr1;hK62wQjDk!=tDV`V$`r2j+eYj7q&!C
z<EEp6<mq$AAVlf(5^54VpPeA7s#ri*idVDk(pO`r3l(hTk`clK-xpI^$`o3FV<H5n
z{3(uRdP>0(`Z-jS@?6=NRVmDKWH2A+D#cqR?XMtIHTQ%H#EO67=fc3Co)*fn7RLgV
zrB1>tv_NZ>)!X1i{7A;~vt%n0ue<Gvm);jUCsS){)O9eMDXxMs$Wi1y-JyB7Ud*4x
zBfp&A`>-BAdgT0#@fu=VBj-cYEWW0}DnlYLk_!y!;3v~lNFApV)dx?e9mX%WnANW1
zzI~Iscmjgeg@31}@*E!DOys5C4`(VKq^60Ve+%JX(M7)P+x<V2PatZXJNXa^<oazj
zr?`FoNBf1yec#$6sg#!F6Nla+HbRDWOF#l5Oo3ey4ElIQ$OFUEZa?3ybo~d4EPCx|
z7%p_48r6Bu9zW9l@`f+?I8@$D+gQGQH5Y=uY;{9Jjs2#qa`2U)y)0-?i9!)%sPq1b
z!H-IrJ67WUlSo~;T4o(C>KRTRuB|K!TKz14Tj&407eW{w5rfm?cT{RDVz@h+sGfPm
z#SrTRhW{wuzRdMrP_4_fU31)Kb{(_)D`@%b0&Hc~Cs6k1+pzYGu>L6)zf%yXP2&I4
zK>YN@N^k`n$Io@PTX}?3Jf;(02yXg0amW_D;5FagW{__#<#XSoV{q?gBieqBPirv$
zJD74JxuxP9p+6(#SkEnQd&r950?G1Caciur<r~Lx4jTu1YGF++-@uJp&uQQ0mLJa6
zMXw%^BAodfspZG{H4oYLuB7YPhw9)Y+ps@6eu`&$sx^Cs$9nWy(mqVh6tK3`!y^^P
z+uOv>KeB~?<X%<RzWDq*94|UPWr^aYcVw@cvmTs)B!T()ph;eor4V?bMy?U37|B#f
znJ&;Urb0<ebiH`Km={eFPo}F9D%sWI&|IkJCegfXBwLlsEB3SdV}*G^=GD*daGFRB
zLdjPmAxDP{oV;66Bf2%1%+Zl$o-s#8k~z9hv5P*cXp`?&gyv>44GEjsWo$3p7gwb|
zuMiBJfTz&BH&R*$u^Q9q-byNAEN3YRu9NA^62|2NVublfW??#kJzao3y@U$9LmRpb
zy}OidIdw$MorHT@FsQDpAS{5)VZ%>`YwKsSyi{N+k^EFXpO4@b&Gb2XilamBL1p)O
zI>(&6kMRItdY8Om?FQ?DKGdeJyP=ln!SFWKrJ_(NEQC=XpUU&74~!vPODAf$zw`W<
zAMR&5Ne#R-RD*s1`ADFHs=`DVi-2)MiWhaT7R0JYkX$HSJ6M-Pa*ypDiE%b`N@GR=
zV<`^v`S|RF<*P@%%M}Q?vFa-bhH?=5CAus(-ejrh$6e#QT+2odB5*xJ;x<y=Z5KQT
zt@=DMQ40ab|NY)IQFtT3H)<m{jnTf#A&$j39WL2At3WIDOo~z87etEGOQIU3{gUXY
zavu$s!=`bN_E4w(B~jxhZqzzXTf^0h8g!lx#`U(OaWmJlg&XH=X!p1_AgoqsJ#q9G
zY!=x`LA_1l2o-eO+dcaALP6ANbciw>6fj&~%jp*Uir%J>8J_WU8EOLl5n|d=%Qenq
zbyx!(FxKUxdg-lnhv@esX`?CIBJy>OoFHsO8Lnlzc-_1*gjd4vsS)2gMAr9D^@QFa
zM#!_Ii0@g_44J#ytw2W?X%p?tWR34}86$4<Ox^%24#J3qo@?LZbn{>-Eqr6?MJn;e
zTCO&=JTzL#o65=(N++?pDKIm_(l~{6-3dAX`@&zzC#3H6f9J|SCS-3-esAL@iQ}|L
zFeT$trz#M$_S=0TZ3TJj)!A@8-%i5YE&dCXWZn|;z+Lh;*Ev#Sxt;4tEo*detNtEg
zOD%7zLCzcR!ZPo|a)*=Cq~SE?B5mA;TvSv>EZwwOUAuPBJegxV_x{Ha_g|GH&66Gf
z*x}-MgX<N-`A#@Qnn-`id-&-u`MYp+2v;YrzLA?cI}=K$F)n}5MNt+KcS`6B-WBiQ
zo=*~K9ikIkL|z@?l>pdVLVlQZTbxO$?xfVYxzS6QhB|vgowAsLraqt%HzPwSiWKTL
zJ9csbwHUwCuN-dN#Q~9i=bPzgJl<WD=b!LQ?Cji5YMj3rMQpm2xHi;8SL4KC{z~gE
zvUvC<j-H)Y(k^>0D`DE+lSn2EV!#l^RVkS*WZZUhhzgc5fX*J_iI2aQ_Yp*?>G;t<
zCh6(dYLObl%}_3cmCz|*FMF-%i$1K8>cHRb+R7p>RL0crDkPY3*etK4AV(4PRp42;
zdkQJ#@mw9SQh}Snonv}hc5_p2+BCGgJsL3t?AH#|WK5=Z?jzn1bLfhz!L4#}FR@{(
za&Kbrrjo&$2Noa%1iM8LjCal45@tv21O%VjDhe(5wPWG3SLc<{>YC8{TXcs=&%Atm
zgh2wIgCC>M|7Am7D$BDK6lKr#;GIDt`EkIG*oiz6=)pZ6UU0fR+tmsf-7s#F>YLb2
z);?4(M$9s`&MkufbLd&o`+YlNBgi+1S_Y)#ejkf?@H`Wr>k$in5s<SZw~FhTk)quN
zHO8|uU@)|+pqV~uJSQOs<Wv9~8}K5(QBf5reVhMk1C<^>mmgA7+)5#T-R@$Z+v6<J
zMo*xDMK-`9|HF>WY~5GBj#l!(-;wUmk?U`B>Y0ksBjrVFdT$m_pr?=a92{NyQ>D>x
zrgrS0XOz1N3}3r`3~n;=v5J}+V+BnqMmuvTo&_W#0tsH`r-sJ4h1yD@-ixSnYzNbJ
zVj2_br%E0Dq}(uPyoA@CF0Ls!vL)#rB&Zfe9#N}!x#8T&Eh+r)d)~Anf)5)&sIocg
znfE*{Le^vh1rONBm$wX5*Nr>iQ&922_>f@q^3W~}NVCXrd;C_bf|{Tx+efh9R2SVe
zGUEJYd&A{w|L2|RkHj~Tr1FKGTVgboQ+6zo??g1KENW9hO{4iCq^*DYq<WdvzF?L5
zS)2WpjVQEMDD*yK9#0)DXmhkqpysSQdC$k@Z1VB?Rw!KTFYer;z579H4*8(mJdt`*
zUiH`o7WM&1N{P*=_4wAJ${x*Xq2iQ>cNOe@UaX|T-=&H1Q49Qw4d%*X&AF4Q2$HnA
z1=^84{Lp<ZHhb~HgKn5Eq&-qYgIAdcqTH!s&DkTQ-0A0ub7FKy<hiI#&-2oSHMY}1
zTgoGF;j|i+fzBWtPYvdy#hS01Na;4j)~Iakh+J4{Jr%SjKXRguYnGNZuQ(TlTrq|@
zvuC%$65p&jy^$2&RlM5)AR_j`pzSUQZBW8O07Qhpdx2O_3<gnh{nWwzu&$;9z92G1
z+*_<%=u^bLa_esuuBI)WLGyXC&O4y{OfgO_e&YEB<*%;i<=u2vK~GD%uO<4l@)phK
zWND8^o*H)HKFcYAJCO1sQZmKZO_Q%s7RCN%f-uHDp`EM@m3I9rd<cm7-@o@uj7dSX
zr9H2KkHLU{0OkEGT3GWfNtAN{HMN(xM_k+4%#$-nfnAXgx5`^XG7)@?-sjfu;gZHi
z6CRpkpS3{ZfC=7Ga2Y(vLRqxcUnZu%jLh)?7x=TF%E6;#loEJ;RiQ@i;;?#a<N+~R
z#IZ)>eR}n>miyWCQ^xWSx%3j`h%Ld<N<6mNxU8A^gtDN4Y(gd}$%Vyb?$hzFkedZ$
z^(p!A4XhD2N!i)KTjcQtaycD|3j~mO3VD3UgI(kzEby-g^}hTndGI*7OeQK60t?yL
zKv<J)rHR~_oE|?WDVc%XXc<j88o7NqKX@8)lIvrbDD!eXLN9{JyGBvzq3w1^?nHg*
zg-WBFdxAE>f0(N!`zpsr+$Pd$T}=&Xuu`~4`54IsK_zkGe$uU@q{Nx_Hu7?xa8bZJ
zDa3y;o?<L-%l~B*gauPVB|jp4O#JlR==hu!C~uly8OAZ`gC&`uwdG?DStx$qCu*z^
zm2VVT7p=uZU)ok&!+ARwk>5_?i8ZalQx`qxm5BA95M);$i}x<tI`qo=y&RE_F~<7m
zF5)@AW<8eckGYl#(YG5#{>4>z=3l%TSGR#w)`_GXi?{M>{IsULi7O%#BR2AaH}%6w
zPr~DEQ<l3qq;8f%6M~e~@<2R+7fHrG;u@Pc0T25W1QR>d={#BMg(1BVsji##EZNVN
z-_IrsgQ!bU@`UJa5_Dxn4ZX5+ODCaUw1ahkhN(K1R~;=N5q&U2k|qn6dbH(6P?1~8
z5>HY*7bE8xJnirZ{9ip<c&^AbV~qt(+$`8fFfx0_6Qs#q!bQ#>wKpuY+sEvbX4!45
zYO+{+Kbr~x0qTg~3PBHdo+UjKz7&XYpQ532S%a5N`q4-HB}W=R;?gse6;L}f`hNy%
zFQIT2>B}i{$v<~mi+@Lj3qPxi_(Tx#feQ5puu1sD^}^&xcPe+2mMh5xSs}>h0&PFe
zne4srMaiBRJy#!}o<N8NCxu5zf&B<z8=`wS4F3P9r|<t=4`d}bHk;URkZQwYy?#H(
zKghEJeCg&5X!U=A7@B@$975k2sUokU*v(nR6k-w%R`7B9PE56yCPK)||Ai`uET6np
zbWYSQvd&wD2O-IP`cDYp2Xm4#Jn;)xUm6kpJTRwRB*=hiM7D%ywr$ZCeN#~LKL3dJ
z00)Z3QyvK`t%86*9r67ZkUC5y<+%2gtZ;oowgLQr^>Yz6%T!{;jkCmxU;@0nYBFvz
zO3L}TKw~h&j3*e!{(jW@MyW)`3Xz~h$#}Zl>AY-dAS#-Sr{Oi1^bRx&0-oHCvGok(
zU_HW8Ps0uh%;z_4W1~YP5S>-`4!*3b#B^HpHi2N#MqGW1-o@36ca@$F#g4&>YJnN`
z!W&lL&^+@kkTulz>_(w2BOynEK1Mf>e5jju&vPIGVYe2L=hg)qT}RIL_XC`VJWJkK
zR?SN0Bh6;u&fPv%74mB=yP#m;*SL1$9~sB~@*D1!*WVpmJ}w^JONkfu<nh>({~C-J
zK&}t1B|rm#OZVm=?C5_DVn?sv7sMXlbpuVJZUB$>86(z**B)M4;1JCxx}HM)`sLT=
z&h$)wz@9$FI6dd1yZ#zH^ZX$)hl?Ge^#{3<#PwrkQ&y)JdA`y!lb~mNT>6A8{Q=MP
zR?m~X=a1WV43MR7v)i|8>vAVcAahNUERasu+v5|osZbRYU132prz?<V6-+MHRA^+H
zN!FHFTT3*&E#{(Y33JoOWF`>J^-;`*vj)efoF&+IlxweY{DX7#34VOGf$W6>O+JEn
zan6?5X8HMVs(T|fQRmOuJAKBUmgpX(RP(04W$=aK_AEr%n2AV&lzO#wCaam$Ge>&S
zV4EY>O#T+b6;&T~i$~Ag_pRSF@C;TuKBDUMsUbL^+%Z&KFWV$5k_Go`?ri2K)j()D
z;SjYAMCtkn_mXP-?^!}7q;-i6SLc1}D>e2?&-a4~Yxo&;5A*+d1H|nbzD+(?7@?8k
zPzJ*g&w%oXmzNVvP|uMOeGUqHLCZM_2FZsGmnbP)toWHB4?oFHVv7=ja1G=08->B^
zRdg%PDQt^uM+cxO?;-+<Z4m**xyY6*O<^ZXLn_gAkP%b~!Le-B16dqgi+Ner;G!3P
zbqKZC780;+3pZ5skiAfmUyNHV!o7>uJ4EY584Jkk3o#iBHmDxv)_%^f+r{jQ+#fSX
zu{-i2;~XY+`7dsY;T4A#@Y8_Fn?q2#KC<Uo0!+rU1Q_45q=ut0zWdf6)vSx`Z1;Sx
zA&U{Ph(L==;21$@y^GO2-hx&Y_5AVL{TlaT>ZM(Z{o|a+Vr%$jnXN6>)p>WWjPh`N
zY=(#`ND@_jfhGCzfjB~#89hB=1=$>h>Vu!(9NETAqer!HBrMVZFs7Yb4E!2*4BG(-
z)pGKpX$A%V6{P>RAH~7i$)Ixv&1>351jyoMIeHPNYy;>E19on`qWY%q<_OgvdQo&+
zd<Sd!k`$dhLeEjH*Frw5s`Xy3;4^Mig~-Vf&X8Vbw=JyFakPn};;{{j&8Ezbq!OZ3
zG0iJC)1-`Pp4BT9rZm~qUWa?$N?~5|aV=hM)Mp%25I%S~V3j#%_b#cjif9{lif$t{
zB%9joNSaUTvXxjvb=gYFdxXLys@5fkzhtFl?%CR7_$c$jAQW`)qQ)kXP1lCs*t(Of
z5hb-DJn4T79?EY#jO>v%1zlbtk}OE7*0N3oY1*1xLB(ZLXC0lD(fCo%Q#wbP&J%Cg
zP+e{eqneCe@n=|MXnufXesbWYbH*1~Z3|a>X;bXk-MeDW=4ZtSIL2|jC+IAsvvh$j
zjO5TO`(lpjREvVD@j+({&2vx0=>I2JD7?QEJQeE~)2gk#gP#4$b@}eN11AJ3-6~$D
z+9Vlum~#uAcH%*7)9mS%Zx9uYg<@Q?I2Y?jF8e&jeh}qq3nE%~$&RCiJ0=z7vjApi
zr`K^`pefibcFv-JIG>1)584s$t@DHt4U`2o`2SpGjwUFu>BzchD<Ps8+8Oj3<C+I}
z!j;^QEdh+zXTiN*sHENA`7NoT^90+ucY}K|hK*DLYbWZOqo-tbYqvlzMW&drhKQfU
z-^a%;4`|x7hsmgGqIz;DA4A(rlublW$AW93voTsZH1T>f(dUKVWvdapfOdUG6+^qE
zqL!+lU5cxHJ@Xl9J@eyU=#yrM^PZ8pTccqvZ*UcgU5}it%}0I9zs|fEvHXC2cQh2-
z(-8<Vht?ktKK}w+(88(CAZ`IISu~6A-uveYx>fLAkTm?TNFRn~Q->Yid4F@AMW9MC
zHgx?suxtyucO13tm}F&W=S<4UP-QJ_SvkQ2=7DF+222Gc-XP0Wa{QGsH<B4FSEmN?
zk?lkEI4%ee2Yg4iGWa~Sh#_Y01G@(fy>fI=yC#5Cq~SuY+MsX8QIzsC6k1EaY%lv+
z7_oA;XUC+ne{b+TTU9T%g#gAxS?RFOTN`4!h?56?i*@g+C|MMr{Y$pVny)i$3*_rk
zL^!V#<{tE}6XdSmU|Fg%enfm&IfZW^(oU1>?*yNeW0ggTUxQ_vX=;VCOs|Yjh=(C7
zw49htLjC>!+f9}T$`yBaz1IGdTmJ%E$!r=@w2M`}%DVE-sp8lWBX_3NXxg!DII=k%
zNaO2Hv~n$<h}<D5>tJ+?L)3XN-o1E>{=GiDC+k%NKl~Qsd$xwmqfoo3zmhqWjQ3#c
zP-iZz;p_BU`cT;s?%Pj9r~|Lu1|qnfKNuaZuLc2TZiVE9<+rJr?Dbe`HI)d9;;`>Y
zx9^HBYmZMqwxSK2iz<zN30PvNtx-q0<vrx!1h~<*aoF;gALTa1RZ7)0HF51n!!XEf
z3s=A}11;|(VugG03Rh|nVezTwsQ{9GJ4B~q@Ywe(nD&Fk)biWB8j1<w#2|wI13wuD
zk?b^NN}RI3S2i8AbKi8~!~jPpn`B4nNfN>~*E+K2$J;B@%T`8L&tI`XGB?*#yR5wx
z)&2}5MEd_+1Es$<)b)~@(D}+b>{0<YKO3RW6!H63=x^TTFD-3cW0Gi-W}kW&-|#nN
zn`f6dch*FA)<y5;YczR_CN2Nwd`<NE&~4@-^YWjroQ}S7JNg!nrSh}}ni9~hLfExA
z7u4{xE6FCyx?lxT2Y_Wv>#T|Itc%~xo4bNg6V}9^CpWFQ8QOU%{vzLbnxr})G>WfA
z0e;Aqs|8q{F``k&xIMGyNLOtp$9ay>2(Q!I`}l>8$6*qxUxYOY>sDY62FcAxi_(JO
zH;67>aTBCZ>g}@fCiu&@6B&*)psE*b#S&jKZyg>K&LjI;)4Vmf3Jr(8;bToErs}ix
zNh0eI9K>KBYJEZ=YSdQ}BZlI+s<l)lP97AW6F+$nk(Oa1VBl7LGRQClk>>$=)iL#6
z>N92AAa|jdtj@*;QSu<1y}|W~jDxI@p;618cTijDz=sNBBq|GAIxr)>(l~cVb=^*D
zz5#D+g%T3L;aW+dxPrqb9;vG<Gsn{FMAliccxNjVyG^urP%IyFWUu&og`f_A`NY4{
zFBs=uufBc5|A*9!Kcx8zC8*2%OBf%amTUiIjS(-AmJUow-(*zJe{NTGM*c)JWy{Yc
zt+CYg8L_-NW0sZ|m*9J$C7uz}r2D+iJ4kzEFSFN7ldj*>pKz^-1MeFt>o02>l$eLI
z?+RskSLOp3cvZ%%#1Q-?CK_>HA}JuC_LI_qqXEgj24~tpKw{q(?_4wx#n8A}OsU^V
z-(|$hbk8!FVR;t~bWWKbLJ`j(s6uGmijzc30pFK-P08gQ9M6@lvR6uh4ZD;w$aYm=
zkWlOHidFk%26fY>cyEm8>>hq#=|Cwj$|w{Q1*AH&^$xaTkx(f4%n=|Wzd51edXT!R
zyj1~ZM*1Y9$vh18@LcKOskRu=^%OHd5UXZJQDp1YU`A1dxd&Ii^$M;E^G~?SvHoS4
zc|h+p4`{uF-!bX?jBc~C^#}ZpPCsh&nxk633tmS!KGZjXLF$tX^YGTw;XavS7<B7;
z0tex4@8fZWG2%TF69*>q14;)-5nCN#gD0tH0&MItKj+{8P{i7b7FXOt+e8_kQM8yB
zK@Umh!V(6bYm-E^fy9BjME&T*2a-!CG8u)1d`v0uCdw$nCQSVRlo!-!rJ2S_N^17#
z_>7WNQcqz4&mf*chRF^pwVE7Z-A;jk^Cisnol(aB!KNiU&pwF-QQ0A8-dk%XYR#Bf
zPrjYFM|>-2o9L;)lbL@K1K~5DLSUwhnNQ+*#>D*uR}=S%uLsi`#t{5W-0Pm$L=Zc3
zHbLyfkI3jubQ8qRd>o7=W8#MxWdFnuNO%>}&%^;EOGhMYQW4`|6mq9Q(dGp+vN>^@
z8E>6U@vqrp7^g{y%d`lgeDI2)97!Tu+s*4W-!^t~4g2l;6xKM(uAtUOidugTB3-5V
zO3=2QYP}q^IVi9!o4pK4X$&$fu^JiL<yYg_o}b(ritq6YVu}yt*>96XKc5zP8A_A7
z^N_s!1XorCf&?|L_i-BsjI4;H3_R)M_K%%~jJr^@^N`Fi?1#<F-YN972-6=JfH_sV
zaUUaIMDZh=BQPS4FSwl>bOOxio?1Ub=w9GsbPq}^lK7;Vn6;89X!Q)CvqweE5y;09
ze*N#z>+aBf1VQejj3Anlul1)xuYc?>ek^o<DSU5f3Eh)qEJFE%p?ebSf!tf%p?ebK
zL3m#ux+mFK9A9!fM~ul#eTqNbifjahocQzLiGOifrc)6o2XNn>68*5DfS-mw9t~y`
zvYJ;i$1=V@(EJ3@h2txHD$lHA#3Lwvw^>9vPU6AScwp8c$Rfl>lZiGJN=${IUdJiC
z8<?4zrXlg9_=oh$5CJ#|45#r<l9@UfAtN!SXSj_UBKV8qpMs9B@j{<jX9P|k3Pgmy
z_<ImX4UV(G_XTu@g>A=HR{UMC@f_E*;VaD$^S43AH~37KnR=9OL+Im{e{)ARH1jp$
zuY;&2%_S46(QiS+C(d&xH#qtI<}V3-mXioJh%gms!gSG$8-)qf63?sLE%9Cl6<A6g
zx`dsZdb54=N7d`Kb0GxHpmq#F42JmUo~VZ3Nh}pO9rV&nT5h6d;H<a1d^DqZG;ye0
zt#f(@5PkfoAFn?xa?7ZywK%V<8qfFoNK`RFN6n8vYO}w=*SYOi+(sG>(M}^G*Nd!z
zcWKd5u^^#ChC2Zndnn}{3K=`1>V3&#>6B)`yx6jpb8V*%)#0!Zcl!Ahc!@KHJ+Vzx
zwPxo8B$U>?@2coq|1Aee#2Qn8Mb#fuSXOrU{Q1MyKbMo+KU?c*{m)+!p$hX9yrXa+
zC9%W|3PkNS#a=Je7?^l{v>=3%Rg?Vf)eXF!q35k&4SScyUbpIW4hm(4UfGjzU3ZQ*
ziLVArOa7(9bi5KQ&1ly!n4+W3ahbLjEvD|Zpw3AWRgm?e9KnDZ{hWahRC9>()IpnL
zaB7$R<;R%)*$rbn2dmv`oWgb<Os~!z<H@bAt{&s5skRNFOtIKNrdOAZ@l;k@2UFE=
ze_RdmD>of}M>w$ExnVz17AZ!9k%ij$4+neMHQZF`tg%{+{5afmUH_zNXV0no5kK|+
zq^jzCO0i8TNgOIp93rgRi6d`1ai7{#Sbz{9?vCC$J9GuKMgjwkv{Ch<k&=eQ6$rR+
z6&tS(xw8Q3Mi|95vmG3MzwflPQ>xc~Z5E|D`6}0ON_7Bvs&UxG8@vTl*D>7R!d<<@
zr<6eVP#}f7L`QGujunBUluCXxWMiPE5o-?4(fWfZ&d;e!1EiJ%l<Ky^rlk17(v%3R
zl19vJ>(RcVn>bvxDe2Ob8*`jOLsR#-nkZF1oF`+z_jtqyb1M}ca#KqjB3)d-4WFTu
zA;S<~0+q}cVg%}ew^WtoV>B;D@*b~pluxPnp_X0S+f$J4E65<uRH(<Qlv@i%xxPaM
z8Kl>vQQLpeYp*f`H*2>A4pFtY!<FgrdmI5~J}g_ZYz1S`k*ZYEHxgs8=+ZR}Lna?&
zZVi)R-;N25&RX_RwfR;hRhkUjGV*|YNm-hx_BG@yoi{(z_GJh^G_7G^;V0tRlDl8;
zqV}u-b`pm~mZpf+xla=DD3QeR#)r??PQ#KLUivN3Q}+a16ha7~#(o5y3?ayQf^i;u
z!+GpQ%U1+Rya^|-h?p@#M8b_F4iFc8`K!=_jL;qgunS{^*i;3SzMiU0ol|!gYW<%6
z{$kDuYhX-tqAnsaLsDvz2uZB4jSJOdB)Xp0L-K4nHR?MK(;@&D9Lt|Lgzboc=Y9@#
zM~6tdextGnDJWZFklMi8675<^sWwB}Ck`gAP1M<OmTF2INdcT3D$pHtf!zXp@QEKG
zo3{l);BK1PSu@B<D}6NE6vtWCQP`Rw^7ctho2x2x%Gf_Izb639f<_Z+HGVMy%2^Af
z0Si|WLlugsr7T7K@mk`%Eo#ehf=nO?7;_g=PC5?fE;d?i%ca`IRsV$D0M{Y0tfAWL
z%t=&<k}ss=meT5_Mi$BF32e*z=Irs=T|Og;oOk}0^d2K--1#5U{YEa(93*`k30jjt
zPyH^Y0&pV)_j(d1_~e~_HKkg}T9uNdP1&KIx()=BHjhDkJ7fs2YW#tt24+JLLn!Y8
z8MVzZx6UKD**FWNPW$%2da7zo<98e%lR;AK+>M=CFkCc^(Fuel;;UfFQ5qNH96(zK
zP&;E4v*N^6<5H8wKrb0uLc^e7<8ToSyJ$EVl%ezxr;_$5LATb9n@M9uL?q0Mla8B!
zgmdJhwYH5DuA2&IQvqWt5WX6h5x)*5emB>St``w%s>J;5jUVCBc}d6_(nk4r9M0I{
z=U!7u5vQk_hB3xSd3#-LEUXW1;3q~B#1D}vFY7s#PuxC+m!~gWp$f37k6B?hRasu5
zT9C6wNgvt5uKg0;!6gC&KpQ5vekVwtA=4WDu<QuJEl0`VX06lm2I!OYEbvzf+n#v)
zwPtY#B0uWu;55uxJ_#nq(L5X0&lgi^4y3zKxC^L&i3`Epo=o~o>Od?sRa_7is}A)Y
z8FOK69b}v(l<HD%2!_CWAs7&z@I8>LNT&q3dc*y{Td!q8xZbLxq)udzs~U%rq1B13
zEBC<Q8b`{S?Aw95QNu;;W3|IE6bPAz?pQ1ss0^T^eGw3sKN%8wrdppFqbtPS%xPSc
z?JJn=k$#sTz%gyYa4wpiE4~64>5;^yvY4vPP*_#F#EH5wi5Y_uP4S6^Q-!X=!Y|u%
zP5+Z{f*-Q?(?3JzTIjcBK4m9HNA)yx&4xfcm)7`Di<86Rj~QX(M34YnM}nXgjKmex
z;had>Av#Wk1sbUURr5mw-w2h5_F38soD~``!4$YuI?%c8=VoTkA)J`bIdmirmN~pa
zpBg$B$JsAz)kMY%Fd$GLPXDL@zVeGL(Hy2Qcttoq?tcWrCi_Sh+S~OPIpmLq-J$i=
zuSKt*HmIJ8ZX?_sTICn3eNKjG!a_b5aLPG<VbuA$26&hbfXyR69&cawg<jgpV|@%%
zd|_)N^}%p3b`!N@3u7|Djsl?1IfUNz>)ExmbK3=Bw9W(**Nh~yA0s!E3qOSp{qtbP
zwu>f`!<iT|<3WcI-uqhS$6ae3@IG1`kaNE}7P-OB<jAps!u%jBqp})@FEvJz)hb?7
z<@z#MbsK(rq_``{wvSUMRN!Pem*C?Xq>8;O|HU(=Z5LENIWb!q3lL8Hf9$<`SX0N=
zKR(&X-rP2t03rz15D0=|i+~DR+XN8>wE_xWTOmLIMMb<|d+gf~6;bh=5PJbH=RjI2
zrP{{WdP93cs(8Z|=}oP+NTpR<TcqBL=KGl)u+($T`@YZf{XW0v_eXh{$=vqLnl-mI
zGi$A}Z=21#K?sm9T~X^|q+FwKcsTjhV`pZmsu}CXNg*M6#nLbnB)}(jMMJu&VWyiR
zf+0<wJB+t14J!Y##5X}5wl_f^fFm8aZej^&`t4$V=`a_=;MGDzx~&RCgMH_a?^jEW
z4XuXFx)pCanOt5mCFtBL73y?HBEF1wuQ_brxEpfR?ujOv@gXcPDQ{j?pu%F!n>R3S
zg;Lv(+EKsF*rWR?{388Qb6&gLNXcNjMg?4^te_Zha5w8^xTP&Gp+|P6P<l9n!$FI{
z2Vkw2`j=VpQgN-^Tq-x^Z2}C4r<?(Eq4?D?2BGoP8O$`lF^&Usg`$Lal?O}O?=#y9
zv%h8VC>u0Lwcli_H%Tf)ybqogFofU~PJja!uy^dZ2cVgTlnlSd_Rn=`#|^EAf@;g9
z*V6a_jEI3}njiu}VZL;YZF$1E_(yig#l-Dz>=#J6UE=*uo|c@iuel}>NC%oO8R_~t
zLo05tbce;YN~Eh(g8j+0rirQkiOs%<Ct#^#zp|l^IQtT_UkMMKHCLHOc|EG{1{_lZ
zU`1dFABU5r_SpnJv;;p>P-&mJ23|{MaY8`l@WW6Q4oaUs0R#OtqMCW&DC7s!q&R2*
z8j+p($n6u$h$0wq3d4kl2kBB}v*U(|Rq1b`4yvtjxQU4v5Am0qnp9_qGOtfvC{|5U
z$Bvgku%hf^Cym4{4la4XvNY%v;2`fm9!F(PZFp)IE=RC{^9+g;ziR$zoG*djkW>C3
z(X-snnPsuYe$K`eQZ~-SO0ck(#aUR!5+^VhX~yFyjSo99Vqgb|!b5d=BT$DWB%?%p
z<~qx-GfhD~Q0GFeK0BY_yd1H!K^W8P_d+c$*?G6qB7TZeLmJ&kI}Y^E-_KRv_?f-V
zrT?<}s*?B48_|B~ckH)dZrrbg#M&nk6ue7>*G$V|_5Gan6gVR*F^(f?Ubne(^gJ)%
z8e1Bn^^vq+#2COW%x89B^f^*}9a_(;usEd<ODy*H&UoI_63bd*Ip}cgX~*r7vdg@i
z(^ZjQy`g+rT7o^E5Z+Cph5|e5Mp@EknZYR6t-*zw*iaE*R5R`E;Aar}vMUjk)L>m`
zxW?*vuHtF$5GSoKk5vlH-^wqA3A@GLxpwZ5VTqP~qtiNhcK3C*4MMviLRVNnye*ju
zGun6tcWC?zS7o?mBYjnF*!4)|&E@>mdja48Hpp*wG|BJ`A}-=U2aEz@9lDsarw9-T
zv$rsgPD|)J-x(Ms&MDr``ZQ;}Kbw-~EPzSJ!N0_VtM~W#Vv>+?SbXLh3%%^_T;&q)
zvwZDX?Esu-9M7mZCDi8l^PK~ouVf6FdhPNLhZt@sDFrvDw~s6O0I$FS`V0K(1IeMo
z?*-5uYT|OEJKJ!by($BVsus1mGk7ou9k^v6X-O8L_qvr57ga%XdGj|?U6Hh);AY1~
z8RhxKq7_O9Q-l_;CLMMPN#+L*QJ#j1M`7!$9MRpWBDBSaop{isQhs2~(`4H<JnOAz
z2rBSKg{K3Y+6=!`yn&fkcbkr12cm$7;lHp}y$lo8hRBLQ6ojkH(n$Q)dg?XB?R_3}
z2kL7*m3<!6(ipIe)Ou#S)7kFdey@M@y}sS`K?VH;nc{ob2eq^W6ZK@fbbrsYY9MSy
zF~Bg&wuJ0g)OsX+X(jHeaO-ZTd^e=GWEE#~4?sZ(ZhZ~=;7SCXZCS;&9_^9`cd4f{
zOJD1ulsxcD)vm3tz!fPmX00uyF|{6ge9t`K{m#;0TTscB2y`Sk+p_eqTe8;F;yG69
z(A7#JOyKCl$-l7MB@V1qiZ-N{Drr9b^qRHp54w0Sz6cY=I8r+Tp|mdjYP!0P(<Bx}
zN%|e@F}FS~VnQ#1FIUq`!*QgPrljBN+wXPxX|*LE^KKPFo+6`WP18$=1%l#*TWMS=
zAE(J}G-KtRuCvtB0*v=l-tKaYQ(@0^nLcavI;LH~3P`(w)Mpk~&<~86^y^={9580$
z>+H@hzqp)NTS3CKLRBJO8|D+U@6sI6hP;GGRPyk0r|+<L)E>DJCP5xp{@m6;j<I~d
zI3<LxfreCRO75l}7_cXp7-<oUaP#VDyO6*wrM8L0GEtNe9U4;MX__h8C8_j*zI>E<
zkIsC%OT;P@PSSDFPS?p|($K*w)Y6z_NUXU+-biGE#G0#$-ZkM2WZ#oigcH)w{!^_d
zt3vqB20RSFK_*93A|mJb{mI~@Q3?DUr@=)h(4-28d~`q@Pjjl3<}yqr2<0Fb9-5U*
zBJ#Y%x<Lje{0-XDk-5Q@t~#x}SXj6;xoaI+Iq(7ed;+L<1GP4pz-4NydWe-@iA&dk
zJX1BSn`Z*2o2QU2!_fp<3r8I3YFg}v4jR2hdqZ7>lh2wn_MHdAp;?Ooakq0oQ&iIk
zTx*ownjM8>0tu=4)Q&rvxKXcSqtK4G#~%$(+BQJmQF~7bdQP<SF23n02*qPx*n*OV
zVQRt|D?Y~+yik<#r2P;MU-0Ir@B#D>*2~+E0}!{=Z6kQhjfs1Bf8`laj59Xh7|YVB
zUYxiG1T)|MDL%=z^#TNA0{WjJ{)4W@yP?Zr`rVMqhv-v9HNPNn%}@3Vcsxvvt1w?<
zDwx^9at=x>a>C|c75!-2ppS`D-mg+SFcr6p>DVkw!d-eCQC_t-&36#rtA9{Py4NCF
z@9m7G3aTsRD{3VcyeCmfY1|&3K{Xi_rQrLAPq+G|u6WHSe6>2<5QO=3gWfMv<4njK
z)dsCxGm+*-%O0@mPWcV?FjwJ{zHfERtmuTMh>#c@sU8m<yiF3~3&K@llMnU`+%~<_
zL(=h?x}ziL{O2w1!YIC0{e%0bxy+1_Cv(Oe!ytti+N|z(w2N=BrOq!iwG%6%hq>;k
z6lkuPnLBf$eFkrqgn)Si*|rY$?O%4&<{`1}Q6KyOD;#u2ADbg`D@uFg!QcVF4f2~w
z2L#}(?qnT;C2*e>A7-fk20bakSP{y~oteft&03O>5tCdSQZW&OCnUO3R0R>`dbYx+
za^m1h7x{T>+7vd#Co~!YOnjdZk^fPDPGIfQG)Pk#{41H6tcD|{&g(riDUzmCyo{HE
z{ZVv=f83}b(G-wZ%QPwMinm<!EVO^?V|hOXj@VAfaYY0im0YFgihw28IX6vSuq@5n
zt-O;hcvD?h2{uA`RnU%e49+_IPf(_^SxXAlQh&YwREX7p7p%cc(cnW_tcDc`<FWwq
zsLsX)|Cv#xLD6wBBHbQq+9WR8D<*EnW|yS9*0gU~c%mFERAy9$+2j;WtK;II2yQc@
zP@MzfnJh}Kb$!RvI8D-&4GExWbi20_^(jJqoK(7H`f0R2Mp_@^INlFWmPdRnFKM?&
z9F;@A25=3Hcen9i0NTrR^7@W3_h@s__9*|A4S;Z=WcUrXxRZ?*Crk?!mtI-#xju6J
zI54LM_M{8A!9L;*?<ySL3BfS^$Ex+;)qG|TxXH%aaL<d4pN$cLb!jLhPkzA%wao6<
z*b3KuzLM;F_F5_mKifgq)2}fC|M(&14dFxD7qDhmi*fP{@h6CkRadj7ykZBVCnUXu
zJOXZEPrS{@eBQLOX;!U8D|E9urLhb9eEK~&gm5pcuYPjffbqQ8SpC!+1A^ze?b|ZE
z#jDHa!F{z2FX7+?mG)Mpgt>H^ZTrR^@xm(Qdk-4Lq(TxLIzHGpwuUg-3=@Onm70Y=
z4D7fo*&p=NQ`oymm{sS?@6ZcweJDL;uPT+As>Aeo#n~IWcuyRVm-)3n6!C#29rhSW
zHgw7js1Y&kzlrdQUwId9u>`#HF1zpIkV{|1t*CW3oapeYG&h+|lV?J}9*p-vBzp)!
z)|c+EH}0{k9<(f83t!8klJ0pX;69uD8(S=J9q2<UV!seUAWeU~%RAQt!e7P#BFg|`
zN#u=*eGC<9GY%IL-HnNTl^aO=08qQ2&FNZ|(Zx30V_O>6w0&teh8a7*v>P@=>7Sz;
znYOT3^<UasTcg@0mN>kIE$Y?{sjb&Wv`t;>cOPMXTbqBZvL39m47K8&BD49{f#>v0
ziNU;V-~MlePc|dN*4A5Xiz!Xg61D-QG&kRBSri1XEo^<umv*c5rfp$h%@aiFPBdTI
z@#aP6_@d77D>}z7i_nJh-kNNG&G_Xta`3oxnX(6E59rc^FD_T!?%QRABQHSd+Z7SZ
zTRyi(Oe!-iP$<huUP_E6rm&6iz?Dk+&vIO;w8eT@k4n6EN-U>6svpn;87B$Xm(=v5
zSt|Q=bt0$5@)|Ek-T_Llu2nxG)0jdVvYlLJ%2!kiZ4K!=01nPJ<NV@?6x`zC4x6YS
zvJokwi0LF^x+uH+LD~H5iz4N>qL`@ec3N_moy_szBvhcCO=01yI|@q82^A?5qf#c0
z(9C=yB^UIDEG5??CD$`0*DEEr->lk*iDAN8;TQ)2_k@n7Si{$4XLSJr2*>emhWFV!
zFa87{KhUP24JJtA2`#5s)7l|%`uSI+&*-LohCA{IL>|g?ArClz&!ehErmuZA3=g|>
z?y$CAmE&>sZlMEVQ)>&P`RW7L=xWru*CaEpKzOZYjzFkkobi7CuH}yWLuoq7ypcy8
zHh3?qt)ELK{6s&P*$vC8&Sb(B+u5)o4ycTQltQh-I+;lwv4N{$>*AzIaq?AbAu|!1
zNdpv_Yw1LU^56lr#*YrT!|oR04n2mF&w7OpHj4Ilr3YCWT}_7_dm)6OPwi$n^?i2L
ztq2VTD?&p@Qi_Il>j=#{n`8|?&^wH~gtr{%Zg!K{d{Ty2yDl7TG7hsM!0->&@Yl`y
zh1N}C_>5ty-^22$J7VDxYUjrZ?xTWxJnYVeHfra`>LqI+T(Dz*HN0meT=hLRLL($w
zASBZW$ri*SHf8==*tQ`QG}@l?sRMyRUn&-GtO%h=aA=}aNFj!>S9A=V*Bto@oY!J9
zs*q7C$>2h!eK?r`dor0&$ke2geTW@M?!Y~W?0`E!AV7diWfrOKD@N<_ehpnL?{2$b
zZ^<8G$q%Jvgwm3P))Y`ragX_C_)-bqZx%%brX93F@I)%SV^q+wL5UrKyWWBWW0PlB
z#%;FjC1vyj)0g(x*{k>syIE*{Xb*m15f?1sIE;VO^Q&xM*;6JLCo|m6q5Oc|PfC!D
z`8*n6_C*^=TX=wng{n4j0mb1*t^RbgUvrkWEI(+~?O35nV}&Nw2u&KRS%<`$D!ccS
z+?nn+y)H2yq-}a?c710UZPN}r+i`t!TfX%=Ew6JZEvP$e0d>db(>9G=K-)An|ES;|
z4_lK@8%whwR_}mEXj5Zt-^suEU%cVOwJ9hcClyH5P=`%HF(?d7>M#l8ls+US0PX0q
zj^3Jm*sh#FaPYMI9(&1|<A>?LvTt|ROw?&6>NOKrw=5b&zaL6-p^9x6^coAr_gVC)
z-B{s<&}jOK!ThzQGqoWuHLr`#xB%fN+=c#wNHlcy4dzk9@&ojFYn2rs&uH7mzC|1Z
zQV~cqQc;=eo^pB?J6fxVP#pB>BBkNsx4eIKUBb{aA~qa~$W}t93(tb)*D56Zh!Tca
zY!CR^5JNG~rX$#_kvU3!NgEp+ivg~(N}RHWH5Jx?2D!t=O9<A(q?!(B!@)x)*<(eH
zLNUJu)3HI(sEr+*<qbDKRUbSazimQ{AOIXYD$D0WigGN?ir<JhlMqL-t&I&It`=UX
zNy~)FBYJ<Z#Ibk}7V0y&gm)3@bJP2~eqag2+dsQqxdWnbtHe9Z3w7c+yz1>C;k`LW
z-GVuWwAdctIiTh|p=K$vms0gg+BISauc0;Tkf@;4ZIM%&2V3mM>77N|5WfaDt{N<5
zZYEc6%Vbem-C^D`bX?PzT9NWDfm~Vx&)N8Ee1g{hDc~Xf?QT4@PZ#kCXWY?@Ef?*!
zDc1nPAEJjKnqp+2O(>sYDcd$U%L`$h%A>H`gm44;WVUTo7CjQ+H#lIWLp$4+lchk|
zWd2f;xJ7A&lWym;sly_CNspnjZT+)ix-|Z-*<0-p|Kj^r1HzJy-F-Ny^ZeRwTo7DU
zYObufcbpOz3H&g8+#8%n=-+eg_c<KooqB;-5vW6AoTds?UC;bZ<N7{|Lq7z?=b)Lq
zitn()8Sac$+#pPcmN42^1x8cqPz26|Ew8#|4AH}(57EmFtZu(rSNplHRD$=C(xN4x
z-+uXx?<@a>Ef;f0gyTMACjCqwIQLE=M1Xhq<r<_M>V?@bcCya2Ag0~$eS-|mbGK}A
zwFj4dUzk4WnBn~}16F6y8I)$wYsQ4vs5ncr@3_^b5P(tW4OOh}tXg-R0t4xdv|82x
z4lef_0vsLmp%MB;o8rQq7d?6Ba!;<>i-X*(>Ac;NsMF^~VD-NI8&X&l=V4<$!FxS*
z(yB&v)m}-?{MIx5xEA*dWmBr1Ib|;xy?TZ<g+dtCdWz2OwN!nBN%rN+eYooWT!S|U
z<nn&{z&J~OKcog>OF6hQ={%T{IUcqmP}P%*ijF1VAO>>)ngzkJ0@gJl#j0erN=^G<
zL<sFkDT7tPQ6a%zN^KAW^<N0VG!&6*1!tGxb?U9Ek(+X8#>U*@fgP((nIol8#q5AF
zU;t-Scx}5E>^mShG$1&}SDWC)J7Wv3@iJ;~-sF@0D|U}Ho@f-M6jp?7I<D13KvIB7
zF=*dGus>vrX`~A*z#GBHQat$J!2Y?WmBtEvdXaU;KGE||vnywptT$BxHMO>POx^v>
zQuRvP`?>}{&M_AihSJ(Z8?DFW$fDMy2|ZG3YyDn|ww$qF^t^LYM;0cd8%xBks;tDw
z7$ZDLe^%d?cjR0lTrGJ=VcYVoJ@{7-00EQoxkw)*R~(tXZ6ZBM#{T~)94;8Yut(&{
zvsVLXQ;-)QA3S@YCd&)wHNLo<%^oI-$nwFF2NEriD~pNpJ3C^9`T<{hg?!s_dXk_3
zE|}~gqH2GRcR@EY&X<E|_%GyHQ%UgtvId_x`tk5VTuW6t?;7v~cWEGJY_Z$=<eTzB
zit@)=@`mz5OnHNwcS?g#j{2&sf3+`XHN<(}b9P(r9qp_Q^~ELc5M-%6-xuLcm8Oqp
zm|X8S4X6o3yO{9x=#pRT#wTJf$vN*64-M93*lK}nwmkQ0i=@^TC%G`i6r``w{C3#&
zc~`iU+TUyvNj!l#u7yS8&92{ApZ$agVZ2*ezO{8aKd|-i>RsZ_7Q1C}WcCu23{E&7
z#}AdZ#NM6v1_yEgXJkYzM|a+?bS+kJy7dlDz?kINWD=amXx9fHW}}mF>${5{-uvL<
zvFr#~K2=rI*L{HZE2|EyKClN}X904=7ct4Z#4YZ_EJvHEj6!2|%h4cA$my7FpHBm0
zi<c+?iEDE42%QLr2*L+#4D{)wee#gXB!tNY9bu43@W)eE(pp#301=c0Iph#7GVMAN
zq6WhwPP1c@^~ZH-6}OD;VR#b{9IsQj+o7T<F31uLk8K{J*8S?%vp3y#c@JQ1ryqKk
zah<0hq`lH<s`|NAw~Wpz`){BNXf!@1+jP)=8cjcq#!K0Nws2H~saZivzHoqui|WP}
zhZEW@xMq7yGWN{=!*+}nL0c!gJCJL}4h>iRQR2qqh}^|yk0P-i;t8V}aNSuvM7vn*
zEtOC;<;s24Jzg!0XxndY8@=y38BaaHLoC5thw%q@Yz>C|jm3j$myvebWK?KmcMxa?
z#hhm>r&cM6D3l^_I-;tT-0`{=*C(};JKH>%PS>Y?*nYJ$aXL`J4+JVMLdos!0Ipee
z^R%SB3!B-0*KF-mkx@+sEahxiw2z}@$|{3>pVr2VYM+TP{reZ7C-Bl;wz)Z~`C>=w
zMf19W13SSH{A_;|5X|vmrQ7u{d{lEA9fWtO+|y34kh15}+#GAsGmz*Q4r0yKG)@=$
zndpMPEpre*I_xj>lDeko`?kPA!Osi|e$L+{)>Y|luJd5AWmP2TFfJ2KNa?DiqRuU!
z+mU{ZC3BE%iVl4@gES20<mQ`-u#oVoo7&ikw?~iH^KYLC;dWH8Mt;XW-)QtZ)0DR@
zQ+8+vxHK(j<7bvVQS-}Vk}owPVoL7rUJ5Xjxs)+I*CCYt86L_h#Q728g>*Id=bh9;
zxQx4OnuZ(8^B!_bhw9C$TG#Y?s3l}d-!(Kxbyd8$wPjM+iFXY@NUomJyRx0G67URA
z0p2-Jw7H5~TfN#QjVQ`<)(&KClcI3OR5&ThbSkJl4cXIcXsA#Dwve-SoT)L9xare!
zJz_+BZ1^6-oO<0>k)dMvP$*AXhL^da0@Q3?=5~JHVWu&dsAgBG##G5;J8H%0aTK1r
zZy8#n(w=fEjGKAltruTyiwiS+B{_Gb)0MRVCcCVoUT%hl*y&H`UB#v&K{}n6J`Rw%
zYM*h!QEr?7TU^x6Q}4*iwwvEI(2Mjl?X|MPEc{Cgvpfp3JPWhD3bXp*iTAjfHHoMI
zCnCyOLPaJ;CVgh56^ZRgJAHfjP_9%IaF6||6tjAD7#`(X3r9EzCe2!&?n;dcx`C_0
ziGc<*bM~or-v7oh?yRWuTYKTW*ur_^3g^WY&KqAiFTQZz1lv@Db{O4DwFzH^(_KV~
zZECr2iG}`K{Un}Ru~mni8N%TfFCtddt^Wz{Gm80bHTRkQ?AE|-8^JI~RYjfVYVI-f
z6^Zft`%OxPh8H@YO7vB&xT@Z=^#jW|yq`-T@TDK;WR~BQgDrU+_-4?rGjNXF@D#^8
z;W1`4y2LxINli>@hL6ULo*6Tl(hP}NC1ci*2oXsUi4-Dc)Q1cgjdRBX0dh@;N^7oo
zyX>5)F{ph!dGYPS_?f)V`qz8)0U^n#*UmK#A#Ur_Cb}A%Zbk4qemvO4!XpiT`L$Cm
zniCnJCbY08&4M@%3PVXK@4)aGdxoJzM>(Z$m(`-2>}OF9Kj58zQ^<w=!_N%mZiG=f
zue>j}%MDv4Jrt3gv$qMGZ0Hec6E@j4Ve>?(XJHF&8dCC(tT5qj;Y6!hxP5^jVSvMR
z8k|AG_*ZMidd4|A!W<&o8JH~4KeJO5N-MY^{=wcUWQ&u;It5+-RUk04t$2u$p<o=e
zn1t=7itgi7-FYQfh?j&*Vi{Raj@v%V5OSQaQ3P9)6w=@zMjOQx2>B_r$Sgz1j7F>e
zB^tS+zhr=F3FnfRK+EYwoA*jdgOH&q><A8i>ZCu>jc?L@d1wBSE0i>86Lz^R!tOX7
zJAizYVe#N6)Vm%qnsr&aIysIt4@=^^?4b6LK4Nej?`(*aHpL}vmScZ}v<KgEtE+ig
zq%veR*NGtb2hk6l>L9H#C+;{c!<I81wq>vib~;8$j!=D}&v}3)(w75s-6xDuL~JsV
z!4S9eT(EDbHZ&NlcDDB~T-X5iwKI2FvpLFK-_cxeKIX@VZp9pv{e!)oC-kyH>#w*p
zoU6V=&vF&d>1fGAiVe*Yr#vbN3^}TM($4wCN>?PN{T%!TLYeK2v`iFu$T!$GK^q!x
zdjCR%j48g$hKEOmM|S8U%{x4Y$9^2NOOoA=SIDwmNa^M>=g`gBEOIi+L|R{ILj+y|
ztsc%<CQCqODH3%xl;jlpNja91=$0KF0Kw)V+KpCdl9`55=x{?@wG*m4sN1wax8B!r
z@q@M-4jL}dD|luo1&~*KJe^N4W`g)@--KJf-5}=tZJ9pUp_mp>dhU`PuXYG+euIcF
zHL_>Q#OiP`x$wR=#@VvNPRo>&(g-TdR#|PP#jo=g^kf)xHxE8-478$o4S!SLxr$>=
zsosOPF*2R*t=4=|RjQ~tRobeR>MG^wm2$&t^58H=`!u5x+O^|^+?Ht-fM3_bMDcyR
zH&O1f2-JMISxnZ;!b_#Yh2An6g{b~73Q_ecq--omS_N%G^l=fCAgJ%KDU35xm{VoZ
z5sIL77p7GUrQ%`RA@s|1dSt7@&Kd5+qZUUWr@Bul?24>)XejiD8<E@@KQ1{{JRAp$
zOT_9Z4ny*a4ez*?Mwm~?yldTf+VLwzqx1E_M}VS^yV9oT%v0qMmOmjw|JOG?@Gf;e
z_@3%HscNd+t*(8t=(r47Zg<^1f@@wcG7Fmhv|)p8jO2>{Dn2ekZb?nDwm=F7-YCFi
z)QSlx(^`C7OheX4ld$*F9=S`$PN$Y`9oiU~G1#hoqCecGKt125>bSaUzvMv5x@)4B
z*#e<enz4_hGX(GZL;YVcc&Eytys~?`0OWDJ%Ok*@=&*Hwd+<E~tQG;>asazQgmWof
zoE*i(YUB1(04!QMcuf=lm39CHzy<)Et#{SdE0U`z>wfwjfOl}_qQV>FA4wa(b=-B7
zM{$>KFc_JILPJFxQ#|<nrc#@^NLE**8GOWCYQ;86*h3j^QH^dlMsbGcq`&W>j_ccU
zj<hh&CnzZ9i?X_lwuMKrFS9rrzFt;WuOCYBXa&j^p!N<L4UIQEn!^^w6gaSE+x;o7
z_=O6xf8598$cflj#1FvJlF@CSi7tvyivb>3hdfo5X=+;2A$ps5UDesotM00+YCktk
zQ*GmU|ITmh(7G{ooo!xhyfgZsaYwWHytTO@9XA=r4zRY1&TzDRW8bkAV*a-0V{7$g
zqumZEx3uq$!O*aI@HNR;oFVt)=yMdl(VR9WhL;FHV5H)1&+}Q^G!;Ow4Atw!8_Z`v
zH{Zn-&gYhC&w4|xoHK=CfN7puKXpT+0y0(pra=FizY3M}KP*uiY2|EQ46R>dU!n~i
zMJr#{Q+cI<#vlBk#m&v;=Bm3WqmOaiY;kk3xH(f_J*cOHA8f4WL?Eqg*c~z1@vz!Y
z1LV#f&DO82&DH6kns)q?HC=RuW8XFrKfv;h-84sCb}d`oe%RIKsrHLI7S%~<4!0&e
zQO^BrN7YMy67J>nOq91XTM@Cd5{PiJ@3+;Oj$7z9oyn%$T!->;JCCia@>!J1yPvaU
zHzITwQ#^+2bTqbIw!vN;#og_D#U`l#vtBjT(D?uvc;ScMBPY9Y0?!4{`MU}Cs1OUt
z6XnS$!$hb`&}IULi4f&j&b!dLVno2xTv>vJdByu(r-rc{4o#2qXWjAWW7;n6kT1@Q
z#)Hi-3)2GbN5<1p+ZI?18{M=mvsihG-i58Ysu#lOac*X@$wOUMS9AQg>Ss8t2AbJw
zjYz7E9~ID#i%vEv_1La1zONT^Mo-3=EE!$85h{Qhy@-Q3qdHx3SOSI+U~Y76a?J#&
zpwtGBFez7uBp17K>qU6nb-{fb!wqRN^3E0<C*m-+UUsm~h7EqQMAsxcS!pob++y4a
z?NuQnOv`@IthlTtHcC5iz!m1g3%i*8GMh}I48?PlqOw8Sc-(F(&D~5Un;=(1_e#6(
zv*2Xqeb7JGGg{xiIC`$hy?@vhett5?qEoq>hL&XKID&+B=ELx;vXO}@i*b9$6dSdR
z&)#?0!bHU|Wn<7VXV8XdmxjBnf1=PbXcr08F^FOtq=zL`^7?nBwXszAz)S1pZVJoX
zpBylV%bt5b9w)CsyeUk(Kl#kF+&PhQ&ixQk8!GoRw0^gta!>eZgZiDtTd5Xz4t?!B
zIzJ90QL@SIkjTEy(n$gHJnFFIK6@cg<HVZ=uR%t_xx?T!H80%fy*M}2t)Irj%QSdh
z_N?xxb?puSVtCqj@8Xs4?1QKeZuNq^SGY#7oZFh&ksBj}gZg><xEqgP)9YHT;@Y>|
zhmu?wcppvuML#9-qic%VEpIvFZ3vr~5ysuglauJ!v&|44t7og#T+JKzPdin|axMO3
zJ{s+2%Upt6Ty2!gSM@l);rT`h**9<;@6vqAibC<_?8wn$H%5Z|07TBv=n%DY7}j4i
zU;}ElEuyDMHLgH{(ukl=w9T`Kevg9gYe{7wema{(%q5Li?E3y}(^>vt&BAu0n5nBA
zQ)!&RR*&OsCm(Vb?9h{b;Uqu5eL*__w^Wn5rZEn%#T4u~PFZ%pdOSxZUIlsweE{7D
z-C(^wHVVjYI$#>QrX~)!<o#(ghPs0Ms2K-;cfZ-iw+CHz^t%LOf-OcLQ>bTT*m9dH
zEx|q>V_nKV08_RHue?NXEEBUj#v-i!v^fRZaR@zN`CUg5Bv3IRcQGLRci&?{`?o<`
z8Xc|DwguE-6RuG}>Ys_{Yzx-%R3lH@MW`_>IUu5E?9XM{rfhQ@%=9Wp4YBlcfsX3A
z@|QcV{FNK2l30ux+{o)04?#akwTMy*6_n}>$NSB${Op?2`<O?fKEwLie?HT`<F^<M
zn7j%dbpXA0pDoSgB|A%3{n+bUTs7m{y7o2qaab_?vzmYWmXLXTDL+ttdi9B=S`Sge
z(jFXuZQgG#RmGV-o+#8}h*IDUB=D}*#9=~2pFd3{as0s6H4|yt<LN9Z;BJ=)+9>oQ
z;&cVl3K*YIm<c^W{Ij9z!=meMesy>d*RTEuzgxEx`(N8)sghLHTXA}|VyjD=E8|wz
zMj4in@uYUOFz*6Kp}c3n1bQSA%SOaXB4Rnb?NG{8Dw=91nc71@yee<m1zk|ZkPQSx
zxqwGG8sRNfhK;*VqsSIo<S|;L^yC(P5=!J<S8SC)iMn6q#%g|&4cwo@+DDU4k+d_G
zw25SGv7#1{M@uYY6L~t`qITpRs^;^Iz(^Ew4|9J!^ZqCQP#+tukFBQ+<?!zMK*~zM
z%XVgyczv?>2TnZmyr{6Dln<^{pQ`5lqSdqp{OE}GVJPLW$gfUA!JpxGi+8!5IFKI`
zk-@Y8ZKtg(w)K7K$1V5$D&6Yu-)iggO50Sj<>2i(KC|EDXPMVq_a~bzx)l{JHaC23
zON6ii&@-ndgw(WyjbGJbO}pMBC&ZUd*dL=Z1XYUgVBEF?Joh{^MLhaN;T@SW$m{uO
zH>PfkD~h^KhZk2X+LkDP+Z?{vd|cFi3AO2FR;EtJcwMreQk&pU^)G2o!TS-?h#(^Z
zGI()8q%=KJp1&eJQkn#*^em&$mk>8P_Ia_uN3KzeG-^hp7HiZJjhfY{!CdZ?F_Dud
z%L{{xS8R5{fu^5AKOTnz6?EY=YV~`kISJYwP1@B6fH1aspWLFwsXrY<2vJYuG*une
zZb;}lE0m1{h)>K+sUk}zatO5yUIW{Fe7U*#midahaPV4itrx~g+Tuhlaf~faTu{2a
zz;LSoqU~|4F^<#6IZ=4%8!Y-*043ySsjh+|<_2i0`+@hxtrK$83pY}R3VA`P)R?IY
zbD?3GI@p>(dd^dzm1;7nBPFaHb}RTr^UI&7U&e+}ytT$jWAlwuXh3J!W*Pt$)cMrW
z680+fLfuY2by)J(_`8`H93n8e9)%1^PY*H_$;_oPYaQ4(aql9<i6zqEnhp;xK}&a~
z)KsObDv}zC<hmkxafY}+D+eyX->J#bQT%1llS(=Z;HXBgX28J?Ib*$=#T&MIwUhFi
z9g}ypfIOSP%3_&M(ThE@#YEn?>JE3ykYc{C`MPwUyYO)GX%VDJd-@6GG*`C%o<|Qm
z4DOq0HhM=kS7<iKp6_G6Al=79kuZgee*2#xt2vLipOLk#2Rw@a9=&<|Zy}UG@=#Rs
z4TTVWV|W4wMM%af`x`!ta{AX`-Q}6GL}mDIifJN~C!E<&!O4K_Dv>kCm`$E8ewAhO
zl}{qjWnc%muC$fl@p6m_<P}?GS5SRR+ytX%aw0cjJ6?5iYGdb4*gl1KkEgdypi=#l
zc9~Dr)x>>WWw@yjbD)e`#z9A2cerxg*9x%{q6|Tsz0Y;UB5I4JA71sO3fyf~cBS`k
zjZm~f>9eo?e)M0Xy?!%IV-!{0^=mQ$Dx8;36QLFqP~dgRBpeS^IBCG`@S<d{8{kBm
zVBc}Up&r_pk+{vk`uo#at?$qiPI%b}NBb?+_nOaJz1^MnZRu~q;eZF1vn8g@liBz8
zNZT|9e3>{F1hM}R>oHPyGR}u)@7r=6s!KXOMeF`?*)~mtWPE6)Q_XdI{7ricJNK)D
zpCp|(w+(dJ_xGc==Uq(Wxb`3ICD-lRL3=ghz(Ve%ftF@en`wFTN^`xwokOKW5Kii3
zT-!V(v0{SwtFn6mX-{yw`nJnHFAaD{l;b1W<*a<>>k3)g0f~imtra=s$o35xYeR!<
zi^q`%1U|~3JUNSh0)#p3x&r-8FRwF;+hvp{=bv76rBevSHlZ`KnES|X#MhM!;HtS~
zFF9hTaETqwaaxl7;C|BQX4CU7+&_hVO28y8gyB8qf!%!2!4Z;R5AaF^By!P=o|)?%
zX!pMRuo^AkTL}Sef%d^S6-?QIU|$9j$~AbWH=3&YcJ!(0L|p#cs?uxTM<%qtCUPy}
zxxw4VQK7VO+K;mTE;2HlMLgHUK+sHACj-CfG!*56cED--27Bi;NgLzV!no4cur9Vt
zgQg4KHqO;DZf<w^>O_vx?ft?>Y>uI%JP~b@$fj^EbRH4?RU&)N;gqTY(jVgf_TR)A
z{+qb+$KvEI86FLWP<22OM_FS*MtL+8NYNIOk(Wq^hIF)vt(V15Kd{=R&30+4SnU12
z)75}xM%+ro=gON!;;Yr?b~hw*)=#UB^VaV?&!ljCpPiHU`m=4HNUhded%GkXf3_Z1
z?>!`$^t1JddhcWj6vErod&9&-e|G!%L7(PN&1d;5{trYQ?vE9gw)p<p@+;MMcQ-Sh
zt;DlK<as4PG>tnmoof|)HWN8<H{g|`@e{LWE|*47{B*DeQu&t|1TrjDo}}6{TuuUh
zvu|sOW+r;fRGd;w*yEndPD;%aPl}unc@tcxX^{`p*oOhX+T|>LT1k{4mZdrn&P!!!
z-7dn*qzRs6B26)wk$>l@p24YFJb5yFCKoQ8H4}!$$!2jGv$-X6K=~JWN0xH?y>;(e
z2hZm!ohOx=PIir&?^5Yp>7zgHY&v-t(#b2fxKe**NM*GCxRgHKbBcFS&*hpW1Z@$%
zTP*)RBSsV|LvsX7=a7GRtXvgqpskXDHxn9O;F`blL_2hJx5GWOLx)&=mcJM9Ky<|)
z*nA9m#{)$3DDtd5$ZOVMPNY36wD^B0(JB@<r;{`3+}+|60al^yPn26}+n?CoOdI~X
zsLa2Ef4syi0agt`TcJ=C-P2-(g!GGM(a~tr(R%Inj82`ooP^UgA-phLo{=6tJpFbc
z6CXs<lhvb?f7t|nOr88zS_<BzlR~|-E@U}%AEjeVSGqhP17dU==xZ69#6waY31fQ_
zHpRvsq3MtaNrhBH;*#R5RQY0LwW5lwc-4K>NJ+TX>Zj;X$iVqBY9ynuiR4M?1<E%E
zc8nScMbfKo76idfFLuf@)8**}!FwD&VGenjkq2~x%mt85V6M`o-%3mC0XBCzb@u?9
zApoldulpwP{8S`t8tE^gbrO;}U_}}VD@`;%Zo-FwkHB5=s`ID_CR|~qU<!^e2NStG
z9TUeNy}}g~#V62MA}0%(mx00p`K_i1f0h)<3LYU4?v)M%zC;oDG7#uUCV7;M!c;`@
zhm=Ahd7N&-he3~k`p-C|I2tulP-{iXa9c&80!(`YSG)`)6`=0%v_S#GBOD3v2snC)
zR{v$-h^C`B>PhB+2WcogJvj1z1kS(W2#qM<s;9|F&QWL8QklF+?%f|FU@S`|<&##(
z3R1&MX3}{CFlK1Dq^04n7d^}w*PJu{>+oeCCaw8!-Kdp0?C|tdc~Yt@X^vXA!+QJV
zGsIP8tb)dqV%7NKq@?mh#q7ul7O1!gf9u1d0V_5+HHHuslFwD=h$VidT&LZUf{FMT
zs|q2v&)-E3<b!I}YsE>ba>(k{|5jBgsC*-;NLl#PYQG{*Oh}Hn1EhTtLdK{IYEkeo
z`kAp>9#|Y6j#85%bv?zd+cNyicR(<EdvG0<GVd7S9Od?TZ~B3yTE4kBTn=qb-dnp+
z4phQ8>c5L2YLz21ztZMX(T2#Jajs7DSwF=#(>9P>JQE)Ep*2#}fvy@UAJ`!eP-D1I
z0ri0$IY(Lb60wQ~6N<+X;SSvc-8g-(`<$T{PMdPZe-XZ{CTUI0jL20pJk>dD;vdmE
z3Bd9$kFbizB~Ux4qET24hV-&oZqwu=R=X*}->NAZ@Jh*WwAqA+sKHVDpne2>tOws8
z_>~I0`?t?udkn{4-=}q_y0CJ@Nq@v^vZG{Uu>%=Ndu8U-aCwjwDvSqz01zH4f8CY@
z2eS1p6xr`k$!ABq<*@Jh72(|i+QvS;ai26&=6#9+0I`)n;ESkM%e-^(kOI${3vM-y
z^5;ms%)D}W(*#YUGtLZ`WN_yF%MTV6IuTu&`X%j-x0m^8iML8#T5M1h<E98rlpbkC
zD{Y9R+R=Kq5gxYyo8%v|O`AdfC0`7v#(p_N{P#A#jf@R?yf9VGyY$ZYV>?;s8h?kj
zX$N}aaJBqRxp$)M(3|ui!fL+NG{)Z*`sb|sm#58v;EFR2ICp1o*5k_si8bEmV4dmY
zEvStJ<BL49m?)}CrV<=?{4c)E@BQuT8*rsw4TXCuLLehZ^BGGzFwnrrRwMTw?R@Ap
z=(qbLKuweW6&~M5@Kjn=sl_C&Iz9~W;4<!itV@3HZz(*}t9ePIKOw55a+=QoQt&J*
zjl`}d{#nxWdB<8=Q>kN|;IR-)LT;+HGF7R(EQF50f>&6e6Js!ZRB=fpA!+)D9jj$&
zArF@<5f_Y*H$F+{rHt-*DQDdKIpZ&cuc=9TwZ?np58kur+<*a8oylz}t%{UZrAk$M
z^hp{$?`qcS_U*+nhst6SoY1EuQd#ugbFlFeK^iS-kDhlqShw#W-mOvXF`4Uh`wlY3
z6QU%AsY;>SVG-PsCjNshk>Rt{O-jEw$OL<-&~)kOa@y+HH|?rYYe$@H!v3LOmSEP|
zX6w+(%D%VKDFl_07KsXepD#dj`9;Q4#gngB5Wh9nXdnlCgF0RMc8)l!ZXb6en(iqL
zw|}?K`V&*NJkv2@VZiXt-j(-wUw|Ed8F}=ex8w(Vucl9QK2)<EO>gM#i+I5FQD3a2
zebG>{d<%V-i|^fjj<zpJCS*I>{(t=T-?lv$+tc<X&vp-vaE06fB^n4ci=+AJ9Mx;=
zI3Id*6UL6N8(vJXkKiq(@KRbpfVX%5cZ{9*U_uFw|M}a0J9Zkqd&W+@*CS-oIlQ~s
z!h22Zj=t)>@_}Qyz<fIzcU8UC%A9e>a>k$S?vwYv_db3D+`H(Is5p8gIwv}%bgF99
z2-i{l8XVBOmG+v~9YOTX4`Wr-iuHrcb;YE<dPbylhUYVW^+H0dnRcuIj+DkXAL3#4
zbCNgqkC_qaJi{}<a!Ta=7w2JawC9cP)$_16SPo;|rE5g%1mjnJ_1<ordAGWwUe@@l
zo%X}^LO+E1MD#<U7rK)L)#ii6RaNCB64deb*%4%GwRwJVl^Ku87!>G-@<@4Eq|g(;
z+<VurzU)VI`ZVvmj%>Ma>^KiBxnS?<puj0;iU~&d8JqiK70emuED&f^q}D-*fImHH
zsl20z5+z_~_blky!wRYU<Q!G0mdjK{@<T<!`sN^BiUei%kJ=z-9MbtX(v{u$J#TNM
zLqU|B`AYQqXJkesJ7cqSaFn|M!>AE=M!m*Nu-u?&UVro9BQQ`J?|~!5z}0}hr=5i|
z9>GFi8tx{fiXJ+i9qy)`9)pFh$-QBI43-HNcj0RXEQ6zNP{_VqZT|x-%&K1<Sos|m
zE@!;77e4L?^>iS>dxqfoJ?)V2xSI6ouYpYb{>YHmqr~Y;<<jvg`HW(}xZoq9n9)GH
zC4sV6g0feQlgZ=cWkD3Eq<Gn?TjAq{*A8e|ua6U+VIoPvAbuQp@iyXNQ%a+ujlEkW
z@>ihUBYh#mOVX2WrKJ+O717GlXD+91(9&92at4>4yL^6X3QI6O&W@vdk(6q)Qj|1C
zo$}T|RjSpRDw-WB%$q#u=8;&1MF|13hO4S>$_+PF1-Insw_;?`vVs!5DpGGK(pOdL
ztF+)&zg1WCQd*MvR?df#>SS?UY3}fY`wt|`5hcGlKQbx(=IAjoO90J$MW{M7gH~Xq
zTJ*A*zOI@Ouu#Hp;N361E8d;Oh4nqn&Kmwa<L%%7*dEtm?&s8F-D8sR!EJw++g<Lv
z+|gqRSYwZUB=X+?;>KD~{?cDSm%Q|n_L%3Wr`ZYMFuMWiYThGMEqoW|Qc!8FY=AH{
zQC1Ttl`6eFysG@2Y8p^hjU&;#-RbGK4s$h8_QTvemr5IuCdp7vb)-jDZ*r}z)@S&I
z$H*fx+#$wNGseEM!4lv{&dX-*ZvIT3WW9OfhPg>U*8SLF&+{YPe!O~VMx^VpJx-%X
zbe?+HnbGGkXN|OmzbS8j61kV2F=Y(g?rO~N-zC=RZt63nH6!hofPrT(k^U-MfdAba
z5dl)Nfzr9x#a6o>`oiz*>Em{2bo-2FobG%ixz=uJdf4%am0XwUns2uLC~r02)ah=u
z8gA*{(KlD>o4?lU>h;aKTeuP2P=D}%S$FG=ddZDs@%_3Db>@zn1U!!ybvvGRvu*(I
z@8GW@nE36)?MVp6C5NhMn@osg;zy9%UOd0y_RT)K+~X;(f$Rz0$W|H3w`_%Y@s_%(
ze^`T0_NO?^swS(e(GW=m<+>ud1I@df(!+1zMsW~yhk;W&!&`2+Raw5vsb;V}z2GLf
zCOcbh3Gl`VocWl33Q*U_ZO;5DIZ;l>K9HoGdYBl0SZs~6s@{@k``Mvz^03&H;q}0^
zGs9<>1f1fw053~`4_d(dgTA>%{sYwVE+THH=I_cm$TTh>Ka6JL=MyqQra1Kwiy-cH
zP(4&GEly;r5~)6rE4}T!J9--WTUg(PuD88iP}|#XyWC4esA^7kRnwcx&wmY(_w(nQ
zKecL4_e)pZN>93(zSN5MGcpE@?bA4vqK5KGX{(`~1JQ>iv|m9Jpo${Iy$2!iDy!T3
z*b9IW$vaDE^UG>8l>P0<4wbM3$k30>M};orF@G$&(2|@;mt%Xl(Ie4??kzbiK@Zv`
zZg;gq3kvT0GdwrB>N7kL;$c6&q$R+UjFz<pc!ZCVx84H30PQf}%-@qU#_3MIq~()`
z2lsaT#Y&!*g^!gN?2yyyb70PUr&zALMM3Gm9?g>7$KKs0{b`#V)xV53@tFUz+i&-Z
zb4Ixw+sD1MLVxPv`eMLRWJNaZBB5OXOh1~5?=B~$t9^fQOF%zcfG@JL-qN?W$?tp=
z?sj4RdpV;+?;H${NhTX*il&D;+9U%zhV{AH(=bXIZ6SG>5RPO+W%6Nyo9?L`gBbH0
zy%&({ytb``eyy@|D|DRA6~txP(<NP4U)!msD%|60xrS`+F0<-k>)*mp+Hscq)!#lX
z9Wbe`wIcjvDXvMra_)fQXUshTL~fGf+&=m5l8hW~$ta1_cW(W^>(588a~(p76Fq%Q
zN}ou!mHO57&-?*ic*^!e1=>&qi-y*vg;3=vyz`1u&r*7-=iGOOvn<EC-+I>~XS}|Q
zID7!kae<|rP{qd1`b5m)xM;&Sd{6#<b>39nJK%}1b^QUJw#fc%V>t9Mn!azTCoRKm
zhO>K)v#iM39`UhQ9%!YTVBu$|<A=hH$F;rhKIor$Y-nVuILG;NQR(3^J+XA1pdj@A
zRqns5-1;3t5r^aaV(O%BUb5=M^UN59K_N|0K!fi_O_JWKTWy76Ldv<4!fmWDrZ9Oz
zm1z20X4R2Hjl6Sxq$*Nc=*^58<u?;zvf)M6y*vEoZ`RKe&vGf8#Z)p8X-p$ShT*N@
zH0^^D2G6>$=QakL(y-hJbOFr^FDq#p@6HlOGbw4}rg3@9EGYRJwbwVro0-2BKs1$t
zAtqWpyV97(#Bdad5OJ9$XAd)YBsZ49`|%2Up(k@iJbK5D*A*6T=B0YeG-f5YP^|Z6
zUKGzie$40zhW?q%hKns}3}hu<=B{$s96(KIJJo;CgQF&o_8$f12MCj=$W_bKE8ggr
zD_-fD$L0pU*l%TIo-*QN>5C&$j!H*mxzUJ?k$LQk{Whi!&T`5{x5&exFM?STM5l>@
zf^rh2N-rvYQ8*a+OpLdIrPy)d?~GW5<51x&*`wj?iGbq)9t|M`FPPcwIFMC|#bW~H
zyFGEXBlnU=TBF58p~B${m`+t<&*w$ouO9pTxPjjXx_|E}8A!1G^Eg`2=tI7bl=zHC
zZ}v$o=|{fL<iDRL@yTxVAU?}WWaRs$l7U=FUoy}sz7P5SP5<vV^G@GM20Ax_=hX!_
zK-A+};zS0z#dD<pcS0mz0#;SJDA340xHKNvR~jDm)31u71+i5HNyDuZz`bvCQMI^)
zHzcUeB!suQs5)K3FD0mMB!rBQPNfItIBmtBiiFFo@$|`1oKaaLl=4_*K+O1r)Ci>_
zRv8$Rov@t4(*uN_5o2r=WRmd9V)-<A(q+#A;ozHU(ZsjC<K(H~e~3n0_%-p6$nXx&
zp7wNG7VPASp%+W9n*Aczz3N(a#H~o{^ds$fx*&`vp$7{6e{Y;0EilRJf>Nbduc&aZ
z6<0t7B{xYiDKhp*SL_jcutZjfd4c9tQ~@;_^x?VdjtmMykQc4zidS7UbSlx%du=F8
zUUpsZ;%kJY92ND?9=tc}9Ks6e%o2O#A%Y9Xi-x8G(~kO~-#N84_HX+Ny-!~yUblMo
z|GE!ecItoG%jt5!z>c22*#EM`=`zSijVBozsYxY6Q=Kl;5exuOFf;&5I0Ek5JyLU|
zHCMdijewP&rGe==#d&N+WWmbf7yIRo)2%OFPkX)L_2NoL$M5$j(MCridgPodADqRn
z#H=NJJt=je)4|C8mpP})J`^!M74E66(`6BW>ITA5Z-{~DmdZeh62X3+;Ya4^M*;~=
zR1j^&8?G^IOuraqi~|Oa`cUrREO89RT>mUdgiyOICW6*$?;2mHY!^83aBN)v?EOL{
zupLhoY^-=yBE&dajH3O|zdteXCkFn+z@HfS69a!@;7<(viGe>c@FxcT#K4~z_!9$v
zV&G2<{E2}-G4Lk_{=~qa82JAg2IAk?eelhFQrDxS_MDg<vNP+ack3E+UYqHDcgyWX
z+6(O14IiIfKmY2;gmM4;@$=WW=2ksF!#L=RC3EW)4IlmGP-W(;Lo)V9Mfg7Wt-tE~
z<bmqAzg?8*zWHJJm#>IScVf;j4m>%!+5b%VGal8a`?l7;ub&n6@-E9SwsoH@=R6t1
z)F%rgt(!i5r?~CN;HUCm`bWy8e$id>*kjI@T~c2t^IDN^|Msi<ZUJP#y|)is`MYNF
zx$>kIpAVeYT$}UO@jj;}=1qET+lcW~rnf7f<`XwQ+qC2B1@GM)_Uo#J+dm9m*136_
zxkGk+^<J^}(lJl`wcv1x--Q1PO1n||ScM;N4$-i-%^!{L_ufkJy0`X6fBLL*j?1e*
z2G=e)>=Wfz|IflZsu2^nB|kML^*if7&VKgmrrq`(&s-=e`s!`jZ#NGb%d=MBi2UVz
z*oT&(rDrNnm8}`*Rs6=1lk?u(IOA#kk(9aqSE?i*tWCV_IeqW9{D8lH(;Cwy-x~DX
zI~9L_w==yt|Jway=g8-S7L7af)3o&uUwS^_M1<|$mb(kRzn=Aa+||?H$H)H7wV~-i
zwz;Ko=M!p8=#zbxB{8!<R{mwfkU1Tk`-H^>+y6`YiO1kCCQtqH#qivb%U`~HT{qt_
z%JjmDx}&d*eZQvNH{-#SRr}n2-Ze>a>xZR*0ms=(+KYQ;=4Gb!tseebf2YwQI%0N7
z|K-2~smDJq=N;U2*BWihp31%2<@?QizvrK;)fZg9@>AiSejnT4-8&&pv{QNF{$JGt
z0#1GAzUX1_%<~a_<?n1?Q^9VlSCnP`aP-pB#`lBftkVv@Gvns#yZ6oA_{H=WzpcCd
z%$ql4CvTnU|Ci0H4;@Z<;>Y)zz8v9ve8UHAr~i4bIce6jQ#4Vo6H7l#oBZU0zqgEi
zTI~7T8_CNP%a;Uxv|`A-d!MJeT^Kdod)Ze-JHB`N`mLwpf6W-5^Br#*<G<ENGBC92
zZ<g6--~O+kH%*&Vy``bgO9?e$#Yc{f9Qw+**CIRfa~F0nA)j2_dhLbERbC~Zw#V*Q
ztsFM`YStj5;pLdct?R>yNCe@X|7;$Q`D6bP4g7;&M4s*K$G2bi^21Bs|J_f$B<7J{
z@G|8+e!)w~Yu)~CFY$Bud%T>B;P3GgrXTe`@)FUQKX?hb*gKXG$@X4}Y0{~`e@k;B
zKL~bjt8IDJyDdJSe`?&g^`H6XzY)=Qx5uuSwdWNd+ssdI|MCm+_~>?i{^;Fe*V(?l
zx{df$G=G0(-Z%Z@U-@k5{BtxbQ6?8rem?1^)Fmks99f5LPN~bcPLE$LbNI=gJNB-&
z7k{l<+U+OR?-tKF_LEN8<0s4so$Rc6$|FBv{~C1ft@_{ngx`@K^i?lE@!uAFptqj{
zpZo3)elo7;kAAZLF+W8QyLQRgcUG_2^m={M^e%h%-@_h9_ixX49#Xshfvf!{9_$(S
zqx_$%ZX3eQeQG!P^u)_1zW79S(Y>W#oDN!WT_(+3dH%TlwV}RFJ@JpV2ibifzTu~D
z_CHJr4=Q~3>W;oY=(e@{vH@8=>2tn!nZNeEoch9F7d<`t*3_C;Qu-v9<+5AfJ-2$0
z@9EY#6;Ex5Esq<u<kR1*AJ%;R;ng{|w3r*R8?)ZhKWqHr1^;&|>YUDs=B)PkXzlQz
zk6-3fmp%Vc;lthE=yq@ywl2G|wV@$z>*bOOAN|s}y`gVYH6OG%?CP+(HOmq&yknkw
zzVzOTl;meB7B&vAJw8}$KK9D2fBx#$+Bl(n#}~<&C%K%^P_MPF`vyk`_&wRRFl>sa
zd-SyFOI@?;UFWZO@`SB;ZCIhP`pQ2|le7bB3pP%&y_uYU%=e1%Ob}Q3<=PQ_ZWdI{
zmwGq6<?Eb3>WRrk69<2I$Q*?iNn#S~&OSHw<hD7#E`BoiXZ_!nEzYc2>9z9s8fWHM
z*?s#*h9C2j-n#SVy^lIqE@@PTk6hk^EBY&T?IUsP>owpBAHPA=KgjQi0X|-0($}qz
zs{}X9Ya$Jg%!_b;(aYaE?li)W_KG_U_lLdwJ!yA67FN^k-;Uomdc~E){a-K%i&kXh
z=Vi&`=1p6ar`5{gTMo@uL{qr%DVQfS;qFN@{joGX;XU7GuguKO&RQz(PDh?gojjS=
zIWlhI2>Kh*{R_Xqa{<5b3qKX(pz*>lO%^w01R0-3O%$QY;-*9rb?Qt<d>SDW(;{Ia
zV1^?eX3B69KXDpKn(8RC8#Z!!f`LR%G>|7@LScen2Ehz~=?5c)af9JtL@-@Qe+Q-$
z<~q#r$IO+-{NHu^zrpXhUU8qp{VB}r3BQ{ya8vW|!XA(7@q0`)5Nf<(2EveT^Hh=}
zoW}XX{UUy!gHd&xQTTll=D@t)&B+V{IR^iG`0WWloNgf0^!R)K_Jq^6>G>O(Z6Ghf
zJOlHl7UgxjX*dm=fUtAjZtC9#vmAz|eGb0~FuniO+T1A_1>i-GUtCy}QJ5u9%2-M#
z<=BkO1-<>_mKPRgFIpy_g0$-RiE{PQrP(y$M<s?w<{;cXW&_;xFJPU4EQ6uH17QeE
z9?Tf(#^3w+?J;k{y$5E0cNmRNTD)}G)Pi{li<XR*Ket#OyDWCOcBwpLMMhqJh9*B7
zV`Itkyuugd)AJT)FJ8V(p0`xq)Af4B(7ZfH8euHOrc9YPE@M$<c7FGl|2|t<wD9*c
z*}dC?KtL<y9Ki%4r|h6ABJq`wXH_ENOo9@Oka-PC@K8xfxN5qy7s>Z?e#tTYLmY*W
z|B@4u|Fw4z!7mAcA@VS?e&qVna3WuScWo3QRfI&-aPl;@CaPdHJH?S`m57;0N~fQ6
zo=kMAf7T@t9bx89C(<N$GLz^gdXc##<ooq*=}1qAV}ZyO-1&lyhQi-6!PXJGGpGT$
z86qXgI^yd^B=Gu>EeO*QsdyjRONg_;>?(ZmyVXI0h>BB*Aez(FmqZcW!&hcMP2|!Y
zjd4g+HDo#wC7J<|9kfb1`Rg>N&@4jc_a(VxF&4K1!n=#eN+KG7>?P;cFDdqtJUj-j
zQOSobvrmUea&Epr!XzIawUThjw_jzs>c|twbq%3}S1F+wEE9+#%ouRLO2C;&DhMTm
zwh=GbRm2naTf_r)EurMaPSlVPGwB2S1A-Tu$bKr7Ob!t@*jC~S`v{?g)p4{RAx(s?
z!ObxEV_3)UAM6ey5yG7rpbV-IsVx<3FTwT^Y=6O)3wDrThcH-RNSI)U3wD%XM+^4T
zf~^wlIKiGM*pnIB3Q2-JU9e{g_FTbE7wjy-&K2x@hQePU*vkZarC_fTY@J}Q5$saI
zE)yErAlR=8c7<SX6YMI%Muva*>mY9l;k67Ue|8GCS+GA4?EQj$NU*JfeMGR2Gn8&>
z66|Kd{#>xn3ibuTZWZjyf_;T~fb>5Jc86f!6zsc#-6hyWOw&jN+gVHrG+wZ!g6$>P
zK7#Ep*mA)R66_H1Z%7{|*x`a5CD_q|P1p;AF-q8~;6GGe@N^Joc0E>6o;?9u%DRjs
z#EVUU?Zd8z?a!WoEoWUu5fa2Ezz$*8!wzFlzz%2KVMno3U`Ml?U_Z^ChOJ_gVaKuM
zuqU!-U{7XWgPp{F0ed=o4)#oTJM6jaMcC==>?0WK><h4S*}uPqsfGP!4O*Xl0z|_y
z_J#3;tYrVLBxDt<K^h&ag}sI?gk8#7-oj{NJJ%3mU?Y(JRkjf6D_9HCZ)0a1$7o{b
zz<!IJ2mA5A5>m_lqZZ?f{k9b2iyf4Q@x{(d!1!YS5sLA}X5uR=y8!kPwg~odc3&;V
z7kj4^<BJ`I^q;duNPm{yhx8ZNJFr{XQ9}s1%of4E!tR6p6MF}C2RjPv<u}<P*mv1|
zu)A10Y>VY_xc<NO)Ab{%aB(IUzj>f{<|SdB%w9HHE}x3UXR)?>feIkgau+Yp&ssEi
znLIb6pdfpZE5Pig>E`8U3QG}D=jSiZoHsdd(SmV{7cI+PxlA6fPMADCE&yqJXgl?|
z$ykzU8S>c0%NJ#3V6BVK&&Z**o;)sYidvq%C=(IOvJ11b<Qa?P>WQ)P?83sug}>)P
zQ>ElB%8^fhu>j5fDDTOW6XIw-z5gz}XCQ|64P-6M0vHX<R2UV^C>R<)48ITYdkY48
zYcY#|B4QXuEEW^4U&8EwMWwo-X~jG7T#Zhpv)WNWCQXN5kB>kD!n^^q8fG!f9GD3(
zkucvj{BC}QdyMUOKaG2;+aHME{=MSd;I<>a4!=F-E4ZoY@zdWP|Ko8z{v#h72sI~;
z7|1_+nV#^ky5oENJ-;+<BjTpZ84?B)*UR9=chY10;m*Q3yAoy@4Cg?8UuXP=!%+V#
zFuG?Q22MNOEOyZ_yO@Z4#1g0=bMhe!4JJQ-W+0xQ8wlUaTtk>E{Pb6h-!A;#>NY-G
z48*+EKy)`im!%kp7wA#Jz1u*ndkm!M0|N=UXdo+F5#DAXRev>*xdum?v+!qq?{J5`
zggya7zg>ghif;Gk-sR-;{^de=*H=h?-awo$7|29YPCA?%;S>GJiOS#M-l;c`sMU^q
zXnn>azyD<BJr+0XG5>%1j)o_}#Pv!)1#UIW7rz?FS(qPT+PZ(wcZbpN-liulg|p``
z@wS2VnCIZ8rpHfzd%}8td*XWh`a8fe%r=;pA2St?`Dy&CFou5<{`j~5xBjyK2W6E0
zhdkCGyytKBeFL$;?11Ta?~i8NzX>ZxSjoQ$fBf73TmN7FACyt>AM(gX`2Y4#>s(HH
z%sH2G5(-n*D~$T7=}FW3mxedWem5uKrsm&;Js#KN_w_9&JtlfUIWfUcO;1=#FLzHE
z{iSJo;(FJ0dM<Wo%d(d)lP_GHm5uEhT_Q8&%L+3VEnS$m49l1h`{<MCkaE&vo`U;Z
zn9pF2!PLXN4^sv68q5ZmRWOTSGGS)I6l5&Q%N#AAI4(gxZt=o}8H=*y*g<MhO#Jfv
z{QuM5*~dp!oO^tB_axaQhhzf*14KByh*1J85P3724X>dFOxYmOQj<smNexL%0)nF1
zwp3}wmR-<NYiru7<@WXkdudC1sjf;bDpl&G)>>|fmRqr+M5RLOn!Vp=_AD$B!M=Uk
zKX$^8-!pH|%z0+coH;Xd5=$P-@ien*J8H+tJ7nJk2|DJimY3i@2@>Kf<vLnh+TNEY
zenCt>qtW3E>NfkA)yhT7)0x?Wf7X>&tA5(I%bRR-ONZ6Is#WyK!@a}m(AMKs*PdVK
z6f2k;H1PO8=XFRO{(R)--FFq|Jhye>qDpn(tLX=(V^7eRCG2dF^oi)JBQY*fj_d3j
zmgqm5Ecp{%@baMA41}X4JY&FBK>YJ;7P&8G5+;a;A4!noVgC%4I)0t9;;wId#5-xM
z7g$a8%_}+@tftzw6>?`ZFu}Vn)_r3!YSxtt7L+cWZTFgZ`ns0-SnpX`+p(;H$hA!^
zwRQ2>v2>T(x_V}atmQDjtfS-iQSiY9esG=-U8wZ(zqZT|$n&AgjN99{$gg(&cSy~K
zmk!yi%HeN+FQh8r15boh6<qOHNY%jwKMtt|xN1j8HNicVj3;p2oFH>2crNoKcn|3V
z@a!Lj)CM@$u{mCx+JgVcqM*7L4zG*pIkqIGXA^oP-!}A1Ipu>lE2&=x^%MPh^OzgJ
zvtNwqEkN(Ame#dxjVl^Dtb%11S(CipsfAW)2e*GqyB^?HG2GR5G`2Li7qSqxY`n!w
zh84@uR^MLVwz|Gfex1olw}dx<#g+5*I`QIC#spl2Un&39{#kS9%`UAh#m_EG<$^`3
z9A+R@yaU<sd@o%w|4PZ@FP}4~!au8YA@UWA7HWOv3;b%af2QKq=*r~_+VwljBhhzV
z&qR+#OQO;H-p)SUTYUTrQCXddyBdVjn^v{e&)~hdewj6i-=*sHPFID5PntaAlIb&w
zcn_u?^|h^5%j){J<xMR&;%9AeK}%b`UI%Qm7S%6nX{)nJ<I9AxabEJB;0wfUtAnaw
zZBVTNdqDY(L1nB7s=`}?>d5Wzx)|2o6jWPp4yxURmvsi!`cKkc0rGEz?~M7oKFwVA
zHoj`SBZj8W^4<LB=^u9mmG^G)KNwVX-$XAMy)CHnZ4|8!Deq@Os^&J@`gZ!oXTcpI
z6@iaz45>YLhSb(Cgw*;_NEur~D*tZ6KOa)lwlKz_ciWeOs%C3Y72iW$@1?9S^BnvN
z*8_X0)2>fZ57=`9V~xOe3tJY}^7uIEs#}8UX%IRKB+ZmQh^OxxF8*`ri{}-V^xi%k
z50|(?8}W2;zi?uFV)#Epma@)N-kHMUb^D;WzovfY(joC;ue0ftG<|Wl^#3k#a$R%c
zs~c8%Et5unM{P&FMek({vivtT%F~TUW@}Tu%#b=_n*e%Jce00{U6@_Jx^Y=OI+~m7
zm&pXHjYp%^u8WbmAd|A|WZgw{GOE-!GJsnCRqZV4)FGWJJ2o?<Mh#Y@y{9*`u8jF6
zn-qz8Ww{3ht?|lQADBf~oHY}p4v7U8BX-+5jpf?!GGstaVI98#cB&ME1vdPt#wXx3
zm1bP8!`()c4o^2$YR)j4b$F)HqS-WBHTN@a(41w+#K2J52HQL6%`s#T!Knrqt27TZ
zR>LXkJVVA^Lk%|8XdYs$)jZU=Nprq&v*z=Sb#RIrZrq~TGH!*_RDmJu9BJwzBcS<W
z<CCycjWs@{xzPBu=5fY)&Et*FXr5r)rrB%Uu6eS-@*??)jL*WXkhnjm+2y`Nv*F$d
z8!F9xC!C_v-Jge@D%1T1?dLBuY3}EiQ8GnkxkH+>-SQN7DUW-L<{bB3I^1F2t=VOM
zQFDs96*iRH{F3&koA+qWFu$xh)4W%6Kl3Y^bIh-5?r+|wd4SoaIoJG}=7HwdH4ies
zq4_-Xe$9F21DXe$4{9D_epB;MbDQRT^FK77Z+=VjF!Mh(4>!N9*)qSQd4&00%_Gh4
zX&z;6*F4&MNb?2e_cf0({|h$Mh2{>;1?CTQ_(kRqHD7H0Nb^{8r{+Ra4qv1w{(zz8
z@unQsNKq5aU79DFKh-?hd|2}(<|CS?m|@LR%||s)Gau7D-F#g040E^UOU<8YE;gUg
zTw?xQ^GtJ(=2_;GnrE9&X`W*~t$D7wSMxmc7n;k=XEe_@pVj<PbD!o#<}YEV@|(|T
z|6=ohG+$-z*Sy61mF6n*dCgawzt((>`GV$;nZJPzRc*cqJ5`POTOIE39MJ6a{I6!0
z=XaV7&q2*8o^H))o|iPIdtTP;$o;)$XYL`*uH66AoRa$o&8fMsXim#Ltl5$Gs%B^2
zA7Qt0<-Ml;M&6NFeB||5eB=$yuE^0?e56NnO5{z=sgbudr$ye@?2a7MoF4g;=8VWY
znlmHEHJgzWnzJK+)|?ahi{}23cQp@)L^S6{-qSoN(yRGA`L!kVkGzO%z@@0c5jm!n
zqJ~6dn<_;Ojkq-DM_BO0-y2EMJS>u`d3YpEvlVe`9uY~`JTj7@c~m4*^Mw&pb3ufS
zNc4CkS(>LrvNcbQcwj?SL~^wMqmlla7exkW_D6CxS4IYEUK|;u`KriynwLcKG*?9i
zYrZ-%L~}GU6c*Rf9n^b_dv^ut7wolsEy%dSj?4(=cJS<DLF&cMP_>LeEUEM3RN17-
zBtC;UgLPpSV`Y?fHQ2j!5o!?2FVZ8VAN!$M__KkBygB6VPxt`*x#S$E&ST${-(dmr
z_<t~ZhLCP3dh*eJJ{U%x;goGr$_P@AMB6Adk0$H_Fa}%*3cy9+VlWmIQrb9bG@iOl
zK(7~_6DemBVUww45%MKq3VNqfr)kt_I%Um3zLfZ4!Y`xte<5!#HI0J4Zli5K1&jT{
zUya#s9d;A@RUM4kuPhv-B=)8r4x*KPse%xt;K&zuvJiCIB2L0P#C+LBX|8Ru=E(ku
zyg$Xx=9Dk6Dr574_wSd?^v9m@)^+u3TUcC@_tYkN#Iq2zqMmsQ0cTGkY3vlWO)~pf
zi!NCYTGd`(rxrI0SqW;|>RG*F(}zf0LWEs|+GWe?TRY@%#Hl)*UW50iNT`Fo?9|w7
zX&t%@dmdx0pn7_Ru7P!k*agPtIMx~J&e}q(;L4U$$=cd#*ILV2d(&$VcE#c+mts0k
z=8GHEwxw+gS+bx4OsuTaZ4tLsyt;|8@wQx8e`CBZC-=chmo>%e!Nn%TpS&b&K_iGI
z-tQ`3<o$3zYmL7Ss>9FoE(7X750JR{`_=-s?JyoMw${wXj&@asolgs}RUi9BQ0=52
zKMX%$%eUAp;a4LIME+aQpS=6_{%v{V<!!a|&w>RLz)(9Zo@M}kmmT(}r-SNM@GI~`
za3{DLlz;+|3lw<msi68bcoIAW?g4dR8W;rJAo3*n9>u=!%iu-u1o%FPm+dEBFamTD
zzS52xjK4M^-9+TxJ-n9_z8iiBh>kGWjQlz9NidQ47T5zXhZlk(Fb4GgJeKEm_&HDp
ziorM#uTPvKPXyIV;A!v;a2vQ4Tn`G*0FyAWnLu<L|5;GI0<NVVzlEO#w}bt=V|D&9
z{Gcu02u}kOzzC2I<odt!IBOC>^nC%o4Kx7<_$gs;Jr-0y0C#{Ea2;3-Bz_h=1>^$J
zB{mX0CVm4%2wMT(0r6}8333~VJNtc0zXi>2Ufy!{H!hxyuLaeKw^+*nWj#T)<0yW3
z&6`2h{RZuTU(%d(o{T}R{M5nbfLKVSe_4xlndKE<`K;=>oEwXsqO4w6zoMn1QLmK|
zmsl^^jc;pdI#<<n0S@IG9=KeK`adVn)x$j8D;yyu&*4{*_aZxaF8&dD-GC61p<Y8?
znj0c@iaLUPj5KVXtJjgePD!7p-ay`noWoP>D6+>Ta=Pk4?$UCGdK3AOmNV5`$fglO
zqp99T-jAHaGyE8GZi>iR>QBhU$TGip2f0qm9(5dfi%yfHP9X0>b})<hGx8zi6lN2D
zK{iuE)GSxMi`=2*fhvN$9XW%!#e2wG(j;%5>P249+f<IsIFOGa^Cw(nvZbu_5H-u^
zt(LVs<Q!%pa%iem%fpllc`LHaN(|(%mMz|LIVXbbV3v}KT$3U4NZxjtPic7+=gc^R
z(@*k_R_Vw~kyDw)WFYU*@)(tg96?TJR%0T!4iULP^+OIL8_aUDkgKvpzL>XR>Vurd
ztjB|V1lc9CALN2;DQleSk6fYU@w_dg2id`_C>MF-P)YAq1CjS2JJduq2>FPXC-FAT
z`5=#kPgZ%z#raa7BHpg4KjAKBQA3csv^+%(MRw;%_*Bl)asCL|!R+dM<S=puv#epr
z1^p#_25;ZkMEAW*m4#e^>|ypb0=bT|3}#^?kt3$G#pP-g@_sFssL{yxYMEc;DCxCa
zs>UFXMmAKZ<3i;8^Q512It!53Bb%zzbrEtwo|cV^k+&kdRA=T`<g&q1hfcE)+0r)e
z>^Dxrk<(PCXFT!_>V}@23CK&&7n^hr^dfH>sO3Quk-dY&{+;JdLVkfhfSflOxhPZD
zXK)enw`1~<OOV$ilV<1?<fSn=e=73!Sl;ueA@3)gdJdb89Er)pXCQk>L%4M*@-$?n
zu8B&xoBD{8DZk7|Wu7Wbx7SRPlk-#wmwBqN%u{7PEAv$0bel75&a~OIxu4BhHfP)H
zu{p=){x-`nD0*{YnJ>%iTKGJh^K2drOFHgOU9WsQ{Ct~-*(~n}GQYNL9%1uHn@7Q-
zf3(f=?jYAG?+?QA4k6{pdxWsOOGvo9PYBC9h0NOvZ5{`UzVS9sfF+*{=)x0io@Dc6
zn~Px4cZtnYY@TZKG+5pXrrSIN7JZl6Tx|1YHp>t%@g+9<Y%aCAlZKc0P8wb_4X>Go
z*Gxmob#&5@a($gNq-GjU$J20{X&{|$kj*rd4yU0s(@>g+*i3_IKMkgt2GdM~X{N!X
zy*jNJUlZm2;+g%ox&uWawc}Fu&%7bEab`%Zna@7O!WjNmooC9oh|Q{w4qk)K6xk<i
zezVoIvbud)OZBpb71gcRcXV*ht-7s#WlKkW^^LWS9o2e0w~(z<R*+|1SzSJV;T6@h
z%1Rf`n-h~ON*9$b@K^iiRO%h|x|U{{?k{e>zPaVbW~+QbMeGQkeSWS_@iA|IPnMbC
zPBrAlKa)FG{52JGizgKf%at4dAL!D8)wc!j<Xr2=-+caAGk5HD*FJaj*aLa=f|wg<
zwWe>KJ>tQtmir#>y>-?_&jr5vK+XjxWT{BIdPcM~hr@8BFto>i;*oG8@hJ|c+mYeO
zbefJVy(p0o&&hA%9cd1?GlM}c_LC5QC-F|F=y$nYrpx2X)kD?E6rDQWWw_i<)0yS)
zIQugxNpN@Qc&Fh^bxH}bpM?0k65`KP{t7!jE!C0kID_qFJ}32ey3;b8S?{m^NITx)
zPD|I<FISl0CiICnJ*UTyx68NdpO7;qvYw57QVg;0`yvT2XcVbC4~|nm2?_Ivcc(fA
zv7~eACm}vp>vv$kgun!`pB<mjKJutJ=?W9-#~+l)a(Yg0pZ>&){Z3}+BfQEYpTm*<
zL3a)FOlHpV@caN5IY)dEi-!(}!^s2r)K7x0OU@Dh9`)m7tL|SXH6-NslAnXG1`ToQ
zCn0{~IpU+Xen+a@Bhm*QnGVy@&ynTGc8H~QerCp}YJZxoxN~&<PS1a;0!|(8Fj7)d
zGEeF_6^(5rzubSPYmgd9vW$5733(F5%yYzNF(CG_{%Q5kK1aL<{nCC8mmY&+R!FEo
zj*d?V=pzn1NBm&QPdTkdrz;q8j{HN<5kE}F$LsH4lsf(XAHhe64kJUBcu)N#RN*3>
zKl1}?c=0*n3;UEWBbhTpdRVNGaXLPsz&_%5;-&xh2|nq4aBE1t^~I3-GJGcxf2Yki
zz}JCFFc(Y%QPL*5nlFXa^Mo&k=K=9gw|Oj_53+y)Z;|fzAkq1{LTVuB0ITkcVJ&<%
zB<9y=Q&{+2RJ&3KFKm$$SRC@R6IF6XNStt7wxcvPxMK0^;c`%svRNG>?JhWuE<256
zDErzbov-M@7<Uhi<=^&D?7H@SEynTiIO|OIe@r#Gm1FN3(lCjBdH5vy`^L+Vk{JKj
z`YrPRE8#Ztyk6>1(99AtFAt@xcDJ`%a&*aSEop1)VB&UK*dkWcNk2<3UCUR3ZPvK>
z#~N~8pshW2K1oNltG9j{;(LUUx)RI+mw~BZA{YxU046ZN6Qu10iSCL=Lh9?_Ua$##
z4%`e{KqFWNJ`R?E8Q@7UHXKr8zzC2J1_2Mq00!tKP25%D|2Vke(U7_ZR0{CVh3|x?
zz+=E5kP6-*><{4A;OAf`*al8H$6m(^99ipOF`&S4$kC;m)EdVQ7O?JhY*4dLrTdVQ
zJHx!-f=QPa&zU>#nvXTNu33BcJ>UA)sl2{fO8MrT@`ny{Ew6^uweWJAuZHt&`CY;v
z2XR-%_n=n09Ku~?&(38>CpJB|WZrL$7%_sxC(mm1Jy7}nla%d^H`QCq+gesy4Jc2{
zD?1JGgP0#8pROa{!SET3%dj2K-P2s^Ib7P`>D>Qnm&PA<#>KB+Y?0`AmYmh`tpB@Q
zyr2B5*yFBJ;mK9Xn(9|xU|r%@K3EmS*f)*yq|-TL3TnVUfC~iRF5sB~(9t9ErRZ=~
zagv~l#kDGxOE|~IUHjpsKxOb02ym9XGs@;Eqj~`DM4SFD)TbQjq#>uLUzPHrYZ}nA
z4<Dg2@LSxAgjry$#7#yQ@a!cH#ZJ~FD6iKTshQ6%JLSERf|T<TbW<8-<J&&WAYGb4
z9r@lf?FDol0((-cSjVhV*HYK6V!zr7^1*0O2#P>4m<`H7C8z>RK@F$_4WJ2hfHhzp
z2!Qoq1K0>Q0pHAQWnJc1<|yiQoZ4{Mz@Uz)ARQEd8sd+`@}=^6Y!Z%^P<iExT~ZB~
zEUR_h!}-tJNIY5|L9W3B(RGH{GR$HiE7|e@3P*<*(Kae9dBm8k#AP{ESgYhiX^b0S
zttZM^*DlJ9K7zJ`;3$Z`7tN<0J%p==#hh;SHvSTDSw@wb4;R3DVBh6_^#)u9SAho5
z0YrH;S`wxLCDD>d^ayEQ2a9nhGO5?)qE|_~94w&!RDo!k#Ze3@9N-eyNZlOja<1W*
zzf|hE=ahQsC8b_|8P(|Tk}{N&GzU>}JQ~)11OK~GbqiNaKjAbjepi&`V&z4DZ&dO6
zudHrKTSA)<=7nW{#LMr7K#^oB{{!K;?X7d93~CV&uj-=fgw-%9GcEe=E79mHAPUMz
zzg4GIC!(Db0)%oMYQ!!Hi)M3XpeOnQGFM#lshm*(<rzf<UFw!M4s??CK8|#$Tbc_2
z4WgVD&1Jzg5%T2Er5^&mI3;Pesz83|q1bn(RoJF<5#KD*r>fC@ZHYtGa6JvW{<7fa
zpc&{_q${R>G{M_MSE^G5;0<8A_~|v9U=P>|y1+iLfxMo1e!V7G0gv`nsZE5@u1e9C
zv(Z@&7J!A|Do_QMf;!LyR)S`*8ms{g)S(f)3|_iveaX$a-<=m&KfW}u{_@g&==P01
z<WtJ>b<&aLdqVlTaDyy5(_$DPOzUUTdAs>XC44^q`3NuBPF~uZG$lO<*=+A9uO+RQ
z=3~y;_3S}XMWfZ+deyL`$tdYY;cz6{K1}{iTqC<is$1)#(}(fWQYw<B4p8VDKylyw
zo_IHmi+W|8i}f2<BVnHa`_Si`Prm|T!AH=`A)fFRoYAM&d~PjyhrJi&DhRX6{W31O
zYT*0HzXfbZ?hHqx@||Tj@`JqX-pf7rAW*$a)CO#so5ncK8TQ$r4y*?|BroU@#-Ey1
zrMgMGA-hVAr+ZxkQWy?S5YL^W!lXF?qR;XNxrmzpT)+V)gO7oUU<p0C(n}k|htL<L
zJ}Kz-F7&H3*o1eY(+6Aldq`6=6q^E13Uww-T}fTxD&PYZ)ae)G*$tind%!NMN-Zkm
zRR83WIXPe?m<+<?-3R3GzYlbP9pEsiK~ESwNB(uR$Nkuan@;V;znt)jd7ObS3##qF
zoX>tNcmdh_QTjSCc?R6icMSQkTQG|LN?)IyQ>FG3egGT>M?l_QUiEP62J_6|8rQ>N
zxPbJP^wYcGLQv7aO3eigpp`Va=-NmALbz+VQlHP$_ffQr@=g$*eIcW)pL>`3jsY)|
z?q%}6eII{cXq8gq@fQKcy5oo8O_ZVN#okIkf6WVf!mq*ISJ9TrpnJL91(J@ke-G&M
z@17toLf8>N7vMJ_M55LbY|1YR*@nJ@*vv~Eo~3RT<na-=iL_1dHqe9IDQT){i;w%2
z!Hwks)$|V+oC(r^1NaH+CQtXZJUdC>MfwhSH~I^ZrH!^zMi}e^0Z9XXi98AHM(zfx
zhH(d!fjSTX_kvwuKR5!+T6BV9PyxEhAEK_?kaq$$=v4G=Ou~GDtyq;hneY7x-yr3J
z0_?n<Ht3+APQwlXX+O|P8iRhi4P8B?J1l9zI_b|ts?@852S~HMj(c3f=<C~H?ArSV
zaaKKJD)2GS_z7k75>|-6oAhPywq{1KChAQ5HJ}Fh3DOjk_W41yT_g4<-6G;-uSoVw
zWbZ}xOJr|G_J<ZPW{;5g0O`0hOIY#tb#k4@(6b4B7InHG-U)UCrVP<mc<(^!$pOje
zQT8P9k0G7>;pRigCxCCbOeNT}9>7C-rC;4jeeR)OEJc>T&$g2XX#lwkgh4kr2DYQ;
zTi8hL`JQUPhE}s*l`!`S?{_F4@*#<1;V{raK2Sqg1^0j#YzM7ei_A~yC~6yiwF;e#
z2|ic_s?_7e9ewyazuQ5&p4Ego$;-2($Q#SIleEfFrTWPTA1Sx?K9h6s^@oPMblu~W
z1th%_Fx;xZ<^#E^n`Z!dPM|9<OrBeLO5eygQozJ-NLcrHWsTq-M(!j%#}rfm?4%BE
z!aS1ZVUmqx{36Ut+5+;=7Cnq5hY2s>o~WRX3xOg`cS@C~4CF9*Jg|o`fP;prf_!gb
z|4nch^ngbnrL7oyQo&Le*8uaYVN^PBgESxqi6486`w%vO1Gs>E&*@vk^@D+w(*&;r
zAEO-~kg<~ZJi?h?a1lIn<(bya+@7!sVBoKTYfS1yzMWh{<s{PZhfR0O_4GQG58gkK
zb^?o#%fP|MvDIjFW}!0!@T6rz9jN&u-GltBoT@#fKfpL$1(%a&HN2X*a<~{i3W|{x
zY=Jj~@oyz<AbR{hpK@E%2-|`mw|)z8dqEjEOxRxHT0xk48?^gw!t?R_!2QVg!@q;~
z5y!|zzj!wKJHiIxf0}U0h(3vbeoQ~DpGLY9!=txzZIpeOG+p$`L$D{)rJjOc;Ch}S
z&nDy^%B@`MS2M}~5s-&G7v4&|B|3XKqYBr78nA1~X4OOgJqCV*Jd*v99=Qj=I%Bh3
zW7rp9h6HxGHgn3vP~lF>x|z8f@D1Lq0;KH*-qg*i2HtcN{a*ES%7?w1C_mcU+Z({q
zGYC(*qy>@|NLnCifuseJ7D!qkX@R5#k`_o>AZdZ51(Fs>S|DkGqy>@|NLnCifuseJ
z7D!qkX@R5#k`_o>AZdZ51(Fs>S|DkGqy>@|NLnCifuseJ7D!qkX@R5#k`_o>AZdZ5
z1(Fs>S|DkGqy>@|NLnCifuseJ7D!qkX@P&F1s=PMUtXf!+osc-@ASwYlleDt{|~7O
B&Pf0O

literal 0
HcmV?d00001

--
1.6.3.3

2010-04-26 11:00:23

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip

Hi marcel,

On Thu, 2010-04-22 at 14:40 +0530, suraj wrote:
> This implements the Atheros Bluetooth serial protocol to
> support the AR300x Bluetooth chipsets.
> The serial protocol implements enhanced power management
> features for the AR300x chipsets.
>
> Reviewed-by: Luis R. Rodriguez <[email protected]>
> Reviewed-by: Gustavo F. Padovan <[email protected]>
> Signed-off-by: Suraj <[email protected]>
>
> ---
> drivers/bluetooth/Kconfig | 14 ++
> drivers/bluetooth/Makefile | 1 +
> drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++
> drivers/bluetooth/hci_ldisc.c | 6 +
> drivers/bluetooth/hci_uart.h | 8 +-
> 5 files changed, 406 insertions(+), 1 deletions(-)
> create mode 100755 drivers/bluetooth/hci_ath.c
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 058fbcc..5546142 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -58,6 +58,20 @@ config BT_HCIUART_BCSP
>
> Say Y here to compile support for HCI BCSP protocol.
>
> +config BT_HCIUART_ATH
> + bool "Atheros AR300x serial Bluetooth support"
> + depends on BT_HCIUART
> + help
> + HCIATH (HCI Atheros) is a serial protocol for communication
> + between the host and Atheros AR300x Bluetooth devices. The
> + protocol implements enhaned power management features for the
> + the AR300x chipsets. it lets the controller chip go to sleep
> + mode if there is no Bluetooth activity for some time and wakes
> + up the chip in case of a Bluetooth activity. Enable this option
> + if you have an UART Atheros AR300x serial device.
> +
> + Say Y here to compile support for HCIATH protocol.
> +
> config BT_HCIUART_LL
> bool "HCILL protocol support"
> depends on BT_HCIUART
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 7e5aed5..1481faa 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
> hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
> hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
> hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
> +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
> hci_uart-objs := $(hci_uart-y)
> diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
> new file mode 100755
> index 0000000..152a1f6
> --- /dev/null
> +++ b/drivers/bluetooth/hci_ath.c
> @@ -0,0 +1,378 @@
> +/*
> + * Copyright (c) 2009-2010 Atheros Communications Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/errno.h>
> +#include <linux/ioctl.h>
> +#include <linux/skbuff.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include "hci_uart.h"
> +
> +/* HCIATH receiver States */
> +#define HCIATH_W4_PACKET_TYPE 0
> +#define HCIATH_W4_EVENT_HDR 1
> +#define HCIATH_W4_ACL_HDR 2
> +#define HCIATH_W4_SCO_HDR 3
> +#define HCIATH_W4_DATA 4
> +
> +struct ath_struct {
> + struct hci_uart *hu;
> + unsigned int rx_state;
> + unsigned int rx_count;
> + unsigned int cur_sleep;
> +
> + spinlock_t hciath_lock;
> + struct sk_buff *rx_skb;
> + struct sk_buff_head txq;
> + wait_queue_head_t wqevt;
> + struct work_struct ctxtsw;
> +};
> +
> +static int ath_wakeup_ar3001(struct tty_struct *tty)
> +{
> + struct termios settings;
> + int status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + if (status & TIOCM_CTS)
> + return status;
> +
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + /* Disable Automatic RTSCTS */
> + settings.c_cflag &= ~CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Clear RTS first */
> + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Set RTS, wake up board */
> + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + settings.c_cflag |= CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> +
> + return status;
> +}
> +
> +static void ath_hci_uart_work(struct work_struct *work)
> +{
> + int status;
> + struct ath_struct *ath;
> + struct hci_uart *hu;
> + struct tty_struct *tty;
> +
> + ath = container_of(work, struct ath_struct, ctxtsw);
> +
> + hu = ath->hu;
> + tty = hu->tty;
> +
> + /* verify and wake up controller */
> + if (ath->cur_sleep) {
> + status = ath_wakeup_ar3001(tty);
> +
> + if (!(status & TIOCM_CTS))
> + return;
> + }
> +
> + /* Ready to send Data */
> + clear_bit(HCI_UART_SENDING, &hu->tx_state);
> + hci_uart_tx_wakeup(hu);
> +}
> +
> +/* Initialize protocol */
> +static int ath_open(struct hci_uart *hu)
> +{
> + struct ath_struct *ath;
> +
> + BT_DBG("hu %p", hu);
> +
> + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
> + if (!ath)
> + return -ENOMEM;
> +
> + skb_queue_head_init(&ath->txq);
> + spin_lock_init(&ath->hciath_lock);
> +
> + hu->priv = ath;
> + ath->hu = hu;
> +
> + init_waitqueue_head(&ath->wqevt);
> + INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
> +
> + return 0;
> +}
> +
> +/* Flush protocol data */
> +static int ath_flush(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + return 0;
> +}
> +
> +/* Close protocol */
> +static int ath_close(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + kfree_skb(ath->rx_skb);
> +
> + cancel_work_sync(&ath->ctxtsw);
> +
> + hu->priv = NULL;
> + kfree(ath);
> +
> + return 0;
> +}
> +
> +/* Enqueue frame for transmittion */
> +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
> +
> + /* Discard SCO packet. AR300x does not support SCO over HCI */
> + BT_DBG("SCO Packet over HCI received Dropping");
> +
> + kfree(skb);
> +
> + return 0;
> + }
> +
> + BT_DBG("hu %p skb %p", hu, skb);
> +
> + /* Prepend skb with frame type */
> + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
> +
> + skb_queue_tail(&ath->txq, skb);
> + set_bit(HCI_UART_SENDING, &hu->tx_state);
> +
> + schedule_work(&ath->ctxtsw);
> +
> + return 0;
> +}
> +
> +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + struct sk_buff *skbuf;
> +
> + skbuf = skb_dequeue(&ath->txq);
> +
> + if (!skbuf)
> + return NULL;
> +
> + /*
> + * Check if the HCI command is HCI sleep enable and
> + * update the sleep enable flag with command parameter.
> + *
> + * Value of sleep enable flag will be used later
> + * to verify if controller has to be woken up before
> + * sending any packet.
> + */
> + if (skbuf->data[0] == 0x01 &&
> + skbuf->data[1] == 0x04 &&
> + skbuf->data[2] == 0xFC)
> + ath->cur_sleep = skbuf->data[4];
> +
> + return skbuf;
> +}
> +
> +static void ath_check_data_len(struct ath_struct *ath, int len)
> +{
> + int room = skb_tailroom(ath->rx_skb);
> +
> + BT_DBG("len %d room %d", len, room);
> +
> + if (len > room) {
> + BT_ERR("Data length is too large");
> + kfree_skb(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + } else {
> + ath->rx_state = HCIATH_W4_DATA;
> + ath->rx_count = len;
> + }
> +}
> +
> +/* Recv data */
> +static int ath_recv(struct hci_uart *hu, void *data, int count)
> +{
> + struct ath_struct *ath = hu->priv;
> + char *ptr = data;
> + struct hci_event_hdr *eh;
> + struct hci_acl_hdr *ah;
> + struct hci_sco_hdr *sh;
> + int len, type, dlen;
> +
> + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> + ath->rx_state, ath->rx_count);
> +
> + while (count) {
> + if (ath->rx_count) {
> +
> + len = min_t(unsigned int, ath->rx_count, count);
> + memcpy(skb_put(ath->rx_skb, len), ptr, len);
> + ath->rx_count -= len;
> + count -= len;
> + ptr += len;
> +
> + if (ath->rx_count)
> + continue;
> + switch (ath->rx_state) {
> + case HCIATH_W4_DATA:
> + hci_recv_frame(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + continue;
> +
> + case HCIATH_W4_EVENT_HDR:
> + eh = hci_event_hdr(ath->rx_skb);
> +
> + BT_DBG("Event header: evt 0x%2.2x plen %d",
> + eh->evt, eh->plen);
> +
> + ath_check_data_len(ath, eh->plen);
> + continue;
> +
> + case HCIATH_W4_ACL_HDR:
> + ah = hci_acl_hdr(ath->rx_skb);
> + dlen = __le16_to_cpu(ah->dlen);
> +
> + BT_DBG("ACL header: dlen %d", dlen);
> +
> + ath_check_data_len(ath, dlen);
> + continue;
> +
> + case HCIATH_W4_SCO_HDR:
> + sh = hci_sco_hdr(ath->rx_skb);
> +
> + BT_DBG("SCO header: dlen %d", sh->dlen);
> +
> + ath_check_data_len(ath, sh->dlen);
> + continue;
> +
> + }
> + }
> +
> + /* HCIATH_W4_PACKET_TYPE */
> + switch (*ptr) {
> + case HCI_EVENT_PKT:
> + BT_DBG("Event packet");
> + ath->rx_state = HCIATH_W4_EVENT_HDR;
> + ath->rx_count = HCI_EVENT_HDR_SIZE;
> + type = HCI_EVENT_PKT;
> + break;
> +
> + case HCI_ACLDATA_PKT:
> + BT_DBG("ACL packet");
> + ath->rx_state = HCIATH_W4_ACL_HDR;
> + ath->rx_count = HCI_ACL_HDR_SIZE;
> + type = HCI_ACLDATA_PKT;
> + break;
> +
> + case HCI_SCODATA_PKT:
> + BT_DBG("SCO packet");
> + ath->rx_state = HCIATH_W4_SCO_HDR;
> + ath->rx_count = HCI_SCO_HDR_SIZE;
> + type = HCI_SCODATA_PKT;
> + break;
> +
> + default:
> + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> + hu->hdev->stat.err_rx++;
> + ptr++;
> + count--;
> + continue;
> +
> + };
> + ptr++;
> + count--;
> +
> + /* Allocate packet */
> + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> + if (!ath->rx_skb) {
> + BT_ERR("Can't allocate mem for new packet");
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_count = 0;
> +
> + return -ENOMEM;
> + }
> + ath->rx_skb->dev = (void *)hu->hdev;
> + bt_cb(ath->rx_skb)->pkt_type = type;
> + }
> +
> + return count;
> +}
> +
> +static struct hci_uart_proto athp = {
> + .id = HCI_UART_ATH,
> + .open = ath_open,
> + .close = ath_close,
> + .recv = ath_recv,
> + .enqueue = ath_enqueue,
> + .dequeue = ath_dequeue,
> + .flush = ath_flush,
> +};
> +
> +int ath_init(void)
> +{
> + int err = hci_uart_register_proto(&athp);
> +
> + if (!err)
> + BT_INFO("HCIATH protocol initialized");
> + else
> + BT_ERR("HCIATH protocol registration failed");
> +
> + return err;
> +}
> +
> +int ath_deinit(void)
> +{
> + return hci_uart_unregister_proto(&athp);
> +}
> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> index 76a1abb..7dd76d1 100644
> --- a/drivers/bluetooth/hci_ldisc.c
> +++ b/drivers/bluetooth/hci_ldisc.c
> @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_init();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_init();
> +#endif
>
> return 0;
> }
> @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_deinit();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_deinit();
> +#endif
>
> /* Release tty registration of line discipline */
> if ((err = tty_unregister_ldisc(N_HCI)))
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index 50113db..385537f 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -33,13 +33,14 @@
> #define HCIUARTGETDEVICE _IOR('U', 202, int)
>
> /* UART protocols */
> -#define HCI_UART_MAX_PROTO 5
> +#define HCI_UART_MAX_PROTO 6
>
> #define HCI_UART_H4 0
> #define HCI_UART_BCSP 1
> #define HCI_UART_3WIRE 2
> #define HCI_UART_H4DS 3
> #define HCI_UART_LL 4
> +#define HCI_UART_ATH 5
>
> struct hci_uart;
>
> @@ -91,3 +92,8 @@ int bcsp_deinit(void);
> int ll_init(void);
> int ll_deinit(void);
> #endif
> +
> +#ifdef CONFIG_BT_HCIUART_ATH
> +int ath_init(void);
> +int ath_deinit(void);
> +#endif

Can you verify the patch let me know your comments?

Regards
Suraj



2010-04-22 09:10:14

by Suraj Sumangala

[permalink] [raw]
Subject: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip

This implements the Atheros Bluetooth serial protocol to
support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management
features for the AR300x chipsets.

Reviewed-by: Luis R. Rodriguez <[email protected]>
Reviewed-by: Gustavo F. Padovan <[email protected]>
Signed-off-by: Suraj <[email protected]>

---
drivers/bluetooth/Kconfig | 14 ++
drivers/bluetooth/Makefile | 1 +
drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++
drivers/bluetooth/hci_ldisc.c | 6 +
drivers/bluetooth/hci_uart.h | 8 +-
5 files changed, 406 insertions(+), 1 deletions(-)
create mode 100755 drivers/bluetooth/hci_ath.c

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 058fbcc..5546142 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -58,6 +58,20 @@ config BT_HCIUART_BCSP

Say Y here to compile support for HCI BCSP protocol.

+config BT_HCIUART_ATH
+ bool "Atheros AR300x serial Bluetooth support"
+ depends on BT_HCIUART
+ help
+ HCIATH (HCI Atheros) is a serial protocol for communication
+ between the host and Atheros AR300x Bluetooth devices. The
+ protocol implements enhaned power management features for the
+ the AR300x chipsets. it lets the controller chip go to sleep
+ mode if there is no Bluetooth activity for some time and wakes
+ up the chip in case of a Bluetooth activity. Enable this option
+ if you have an UART Atheros AR300x serial device.
+
+ Say Y here to compile support for HCIATH protocol.
+
config BT_HCIUART_LL
bool "HCILL protocol support"
depends on BT_HCIUART
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 7e5aed5..1481faa 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
+hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
hci_uart-objs := $(hci_uart-y)
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
new file mode 100755
index 0000000..152a1f6
--- /dev/null
+++ b/drivers/bluetooth/hci_ath.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+/* HCIATH receiver States */
+#define HCIATH_W4_PACKET_TYPE 0
+#define HCIATH_W4_EVENT_HDR 1
+#define HCIATH_W4_ACL_HDR 2
+#define HCIATH_W4_SCO_HDR 3
+#define HCIATH_W4_DATA 4
+
+struct ath_struct {
+ struct hci_uart *hu;
+ unsigned int rx_state;
+ unsigned int rx_count;
+ unsigned int cur_sleep;
+
+ spinlock_t hciath_lock;
+ struct sk_buff *rx_skb;
+ struct sk_buff_head txq;
+ wait_queue_head_t wqevt;
+ struct work_struct ctxtsw;
+};
+
+static int ath_wakeup_ar3001(struct tty_struct *tty)
+{
+ struct termios settings;
+ int status = tty->driver->ops->tiocmget(tty, NULL);
+
+ if (status & TIOCM_CTS)
+ return status;
+
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+
+ /* Disable Automatic RTSCTS */
+ settings.c_cflag &= ~CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ /* Clear RTS first */
+ tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
+ mdelay(20);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ /* Set RTS, wake up board */
+ tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
+ mdelay(20);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+
+ settings.c_cflag |= CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+ return status;
+}
+
+static void ath_hci_uart_work(struct work_struct *work)
+{
+ int status;
+ struct ath_struct *ath;
+ struct hci_uart *hu;
+ struct tty_struct *tty;
+
+ ath = container_of(work, struct ath_struct, ctxtsw);
+
+ hu = ath->hu;
+ tty = hu->tty;
+
+ /* verify and wake up controller */
+ if (ath->cur_sleep) {
+ status = ath_wakeup_ar3001(tty);
+
+ if (!(status & TIOCM_CTS))
+ return;
+ }
+
+ /* Ready to send Data */
+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
+ hci_uart_tx_wakeup(hu);
+}
+
+/* Initialize protocol */
+static int ath_open(struct hci_uart *hu)
+{
+ struct ath_struct *ath;
+
+ BT_DBG("hu %p", hu);
+
+ ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
+ if (!ath)
+ return -ENOMEM;
+
+ skb_queue_head_init(&ath->txq);
+ spin_lock_init(&ath->hciath_lock);
+
+ hu->priv = ath;
+ ath->hu = hu;
+
+ init_waitqueue_head(&ath->wqevt);
+ INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
+
+ return 0;
+}
+
+/* Flush protocol data */
+static int ath_flush(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ath->txq);
+
+ return 0;
+}
+
+/* Close protocol */
+static int ath_close(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ath->txq);
+
+ kfree_skb(ath->rx_skb);
+
+ cancel_work_sync(&ath->ctxtsw);
+
+ hu->priv = NULL;
+ kfree(ath);
+
+ return 0;
+}
+
+/* Enqueue frame for transmittion */
+static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+ struct ath_struct *ath = hu->priv;
+
+ if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
+
+ /* Discard SCO packet. AR300x does not support SCO over HCI */
+ BT_DBG("SCO Packet over HCI received Dropping");
+
+ kfree(skb);
+
+ return 0;
+ }
+
+ BT_DBG("hu %p skb %p", hu, skb);
+
+ /* Prepend skb with frame type */
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+ skb_queue_tail(&ath->txq, skb);
+ set_bit(HCI_UART_SENDING, &hu->tx_state);
+
+ schedule_work(&ath->ctxtsw);
+
+ return 0;
+}
+
+static struct sk_buff *ath_dequeue(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+ struct sk_buff *skbuf;
+
+ skbuf = skb_dequeue(&ath->txq);
+
+ if (!skbuf)
+ return NULL;
+
+ /*
+ * Check if the HCI command is HCI sleep enable and
+ * update the sleep enable flag with command parameter.
+ *
+ * Value of sleep enable flag will be used later
+ * to verify if controller has to be woken up before
+ * sending any packet.
+ */
+ if (skbuf->data[0] == 0x01 &&
+ skbuf->data[1] == 0x04 &&
+ skbuf->data[2] == 0xFC)
+ ath->cur_sleep = skbuf->data[4];
+
+ return skbuf;
+}
+
+static void ath_check_data_len(struct ath_struct *ath, int len)
+{
+ int room = skb_tailroom(ath->rx_skb);
+
+ BT_DBG("len %d room %d", len, room);
+
+ if (len > room) {
+ BT_ERR("Data length is too large");
+ kfree_skb(ath->rx_skb);
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_skb = NULL;
+ ath->rx_count = 0;
+ } else {
+ ath->rx_state = HCIATH_W4_DATA;
+ ath->rx_count = len;
+ }
+}
+
+/* Recv data */
+static int ath_recv(struct hci_uart *hu, void *data, int count)
+{
+ struct ath_struct *ath = hu->priv;
+ char *ptr = data;
+ struct hci_event_hdr *eh;
+ struct hci_acl_hdr *ah;
+ struct hci_sco_hdr *sh;
+ int len, type, dlen;
+
+ BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
+ ath->rx_state, ath->rx_count);
+
+ while (count) {
+ if (ath->rx_count) {
+
+ len = min_t(unsigned int, ath->rx_count, count);
+ memcpy(skb_put(ath->rx_skb, len), ptr, len);
+ ath->rx_count -= len;
+ count -= len;
+ ptr += len;
+
+ if (ath->rx_count)
+ continue;
+ switch (ath->rx_state) {
+ case HCIATH_W4_DATA:
+ hci_recv_frame(ath->rx_skb);
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_skb = NULL;
+ ath->rx_count = 0;
+ continue;
+
+ case HCIATH_W4_EVENT_HDR:
+ eh = hci_event_hdr(ath->rx_skb);
+
+ BT_DBG("Event header: evt 0x%2.2x plen %d",
+ eh->evt, eh->plen);
+
+ ath_check_data_len(ath, eh->plen);
+ continue;
+
+ case HCIATH_W4_ACL_HDR:
+ ah = hci_acl_hdr(ath->rx_skb);
+ dlen = __le16_to_cpu(ah->dlen);
+
+ BT_DBG("ACL header: dlen %d", dlen);
+
+ ath_check_data_len(ath, dlen);
+ continue;
+
+ case HCIATH_W4_SCO_HDR:
+ sh = hci_sco_hdr(ath->rx_skb);
+
+ BT_DBG("SCO header: dlen %d", sh->dlen);
+
+ ath_check_data_len(ath, sh->dlen);
+ continue;
+
+ }
+ }
+
+ /* HCIATH_W4_PACKET_TYPE */
+ switch (*ptr) {
+ case HCI_EVENT_PKT:
+ BT_DBG("Event packet");
+ ath->rx_state = HCIATH_W4_EVENT_HDR;
+ ath->rx_count = HCI_EVENT_HDR_SIZE;
+ type = HCI_EVENT_PKT;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ BT_DBG("ACL packet");
+ ath->rx_state = HCIATH_W4_ACL_HDR;
+ ath->rx_count = HCI_ACL_HDR_SIZE;
+ type = HCI_ACLDATA_PKT;
+ break;
+
+ case HCI_SCODATA_PKT:
+ BT_DBG("SCO packet");
+ ath->rx_state = HCIATH_W4_SCO_HDR;
+ ath->rx_count = HCI_SCO_HDR_SIZE;
+ type = HCI_SCODATA_PKT;
+ break;
+
+ default:
+ BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
+ hu->hdev->stat.err_rx++;
+ ptr++;
+ count--;
+ continue;
+
+ };
+ ptr++;
+ count--;
+
+ /* Allocate packet */
+ ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!ath->rx_skb) {
+ BT_ERR("Can't allocate mem for new packet");
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_count = 0;
+
+ return -ENOMEM;
+ }
+ ath->rx_skb->dev = (void *)hu->hdev;
+ bt_cb(ath->rx_skb)->pkt_type = type;
+ }
+
+ return count;
+}
+
+static struct hci_uart_proto athp = {
+ .id = HCI_UART_ATH,
+ .open = ath_open,
+ .close = ath_close,
+ .recv = ath_recv,
+ .enqueue = ath_enqueue,
+ .dequeue = ath_dequeue,
+ .flush = ath_flush,
+};
+
+int ath_init(void)
+{
+ int err = hci_uart_register_proto(&athp);
+
+ if (!err)
+ BT_INFO("HCIATH protocol initialized");
+ else
+ BT_ERR("HCIATH protocol registration failed");
+
+ return err;
+}
+
+int ath_deinit(void)
+{
+ return hci_uart_unregister_proto(&athp);
+}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 76a1abb..7dd76d1 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_init();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH
+ ath_init();
+#endif

return 0;
}
@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_deinit();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH
+ ath_deinit();
+#endif

/* Release tty registration of line discipline */
if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 50113db..385537f 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -33,13 +33,14 @@
#define HCIUARTGETDEVICE _IOR('U', 202, int)

/* UART protocols */
-#define HCI_UART_MAX_PROTO 5
+#define HCI_UART_MAX_PROTO 6

#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH 5

struct hci_uart;

@@ -91,3 +92,8 @@ int bcsp_deinit(void);
int ll_init(void);
int ll_deinit(void);
#endif
+
+#ifdef CONFIG_BT_HCIUART_ATH
+int ath_init(void);
+int ath_deinit(void);
+#endif
--
1.7.0

2010-04-22 08:59:22

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH v4] Add support for the Atheros AR300x Bluetooth Chip

Hi Suraj,

* Suraj Sumangala <[email protected]> [2010-04-22 12:24:04 +0530]:

>
> Hi Gustavo,
>
> Gustavo F. Padovan wrote:
> >* suraj <[email protected]> [2010-04-21 15:52:17 +0530]:
> >
> >>This implements the Atheros Bluetooth serial protocol to
> >>support the AR300x Bluetooth chipsets.
> >>The serial protocol implements enhanced power management
> >>features for the AR300x chipsets.
> >>
> >>Reviewed-by: Luis R. Rodriguez <[email protected]>
> >>Signed-off-by: Suraj <[email protected]>
> >>
> >>---
> >> drivers/bluetooth/Kconfig | 14 ++
> >> drivers/bluetooth/Makefile | 1 +
> >> drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++
> >> drivers/bluetooth/hci_ldisc.c | 6 +
> >> drivers/bluetooth/hci_uart.h | 8 +-
> >> 5 files changed, 406 insertions(+), 1 deletions(-)
> >> create mode 100755 drivers/bluetooth/hci_ath.c
> >>

..snip..

> >>+
> >>+static void ath_check_data_len(struct ath_struct *ath, int len)
> >>+{
> >>+ int room = skb_tailroom(ath->rx_skb);
> >>+
> >>+ BT_DBG("len %d room %d", len, room);
> >>+
> >>+ if (len > room) {
> >>+ BT_ERR("Data length is too large");
> >>+ kfree_skb(ath->rx_skb);
> >>+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
> >>+ ath->rx_skb = NULL;
> >>+ ath->rx_count = 0;
> >>+ } else {
> >>+ ath->rx_state = HCIATH_W4_DATA;
> >>+ ath->rx_count = len;
> >>+ }
> >>+}
> >>+
> >>+/* Recv data */
> >>+static int ath_recv(struct hci_uart *hu, void *data, int count)
> >>+{
> >>+ struct ath_struct *ath = hu->priv;
> >>+ char *ptr = data;
> >>+ struct hci_event_hdr *eh;
> >>+ struct hci_acl_hdr *ah;
> >>+ struct hci_sco_hdr *sh;
> >>+ int len, type, dlen;
> >>+
> >>+ BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> >>+ ath->rx_state, ath->rx_count);
> >>+
> >>+ while (count) {
> >>+ if (ath->rx_count) {
> >>+
> >>+ len = min_t(unsigned int, ath->rx_count, count);
> >>+ memcpy(skb_put(ath->rx_skb, len), ptr, len);
> >>+ ath->rx_count -= len;
> >>+ count -= len;
> >>+ ptr += len;
> >>+
> >>+ if (ath->rx_count)
> >>+ continue;
> >>+ switch (ath->rx_state) {
> >>+ case HCIATH_W4_DATA:
> >>+ hci_recv_frame(ath->rx_skb);
> >>+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
> >>+ ath->rx_skb = NULL;
> >>+ ath->rx_count = 0;
> >>+ continue;
> >>+
> >>+ case HCIATH_W4_EVENT_HDR:
> >>+ eh = (struct hci_event_hdr *)ath->rx_skb->data;
> >
> >Use hci_event_hdr() here like hci_h4.c does.
> >
> >>+
> >>+ BT_DBG("Event header: evt 0x%2.2x plen %d",
> >>+ eh->evt, eh->plen);
> >>+
> >>+ ath_check_data_len(ath, eh->plen);
> >>+ continue;
> >>+
> >>+ case HCIATH_W4_ACL_HDR:
> >>+ ah = (struct hci_acl_hdr *)ath->rx_skb->data;
> >
> >And hci_acl_hdr() here.
> >
> >>+ dlen = __le16_to_cpu(ah->dlen);
> >>+
> >>+ BT_DBG("ACL header: dlen %d", dlen);
> >>+
> >>+ ath_check_data_len(ath, dlen);
> >>+ continue;
> >>+
> >>+ case HCIATH_W4_SCO_HDR:
> >>+ sh = (struct hci_sco_hdr *)ath->rx_skb->data;
> >
> >hci_sco_hdr() here.
> >
> >>+
> >>+ BT_DBG("SCO header: dlen %d", sh->dlen);
> >>+
> >>+ ath_check_data_len(ath, sh->dlen);
> >>+ continue;
> >>+
> >>+ }
> >>+ }
> >>+
> >>+ /* HCIATH_W4_PACKET_TYPE */
> >>+ switch (*ptr) {
> >>+ case HCI_EVENT_PKT:
> >>+ BT_DBG("Event packet");
> >>+ ath->rx_state = HCIATH_W4_EVENT_HDR;
> >>+ ath->rx_count = HCI_EVENT_HDR_SIZE;
> >>+ type = HCI_EVENT_PKT;
> >>+ break;
> >>+
> >>+ case HCI_ACLDATA_PKT:
> >>+ BT_DBG("ACL packet");
> >>+ ath->rx_state = HCIATH_W4_ACL_HDR;
> >>+ ath->rx_count = HCI_ACL_HDR_SIZE;
> >>+ type = HCI_ACLDATA_PKT;
> >>+ break;
> >>+
> >>+ case HCI_SCODATA_PKT:
> >>+ BT_DBG("SCO packet");
> >>+ ath->rx_state = HCIATH_W4_SCO_HDR;
> >>+ ath->rx_count = HCI_SCO_HDR_SIZE;
> >>+ type = HCI_SCODATA_PKT;
> >>+ break;
> >>+
> >>+ default:
> >>+ BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> >>+ hu->hdev->stat.err_rx++;
> >>+ ptr++;
> >>+ count--;
> >>+ continue;
> >>+
> >>+ };
> >>+ ptr++;
> >>+ count--;
> >>+
> >>+ /* Allocate packet */
> >>+ ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> >>+ if (!ath->rx_skb) {
> >>+ BT_ERR("Can't allocate mem for new packet");
> >>+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
> >>+ ath->rx_count = 0;
> >>+
> >>+ return -ENOMEM;
> >>+ }
> >>+ ath->rx_skb->dev = (void *)hu->hdev;
> >>+ bt_cb(ath->rx_skb)->pkt_type = type;
> >>+ }
> >>+
> >>+ return count;
> >>+}
> >
> >Just out of curiosity. I never worked in the driver world, but is it ok
> >to duplicate lots of code when working with drivers? hci_h4.c and this
> >patch share lots of similar code. ath_recv() and h4_recv() are exactly
> >the same except for one line, the ath->rx_count = 0; at case HCIATH_W4_DATA.
> >Does this line makes real difference? recv() is not the only function
> >duplicating code here.
>
> Let me try to anwer you here. I am also new to the driver world, so
> correct me if I am wrong.
>
> Both drivers do the same job, expect that the ATH driver does
> something more on the data transmit path. So, the receive path does
> the same thing. That is the reason why both looks same. This could
> possibly change later as new feature will be added to the ATH
> protocol.

Ok. I'm thinking if it is not possible create a separated 'lib' with the
common code. That's why I asked about the code duplication. I don't know
how worth it is, since we have only 3 drivers using similar code.

>
>
> The function "hci_recv_fragment()" could potentially replace most of
> the code in the ath_recv() function. But, unfortunately this
> function require the caller to provide the HCI Packet type as
> parameter.
>
> This defeats all the advantage of "hci_recv_fragment()" in a UART
> HCI transport driver as all types of packets are received through
> the same callback. So the caller will have to write the same messy
> code in ath_recv() to find out the packet type negating all the
> advantages of "hci_recv_fragment()".
>
>
> >
> >>+
> >>+static struct hci_uart_proto athp = {
> >>+ .id = HCI_UART_ATH,
> >>+ .open = ath_open,
> >>+ .close = ath_close,
> >>+ .recv = ath_recv,
> >>+ .enqueue = ath_enqueue,
> >>+ .dequeue = ath_dequeue,
> >>+ .flush = ath_flush,
> >>+};
> >>+
> >>+int ath_init(void)
> >>+{
> >>+ int err = hci_uart_register_proto(&athp);
> >>+
> >>+ if (!err)
> >>+ BT_INFO("HCIATH protocol initialized");
> >>+ else
> >>+ BT_ERR("HCIATH protocol registration failed");
> >>+
> >>+ return err;
> >>+}
> >
> >BTW, we never check this return value on hci_ldisc.c, why?
>
> you, are correct. Just thought of keeping the same signature used by
> other protocol. moreover hci_ldisc.c being a common file used by all
> protocol it is possible that somebody want to check the return value
> at later point of time. So, kept it that way so that we do not have
> a problem then :-D
>
> Your thoughts?

Yes, your code is right, the return value should be kept. The problem
is that hci_uart_init() doesn't check any other protocol initialization
(h4, bcsp and ll). My thought is: we really need to check?

Marcel, can you answer that?

> >
> >>+
> >>+int ath_deinit(void)
> >>+{
> >>+ return hci_uart_unregister_proto(&athp);
> >>+}
> >>diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> >>index 76a1abb..7dd76d1 100644
> >>--- a/drivers/bluetooth/hci_ldisc.c
> >>+++ b/drivers/bluetooth/hci_ldisc.c
> >>@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
> >> #ifdef CONFIG_BT_HCIUART_LL
> >> ll_init();
> >> #endif
> >>+#ifdef CONFIG_BT_HCIUART_ATH
> >>+ ath_init();
> >>+#endif
> >>
> >> return 0;
> >> }
> >>@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
> >> #ifdef CONFIG_BT_HCIUART_LL
> >> ll_deinit();
> >> #endif
> >>+#ifdef CONFIG_BT_HCIUART_ATH
> >>+ ath_deinit();
> >>+#endif
> >>
> >> /* Release tty registration of line discipline */
> >> if ((err = tty_unregister_ldisc(N_HCI)))
> >>diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> >>index 50113db..385537f 100644
> >>--- a/drivers/bluetooth/hci_uart.h
> >>+++ b/drivers/bluetooth/hci_uart.h
> >>@@ -33,13 +33,14 @@
> >> #define HCIUARTGETDEVICE _IOR('U', 202, int)
> >>
> >> /* UART protocols */
> >>-#define HCI_UART_MAX_PROTO 5
> >>+#define HCI_UART_MAX_PROTO 6
> >>
> >> #define HCI_UART_H4 0
> >> #define HCI_UART_BCSP 1
> >> #define HCI_UART_3WIRE 2
> >> #define HCI_UART_H4DS 3
> >> #define HCI_UART_LL 4
> >>+#define HCI_UART_ATH 5
> >>
> >> struct hci_uart;
> >>
> >>@@ -91,3 +92,8 @@ int bcsp_deinit(void);
> >> int ll_init(void);
> >> int ll_deinit(void);
> >> #endif
> >>+
> >>+#ifdef CONFIG_BT_HCIUART_ATH
> >>+int ath_init(void);
> >>+int ath_deinit(void);
> >>+#endif
> >>--
> >>1.7.0
> >>
> >>
> >>
> >>
> >>
> >
> >--
> >Gustavo F. Padovan
> >http://padovan.org
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

--
Gustavo F. Padovan
http://padovan.org

2010-04-22 06:54:04

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH v4] Add support for the Atheros AR300x Bluetooth Chip


Hi Gustavo,

Gustavo F. Padovan wrote:
> * suraj <[email protected]> [2010-04-21 15:52:17 +0530]:
>
>> This implements the Atheros Bluetooth serial protocol to
>> support the AR300x Bluetooth chipsets.
>> The serial protocol implements enhanced power management
>> features for the AR300x chipsets.
>>
>> Reviewed-by: Luis R. Rodriguez <[email protected]>
>> Signed-off-by: Suraj <[email protected]>
>>
>> ---
>> drivers/bluetooth/Kconfig | 14 ++
>> drivers/bluetooth/Makefile | 1 +
>> drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++
>> drivers/bluetooth/hci_ldisc.c | 6 +
>> drivers/bluetooth/hci_uart.h | 8 +-
>> 5 files changed, 406 insertions(+), 1 deletions(-)
>> create mode 100755 drivers/bluetooth/hci_ath.c
>>
>> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
>> index 058fbcc..5546142 100644
>> --- a/drivers/bluetooth/Kconfig
>> +++ b/drivers/bluetooth/Kconfig
>> @@ -58,6 +58,20 @@ config BT_HCIUART_BCSP
>>
>> Say Y here to compile support for HCI BCSP protocol.
>>
>> +config BT_HCIUART_ATH
>> + bool "Atheros AR300x serial Bluetooth support"
>> + depends on BT_HCIUART
>> + help
>> + HCIATH (HCI Atheros) is a serial protocol for communication
>> + between the host and Atheros AR300x Bluetooth devices. The
>> + protocol implements enhaned power management features for the
>> + the AR300x chipsets. it lets the controller chip go to sleep
>> + mode if there is no Bluetooth activity for some time and wakes
>> + up the chip in case of a Bluetooth activity. Enable this option
>> + if you have an UART Atheros AR300x serial device.
>> +
>> + Say Y here to compile support for HCIATH protocol.
>> +
>> config BT_HCIUART_LL
>> bool "HCILL protocol support"
>> depends on BT_HCIUART
>> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
>> index 7e5aed5..1481faa 100644
>> --- a/drivers/bluetooth/Makefile
>> +++ b/drivers/bluetooth/Makefile
>> @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
>> hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
>> hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
>> hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
>> +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
>> hci_uart-objs := $(hci_uart-y)
>> diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
>> new file mode 100755
>> index 0000000..7e99559
>> --- /dev/null
>> +++ b/drivers/bluetooth/hci_ath.c
>> @@ -0,0 +1,378 @@
>> +/*
>> + * Copyright (c) 2009-2010 Atheros Communications Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +
>> +#include <linux/init.h>
>> +#include <linux/slab.h>
>> +#include <linux/tty.h>
>> +#include <linux/errno.h>
>> +#include <linux/ioctl.h>
>> +#include <linux/skbuff.h>
>> +
>> +#include <net/bluetooth/bluetooth.h>
>> +#include <net/bluetooth/hci_core.h>
>> +
>> +#include "hci_uart.h"
>> +
>> +/* HCIATH receiver States */
>> +#define HCIATH_W4_PACKET_TYPE 0
>> +#define HCIATH_W4_EVENT_HDR 1
>> +#define HCIATH_W4_ACL_HDR 2
>> +#define HCIATH_W4_SCO_HDR 3
>> +#define HCIATH_W4_DATA 4
>> +
>> +struct ath_struct {
>> + struct hci_uart *hu;
>> + unsigned int rx_state;
>> + unsigned int rx_count;
>> + unsigned int cur_sleep;
>> +
>> + spinlock_t hciath_lock;
>> + struct sk_buff *rx_skb;
>> + struct sk_buff_head txq;
>> + wait_queue_head_t wqevt;
>> + struct work_struct ctxtsw;
>> +};
>> +
>> +static int ath_wakeup_ar3001(struct tty_struct *tty)
>> +{
>> + struct termios settings;
>> + int status = tty->driver->ops->tiocmget(tty, NULL);
>> +
>> + if (status & TIOCM_CTS)
>> + return status;
>> +
>> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
>> +
>> + /* Disable Automatic RTSCTS */
>> + settings.c_cflag &= ~CRTSCTS;
>> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
>> +
>> + status = tty->driver->ops->tiocmget(tty, NULL);
>> +
>> + /* Clear RTS first */
>> + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
>> + mdelay(20);
>> +
>> + status = tty->driver->ops->tiocmget(tty, NULL);
>> +
>> + /* Set RTS, wake up board */
>> + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
>> + mdelay(20);
>> +
>> + status = tty->driver->ops->tiocmget(tty, NULL);
>> +
>> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
>> +
>> + settings.c_cflag |= CRTSCTS;
>> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
>> +
>> + return status;
>> +}
>> +
>> +static void ath_hci_uart_work(struct work_struct *work)
>> +{
>> + int status;
>> + struct ath_struct *ath;
>> + struct hci_uart *hu;
>> + struct tty_struct *tty;
>> +
>> + ath = container_of(work, struct ath_struct, ctxtsw);
>> +
>> + hu = ath->hu;
>> + tty = hu->tty;
>> +
>> + /* verify and wake up controller */
>> + if (ath->cur_sleep) {
>> + status = ath_wakeup_ar3001(tty);
>> +
>> + if (!(status & TIOCM_CTS))
>> + return;
>> + }
>> +
>> + /* Ready to send Data */
>> + clear_bit(HCI_UART_SENDING, &hu->tx_state);
>> + hci_uart_tx_wakeup(hu);
>> +}
>> +
>> +/* Initialize protocol */
>> +static int ath_open(struct hci_uart *hu)
>> +{
>> + struct ath_struct *ath;
>> +
>> + BT_DBG("hu %p", hu);
>> +
>> + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
>> + if (!ath)
>> + return -ENOMEM;
>> +
>> + skb_queue_head_init(&ath->txq);
>> + spin_lock_init(&ath->hciath_lock);
>> +
>> + hu->priv = ath;
>> + ath->hu = hu;
>> +
>> + init_waitqueue_head(&ath->wqevt);
>> + INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
>> +
>> + return 0;
>> +}
>> +
>> +/* Flush protocol data */
>> +static int ath_flush(struct hci_uart *hu)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> +
>> + BT_DBG("hu %p", hu);
>> +
>> + skb_queue_purge(&ath->txq);
>> +
>> + return 0;
>> +}
>> +
>> +/* Close protocol */
>> +static int ath_close(struct hci_uart *hu)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> +
>> + BT_DBG("hu %p", hu);
>> +
>> + skb_queue_purge(&ath->txq);
>> +
>> + kfree_skb(ath->rx_skb);
>> +
>> + cancel_work_sync(&ath->ctxtsw);
>> +
>> + hu->priv = NULL;
>> + kfree(ath);
>> +
>> + return 0;
>> +}
>> +
>> +/* Enqueue frame for transmittion */
>> +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> +
>> + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
>> +
>> + /* Discard SCO packet. AR3001 does not support SCO over HCI */
>> + BT_DBG("SCO Packet over HCI received Dropping");
>> +
>> + kfree(skb);
>> +
>> + return 0;
>> + }
>> +
>> + BT_DBG("hu %p skb %p", hu, skb);
>> +
>> + /* Prepend skb with frame type */
>> + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
>> +
>> + skb_queue_tail(&ath->txq, skb);
>> + set_bit(HCI_UART_SENDING, &hu->tx_state);
>> +
>> + schedule_work(&ath->ctxtsw);
>> +
>> + return 0;
>> +}
>> +
>> +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> + struct sk_buff *skbuf;
>> +
>> + skbuf = skb_dequeue(&ath->txq);
>> +
>> + if (!skbuf)
>> + return NULL;
>> +
>> + /*
>> + * Check if the HCI command is HCI sleep enable and
>> + * update the sleep enable flag with command parameter.
>> + *
>> + * Value of sleep enable flag will be used later
>> + * to verify if controller has to be woken up before
>> + * sending any packet.
>> + */
>> + if (skbuf->data[0] == 0x01 &&
>> + skbuf->data[1] == 0x04 &&
>> + skbuf->data[2] == 0xFC)
>> + ath->cur_sleep = skbuf->data[4];
>> +
>> + return skbuf;
>> +}
>> +
>> +static void ath_check_data_len(struct ath_struct *ath, int len)
>> +{
>> + int room = skb_tailroom(ath->rx_skb);
>> +
>> + BT_DBG("len %d room %d", len, room);
>> +
>> + if (len > room) {
>> + BT_ERR("Data length is too large");
>> + kfree_skb(ath->rx_skb);
>> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
>> + ath->rx_skb = NULL;
>> + ath->rx_count = 0;
>> + } else {
>> + ath->rx_state = HCIATH_W4_DATA;
>> + ath->rx_count = len;
>> + }
>> +}
>> +
>> +/* Recv data */
>> +static int ath_recv(struct hci_uart *hu, void *data, int count)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> + char *ptr = data;
>> + struct hci_event_hdr *eh;
>> + struct hci_acl_hdr *ah;
>> + struct hci_sco_hdr *sh;
>> + int len, type, dlen;
>> +
>> + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
>> + ath->rx_state, ath->rx_count);
>> +
>> + while (count) {
>> + if (ath->rx_count) {
>> +
>> + len = min_t(unsigned int, ath->rx_count, count);
>> + memcpy(skb_put(ath->rx_skb, len), ptr, len);
>> + ath->rx_count -= len;
>> + count -= len;
>> + ptr += len;
>> +
>> + if (ath->rx_count)
>> + continue;
>> + switch (ath->rx_state) {
>> + case HCIATH_W4_DATA:
>> + hci_recv_frame(ath->rx_skb);
>> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
>> + ath->rx_skb = NULL;
>> + ath->rx_count = 0;
>> + continue;
>> +
>> + case HCIATH_W4_EVENT_HDR:
>> + eh = (struct hci_event_hdr *)ath->rx_skb->data;
>
> Use hci_event_hdr() here like hci_h4.c does.
>
>> +
>> + BT_DBG("Event header: evt 0x%2.2x plen %d",
>> + eh->evt, eh->plen);
>> +
>> + ath_check_data_len(ath, eh->plen);
>> + continue;
>> +
>> + case HCIATH_W4_ACL_HDR:
>> + ah = (struct hci_acl_hdr *)ath->rx_skb->data;
>
> And hci_acl_hdr() here.
>
>> + dlen = __le16_to_cpu(ah->dlen);
>> +
>> + BT_DBG("ACL header: dlen %d", dlen);
>> +
>> + ath_check_data_len(ath, dlen);
>> + continue;
>> +
>> + case HCIATH_W4_SCO_HDR:
>> + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
>
> hci_sco_hdr() here.
>
>> +
>> + BT_DBG("SCO header: dlen %d", sh->dlen);
>> +
>> + ath_check_data_len(ath, sh->dlen);
>> + continue;
>> +
>> + }
>> + }
>> +
>> + /* HCIATH_W4_PACKET_TYPE */
>> + switch (*ptr) {
>> + case HCI_EVENT_PKT:
>> + BT_DBG("Event packet");
>> + ath->rx_state = HCIATH_W4_EVENT_HDR;
>> + ath->rx_count = HCI_EVENT_HDR_SIZE;
>> + type = HCI_EVENT_PKT;
>> + break;
>> +
>> + case HCI_ACLDATA_PKT:
>> + BT_DBG("ACL packet");
>> + ath->rx_state = HCIATH_W4_ACL_HDR;
>> + ath->rx_count = HCI_ACL_HDR_SIZE;
>> + type = HCI_ACLDATA_PKT;
>> + break;
>> +
>> + case HCI_SCODATA_PKT:
>> + BT_DBG("SCO packet");
>> + ath->rx_state = HCIATH_W4_SCO_HDR;
>> + ath->rx_count = HCI_SCO_HDR_SIZE;
>> + type = HCI_SCODATA_PKT;
>> + break;
>> +
>> + default:
>> + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
>> + hu->hdev->stat.err_rx++;
>> + ptr++;
>> + count--;
>> + continue;
>> +
>> + };
>> + ptr++;
>> + count--;
>> +
>> + /* Allocate packet */
>> + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
>> + if (!ath->rx_skb) {
>> + BT_ERR("Can't allocate mem for new packet");
>> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
>> + ath->rx_count = 0;
>> +
>> + return -ENOMEM;
>> + }
>> + ath->rx_skb->dev = (void *)hu->hdev;
>> + bt_cb(ath->rx_skb)->pkt_type = type;
>> + }
>> +
>> + return count;
>> +}
>
> Just out of curiosity. I never worked in the driver world, but is it ok
> to duplicate lots of code when working with drivers? hci_h4.c and this
> patch share lots of similar code. ath_recv() and h4_recv() are exactly
> the same except for one line, the ath->rx_count = 0; at case HCIATH_W4_DATA.
> Does this line makes real difference? recv() is not the only function
> duplicating code here.

Let me try to anwer you here. I am also new to the driver world, so
correct me if I am wrong.

Both drivers do the same job, expect that the ATH driver does something
more on the data transmit path. So, the receive path does the same
thing. That is the reason why both looks same. This could possibly
change later as new feature will be added to the ATH protocol.


The function "hci_recv_fragment()" could potentially replace most of the
code in the ath_recv() function. But, unfortunately this function
require the caller to provide the HCI Packet type as parameter.

This defeats all the advantage of "hci_recv_fragment()" in a UART HCI
transport driver as all types of packets are received through the same
callback. So the caller will have to write the same messy code in
ath_recv() to find out the packet type negating all the advantages of
"hci_recv_fragment()".


>
>> +
>> +static struct hci_uart_proto athp = {
>> + .id = HCI_UART_ATH,
>> + .open = ath_open,
>> + .close = ath_close,
>> + .recv = ath_recv,
>> + .enqueue = ath_enqueue,
>> + .dequeue = ath_dequeue,
>> + .flush = ath_flush,
>> +};
>> +
>> +int ath_init(void)
>> +{
>> + int err = hci_uart_register_proto(&athp);
>> +
>> + if (!err)
>> + BT_INFO("HCIATH protocol initialized");
>> + else
>> + BT_ERR("HCIATH protocol registration failed");
>> +
>> + return err;
>> +}
>
> BTW, we never check this return value on hci_ldisc.c, why?

you, are correct. Just thought of keeping the same signature used by
other protocol. moreover hci_ldisc.c being a common file used by all
protocol it is possible that somebody want to check the return value at
later point of time. So, kept it that way so that we do not have a
problem then :-D

Your thoughts?
>
>> +
>> +int ath_deinit(void)
>> +{
>> + return hci_uart_unregister_proto(&athp);
>> +}
>> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
>> index 76a1abb..7dd76d1 100644
>> --- a/drivers/bluetooth/hci_ldisc.c
>> +++ b/drivers/bluetooth/hci_ldisc.c
>> @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
>> #ifdef CONFIG_BT_HCIUART_LL
>> ll_init();
>> #endif
>> +#ifdef CONFIG_BT_HCIUART_ATH
>> + ath_init();
>> +#endif
>>
>> return 0;
>> }
>> @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
>> #ifdef CONFIG_BT_HCIUART_LL
>> ll_deinit();
>> #endif
>> +#ifdef CONFIG_BT_HCIUART_ATH
>> + ath_deinit();
>> +#endif
>>
>> /* Release tty registration of line discipline */
>> if ((err = tty_unregister_ldisc(N_HCI)))
>> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
>> index 50113db..385537f 100644
>> --- a/drivers/bluetooth/hci_uart.h
>> +++ b/drivers/bluetooth/hci_uart.h
>> @@ -33,13 +33,14 @@
>> #define HCIUARTGETDEVICE _IOR('U', 202, int)
>>
>> /* UART protocols */
>> -#define HCI_UART_MAX_PROTO 5
>> +#define HCI_UART_MAX_PROTO 6
>>
>> #define HCI_UART_H4 0
>> #define HCI_UART_BCSP 1
>> #define HCI_UART_3WIRE 2
>> #define HCI_UART_H4DS 3
>> #define HCI_UART_LL 4
>> +#define HCI_UART_ATH 5
>>
>> struct hci_uart;
>>
>> @@ -91,3 +92,8 @@ int bcsp_deinit(void);
>> int ll_init(void);
>> int ll_deinit(void);
>> #endif
>> +
>> +#ifdef CONFIG_BT_HCIUART_ATH
>> +int ath_init(void);
>> +int ath_deinit(void);
>> +#endif
>> --
>> 1.7.0
>>
>>
>>
>>
>>
>
> --
> Gustavo F. Padovan
> http://padovan.org

2010-04-22 06:10:56

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH v4] Add support for the Atheros AR300x Bluetooth Chip

* suraj <[email protected]> [2010-04-21 15:52:17 +0530]:

> This implements the Atheros Bluetooth serial protocol to
> support the AR300x Bluetooth chipsets.
> The serial protocol implements enhanced power management
> features for the AR300x chipsets.
>
> Reviewed-by: Luis R. Rodriguez <[email protected]>
> Signed-off-by: Suraj <[email protected]>
>
> ---
> drivers/bluetooth/Kconfig | 14 ++
> drivers/bluetooth/Makefile | 1 +
> drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++
> drivers/bluetooth/hci_ldisc.c | 6 +
> drivers/bluetooth/hci_uart.h | 8 +-
> 5 files changed, 406 insertions(+), 1 deletions(-)
> create mode 100755 drivers/bluetooth/hci_ath.c
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 058fbcc..5546142 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -58,6 +58,20 @@ config BT_HCIUART_BCSP
>
> Say Y here to compile support for HCI BCSP protocol.
>
> +config BT_HCIUART_ATH
> + bool "Atheros AR300x serial Bluetooth support"
> + depends on BT_HCIUART
> + help
> + HCIATH (HCI Atheros) is a serial protocol for communication
> + between the host and Atheros AR300x Bluetooth devices. The
> + protocol implements enhaned power management features for the
> + the AR300x chipsets. it lets the controller chip go to sleep
> + mode if there is no Bluetooth activity for some time and wakes
> + up the chip in case of a Bluetooth activity. Enable this option
> + if you have an UART Atheros AR300x serial device.
> +
> + Say Y here to compile support for HCIATH protocol.
> +
> config BT_HCIUART_LL
> bool "HCILL protocol support"
> depends on BT_HCIUART
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 7e5aed5..1481faa 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
> hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
> hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
> hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
> +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
> hci_uart-objs := $(hci_uart-y)
> diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
> new file mode 100755
> index 0000000..7e99559
> --- /dev/null
> +++ b/drivers/bluetooth/hci_ath.c
> @@ -0,0 +1,378 @@
> +/*
> + * Copyright (c) 2009-2010 Atheros Communications Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/errno.h>
> +#include <linux/ioctl.h>
> +#include <linux/skbuff.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include "hci_uart.h"
> +
> +/* HCIATH receiver States */
> +#define HCIATH_W4_PACKET_TYPE 0
> +#define HCIATH_W4_EVENT_HDR 1
> +#define HCIATH_W4_ACL_HDR 2
> +#define HCIATH_W4_SCO_HDR 3
> +#define HCIATH_W4_DATA 4
> +
> +struct ath_struct {
> + struct hci_uart *hu;
> + unsigned int rx_state;
> + unsigned int rx_count;
> + unsigned int cur_sleep;
> +
> + spinlock_t hciath_lock;
> + struct sk_buff *rx_skb;
> + struct sk_buff_head txq;
> + wait_queue_head_t wqevt;
> + struct work_struct ctxtsw;
> +};
> +
> +static int ath_wakeup_ar3001(struct tty_struct *tty)
> +{
> + struct termios settings;
> + int status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + if (status & TIOCM_CTS)
> + return status;
> +
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + /* Disable Automatic RTSCTS */
> + settings.c_cflag &= ~CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Clear RTS first */
> + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Set RTS, wake up board */
> + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + settings.c_cflag |= CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> +
> + return status;
> +}
> +
> +static void ath_hci_uart_work(struct work_struct *work)
> +{
> + int status;
> + struct ath_struct *ath;
> + struct hci_uart *hu;
> + struct tty_struct *tty;
> +
> + ath = container_of(work, struct ath_struct, ctxtsw);
> +
> + hu = ath->hu;
> + tty = hu->tty;
> +
> + /* verify and wake up controller */
> + if (ath->cur_sleep) {
> + status = ath_wakeup_ar3001(tty);
> +
> + if (!(status & TIOCM_CTS))
> + return;
> + }
> +
> + /* Ready to send Data */
> + clear_bit(HCI_UART_SENDING, &hu->tx_state);
> + hci_uart_tx_wakeup(hu);
> +}
> +
> +/* Initialize protocol */
> +static int ath_open(struct hci_uart *hu)
> +{
> + struct ath_struct *ath;
> +
> + BT_DBG("hu %p", hu);
> +
> + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
> + if (!ath)
> + return -ENOMEM;
> +
> + skb_queue_head_init(&ath->txq);
> + spin_lock_init(&ath->hciath_lock);
> +
> + hu->priv = ath;
> + ath->hu = hu;
> +
> + init_waitqueue_head(&ath->wqevt);
> + INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
> +
> + return 0;
> +}
> +
> +/* Flush protocol data */
> +static int ath_flush(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + return 0;
> +}
> +
> +/* Close protocol */
> +static int ath_close(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + kfree_skb(ath->rx_skb);
> +
> + cancel_work_sync(&ath->ctxtsw);
> +
> + hu->priv = NULL;
> + kfree(ath);
> +
> + return 0;
> +}
> +
> +/* Enqueue frame for transmittion */
> +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
> +
> + /* Discard SCO packet. AR3001 does not support SCO over HCI */
> + BT_DBG("SCO Packet over HCI received Dropping");
> +
> + kfree(skb);
> +
> + return 0;
> + }
> +
> + BT_DBG("hu %p skb %p", hu, skb);
> +
> + /* Prepend skb with frame type */
> + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
> +
> + skb_queue_tail(&ath->txq, skb);
> + set_bit(HCI_UART_SENDING, &hu->tx_state);
> +
> + schedule_work(&ath->ctxtsw);
> +
> + return 0;
> +}
> +
> +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + struct sk_buff *skbuf;
> +
> + skbuf = skb_dequeue(&ath->txq);
> +
> + if (!skbuf)
> + return NULL;
> +
> + /*
> + * Check if the HCI command is HCI sleep enable and
> + * update the sleep enable flag with command parameter.
> + *
> + * Value of sleep enable flag will be used later
> + * to verify if controller has to be woken up before
> + * sending any packet.
> + */
> + if (skbuf->data[0] == 0x01 &&
> + skbuf->data[1] == 0x04 &&
> + skbuf->data[2] == 0xFC)
> + ath->cur_sleep = skbuf->data[4];
> +
> + return skbuf;
> +}
> +
> +static void ath_check_data_len(struct ath_struct *ath, int len)
> +{
> + int room = skb_tailroom(ath->rx_skb);
> +
> + BT_DBG("len %d room %d", len, room);
> +
> + if (len > room) {
> + BT_ERR("Data length is too large");
> + kfree_skb(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + } else {
> + ath->rx_state = HCIATH_W4_DATA;
> + ath->rx_count = len;
> + }
> +}
> +
> +/* Recv data */
> +static int ath_recv(struct hci_uart *hu, void *data, int count)
> +{
> + struct ath_struct *ath = hu->priv;
> + char *ptr = data;
> + struct hci_event_hdr *eh;
> + struct hci_acl_hdr *ah;
> + struct hci_sco_hdr *sh;
> + int len, type, dlen;
> +
> + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> + ath->rx_state, ath->rx_count);
> +
> + while (count) {
> + if (ath->rx_count) {
> +
> + len = min_t(unsigned int, ath->rx_count, count);
> + memcpy(skb_put(ath->rx_skb, len), ptr, len);
> + ath->rx_count -= len;
> + count -= len;
> + ptr += len;
> +
> + if (ath->rx_count)
> + continue;
> + switch (ath->rx_state) {
> + case HCIATH_W4_DATA:
> + hci_recv_frame(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + continue;
> +
> + case HCIATH_W4_EVENT_HDR:
> + eh = (struct hci_event_hdr *)ath->rx_skb->data;

Use hci_event_hdr() here like hci_h4.c does.

> +
> + BT_DBG("Event header: evt 0x%2.2x plen %d",
> + eh->evt, eh->plen);
> +
> + ath_check_data_len(ath, eh->plen);
> + continue;
> +
> + case HCIATH_W4_ACL_HDR:
> + ah = (struct hci_acl_hdr *)ath->rx_skb->data;

And hci_acl_hdr() here.

> + dlen = __le16_to_cpu(ah->dlen);
> +
> + BT_DBG("ACL header: dlen %d", dlen);
> +
> + ath_check_data_len(ath, dlen);
> + continue;
> +
> + case HCIATH_W4_SCO_HDR:
> + sh = (struct hci_sco_hdr *)ath->rx_skb->data;

hci_sco_hdr() here.

> +
> + BT_DBG("SCO header: dlen %d", sh->dlen);
> +
> + ath_check_data_len(ath, sh->dlen);
> + continue;
> +
> + }
> + }
> +
> + /* HCIATH_W4_PACKET_TYPE */
> + switch (*ptr) {
> + case HCI_EVENT_PKT:
> + BT_DBG("Event packet");
> + ath->rx_state = HCIATH_W4_EVENT_HDR;
> + ath->rx_count = HCI_EVENT_HDR_SIZE;
> + type = HCI_EVENT_PKT;
> + break;
> +
> + case HCI_ACLDATA_PKT:
> + BT_DBG("ACL packet");
> + ath->rx_state = HCIATH_W4_ACL_HDR;
> + ath->rx_count = HCI_ACL_HDR_SIZE;
> + type = HCI_ACLDATA_PKT;
> + break;
> +
> + case HCI_SCODATA_PKT:
> + BT_DBG("SCO packet");
> + ath->rx_state = HCIATH_W4_SCO_HDR;
> + ath->rx_count = HCI_SCO_HDR_SIZE;
> + type = HCI_SCODATA_PKT;
> + break;
> +
> + default:
> + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> + hu->hdev->stat.err_rx++;
> + ptr++;
> + count--;
> + continue;
> +
> + };
> + ptr++;
> + count--;
> +
> + /* Allocate packet */
> + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> + if (!ath->rx_skb) {
> + BT_ERR("Can't allocate mem for new packet");
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_count = 0;
> +
> + return -ENOMEM;
> + }
> + ath->rx_skb->dev = (void *)hu->hdev;
> + bt_cb(ath->rx_skb)->pkt_type = type;
> + }
> +
> + return count;
> +}

Just out of curiosity. I never worked in the driver world, but is it ok
to duplicate lots of code when working with drivers? hci_h4.c and this
patch share lots of similar code. ath_recv() and h4_recv() are exactly
the same except for one line, the ath->rx_count = 0; at case HCIATH_W4_DATA.
Does this line makes real difference? recv() is not the only function
duplicating code here.

> +
> +static struct hci_uart_proto athp = {
> + .id = HCI_UART_ATH,
> + .open = ath_open,
> + .close = ath_close,
> + .recv = ath_recv,
> + .enqueue = ath_enqueue,
> + .dequeue = ath_dequeue,
> + .flush = ath_flush,
> +};
> +
> +int ath_init(void)
> +{
> + int err = hci_uart_register_proto(&athp);
> +
> + if (!err)
> + BT_INFO("HCIATH protocol initialized");
> + else
> + BT_ERR("HCIATH protocol registration failed");
> +
> + return err;
> +}

BTW, we never check this return value on hci_ldisc.c, why?

> +
> +int ath_deinit(void)
> +{
> + return hci_uart_unregister_proto(&athp);
> +}
> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> index 76a1abb..7dd76d1 100644
> --- a/drivers/bluetooth/hci_ldisc.c
> +++ b/drivers/bluetooth/hci_ldisc.c
> @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_init();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_init();
> +#endif
>
> return 0;
> }
> @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_deinit();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_deinit();
> +#endif
>
> /* Release tty registration of line discipline */
> if ((err = tty_unregister_ldisc(N_HCI)))
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index 50113db..385537f 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -33,13 +33,14 @@
> #define HCIUARTGETDEVICE _IOR('U', 202, int)
>
> /* UART protocols */
> -#define HCI_UART_MAX_PROTO 5
> +#define HCI_UART_MAX_PROTO 6
>
> #define HCI_UART_H4 0
> #define HCI_UART_BCSP 1
> #define HCI_UART_3WIRE 2
> #define HCI_UART_H4DS 3
> #define HCI_UART_LL 4
> +#define HCI_UART_ATH 5
>
> struct hci_uart;
>
> @@ -91,3 +92,8 @@ int bcsp_deinit(void);
> int ll_init(void);
> int ll_deinit(void);
> #endif
> +
> +#ifdef CONFIG_BT_HCIUART_ATH
> +int ath_init(void);
> +int ath_deinit(void);
> +#endif
> --
> 1.7.0
>
>
>
>
>

--
Gustavo F. Padovan
http://padovan.org

2010-04-21 17:30:21

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [PATCH v4] Add support for the Atheros AR300x Bluetooth Chip

On Wed, Apr 21, 2010 at 03:22:17AM -0700, Suraj Sumangala wrote:
> This implements the Atheros Bluetooth serial protocol to
> support the AR300x Bluetooth chipsets.
> The serial protocol implements enhanced power management
> features for the AR300x chipsets.
>
> Reviewed-by: Luis R. Rodriguez <[email protected]>
> Signed-off-by: Suraj <[email protected]>

Looks good to me now, thanks for your patience and the resends. Marcel?

Luis

2010-04-21 10:22:17

by Suraj Sumangala

[permalink] [raw]
Subject: [PATCH v4] Add support for the Atheros AR300x Bluetooth Chip

This implements the Atheros Bluetooth serial protocol to
support the AR300x Bluetooth chipsets.
The serial protocol implements enhanced power management
features for the AR300x chipsets.

Reviewed-by: Luis R. Rodriguez <[email protected]>
Signed-off-by: Suraj <[email protected]>

---
drivers/bluetooth/Kconfig | 14 ++
drivers/bluetooth/Makefile | 1 +
drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++
drivers/bluetooth/hci_ldisc.c | 6 +
drivers/bluetooth/hci_uart.h | 8 +-
5 files changed, 406 insertions(+), 1 deletions(-)
create mode 100755 drivers/bluetooth/hci_ath.c

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 058fbcc..5546142 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -58,6 +58,20 @@ config BT_HCIUART_BCSP

Say Y here to compile support for HCI BCSP protocol.

+config BT_HCIUART_ATH
+ bool "Atheros AR300x serial Bluetooth support"
+ depends on BT_HCIUART
+ help
+ HCIATH (HCI Atheros) is a serial protocol for communication
+ between the host and Atheros AR300x Bluetooth devices. The
+ protocol implements enhaned power management features for the
+ the AR300x chipsets. it lets the controller chip go to sleep
+ mode if there is no Bluetooth activity for some time and wakes
+ up the chip in case of a Bluetooth activity. Enable this option
+ if you have an UART Atheros AR300x serial device.
+
+ Say Y here to compile support for HCIATH protocol.
+
config BT_HCIUART_LL
bool "HCILL protocol support"
depends on BT_HCIUART
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 7e5aed5..1481faa 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
+hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
hci_uart-objs := $(hci_uart-y)
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
new file mode 100755
index 0000000..7e99559
--- /dev/null
+++ b/drivers/bluetooth/hci_ath.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+/* HCIATH receiver States */
+#define HCIATH_W4_PACKET_TYPE 0
+#define HCIATH_W4_EVENT_HDR 1
+#define HCIATH_W4_ACL_HDR 2
+#define HCIATH_W4_SCO_HDR 3
+#define HCIATH_W4_DATA 4
+
+struct ath_struct {
+ struct hci_uart *hu;
+ unsigned int rx_state;
+ unsigned int rx_count;
+ unsigned int cur_sleep;
+
+ spinlock_t hciath_lock;
+ struct sk_buff *rx_skb;
+ struct sk_buff_head txq;
+ wait_queue_head_t wqevt;
+ struct work_struct ctxtsw;
+};
+
+static int ath_wakeup_ar3001(struct tty_struct *tty)
+{
+ struct termios settings;
+ int status = tty->driver->ops->tiocmget(tty, NULL);
+
+ if (status & TIOCM_CTS)
+ return status;
+
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+
+ /* Disable Automatic RTSCTS */
+ settings.c_cflag &= ~CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ /* Clear RTS first */
+ tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
+ mdelay(20);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ /* Set RTS, wake up board */
+ tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
+ mdelay(20);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+
+ settings.c_cflag |= CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+ return status;
+}
+
+static void ath_hci_uart_work(struct work_struct *work)
+{
+ int status;
+ struct ath_struct *ath;
+ struct hci_uart *hu;
+ struct tty_struct *tty;
+
+ ath = container_of(work, struct ath_struct, ctxtsw);
+
+ hu = ath->hu;
+ tty = hu->tty;
+
+ /* verify and wake up controller */
+ if (ath->cur_sleep) {
+ status = ath_wakeup_ar3001(tty);
+
+ if (!(status & TIOCM_CTS))
+ return;
+ }
+
+ /* Ready to send Data */
+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
+ hci_uart_tx_wakeup(hu);
+}
+
+/* Initialize protocol */
+static int ath_open(struct hci_uart *hu)
+{
+ struct ath_struct *ath;
+
+ BT_DBG("hu %p", hu);
+
+ ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
+ if (!ath)
+ return -ENOMEM;
+
+ skb_queue_head_init(&ath->txq);
+ spin_lock_init(&ath->hciath_lock);
+
+ hu->priv = ath;
+ ath->hu = hu;
+
+ init_waitqueue_head(&ath->wqevt);
+ INIT_WORK(&ath->ctxtsw, ath_hci_uart_work);
+
+ return 0;
+}
+
+/* Flush protocol data */
+static int ath_flush(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ath->txq);
+
+ return 0;
+}
+
+/* Close protocol */
+static int ath_close(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ath->txq);
+
+ kfree_skb(ath->rx_skb);
+
+ cancel_work_sync(&ath->ctxtsw);
+
+ hu->priv = NULL;
+ kfree(ath);
+
+ return 0;
+}
+
+/* Enqueue frame for transmittion */
+static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+ struct ath_struct *ath = hu->priv;
+
+ if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
+
+ /* Discard SCO packet. AR3001 does not support SCO over HCI */
+ BT_DBG("SCO Packet over HCI received Dropping");
+
+ kfree(skb);
+
+ return 0;
+ }
+
+ BT_DBG("hu %p skb %p", hu, skb);
+
+ /* Prepend skb with frame type */
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+ skb_queue_tail(&ath->txq, skb);
+ set_bit(HCI_UART_SENDING, &hu->tx_state);
+
+ schedule_work(&ath->ctxtsw);
+
+ return 0;
+}
+
+static struct sk_buff *ath_dequeue(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+ struct sk_buff *skbuf;
+
+ skbuf = skb_dequeue(&ath->txq);
+
+ if (!skbuf)
+ return NULL;
+
+ /*
+ * Check if the HCI command is HCI sleep enable and
+ * update the sleep enable flag with command parameter.
+ *
+ * Value of sleep enable flag will be used later
+ * to verify if controller has to be woken up before
+ * sending any packet.
+ */
+ if (skbuf->data[0] == 0x01 &&
+ skbuf->data[1] == 0x04 &&
+ skbuf->data[2] == 0xFC)
+ ath->cur_sleep = skbuf->data[4];
+
+ return skbuf;
+}
+
+static void ath_check_data_len(struct ath_struct *ath, int len)
+{
+ int room = skb_tailroom(ath->rx_skb);
+
+ BT_DBG("len %d room %d", len, room);
+
+ if (len > room) {
+ BT_ERR("Data length is too large");
+ kfree_skb(ath->rx_skb);
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_skb = NULL;
+ ath->rx_count = 0;
+ } else {
+ ath->rx_state = HCIATH_W4_DATA;
+ ath->rx_count = len;
+ }
+}
+
+/* Recv data */
+static int ath_recv(struct hci_uart *hu, void *data, int count)
+{
+ struct ath_struct *ath = hu->priv;
+ char *ptr = data;
+ struct hci_event_hdr *eh;
+ struct hci_acl_hdr *ah;
+ struct hci_sco_hdr *sh;
+ int len, type, dlen;
+
+ BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
+ ath->rx_state, ath->rx_count);
+
+ while (count) {
+ if (ath->rx_count) {
+
+ len = min_t(unsigned int, ath->rx_count, count);
+ memcpy(skb_put(ath->rx_skb, len), ptr, len);
+ ath->rx_count -= len;
+ count -= len;
+ ptr += len;
+
+ if (ath->rx_count)
+ continue;
+ switch (ath->rx_state) {
+ case HCIATH_W4_DATA:
+ hci_recv_frame(ath->rx_skb);
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_skb = NULL;
+ ath->rx_count = 0;
+ continue;
+
+ case HCIATH_W4_EVENT_HDR:
+ eh = (struct hci_event_hdr *)ath->rx_skb->data;
+
+ BT_DBG("Event header: evt 0x%2.2x plen %d",
+ eh->evt, eh->plen);
+
+ ath_check_data_len(ath, eh->plen);
+ continue;
+
+ case HCIATH_W4_ACL_HDR:
+ ah = (struct hci_acl_hdr *)ath->rx_skb->data;
+ dlen = __le16_to_cpu(ah->dlen);
+
+ BT_DBG("ACL header: dlen %d", dlen);
+
+ ath_check_data_len(ath, dlen);
+ continue;
+
+ case HCIATH_W4_SCO_HDR:
+ sh = (struct hci_sco_hdr *)ath->rx_skb->data;
+
+ BT_DBG("SCO header: dlen %d", sh->dlen);
+
+ ath_check_data_len(ath, sh->dlen);
+ continue;
+
+ }
+ }
+
+ /* HCIATH_W4_PACKET_TYPE */
+ switch (*ptr) {
+ case HCI_EVENT_PKT:
+ BT_DBG("Event packet");
+ ath->rx_state = HCIATH_W4_EVENT_HDR;
+ ath->rx_count = HCI_EVENT_HDR_SIZE;
+ type = HCI_EVENT_PKT;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ BT_DBG("ACL packet");
+ ath->rx_state = HCIATH_W4_ACL_HDR;
+ ath->rx_count = HCI_ACL_HDR_SIZE;
+ type = HCI_ACLDATA_PKT;
+ break;
+
+ case HCI_SCODATA_PKT:
+ BT_DBG("SCO packet");
+ ath->rx_state = HCIATH_W4_SCO_HDR;
+ ath->rx_count = HCI_SCO_HDR_SIZE;
+ type = HCI_SCODATA_PKT;
+ break;
+
+ default:
+ BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
+ hu->hdev->stat.err_rx++;
+ ptr++;
+ count--;
+ continue;
+
+ };
+ ptr++;
+ count--;
+
+ /* Allocate packet */
+ ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!ath->rx_skb) {
+ BT_ERR("Can't allocate mem for new packet");
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_count = 0;
+
+ return -ENOMEM;
+ }
+ ath->rx_skb->dev = (void *)hu->hdev;
+ bt_cb(ath->rx_skb)->pkt_type = type;
+ }
+
+ return count;
+}
+
+static struct hci_uart_proto athp = {
+ .id = HCI_UART_ATH,
+ .open = ath_open,
+ .close = ath_close,
+ .recv = ath_recv,
+ .enqueue = ath_enqueue,
+ .dequeue = ath_dequeue,
+ .flush = ath_flush,
+};
+
+int ath_init(void)
+{
+ int err = hci_uart_register_proto(&athp);
+
+ if (!err)
+ BT_INFO("HCIATH protocol initialized");
+ else
+ BT_ERR("HCIATH protocol registration failed");
+
+ return err;
+}
+
+int ath_deinit(void)
+{
+ return hci_uart_unregister_proto(&athp);
+}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 76a1abb..7dd76d1 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_init();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH
+ ath_init();
+#endif

return 0;
}
@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_deinit();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH
+ ath_deinit();
+#endif

/* Release tty registration of line discipline */
if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 50113db..385537f 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -33,13 +33,14 @@
#define HCIUARTGETDEVICE _IOR('U', 202, int)

/* UART protocols */
-#define HCI_UART_MAX_PROTO 5
+#define HCI_UART_MAX_PROTO 6

#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH 5

struct hci_uart;

@@ -91,3 +92,8 @@ int bcsp_deinit(void);
int ll_init(void);
int ll_deinit(void);
#endif
+
+#ifdef CONFIG_BT_HCIUART_ATH
+int ath_init(void);
+int ath_deinit(void);
+#endif
--
1.7.0

2010-04-21 04:21:25

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH v3] Added support for Atheros AR300x Bluetooth Chip

Hi Luis,

Luis Rodriguez wrote:
> On Tue, Apr 20, 2010 at 03:20:32AM -0700, Suraj Sumangala wrote:
>> This protocol implements support for power management feature provided by AR300x chip.
>> This lets the controller chip go to sleep mode if there is no Bluetooth
>> activity for some time.
>> It then wakes up the chip in case of a Bluetooth activity.
>
> The above commit log needs some more work. Try to keep the
> commit log entry subject to about 50 characters, the context should
> not pass around 75 characters. Your commit also indicates this is a
> "protocol" ? This is driver, and you do have some hacks for enhancing
> power saving, but that is not that relevant to the commit log.
>
> How about:
>
> ---
> Add support for the Atheros AR300x Bluetooth Chip
>
> This adds support for the Atheros Bluetooth serial protocol to
> support the AR300x chipsets. The serial protocol implements
> enhanced power management features for the AR300x chipsets.
>
> Reviewed-by: Luis R. Rodriguez <[email protected]>
> Signed-off-by: Suraj <[email protected]>
> ---
>
> Of course you will need to adjust the subject and prepend it with
> PATCH v4, just as you did with a v3 for this patch.
>
> Then, this stuff:
>
>> * Third version
>>
>> ** Updated with extra spacing and indentation
>
> Do you use checkpatch.pl for your patches? If not please
> add check your patches after committing them with:
>
> git show ./scripts/checkpatch.pl -
> vi drivers/bluetooth/hci_ath.c
> git commit -a --amend
>
> And repeat until checkpatch.pl is git happy :)

Yes, I had done a checkpatch round with the patch. it looked happy. Did
you see any issue that could should have been caught by it?

>
>> ** made function definitions static
>> ** Removed inline and register keyword usage.
>> ** Removed unused return calls.
>> ** Incorporated code comments by Luis and Gustavo
>>
>> Thanks Luis and Gustavo for your comments
>
>
> Remove it from the commit log, if you do want to add some extra text
> to the patch youc an put it below the three dashes ("-") where the
> diff stat goes:
>
>>
>> Signed-off-by: Suraj <[email protected]>
>>
>> ---
> ^^^
>
> These are the three lines, anything below is ignored by git am
> when the maintainer applies the patch. So you can add anything you
> want ignored by git am here.
>
>> drivers/bluetooth/Kconfig | 11 ++
>> drivers/bluetooth/Makefile | 1 +
>> drivers/bluetooth/hci_ath.c | 384 +++++++++++++++++++++++++++++++++++++++++
>> drivers/bluetooth/hci_ldisc.c | 6 +
>> drivers/bluetooth/hci_uart.h | 8 +-
>> 5 files changed, 409 insertions(+), 1 deletions(-)
>> create mode 100755 drivers/bluetooth/hci_ath.c
>>
>> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
>> index 058fbcc..81abeff 100644
>> --- a/drivers/bluetooth/Kconfig
>> +++ b/drivers/bluetooth/Kconfig
>> @@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
>>
>> Say Y here to compile support for HCI BCSP protocol.
>>
>> +config BT_HCIUART_ATH
>> + bool "Atheros AR300x Board support"
>> + depends on BT_HCIUART
>> + help
>> + HCIATH (HCI Atheros) is a serial protocol for communication
>> + between Bluetooth device and host with support for Atheros AR300x
>> + power management feature. This protocol is required for
>> + serial Bluetooth devices that are based on Atheros AR300x chips.
>
> Please adjust the description as well. How about:
>
> + HCIATH (HCI Atheros) is a serial protocol for communication
> + between the host and Atheros AR300x Bluetooth devices. The
> + protocol implements enhaned power management features for the
> + the AR300x chipsets, it lets the controller chip go to sleep
> + mode if there is no Bluetooth activity for some time and wakes
> + up the chip in case of a Bluetooth activity. Enabling this
> + option will build HCI Atheros support into the hci_uart driver.
> + Enable this option if you have an UART Atheros AR300x serial
> + device.
>
>
>> +
>> + Say Y here to compile support for HCIATH protocol.
>> +
>> config BT_HCIUART_LL
>> bool "HCILL protocol support"
>> depends on BT_HCIUART
>> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
>> index 7e5aed5..1481faa 100644
>> --- a/drivers/bluetooth/Makefile
>> +++ b/drivers/bluetooth/Makefile
>> @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
>> hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
>> hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
>> hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
>> +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
>> hci_uart-objs := $(hci_uart-y)
>> diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
>> new file mode 100755
>> index 0000000..2f91954
>> --- /dev/null
>> +++ b/drivers/bluetooth/hci_ath.c
>> @@ -0,0 +1,384 @@
>> +/*
>> + * Copyright (c) 2009-2010 Atheros Communications Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program; if not, write to the Free Software
>> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
>> + *
>> + */
>> +
>> +#include <linux/module.h>
>> +#include <linux/kernel.h>
>> +
>> +#include <linux/init.h>
>> +#include <linux/slab.h>
>> +#include <linux/tty.h>
>> +#include <linux/errno.h>
>> +#include <linux/ioctl.h>
>> +#include <linux/skbuff.h>
>> +
>> +#include <net/bluetooth/bluetooth.h>
>> +#include <net/bluetooth/hci_core.h>
>> +
>> +#include "hci_uart.h"
>> +
>> +
>> +/* HCIATH receiver States */
>> +#define HCIATH_W4_PACKET_TYPE 0
>> +#define HCIATH_W4_EVENT_HDR 1
>> +#define HCIATH_W4_ACL_HDR 2
>> +#define HCIATH_W4_SCO_HDR 3
>> +#define HCIATH_W4_DATA 4
>> +
>> +struct ath_struct {
>> + struct hci_uart *hu;
>> + unsigned int rx_state;
>> + unsigned int rx_count;
>> + unsigned int cur_sleep;
>> +
>> + spinlock_t hciath_lock;
>> + struct sk_buff *rx_skb;
>> + struct sk_buff_head txq;
>> + wait_queue_head_t wqevt;
>> + struct work_struct ctxtsw;
>> +};
>> +
>> +static int ath_wakeup_ar3001(struct tty_struct *tty)
>> +{
>> + struct termios settings;
>> + int status = 0x00;
>> +
>> + status = tty->driver->ops->tiocmget(tty, NULL);
>> +
>> + if ((status & TIOCM_CTS))
>> + return status;
>
> No need for double () parens here. This should be fine:
>
> + if (status & TIOCM_CTS)
> + return status;
>
> You would use double parens if you are doing a check against
> another flag as well.
>
>> +
>> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
>> +
>> + /* Disable Automatic RTSCTS */
>> + settings.c_cflag &= ~CRTSCTS;
>> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
>> +
>> + status = tty->driver->ops->tiocmget(tty, NULL);
>> +
>> + /* Clear RTS first */
>> + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
>> + mdelay(20);
>> +
>> + status = tty->driver->ops->tiocmget(tty, NULL);
>> +
>> + /* Set RTS, wake up board */
>> + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
>> + mdelay(20);
>> +
>> + status = tty->driver->ops->tiocmget(tty, NULL);
>> +
>> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
>> +
>> + settings.c_cflag |= CRTSCTS;
>> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
>> +
>> + return status;
>> +}
>> +
>> +static void ath_context_switch(struct work_struct *work)
>
> Can you please rename this to ath_hci_uart_work()
>
>> +{
>> + int status;
>> + struct ath_struct *ath;
>> + struct hci_uart *hu;
>> + struct tty_struct *tty;
>> +
>> + ath = container_of(work, struct ath_struct, ctxtsw);
>> +
>> + hu = ath->hu;
>> + tty = hu->tty;
>> +
>> + /* verify and wake up controller */
>> + if (ath->cur_sleep) {
>> +
>> + status = ath_wakeup_ar3001(tty);
>> +
>> + if (!(status & TIOCM_CTS))
>> + return;
>> + }
>> +
>> + /* Ready to send Data */
>> + clear_bit(HCI_UART_SENDING, &hu->tx_state);
>> + hci_uart_tx_wakeup(hu);
>> +}
>> +
>> +/* Initialize protocol */
>> +static int ath_open(struct hci_uart *hu)
>> +{
>> + struct ath_struct *ath;
>> +
>> + BT_DBG("hu %p", hu);
>> +
>> + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
>> + if (!ath)
>> + return -ENOMEM;
>> +
>> + skb_queue_head_init(&ath->txq);
>> + spin_lock_init(&ath->hciath_lock);
>> +
>> + hu->priv = ath;
>> + ath->hu = hu;
>> +
>> + init_waitqueue_head(&ath->wqevt);
>> + INIT_WORK(&ath->ctxtsw, ath_context_switch);
>> +
>> + return 0;
>> +}
>> +
>> +/* Flush protocol data */
>> +static int ath_flush(struct hci_uart *hu)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> +
>> + BT_DBG("hu %p", hu);
>> +
>> + skb_queue_purge(&ath->txq);
>> +
>> + return 0;
>> +}
>> +
>> +/* Close protocol */
>> +static int ath_close(struct hci_uart *hu)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> +
>> + BT_DBG("hu %p", hu);
>> +
>> + skb_queue_purge(&ath->txq);
>> +
>> + if (ath->rx_skb)
>> + kfree_skb(ath->rx_skb);
>
> No need for the check, kfree_skb() does that for you
> and it has it optimized for the case where the skb you
> pass is NULL. You can just do:
>
> + kfree_skb(ath->rx_skb);
>
>> +
>> + cancel_work_sync(&ath->ctxtsw);
>> +
>> + hu->priv = NULL;
>> + kfree(ath);
>> +
>> + return 0;
>> +}
>
> Did you give this new patch a spin by looping bringing up,
> scanning, bringing the interface down? Or have a loop doing
> a scan while in another window you bring the interface up
> and down?
>
Yep, Have been testing it for sometime. Haven't seen any issue yet (Hope
I dont see any :-) )
>> +
>> +/* Enqueue frame for transmittion */
>> +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> +
>> + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
>> +
>> + /* Discard SCO packet.AR3001 does not support SCO over HCI */
>
> Add a space after packet. Why does it not support SCO over HCI BTW?
> Just curious. I'm new to BT :) Is this common? If this is common can't
> the BT stack be informed of these things so that they don't pass the skbs
> to the driver?
>
From my experience, it is common for smaller BT devices (headsets) and
devices with memory limitations.

I guess, there is no way to tell SCO routing using any HCI cmd/Event.

In the Linux Ubuntu distro that I use, it is controlled using the
"SCORouting" flag in "/etc/bluetooth/audio.conf". Since it is a user
configuration, driver can not assume that the flag will be set.

So, this is like a precautionary check.



> This could be done in a separate patch though if this is the case
> though.
>
>> + BT_DBG("SCO Packet over HCI received Dropping");
>> +
>> + kfree(skb);
>> +
>> + return 0;
>> + }
>> +
>> + BT_DBG("hu %p skb %p", hu, skb);
>> +
>> + /* Prepend skb with frame type */
>> + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
>> +
>> + skb_queue_tail(&ath->txq, skb);
>> + set_bit(HCI_UART_SENDING, &hu->tx_state);
>> +
>> + schedule_work(&ath->ctxtsw);
>> +
>> + return 0;
>> +}
>> +
>> +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> + struct sk_buff *skbuf;
>> +
>> + skbuf = skb_dequeue(&ath->txq);
>> +
>> + if (!skbuf)
>> + return NULL;
>> +
>> +
>> + /*
>> + * Check if the HCI command is HCI sleep enable and
>> + * update the sleep enable flag with command parameter.
>> + *
>> + * Value of sleep enable flag will be used later
>> + * to verify if controller has to be woken up before
>> + * sending any packet.
>> + */
>> + if (skbuf->data[0] == 0x01 && skbuf->data[1] == 0x04 &&
>> + skbuf->data[2] == 0xFC)
>> + ath->cur_sleep = skbuf->data[4];
>
> Might as well just do this:
>
> + if (skbuf->data[0] == 0x01 &&
> + skbuf->data[1] == 0x04 &&
> + skbuf->data[2] == 0xFC)
> + ath->cur_sleep = skbuf->data[4];
>
> Is this sort of check done in any other drivers/protocols? If so a
> helper could be added to hci_uart.h if this is the case, but likely
> better though a separate patch.

No, this check is done only for this specific driver/protocol.

This is the reason why we had to go for board specific driver change.
Otherways, we could have used the default HCI driver implementation.

>
>> +
>> + return skbuf;
>> +}
>> +
>> +static void ath_check_data_len(struct ath_struct *ath, int len)
>> +{
>> + int room = skb_tailroom(ath->rx_skb);
>> +
>> + BT_DBG("len %d room %d", len, room);
>> +
>> + if (len > room) {
>> + BT_ERR("Data length is too large");
>> + kfree_skb(ath->rx_skb);
>> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
>> + ath->rx_skb = NULL;
>> + ath->rx_count = 0;
>> + } else {
>> + ath->rx_state = HCIATH_W4_DATA;
>> + ath->rx_count = len;
>> + }
>> +}
>> +
>> +/* Recv data */
>> +static int ath_recv(struct hci_uart *hu, void *data, int count)
>> +{
>> + struct ath_struct *ath = hu->priv;
>> + char *ptr = data;
>> + struct hci_event_hdr *eh;
>> + struct hci_acl_hdr *ah;
>> + struct hci_sco_hdr *sh;
>> + int len, type, dlen;
>> +
>> +
>> + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
>> + ath->rx_state, ath->rx_count);
>> +
>> + while (count) {
>> + if (ath->rx_count) {
>> +
>> + len = min_t(unsigned int, ath->rx_count, count);
>> + memcpy(skb_put(ath->rx_skb, len), ptr, len);
>> + ath->rx_count -= len;
>> + count -= len;
>> + ptr += len;
>> +
>> + if (ath->rx_count)
>> + continue;
>> + switch (ath->rx_state) {
>> + case HCIATH_W4_DATA:
>> + hci_recv_frame(ath->rx_skb);
>> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
>> + ath->rx_skb = NULL;
>> + ath->rx_count = 0;
>> + continue;
>> +
>> + case HCIATH_W4_EVENT_HDR:
>> + eh = (struct hci_event_hdr *)ath->rx_skb->data;
>> +
>> + BT_DBG("Event header: evt 0x%2.2x plen %d",
>> + eh->evt, eh->plen);
>> +
>> + ath_check_data_len(ath, eh->plen);
>> + continue;
>> +
>> + case HCIATH_W4_ACL_HDR:
>> + ah = (struct hci_acl_hdr *)ath->rx_skb->data;
>> + dlen = __le16_to_cpu(ah->dlen);
>> +
>> + BT_DBG("ACL header: dlen %d", dlen);
>> +
>> + ath_check_data_len(ath, dlen);
>> + continue;
>> +
>> + case HCIATH_W4_SCO_HDR:
>> + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
>> +
>> + BT_DBG("SCO header: dlen %d", sh->dlen);
>> +
>> + ath_check_data_len(ath, sh->dlen);
>> + continue;
>> +
>> + }
>> + }
>> +
>> + /* HCIATH_W4_PACKET_TYPE */
>> + switch (*ptr) {
>> + case HCI_EVENT_PKT:
>> + BT_DBG("Event packet");
>> + ath->rx_state = HCIATH_W4_EVENT_HDR;
>> + ath->rx_count = HCI_EVENT_HDR_SIZE;
>> + type = HCI_EVENT_PKT;
>> + break;
>> +
>> + case HCI_ACLDATA_PKT:
>> + BT_DBG("ACL packet");
>> + ath->rx_state = HCIATH_W4_ACL_HDR;
>> + ath->rx_count = HCI_ACL_HDR_SIZE;
>> + type = HCI_ACLDATA_PKT;
>> + break;
>> +
>> + case HCI_SCODATA_PKT:
>> + BT_DBG("SCO packet");
>> + ath->rx_state = HCIATH_W4_SCO_HDR;
>> + ath->rx_count = HCI_SCO_HDR_SIZE;
>> + type = HCI_SCODATA_PKT;
>> + break;
>> +
>> + default:
>> + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
>> + hu->hdev->stat.err_rx++;
>> + ptr++;
>> + count--;
>> + continue;
>> +
>> + };
>> + ptr++;
>> + count--;
>> +
>> + /* Allocate packet */
>> + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
>> + if (!ath->rx_skb) {
>> + BT_ERR("Can't allocate mem for new packet");
>> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
>> + ath->rx_count = 0;
>> +
>> + return -ENOMEM;
>> + }
>> + ath->rx_skb->dev = (void *)hu->hdev;
>> + bt_cb(ath->rx_skb)->pkt_type = type;
>> + }
>> +
>> + return count;
>> +}
>> +
>> +static struct hci_uart_proto athp = {
>> + .id = HCI_UART_ATH,
>> + .open = ath_open,
>> + .close = ath_close,
>> + .recv = ath_recv,
>> + .enqueue = ath_enqueue,
>> + .dequeue = ath_dequeue,
>> + .flush = ath_flush,
>> +};
>> +
>> +int ath_init(void)
>> +{
>> + int err = hci_uart_register_proto(&athp);
>> +
>> + if (!err)
>> + BT_INFO("HCIATH protocol initialized");
>> + else
>> + BT_ERR("HCIATH protocol registration failed");
>> +
>> + return err;
>> +}
>> +
>> +int ath_deinit(void)
>> +{
>> + return hci_uart_unregister_proto(&athp);
>> +}
>> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
>> index 76a1abb..7dd76d1 100644
>> --- a/drivers/bluetooth/hci_ldisc.c
>> +++ b/drivers/bluetooth/hci_ldisc.c
>> @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
>> #ifdef CONFIG_BT_HCIUART_LL
>> ll_init();
>> #endif
>> +#ifdef CONFIG_BT_HCIUART_ATH
>> + ath_init();
>> +#endif
>>
>> return 0;
>> }
>> @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
>> #ifdef CONFIG_BT_HCIUART_LL
>> ll_deinit();
>> #endif
>> +#ifdef CONFIG_BT_HCIUART_ATH
>> + ath_deinit();
>> +#endif
>>
>> /* Release tty registration of line discipline */
>> if ((err = tty_unregister_ldisc(N_HCI)))
>> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
>> index 50113db..385537f 100644
>> --- a/drivers/bluetooth/hci_uart.h
>> +++ b/drivers/bluetooth/hci_uart.h
>> @@ -33,13 +33,14 @@
>> #define HCIUARTGETDEVICE _IOR('U', 202, int)
>>
>> /* UART protocols */
>> -#define HCI_UART_MAX_PROTO 5
>> +#define HCI_UART_MAX_PROTO 6
>>
>> #define HCI_UART_H4 0
>> #define HCI_UART_BCSP 1
>> #define HCI_UART_3WIRE 2
>> #define HCI_UART_H4DS 3
>> #define HCI_UART_LL 4
>> +#define HCI_UART_ATH 5
>>
>> struct hci_uart;
>>
>> @@ -91,3 +92,8 @@ int bcsp_deinit(void);
>> int ll_init(void);
>> int ll_deinit(void);
>> #endif
>> +
>> +#ifdef CONFIG_BT_HCIUART_ATH
>> +int ath_init(void);
>> +int ath_deinit(void);
>> +#endif
>> --
>> 1.7.0
>>
>>
>>

Thanks for the comments.

Regards,
Suraj

2010-04-20 17:34:28

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [PATCH v3] Added support for Atheros AR300x Bluetooth Chip

On Tue, Apr 20, 2010 at 03:20:32AM -0700, Suraj Sumangala wrote:
> This protocol implements support for power management feature provided by AR300x chip.
> This lets the controller chip go to sleep mode if there is no Bluetooth
> activity for some time.
> It then wakes up the chip in case of a Bluetooth activity.

The above commit log needs some more work. Try to keep the
commit log entry subject to about 50 characters, the context should
not pass around 75 characters. Your commit also indicates this is a
"protocol" ? This is driver, and you do have some hacks for enhancing
power saving, but that is not that relevant to the commit log.

How about:

---
Add support for the Atheros AR300x Bluetooth Chip

This adds support for the Atheros Bluetooth serial protocol to
support the AR300x chipsets. The serial protocol implements
enhanced power management features for the AR300x chipsets.

Reviewed-by: Luis R. Rodriguez <[email protected]>
Signed-off-by: Suraj <[email protected]>
---

Of course you will need to adjust the subject and prepend it with
PATCH v4, just as you did with a v3 for this patch.

Then, this stuff:

> * Third version
>
> ** Updated with extra spacing and indentation

Do you use checkpatch.pl for your patches? If not please
add check your patches after committing them with:

git show ./scripts/checkpatch.pl -
vi drivers/bluetooth/hci_ath.c
git commit -a --amend

And repeat until checkpatch.pl is git happy :)

> ** made function definitions static
> ** Removed inline and register keyword usage.
> ** Removed unused return calls.
> ** Incorporated code comments by Luis and Gustavo
>
> Thanks Luis and Gustavo for your comments


Remove it from the commit log, if you do want to add some extra text
to the patch youc an put it below the three dashes ("-") where the
diff stat goes:

>
>
> Signed-off-by: Suraj <[email protected]>
>
> ---
^^^

These are the three lines, anything below is ignored by git am
when the maintainer applies the patch. So you can add anything you
want ignored by git am here.

> drivers/bluetooth/Kconfig | 11 ++
> drivers/bluetooth/Makefile | 1 +
> drivers/bluetooth/hci_ath.c | 384 +++++++++++++++++++++++++++++++++++++++++
> drivers/bluetooth/hci_ldisc.c | 6 +
> drivers/bluetooth/hci_uart.h | 8 +-
> 5 files changed, 409 insertions(+), 1 deletions(-)
> create mode 100755 drivers/bluetooth/hci_ath.c
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 058fbcc..81abeff 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
>
> Say Y here to compile support for HCI BCSP protocol.
>
> +config BT_HCIUART_ATH
> + bool "Atheros AR300x Board support"
> + depends on BT_HCIUART
> + help
> + HCIATH (HCI Atheros) is a serial protocol for communication
> + between Bluetooth device and host with support for Atheros AR300x
> + power management feature. This protocol is required for
> + serial Bluetooth devices that are based on Atheros AR300x chips.

Please adjust the description as well. How about:

+ HCIATH (HCI Atheros) is a serial protocol for communication
+ between the host and Atheros AR300x Bluetooth devices. The
+ protocol implements enhaned power management features for the
+ the AR300x chipsets, it lets the controller chip go to sleep
+ mode if there is no Bluetooth activity for some time and wakes
+ up the chip in case of a Bluetooth activity. Enabling this
+ option will build HCI Atheros support into the hci_uart driver.
+ Enable this option if you have an UART Atheros AR300x serial
+ device.


> +
> + Say Y here to compile support for HCIATH protocol.
> +
> config BT_HCIUART_LL
> bool "HCILL protocol support"
> depends on BT_HCIUART
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 7e5aed5..1481faa 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
> hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
> hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
> hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
> +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
> hci_uart-objs := $(hci_uart-y)
> diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
> new file mode 100755
> index 0000000..2f91954
> --- /dev/null
> +++ b/drivers/bluetooth/hci_ath.c
> @@ -0,0 +1,384 @@
> +/*
> + * Copyright (c) 2009-2010 Atheros Communications Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/errno.h>
> +#include <linux/ioctl.h>
> +#include <linux/skbuff.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include "hci_uart.h"
> +
> +
> +/* HCIATH receiver States */
> +#define HCIATH_W4_PACKET_TYPE 0
> +#define HCIATH_W4_EVENT_HDR 1
> +#define HCIATH_W4_ACL_HDR 2
> +#define HCIATH_W4_SCO_HDR 3
> +#define HCIATH_W4_DATA 4
> +
> +struct ath_struct {
> + struct hci_uart *hu;
> + unsigned int rx_state;
> + unsigned int rx_count;
> + unsigned int cur_sleep;
> +
> + spinlock_t hciath_lock;
> + struct sk_buff *rx_skb;
> + struct sk_buff_head txq;
> + wait_queue_head_t wqevt;
> + struct work_struct ctxtsw;
> +};
> +
> +static int ath_wakeup_ar3001(struct tty_struct *tty)
> +{
> + struct termios settings;
> + int status = 0x00;
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + if ((status & TIOCM_CTS))
> + return status;

No need for double () parens here. This should be fine:

+ if (status & TIOCM_CTS)
+ return status;

You would use double parens if you are doing a check against
another flag as well.

> +
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + /* Disable Automatic RTSCTS */
> + settings.c_cflag &= ~CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Clear RTS first */
> + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Set RTS, wake up board */
> + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + settings.c_cflag |= CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> +
> + return status;
> +}
> +
> +static void ath_context_switch(struct work_struct *work)

Can you please rename this to ath_hci_uart_work()

> +{
> + int status;
> + struct ath_struct *ath;
> + struct hci_uart *hu;
> + struct tty_struct *tty;
> +
> + ath = container_of(work, struct ath_struct, ctxtsw);
> +
> + hu = ath->hu;
> + tty = hu->tty;
> +
> + /* verify and wake up controller */
> + if (ath->cur_sleep) {
> +
> + status = ath_wakeup_ar3001(tty);
> +
> + if (!(status & TIOCM_CTS))
> + return;
> + }
> +
> + /* Ready to send Data */
> + clear_bit(HCI_UART_SENDING, &hu->tx_state);
> + hci_uart_tx_wakeup(hu);
> +}
> +
> +/* Initialize protocol */
> +static int ath_open(struct hci_uart *hu)
> +{
> + struct ath_struct *ath;
> +
> + BT_DBG("hu %p", hu);
> +
> + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
> + if (!ath)
> + return -ENOMEM;
> +
> + skb_queue_head_init(&ath->txq);
> + spin_lock_init(&ath->hciath_lock);
> +
> + hu->priv = ath;
> + ath->hu = hu;
> +
> + init_waitqueue_head(&ath->wqevt);
> + INIT_WORK(&ath->ctxtsw, ath_context_switch);
> +
> + return 0;
> +}
> +
> +/* Flush protocol data */
> +static int ath_flush(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + return 0;
> +}
> +
> +/* Close protocol */
> +static int ath_close(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + if (ath->rx_skb)
> + kfree_skb(ath->rx_skb);

No need for the check, kfree_skb() does that for you
and it has it optimized for the case where the skb you
pass is NULL. You can just do:

+ kfree_skb(ath->rx_skb);

> +
> + cancel_work_sync(&ath->ctxtsw);
> +
> + hu->priv = NULL;
> + kfree(ath);
> +
> + return 0;
> +}

Did you give this new patch a spin by looping bringing up,
scanning, bringing the interface down? Or have a loop doing
a scan while in another window you bring the interface up
and down?

> +
> +/* Enqueue frame for transmittion */
> +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
> +
> + /* Discard SCO packet.AR3001 does not support SCO over HCI */

Add a space after packet. Why does it not support SCO over HCI BTW?
Just curious. I'm new to BT :) Is this common? If this is common can't
the BT stack be informed of these things so that they don't pass the skbs
to the driver?

This could be done in a separate patch though if this is the case
though.

> + BT_DBG("SCO Packet over HCI received Dropping");
> +
> + kfree(skb);
> +
> + return 0;
> + }
> +
> + BT_DBG("hu %p skb %p", hu, skb);
> +
> + /* Prepend skb with frame type */
> + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
> +
> + skb_queue_tail(&ath->txq, skb);
> + set_bit(HCI_UART_SENDING, &hu->tx_state);
> +
> + schedule_work(&ath->ctxtsw);
> +
> + return 0;
> +}
> +
> +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + struct sk_buff *skbuf;
> +
> + skbuf = skb_dequeue(&ath->txq);
> +
> + if (!skbuf)
> + return NULL;
> +
> +
> + /*
> + * Check if the HCI command is HCI sleep enable and
> + * update the sleep enable flag with command parameter.
> + *
> + * Value of sleep enable flag will be used later
> + * to verify if controller has to be woken up before
> + * sending any packet.
> + */
> + if (skbuf->data[0] == 0x01 && skbuf->data[1] == 0x04 &&
> + skbuf->data[2] == 0xFC)
> + ath->cur_sleep = skbuf->data[4];

Might as well just do this:

+ if (skbuf->data[0] == 0x01 &&
+ skbuf->data[1] == 0x04 &&
+ skbuf->data[2] == 0xFC)
+ ath->cur_sleep = skbuf->data[4];

Is this sort of check done in any other drivers/protocols? If so a
helper could be added to hci_uart.h if this is the case, but likely
better though a separate patch.

> +
> + return skbuf;
> +}
> +
> +static void ath_check_data_len(struct ath_struct *ath, int len)
> +{
> + int room = skb_tailroom(ath->rx_skb);
> +
> + BT_DBG("len %d room %d", len, room);
> +
> + if (len > room) {
> + BT_ERR("Data length is too large");
> + kfree_skb(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + } else {
> + ath->rx_state = HCIATH_W4_DATA;
> + ath->rx_count = len;
> + }
> +}
> +
> +/* Recv data */
> +static int ath_recv(struct hci_uart *hu, void *data, int count)
> +{
> + struct ath_struct *ath = hu->priv;
> + char *ptr = data;
> + struct hci_event_hdr *eh;
> + struct hci_acl_hdr *ah;
> + struct hci_sco_hdr *sh;
> + int len, type, dlen;
> +
> +
> + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> + ath->rx_state, ath->rx_count);
> +
> + while (count) {
> + if (ath->rx_count) {
> +
> + len = min_t(unsigned int, ath->rx_count, count);
> + memcpy(skb_put(ath->rx_skb, len), ptr, len);
> + ath->rx_count -= len;
> + count -= len;
> + ptr += len;
> +
> + if (ath->rx_count)
> + continue;
> + switch (ath->rx_state) {
> + case HCIATH_W4_DATA:
> + hci_recv_frame(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + continue;
> +
> + case HCIATH_W4_EVENT_HDR:
> + eh = (struct hci_event_hdr *)ath->rx_skb->data;
> +
> + BT_DBG("Event header: evt 0x%2.2x plen %d",
> + eh->evt, eh->plen);
> +
> + ath_check_data_len(ath, eh->plen);
> + continue;
> +
> + case HCIATH_W4_ACL_HDR:
> + ah = (struct hci_acl_hdr *)ath->rx_skb->data;
> + dlen = __le16_to_cpu(ah->dlen);
> +
> + BT_DBG("ACL header: dlen %d", dlen);
> +
> + ath_check_data_len(ath, dlen);
> + continue;
> +
> + case HCIATH_W4_SCO_HDR:
> + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
> +
> + BT_DBG("SCO header: dlen %d", sh->dlen);
> +
> + ath_check_data_len(ath, sh->dlen);
> + continue;
> +
> + }
> + }
> +
> + /* HCIATH_W4_PACKET_TYPE */
> + switch (*ptr) {
> + case HCI_EVENT_PKT:
> + BT_DBG("Event packet");
> + ath->rx_state = HCIATH_W4_EVENT_HDR;
> + ath->rx_count = HCI_EVENT_HDR_SIZE;
> + type = HCI_EVENT_PKT;
> + break;
> +
> + case HCI_ACLDATA_PKT:
> + BT_DBG("ACL packet");
> + ath->rx_state = HCIATH_W4_ACL_HDR;
> + ath->rx_count = HCI_ACL_HDR_SIZE;
> + type = HCI_ACLDATA_PKT;
> + break;
> +
> + case HCI_SCODATA_PKT:
> + BT_DBG("SCO packet");
> + ath->rx_state = HCIATH_W4_SCO_HDR;
> + ath->rx_count = HCI_SCO_HDR_SIZE;
> + type = HCI_SCODATA_PKT;
> + break;
> +
> + default:
> + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> + hu->hdev->stat.err_rx++;
> + ptr++;
> + count--;
> + continue;
> +
> + };
> + ptr++;
> + count--;
> +
> + /* Allocate packet */
> + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> + if (!ath->rx_skb) {
> + BT_ERR("Can't allocate mem for new packet");
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_count = 0;
> +
> + return -ENOMEM;
> + }
> + ath->rx_skb->dev = (void *)hu->hdev;
> + bt_cb(ath->rx_skb)->pkt_type = type;
> + }
> +
> + return count;
> +}
> +
> +static struct hci_uart_proto athp = {
> + .id = HCI_UART_ATH,
> + .open = ath_open,
> + .close = ath_close,
> + .recv = ath_recv,
> + .enqueue = ath_enqueue,
> + .dequeue = ath_dequeue,
> + .flush = ath_flush,
> +};
> +
> +int ath_init(void)
> +{
> + int err = hci_uart_register_proto(&athp);
> +
> + if (!err)
> + BT_INFO("HCIATH protocol initialized");
> + else
> + BT_ERR("HCIATH protocol registration failed");
> +
> + return err;
> +}
> +
> +int ath_deinit(void)
> +{
> + return hci_uart_unregister_proto(&athp);
> +}
> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> index 76a1abb..7dd76d1 100644
> --- a/drivers/bluetooth/hci_ldisc.c
> +++ b/drivers/bluetooth/hci_ldisc.c
> @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_init();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_init();
> +#endif
>
> return 0;
> }
> @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_deinit();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_deinit();
> +#endif
>
> /* Release tty registration of line discipline */
> if ((err = tty_unregister_ldisc(N_HCI)))
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index 50113db..385537f 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -33,13 +33,14 @@
> #define HCIUARTGETDEVICE _IOR('U', 202, int)
>
> /* UART protocols */
> -#define HCI_UART_MAX_PROTO 5
> +#define HCI_UART_MAX_PROTO 6
>
> #define HCI_UART_H4 0
> #define HCI_UART_BCSP 1
> #define HCI_UART_3WIRE 2
> #define HCI_UART_H4DS 3
> #define HCI_UART_LL 4
> +#define HCI_UART_ATH 5
>
> struct hci_uart;
>
> @@ -91,3 +92,8 @@ int bcsp_deinit(void);
> int ll_init(void);
> int ll_deinit(void);
> #endif
> +
> +#ifdef CONFIG_BT_HCIUART_ATH
> +int ath_init(void);
> +int ath_deinit(void);
> +#endif
> --
> 1.7.0
>
>
>

2010-04-20 15:36:55

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH v3] Added support for Atheros AR300x Bluetooth Chip

Hi Suraj,

* suraj <[email protected]> [2010-04-20 15:50:32 +0530]:

> This protocol implements support for power management feature provided by AR300x chip.
> This lets the controller chip go to sleep mode if there is no Bluetooth
> activity for some time.
> It then wakes up the chip in case of a Bluetooth activity.
>
> * Third version
>
> ** Updated with extra spacing and indentation
> ** made function definitions static
> ** Removed inline and register keyword usage.
> ** Removed unused return calls.
> ** Incorporated code comments by Luis and Gustavo
>
> Thanks Luis and Gustavo for your comments
>
>
> Signed-off-by: Suraj <[email protected]>
>
> ---
> drivers/bluetooth/Kconfig | 11 ++
> drivers/bluetooth/Makefile | 1 +
> drivers/bluetooth/hci_ath.c | 384 +++++++++++++++++++++++++++++++++++++++++
> drivers/bluetooth/hci_ldisc.c | 6 +
> drivers/bluetooth/hci_uart.h | 8 +-
> 5 files changed, 409 insertions(+), 1 deletions(-)
> create mode 100755 drivers/bluetooth/hci_ath.c
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 058fbcc..81abeff 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
>
> Say Y here to compile support for HCI BCSP protocol.
>
> +config BT_HCIUART_ATH
> + bool "Atheros AR300x Board support"
> + depends on BT_HCIUART
> + help
> + HCIATH (HCI Atheros) is a serial protocol for communication
> + between Bluetooth device and host with support for Atheros AR300x
> + power management feature. This protocol is required for
> + serial Bluetooth devices that are based on Atheros AR300x chips.
> +
> + Say Y here to compile support for HCIATH protocol.
> +
> config BT_HCIUART_LL
> bool "HCILL protocol support"
> depends on BT_HCIUART
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 7e5aed5..1481faa 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
> hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
> hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
> hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
> +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
> hci_uart-objs := $(hci_uart-y)
> diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
> new file mode 100755
> index 0000000..2f91954
> --- /dev/null
> +++ b/drivers/bluetooth/hci_ath.c
> @@ -0,0 +1,384 @@
> +/*
> + * Copyright (c) 2009-2010 Atheros Communications Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/errno.h>
> +#include <linux/ioctl.h>
> +#include <linux/skbuff.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include "hci_uart.h"
> +
> +
> +/* HCIATH receiver States */
> +#define HCIATH_W4_PACKET_TYPE 0
> +#define HCIATH_W4_EVENT_HDR 1
> +#define HCIATH_W4_ACL_HDR 2
> +#define HCIATH_W4_SCO_HDR 3
> +#define HCIATH_W4_DATA 4
> +
> +struct ath_struct {
> + struct hci_uart *hu;
> + unsigned int rx_state;
> + unsigned int rx_count;
> + unsigned int cur_sleep;
> +
> + spinlock_t hciath_lock;
> + struct sk_buff *rx_skb;
> + struct sk_buff_head txq;
> + wait_queue_head_t wqevt;
> + struct work_struct ctxtsw;
> +};
> +
> +static int ath_wakeup_ar3001(struct tty_struct *tty)
> +{
> + struct termios settings;
> + int status = 0x00;
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + if ((status & TIOCM_CTS))
> + return status;
> +
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + /* Disable Automatic RTSCTS */
> + settings.c_cflag &= ~CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Clear RTS first */
> + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Set RTS, wake up board */
> + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + settings.c_cflag |= CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> +
> + return status;
> +}
> +
> +static void ath_context_switch(struct work_struct *work)
> +{
> + int status;
> + struct ath_struct *ath;
> + struct hci_uart *hu;
> + struct tty_struct *tty;
> +
> + ath = container_of(work, struct ath_struct, ctxtsw);
> +
> + hu = ath->hu;
> + tty = hu->tty;
> +
> + /* verify and wake up controller */
> + if (ath->cur_sleep) {
> +

Extra blank line here.

> + status = ath_wakeup_ar3001(tty);
> +
> + if (!(status & TIOCM_CTS))
> + return;
> + }
> +
> + /* Ready to send Data */
> + clear_bit(HCI_UART_SENDING, &hu->tx_state);
> + hci_uart_tx_wakeup(hu);
> +}
> +
> +/* Initialize protocol */
> +static int ath_open(struct hci_uart *hu)
> +{
> + struct ath_struct *ath;
> +
> + BT_DBG("hu %p", hu);
> +
> + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
> + if (!ath)
> + return -ENOMEM;
> +
> + skb_queue_head_init(&ath->txq);
> + spin_lock_init(&ath->hciath_lock);
> +
> + hu->priv = ath;
> + ath->hu = hu;
> +
> + init_waitqueue_head(&ath->wqevt);
> + INIT_WORK(&ath->ctxtsw, ath_context_switch);
> +
> + return 0;
> +}
> +
> +/* Flush protocol data */
> +static int ath_flush(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + return 0;
> +}
> +
> +/* Close protocol */
> +static int ath_close(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + if (ath->rx_skb)
> + kfree_skb(ath->rx_skb);
> +
> + cancel_work_sync(&ath->ctxtsw);
> +
> + hu->priv = NULL;
> + kfree(ath);
> +
> + return 0;
> +}
> +
> +/* Enqueue frame for transmittion */
> +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> +{
> + struct ath_struct *ath = hu->priv;
> +
> + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
> +
> + /* Discard SCO packet.AR3001 does not support SCO over HCI */
> + BT_DBG("SCO Packet over HCI received Dropping");
> +
> + kfree(skb);
> +
> + return 0;
> + }
> +
> + BT_DBG("hu %p skb %p", hu, skb);
> +
> + /* Prepend skb with frame type */
> + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
> +
> + skb_queue_tail(&ath->txq, skb);
> + set_bit(HCI_UART_SENDING, &hu->tx_state);
> +
> + schedule_work(&ath->ctxtsw);
> +
> + return 0;
> +}
> +
> +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + struct sk_buff *skbuf;
> +
> + skbuf = skb_dequeue(&ath->txq);
> +
> + if (!skbuf)
> + return NULL;
> +
> +

Another extra blank line here.

> + /*
> + * Check if the HCI command is HCI sleep enable and
> + * update the sleep enable flag with command parameter.
> + *
> + * Value of sleep enable flag will be used later
> + * to verify if controller has to be woken up before
> + * sending any packet.
> + */
> + if (skbuf->data[0] == 0x01 && skbuf->data[1] == 0x04 &&
> + skbuf->data[2] == 0xFC)
> + ath->cur_sleep = skbuf->data[4];
> +
> + return skbuf;
> +}
> +
> +static void ath_check_data_len(struct ath_struct *ath, int len)
> +{
> + int room = skb_tailroom(ath->rx_skb);
> +
> + BT_DBG("len %d room %d", len, room);
> +
> + if (len > room) {
> + BT_ERR("Data length is too large");
> + kfree_skb(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + } else {
> + ath->rx_state = HCIATH_W4_DATA;
> + ath->rx_count = len;
> + }
> +}
> +
> +/* Recv data */
> +static int ath_recv(struct hci_uart *hu, void *data, int count)
> +{
> + struct ath_struct *ath = hu->priv;
> + char *ptr = data;
> + struct hci_event_hdr *eh;
> + struct hci_acl_hdr *ah;
> + struct hci_sco_hdr *sh;
> + int len, type, dlen;
> +
> +

Extra blank line here too.

> + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> + ath->rx_state, ath->rx_count);
> +
> + while (count) {
> + if (ath->rx_count) {
> +
> + len = min_t(unsigned int, ath->rx_count, count);
> + memcpy(skb_put(ath->rx_skb, len), ptr, len);
> + ath->rx_count -= len;
> + count -= len;
> + ptr += len;
> +
> + if (ath->rx_count)
> + continue;
> + switch (ath->rx_state) {
> + case HCIATH_W4_DATA:
> + hci_recv_frame(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + continue;
> +
> + case HCIATH_W4_EVENT_HDR:
> + eh = (struct hci_event_hdr *)ath->rx_skb->data;
> +
> + BT_DBG("Event header: evt 0x%2.2x plen %d",
> + eh->evt, eh->plen);
> +
> + ath_check_data_len(ath, eh->plen);
> + continue;
> +
> + case HCIATH_W4_ACL_HDR:
> + ah = (struct hci_acl_hdr *)ath->rx_skb->data;
> + dlen = __le16_to_cpu(ah->dlen);
> +
> + BT_DBG("ACL header: dlen %d", dlen);
> +
> + ath_check_data_len(ath, dlen);
> + continue;
> +
> + case HCIATH_W4_SCO_HDR:
> + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
> +
> + BT_DBG("SCO header: dlen %d", sh->dlen);
> +
> + ath_check_data_len(ath, sh->dlen);
> + continue;
> +
> + }
> + }
> +
> + /* HCIATH_W4_PACKET_TYPE */
> + switch (*ptr) {
> + case HCI_EVENT_PKT:
> + BT_DBG("Event packet");
> + ath->rx_state = HCIATH_W4_EVENT_HDR;
> + ath->rx_count = HCI_EVENT_HDR_SIZE;
> + type = HCI_EVENT_PKT;
> + break;
> +
> + case HCI_ACLDATA_PKT:
> + BT_DBG("ACL packet");
> + ath->rx_state = HCIATH_W4_ACL_HDR;
> + ath->rx_count = HCI_ACL_HDR_SIZE;
> + type = HCI_ACLDATA_PKT;
> + break;
> +
> + case HCI_SCODATA_PKT:
> + BT_DBG("SCO packet");
> + ath->rx_state = HCIATH_W4_SCO_HDR;
> + ath->rx_count = HCI_SCO_HDR_SIZE;
> + type = HCI_SCODATA_PKT;
> + break;
> +
> + default:
> + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> + hu->hdev->stat.err_rx++;
> + ptr++;
> + count--;
> + continue;
> +
> + };
> + ptr++;
> + count--;
> +
> + /* Allocate packet */
> + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> + if (!ath->rx_skb) {
> + BT_ERR("Can't allocate mem for new packet");
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_count = 0;
> +
> + return -ENOMEM;
> + }
> + ath->rx_skb->dev = (void *)hu->hdev;
> + bt_cb(ath->rx_skb)->pkt_type = type;
> + }
> +
> + return count;
> +}
> +
> +static struct hci_uart_proto athp = {
> + .id = HCI_UART_ATH,
> + .open = ath_open,
> + .close = ath_close,
> + .recv = ath_recv,
> + .enqueue = ath_enqueue,
> + .dequeue = ath_dequeue,
> + .flush = ath_flush,
> +};
> +
> +int ath_init(void)
> +{
> + int err = hci_uart_register_proto(&athp);
> +
> + if (!err)
> + BT_INFO("HCIATH protocol initialized");
> + else
> + BT_ERR("HCIATH protocol registration failed");
> +
> + return err;
> +}
> +
> +int ath_deinit(void)
> +{
> + return hci_uart_unregister_proto(&athp);
> +}
> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> index 76a1abb..7dd76d1 100644
> --- a/drivers/bluetooth/hci_ldisc.c
> +++ b/drivers/bluetooth/hci_ldisc.c
> @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_init();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_init();
> +#endif
>
> return 0;
> }
> @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_deinit();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_deinit();
> +#endif
>
> /* Release tty registration of line discipline */
> if ((err = tty_unregister_ldisc(N_HCI)))
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index 50113db..385537f 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -33,13 +33,14 @@
> #define HCIUARTGETDEVICE _IOR('U', 202, int)
>
> /* UART protocols */
> -#define HCI_UART_MAX_PROTO 5
> +#define HCI_UART_MAX_PROTO 6
>
> #define HCI_UART_H4 0
> #define HCI_UART_BCSP 1
> #define HCI_UART_3WIRE 2
> #define HCI_UART_H4DS 3
> #define HCI_UART_LL 4
> +#define HCI_UART_ATH 5
>
> struct hci_uart;
>
> @@ -91,3 +92,8 @@ int bcsp_deinit(void);
> int ll_init(void);
> int ll_deinit(void);
> #endif
> +
> +#ifdef CONFIG_BT_HCIUART_ATH
> +int ath_init(void);
> +int ath_deinit(void);
> +#endif
> --
> 1.7.0
>
>
>

--
Gustavo F. Padovan
http://padovan.org

2010-04-20 10:20:32

by Suraj Sumangala

[permalink] [raw]
Subject: [PATCH v3] Added support for Atheros AR300x Bluetooth Chip

This protocol implements support for power management feature provided by AR300x chip.
This lets the controller chip go to sleep mode if there is no Bluetooth
activity for some time.
It then wakes up the chip in case of a Bluetooth activity.

* Third version

** Updated with extra spacing and indentation
** made function definitions static
** Removed inline and register keyword usage.
** Removed unused return calls.
** Incorporated code comments by Luis and Gustavo

Thanks Luis and Gustavo for your comments


Signed-off-by: Suraj <[email protected]>

---
drivers/bluetooth/Kconfig | 11 ++
drivers/bluetooth/Makefile | 1 +
drivers/bluetooth/hci_ath.c | 384 +++++++++++++++++++++++++++++++++++++++++
drivers/bluetooth/hci_ldisc.c | 6 +
drivers/bluetooth/hci_uart.h | 8 +-
5 files changed, 409 insertions(+), 1 deletions(-)
create mode 100755 drivers/bluetooth/hci_ath.c

diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
index 058fbcc..81abeff 100644
--- a/drivers/bluetooth/Kconfig
+++ b/drivers/bluetooth/Kconfig
@@ -58,6 +58,17 @@ config BT_HCIUART_BCSP

Say Y here to compile support for HCI BCSP protocol.

+config BT_HCIUART_ATH
+ bool "Atheros AR300x Board support"
+ depends on BT_HCIUART
+ help
+ HCIATH (HCI Atheros) is a serial protocol for communication
+ between Bluetooth device and host with support for Atheros AR300x
+ power management feature. This protocol is required for
+ serial Bluetooth devices that are based on Atheros AR300x chips.
+
+ Say Y here to compile support for HCIATH protocol.
+
config BT_HCIUART_LL
bool "HCILL protocol support"
depends on BT_HCIUART
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 7e5aed5..1481faa 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
+hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
hci_uart-objs := $(hci_uart-y)
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
new file mode 100755
index 0000000..2f91954
--- /dev/null
+++ b/drivers/bluetooth/hci_ath.c
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/skbuff.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "hci_uart.h"
+
+
+/* HCIATH receiver States */
+#define HCIATH_W4_PACKET_TYPE 0
+#define HCIATH_W4_EVENT_HDR 1
+#define HCIATH_W4_ACL_HDR 2
+#define HCIATH_W4_SCO_HDR 3
+#define HCIATH_W4_DATA 4
+
+struct ath_struct {
+ struct hci_uart *hu;
+ unsigned int rx_state;
+ unsigned int rx_count;
+ unsigned int cur_sleep;
+
+ spinlock_t hciath_lock;
+ struct sk_buff *rx_skb;
+ struct sk_buff_head txq;
+ wait_queue_head_t wqevt;
+ struct work_struct ctxtsw;
+};
+
+static int ath_wakeup_ar3001(struct tty_struct *tty)
+{
+ struct termios settings;
+ int status = 0x00;
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ if ((status & TIOCM_CTS))
+ return status;
+
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+
+ /* Disable Automatic RTSCTS */
+ settings.c_cflag &= ~CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ /* Clear RTS first */
+ tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
+ mdelay(20);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ /* Set RTS, wake up board */
+ tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
+ mdelay(20);
+
+ status = tty->driver->ops->tiocmget(tty, NULL);
+
+ n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
+
+ settings.c_cflag |= CRTSCTS;
+ n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
+
+ return status;
+}
+
+static void ath_context_switch(struct work_struct *work)
+{
+ int status;
+ struct ath_struct *ath;
+ struct hci_uart *hu;
+ struct tty_struct *tty;
+
+ ath = container_of(work, struct ath_struct, ctxtsw);
+
+ hu = ath->hu;
+ tty = hu->tty;
+
+ /* verify and wake up controller */
+ if (ath->cur_sleep) {
+
+ status = ath_wakeup_ar3001(tty);
+
+ if (!(status & TIOCM_CTS))
+ return;
+ }
+
+ /* Ready to send Data */
+ clear_bit(HCI_UART_SENDING, &hu->tx_state);
+ hci_uart_tx_wakeup(hu);
+}
+
+/* Initialize protocol */
+static int ath_open(struct hci_uart *hu)
+{
+ struct ath_struct *ath;
+
+ BT_DBG("hu %p", hu);
+
+ ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
+ if (!ath)
+ return -ENOMEM;
+
+ skb_queue_head_init(&ath->txq);
+ spin_lock_init(&ath->hciath_lock);
+
+ hu->priv = ath;
+ ath->hu = hu;
+
+ init_waitqueue_head(&ath->wqevt);
+ INIT_WORK(&ath->ctxtsw, ath_context_switch);
+
+ return 0;
+}
+
+/* Flush protocol data */
+static int ath_flush(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ath->txq);
+
+ return 0;
+}
+
+/* Close protocol */
+static int ath_close(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+
+ BT_DBG("hu %p", hu);
+
+ skb_queue_purge(&ath->txq);
+
+ if (ath->rx_skb)
+ kfree_skb(ath->rx_skb);
+
+ cancel_work_sync(&ath->ctxtsw);
+
+ hu->priv = NULL;
+ kfree(ath);
+
+ return 0;
+}
+
+/* Enqueue frame for transmittion */
+static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
+{
+ struct ath_struct *ath = hu->priv;
+
+ if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
+
+ /* Discard SCO packet.AR3001 does not support SCO over HCI */
+ BT_DBG("SCO Packet over HCI received Dropping");
+
+ kfree(skb);
+
+ return 0;
+ }
+
+ BT_DBG("hu %p skb %p", hu, skb);
+
+ /* Prepend skb with frame type */
+ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+ skb_queue_tail(&ath->txq, skb);
+ set_bit(HCI_UART_SENDING, &hu->tx_state);
+
+ schedule_work(&ath->ctxtsw);
+
+ return 0;
+}
+
+static struct sk_buff *ath_dequeue(struct hci_uart *hu)
+{
+ struct ath_struct *ath = hu->priv;
+ struct sk_buff *skbuf;
+
+ skbuf = skb_dequeue(&ath->txq);
+
+ if (!skbuf)
+ return NULL;
+
+
+ /*
+ * Check if the HCI command is HCI sleep enable and
+ * update the sleep enable flag with command parameter.
+ *
+ * Value of sleep enable flag will be used later
+ * to verify if controller has to be woken up before
+ * sending any packet.
+ */
+ if (skbuf->data[0] == 0x01 && skbuf->data[1] == 0x04 &&
+ skbuf->data[2] == 0xFC)
+ ath->cur_sleep = skbuf->data[4];
+
+ return skbuf;
+}
+
+static void ath_check_data_len(struct ath_struct *ath, int len)
+{
+ int room = skb_tailroom(ath->rx_skb);
+
+ BT_DBG("len %d room %d", len, room);
+
+ if (len > room) {
+ BT_ERR("Data length is too large");
+ kfree_skb(ath->rx_skb);
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_skb = NULL;
+ ath->rx_count = 0;
+ } else {
+ ath->rx_state = HCIATH_W4_DATA;
+ ath->rx_count = len;
+ }
+}
+
+/* Recv data */
+static int ath_recv(struct hci_uart *hu, void *data, int count)
+{
+ struct ath_struct *ath = hu->priv;
+ char *ptr = data;
+ struct hci_event_hdr *eh;
+ struct hci_acl_hdr *ah;
+ struct hci_sco_hdr *sh;
+ int len, type, dlen;
+
+
+ BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
+ ath->rx_state, ath->rx_count);
+
+ while (count) {
+ if (ath->rx_count) {
+
+ len = min_t(unsigned int, ath->rx_count, count);
+ memcpy(skb_put(ath->rx_skb, len), ptr, len);
+ ath->rx_count -= len;
+ count -= len;
+ ptr += len;
+
+ if (ath->rx_count)
+ continue;
+ switch (ath->rx_state) {
+ case HCIATH_W4_DATA:
+ hci_recv_frame(ath->rx_skb);
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_skb = NULL;
+ ath->rx_count = 0;
+ continue;
+
+ case HCIATH_W4_EVENT_HDR:
+ eh = (struct hci_event_hdr *)ath->rx_skb->data;
+
+ BT_DBG("Event header: evt 0x%2.2x plen %d",
+ eh->evt, eh->plen);
+
+ ath_check_data_len(ath, eh->plen);
+ continue;
+
+ case HCIATH_W4_ACL_HDR:
+ ah = (struct hci_acl_hdr *)ath->rx_skb->data;
+ dlen = __le16_to_cpu(ah->dlen);
+
+ BT_DBG("ACL header: dlen %d", dlen);
+
+ ath_check_data_len(ath, dlen);
+ continue;
+
+ case HCIATH_W4_SCO_HDR:
+ sh = (struct hci_sco_hdr *)ath->rx_skb->data;
+
+ BT_DBG("SCO header: dlen %d", sh->dlen);
+
+ ath_check_data_len(ath, sh->dlen);
+ continue;
+
+ }
+ }
+
+ /* HCIATH_W4_PACKET_TYPE */
+ switch (*ptr) {
+ case HCI_EVENT_PKT:
+ BT_DBG("Event packet");
+ ath->rx_state = HCIATH_W4_EVENT_HDR;
+ ath->rx_count = HCI_EVENT_HDR_SIZE;
+ type = HCI_EVENT_PKT;
+ break;
+
+ case HCI_ACLDATA_PKT:
+ BT_DBG("ACL packet");
+ ath->rx_state = HCIATH_W4_ACL_HDR;
+ ath->rx_count = HCI_ACL_HDR_SIZE;
+ type = HCI_ACLDATA_PKT;
+ break;
+
+ case HCI_SCODATA_PKT:
+ BT_DBG("SCO packet");
+ ath->rx_state = HCIATH_W4_SCO_HDR;
+ ath->rx_count = HCI_SCO_HDR_SIZE;
+ type = HCI_SCODATA_PKT;
+ break;
+
+ default:
+ BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
+ hu->hdev->stat.err_rx++;
+ ptr++;
+ count--;
+ continue;
+
+ };
+ ptr++;
+ count--;
+
+ /* Allocate packet */
+ ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ if (!ath->rx_skb) {
+ BT_ERR("Can't allocate mem for new packet");
+ ath->rx_state = HCIATH_W4_PACKET_TYPE;
+ ath->rx_count = 0;
+
+ return -ENOMEM;
+ }
+ ath->rx_skb->dev = (void *)hu->hdev;
+ bt_cb(ath->rx_skb)->pkt_type = type;
+ }
+
+ return count;
+}
+
+static struct hci_uart_proto athp = {
+ .id = HCI_UART_ATH,
+ .open = ath_open,
+ .close = ath_close,
+ .recv = ath_recv,
+ .enqueue = ath_enqueue,
+ .dequeue = ath_dequeue,
+ .flush = ath_flush,
+};
+
+int ath_init(void)
+{
+ int err = hci_uart_register_proto(&athp);
+
+ if (!err)
+ BT_INFO("HCIATH protocol initialized");
+ else
+ BT_ERR("HCIATH protocol registration failed");
+
+ return err;
+}
+
+int ath_deinit(void)
+{
+ return hci_uart_unregister_proto(&athp);
+}
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 76a1abb..7dd76d1 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_init();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH
+ ath_init();
+#endif

return 0;
}
@@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
#ifdef CONFIG_BT_HCIUART_LL
ll_deinit();
#endif
+#ifdef CONFIG_BT_HCIUART_ATH
+ ath_deinit();
+#endif

/* Release tty registration of line discipline */
if ((err = tty_unregister_ldisc(N_HCI)))
diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
index 50113db..385537f 100644
--- a/drivers/bluetooth/hci_uart.h
+++ b/drivers/bluetooth/hci_uart.h
@@ -33,13 +33,14 @@
#define HCIUARTGETDEVICE _IOR('U', 202, int)

/* UART protocols */
-#define HCI_UART_MAX_PROTO 5
+#define HCI_UART_MAX_PROTO 6

#define HCI_UART_H4 0
#define HCI_UART_BCSP 1
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH 5

struct hci_uart;

@@ -91,3 +92,8 @@ int bcsp_deinit(void);
int ll_init(void);
int ll_deinit(void);
#endif
+
+#ifdef CONFIG_BT_HCIUART_ATH
+int ath_init(void);
+int ath_deinit(void);
+#endif
--
1.7.0

2010-04-19 23:53:42

by Gustavo Padovan

[permalink] [raw]
Subject: Re: [PATCH] Added support for Atheros AR300x Bluetooth Chip

Hi Suraj,

* suraj <[email protected]> [2010-03-15 10:31:36 +0530]:

>
> This protocol implements support for power management feature provided by AR300x chip.
> This lets the controller chip go to sleep mode if there is no Bluetooth activity for some time.
> It then wakes up the chip in case of a Bluetooth activity.
>
>
> Signed-off-by: Suraj <[email protected]>
>
> ---
> drivers/bluetooth/Kconfig | 11 ++
> drivers/bluetooth/Makefile | 1 +
> drivers/bluetooth/hci_ath.c | 353 +++++++++++++++++++++++++++++++++++++++++
> drivers/bluetooth/hci_ldisc.c | 6 +
> drivers/bluetooth/hci_uart.h | 8 +-
> 5 files changed, 378 insertions(+), 1 deletions(-)
> create mode 100755 drivers/bluetooth/hci_ath.c
>
> diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig
> index 058fbcc..81abeff 100644
> --- a/drivers/bluetooth/Kconfig
> +++ b/drivers/bluetooth/Kconfig
> @@ -58,6 +58,17 @@ config BT_HCIUART_BCSP
>
> Say Y here to compile support for HCI BCSP protocol.
>
> +config BT_HCIUART_ATH
> + bool "Atheros AR300x Board support"
> + depends on BT_HCIUART
> + help
> + HCIATH (HCI Atheros) is a serial protocol for communication
> + between Bluetooth device and host with support for Atheros AR300x
> + power management feature. This protocol is required for
> + serial Bluetooth devices that are based on Atheros AR300x chips.
> +
> + Say Y here to compile support for HCIATH protocol.
> +
> config BT_HCIUART_LL
> bool "HCILL protocol support"
> depends on BT_HCIUART
> diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
> index 7e5aed5..1481faa 100644
> --- a/drivers/bluetooth/Makefile
> +++ b/drivers/bluetooth/Makefile
> @@ -26,4 +26,5 @@ hci_uart-y := hci_ldisc.o
> hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
> hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
> hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
> +hci_uart-$(CONFIG_BT_HCIUART_ATH) += hci_ath.o
> hci_uart-objs := $(hci_uart-y)
> diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
> new file mode 100755
> index 0000000..13e4404
> --- /dev/null
> +++ b/drivers/bluetooth/hci_ath.c
> @@ -0,0 +1,353 @@
> +/*
> + * Copyright (c) 2009-2010 Atheros Communications Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +
> +#include <linux/init.h>
> +#include <linux/slab.h>
> +#include <linux/tty.h>
> +#include <linux/errno.h>
> +#include <linux/ioctl.h>
> +#include <linux/skbuff.h>
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +
> +#include "hci_uart.h"
> +
> +
> +/* HCIATH receiver States */
> +#define HCIATH_W4_PACKET_TYPE 0
> +#define HCIATH_W4_EVENT_HDR 1
> +#define HCIATH_W4_ACL_HDR 2
> +#define HCIATH_W4_SCO_HDR 3
> +#define HCIATH_W4_DATA 4
> +
> +struct ath_struct {
> + struct hci_uart *hu;
> + unsigned int rx_state;
> + unsigned int rx_count;
> + unsigned int cur_sleep;
> +
> + spinlock_t hciath_lock;
> + struct sk_buff *rx_skb;
> + struct sk_buff_head txq;
> + wait_queue_head_t wqevt;
> + struct work_struct ctxtsw;
> +};
> +
> +int ath_wakeup_ar3001(struct tty_struct *tty)
> +{
> + struct termios settings;
> + int status = 0x00;
> + mm_segment_t oldfs;
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + if ((status & TIOCM_CTS))
> + return status;
> +
> + oldfs = get_fs();
> + set_fs(KERNEL_DS);
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + settings.c_cflag &= ~CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> + set_fs(oldfs);
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + /* Wake up board */
> + tty->driver->ops->tiocmset(tty, NULL, 0x00, TIOCM_RTS);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> +
> + tty->driver->ops->tiocmset(tty, NULL, TIOCM_RTS, 0x00);
> + mdelay(20);
> +
> + status = tty->driver->ops->tiocmget(tty, NULL);
> + oldfs = get_fs();
> + set_fs(KERNEL_DS);
> + n_tty_ioctl_helper(tty, NULL, TCGETS, (unsigned long)&settings);
> +
> + settings.c_cflag |= CRTSCTS;
> + n_tty_ioctl_helper(tty, NULL, TCSETS, (unsigned long)&settings);
> + set_fs(oldfs);
> + return status;
> +}
> +
> +static void ath_context_switch(struct work_struct *work)
> +{
> + int status;
> + struct ath_struct *ath;
> + struct hci_uart *hu;
> + struct tty_struct *tty;
> +
> + ath = container_of(work, struct ath_struct, ctxtsw);
> +
> + hu = ath->hu;
> + tty = hu->tty;
> +
> + /* verify and wake up controller */
> + if (ath->cur_sleep) {
> +

Extra new line here.

> + status = ath_wakeup_ar3001(tty);
> + if (!(status & TIOCM_CTS))
> + return;
> + }
> +
> + /* Ready to send Data */
> + clear_bit(HCI_UART_SENDING, &hu->tx_state);
> + hci_uart_tx_wakeup(hu);
> +}
> +
> +int ath_check_sleep_cmd(struct ath_struct *ath, unsigned char *packet)
> +{
> + if (packet[0] == 0x04 && packet[1] == 0xFC)
> + ath->cur_sleep = packet[3];
> +
> + return 0;
> +}
> +
> +
> +/* Initialize protocol */
> +static int ath_open(struct hci_uart *hu)
> +{
> + struct ath_struct *ath;
> + BT_DBG("hu %p", hu);
> +
> + ath = kzalloc(sizeof(*ath), GFP_ATOMIC);
> + if (!ath)
> + return -ENOMEM;
> +
> + skb_queue_head_init(&ath->txq);
> + spin_lock_init(&ath->hciath_lock);
> +
> + ath->cur_sleep = 0;

You've used kzalloc, so cur_sleep is already 0

> + hu->priv = ath;
> + ath->hu = hu;
> +
> + init_waitqueue_head(&ath->wqevt);
> + INIT_WORK(&ath->ctxtsw, ath_context_switch);
> + return 0;
> +}
> +
> +/* Flush protocol data */
> +static int ath_flush(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + BT_DBG("hu %p", hu);
> + skb_queue_purge(&ath->txq);
> +
> + return 0;
> +}
> +
> +/* Close protocol */
> +static int ath_close(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;

Add a extra line before the BT_DBG()

> + BT_DBG("hu %p", hu);
> +
> + skb_queue_purge(&ath->txq);
> +
> + if (ath->rx_skb)
> + kfree_skb(ath->rx_skb);
> +
> + wake_up_interruptible(&ath->wqevt);
> + hu->priv = NULL;
> + kfree(ath);
> + return 0;
> +}
> +
> +/* Enqueue frame for transmittion */
> +static int ath_enqueue(struct hci_uart *hu, struct sk_buff *skb)
> +{
> + struct ath_struct *ath = hu->priv;
> + if (bt_cb(skb)->pkt_type == HCI_SCODATA_PKT) {
> +
> + /* Discard SCO packet.AR3001 does not support SCO over HCI */
> + BT_DBG("SCO Packet over HCI received Dropping\n");
> + kfree(skb);
> + return 0;
> + }
> + BT_DBG("hu %p skb %p", hu, skb);

Add a extra line before the BT_DBG()

> +
> + /* Prepend skb with frame type */
> + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
> +
> + skb_queue_tail(&ath->txq, skb);
> + set_bit(HCI_UART_SENDING, &hu->tx_state);
> +
> + schedule_work(&ath->ctxtsw);
> + return 0;
> +}
> +
> +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + struct sk_buff *skbuf;
> +
> + skbuf = skb_dequeue(&ath->txq);
> + if (skbuf != NULL)
> + ath_check_sleep_cmd(ath, &skbuf->data[1]);
> +
> + return skbuf;
> +}
> +
> +static inline int ath_check_data_len(struct ath_struct *ath, int len)
> +{
> + register int room = skb_tailroom(ath->rx_skb);
> + BT_DBG("len %d room %d", len, room);
> +
> + if (len > room) {
> + BT_ERR("Data length is too large");
> + kfree_skb(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + } else {
> + ath->rx_state = HCIATH_W4_DATA;
> + ath->rx_count = len;
> + return len;
> + }
> +
> + return 0;

You can return ath->rx_count here and remove the return from the else.
Or ad the return 0 on the if (len > room).

> +}
> +
> +/* Recv data */
> +static int ath_recv(struct hci_uart *hu, void *data, int count)
> +{
> + struct ath_struct *ath = hu->priv;
> + register char *ptr;
> + struct hci_event_hdr *eh;
> + struct hci_acl_hdr *ah;
> + struct hci_sco_hdr *sh;
> + struct sk_buff *skbuf;
> + register int len, type, dlen;

Wouldn't be better let the compiler choose which vars it will put on the
registers?

> +
> + skbuf = NULL;

You never use skbuf after here.

> + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> + ath->rx_state, ath->rx_count);
> + ptr = data;

You can set ptr to data when you declare it.

> + while (count) {
> + if (ath->rx_count) {
> +
> + len = min_t(unsigned int, ath->rx_count, count);
> + memcpy(skb_put(ath->rx_skb, len), ptr, len);
> + ath->rx_count -= len;
> + count -= len;
> + ptr += len;
> +
> + if (ath->rx_count)
> + continue;
> + switch (ath->rx_state) {
> + case HCIATH_W4_DATA:
> + hci_recv_frame(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + continue;
> + case HCIATH_W4_EVENT_HDR:
> + eh = (struct hci_event_hdr *)ath->rx_skb->data;
> + BT_DBG("Event header: evt 0x%2.2x plen %d",
> + eh->evt, eh->plen);
> + ath_check_data_len(ath, eh->plen);
> + continue;
> + case HCIATH_W4_ACL_HDR:
> + ah = (struct hci_acl_hdr *)ath->rx_skb->data;
> + dlen = __le16_to_cpu(ah->dlen);
> + BT_DBG("ACL header: dlen %d", dlen);
> + ath_check_data_len(ath, dlen);
> + continue;
> + case HCIATH_W4_SCO_HDR:
> + sh = (struct hci_sco_hdr *)ath->rx_skb->data;
> + BT_DBG("SCO header: dlen %d", sh->dlen);
> + ath_check_data_len(ath, sh->dlen);
> + continue;
> + }
> + }
> +
> + /* HCIATH_W4_PACKET_TYPE */
> + switch (*ptr) {
> + case HCI_EVENT_PKT:
> + BT_DBG("Event packet");
> + ath->rx_state = HCIATH_W4_EVENT_HDR;
> + ath->rx_count = HCI_EVENT_HDR_SIZE;
> + type = HCI_EVENT_PKT;
> + break;
> + case HCI_ACLDATA_PKT:
> + BT_DBG("ACL packet");
> + ath->rx_state = HCIATH_W4_ACL_HDR;
> + ath->rx_count = HCI_ACL_HDR_SIZE;
> + type = HCI_ACLDATA_PKT;
> + break;
> + case HCI_SCODATA_PKT:
> + BT_DBG("SCO packet");
> + ath->rx_state = HCIATH_W4_SCO_HDR;
> + ath->rx_count = HCI_SCO_HDR_SIZE;
> + type = HCI_SCODATA_PKT;
> + break;
> + default:
> + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> + hu->hdev->stat.err_rx++;
> + ptr++;
> + count--;
> + continue;
> + };
> + ptr++;
> + count--;
> +
> + /* Allocate packet */
> + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> + if (!ath->rx_skb) {
> + BT_ERR("Can't allocate mem for new packet");
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_count = 0;
> + return -ENOMEM;
> + }
> + ath->rx_skb->dev = (void *)hu->hdev;
> + bt_cb(ath->rx_skb)->pkt_type = type;
> + } return count;
> +}
> +
> +static struct hci_uart_proto athp = {
> + .id = HCI_UART_ATH,
> + .open = ath_open,
> + .close = ath_close,
> + .recv = ath_recv,
> + .enqueue = ath_enqueue,
> + .dequeue = ath_dequeue,
> + .flush = ath_flush,
> +};
> +
> +int ath_init(void)
> +{
> + int err = hci_uart_register_proto(&athp);
> + if (!err)
> + BT_INFO("HCIATH protocol initialized");
> +
> + else
> + BT_ERR("HCIATH protocol registration failed");

Add a new line here.

> + return err;
> +}
> +
> +int ath_deinit(void)
> +{
> + return hci_uart_unregister_proto(&athp);
> +}
> diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
> index 76a1abb..7dd76d1 100644
> --- a/drivers/bluetooth/hci_ldisc.c
> +++ b/drivers/bluetooth/hci_ldisc.c
> @@ -542,6 +542,9 @@ static int __init hci_uart_init(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_init();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_init();
> +#endif
>
> return 0;
> }
> @@ -559,6 +562,9 @@ static void __exit hci_uart_exit(void)
> #ifdef CONFIG_BT_HCIUART_LL
> ll_deinit();
> #endif
> +#ifdef CONFIG_BT_HCIUART_ATH
> + ath_deinit();
> +#endif
>
> /* Release tty registration of line discipline */
> if ((err = tty_unregister_ldisc(N_HCI)))
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index 50113db..385537f 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -33,13 +33,14 @@
> #define HCIUARTGETDEVICE _IOR('U', 202, int)
>
> /* UART protocols */
> -#define HCI_UART_MAX_PROTO 5
> +#define HCI_UART_MAX_PROTO 6
>
> #define HCI_UART_H4 0
> #define HCI_UART_BCSP 1
> #define HCI_UART_3WIRE 2
> #define HCI_UART_H4DS 3
> #define HCI_UART_LL 4
> +#define HCI_UART_ATH 5
>
> struct hci_uart;
>
> @@ -91,3 +92,8 @@ int bcsp_deinit(void);
> int ll_init(void);
> int ll_deinit(void);
> #endif
> +
> +#ifdef CONFIG_BT_HCIUART_ATH
> +int ath_init(void);
> +int ath_deinit(void);
> +#endif
> --
> 1.6.3.3
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

--
Gustavo F. Padovan
http://padovan.org

2010-05-21 07:34:53

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v3] hciattach application support for Atheros AR300x Bluetooth Chip

Hi Suraj,

> >> Implements support for Atheros AR300x Bluetooth chip in hciattach.
> >> Adds feature to bring up AR300x Bluetooth chip
> >> with and without enhanced power management enabled.
> >>
> >> Signed-off-by: Suraj <[email protected]>
> >
> > not SOBs for BlueZ userspace. That is kernel only.
> >
> >> ---
> >> Makefile.tools | 1 +
> >> tools/hciattach.8 | 6 +
> >> tools/hciattach.c | 111 +++++
> >> tools/hciattach.h | 3 +
> >> tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++
> >> 5 files changed, 1344 insertions(+), 0 deletions(-)
> >> create mode 100755 tools/hciattach_ar3k.c
> >
> > While hciattach is kinda the bad sheep inside BlueZ, I will enforce the
> > general coding style for it for all new contributions. So could you
> > please fix that one first. Otherwise it makes no sense for me to go
> > through such a big patch if I have to complain about the coding style
> > breakage for every second line. A general rule is if it fails
> > check-patch.pl from the kernel, then you are doing something wrong.
>
> I had verified this patch using checkpatch and it did not complain. I
> had also verified it manually according to the comments others have
> given previously for different patches.
>
> If you still see issues, then we can add that check too to checkpatch if
> possible.

then maybe checkpatch.pl is not good enough for this. I see way too many
empty lines, weird if breakages, and many more. So as I said, this needs
cleanup first.

Regards

Marcel



2010-05-21 05:01:35

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH v3] hciattach application support for Atheros AR300x Bluetooth Chip

Hi Marcel,

Marcel Holtmann wrote:
> Hi Suraj,
>
>> Implements support for Atheros AR300x Bluetooth chip in hciattach.
>> Adds feature to bring up AR300x Bluetooth chip
>> with and without enhanced power management enabled.
>>
>> Signed-off-by: Suraj <[email protected]>
>
> not SOBs for BlueZ userspace. That is kernel only.
>
>> ---
>> Makefile.tools | 1 +
>> tools/hciattach.8 | 6 +
>> tools/hciattach.c | 111 +++++
>> tools/hciattach.h | 3 +
>> tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++
>> 5 files changed, 1344 insertions(+), 0 deletions(-)
>> create mode 100755 tools/hciattach_ar3k.c
>
> While hciattach is kinda the bad sheep inside BlueZ, I will enforce the
> general coding style for it for all new contributions. So could you
> please fix that one first. Otherwise it makes no sense for me to go
> through such a big patch if I have to complain about the coding style
> breakage for every second line. A general rule is if it fails
> check-patch.pl from the kernel, then you are doing something wrong.
>
> Regards
>
> Marcel
>
>

I had verified this patch using checkpatch and it did not complain. I
had also verified it manually according to the comments others have
given previously for different patches.

If you still see issues, then we can add that check too to checkpatch if
possible.

Being a big patch, there are bound to be problems.But I would appreciate
if you could review atleast part of it and give your comments. I can do
the changes for the full patch.

Also I would request others in the community to pitch in.

Regards
Suraj

2010-05-20 16:09:11

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip

Hi Suraj,

for every new patch version, please start a new thread. If you re-use an
old thread, I will most likely ignore it.

> +static struct sk_buff *ath_dequeue(struct hci_uart *hu)
> +{
> + struct ath_struct *ath = hu->priv;
> + struct sk_buff *skbuf;
> +
> + skbuf = skb_dequeue(&ath->txq);
> +
> + if (!skbuf)
> + return NULL;
> +
> + /*
> + * Check if the HCI command is HCI sleep enable and
> + * update the sleep enable flag with command parameter.
> + *
> + * Value of sleep enable flag will be used later
> + * to verify if controller has to be woken up before
> + * sending any packet.
> + */
> + if (skbuf->data[0] == 0x01 &&
> + skbuf->data[1] == 0x04 &&
> + skbuf->data[2] == 0xFC)
> + ath->cur_sleep = skbuf->data[4];
> +
> + return skbuf;
> +}

I don't really like this. I know we don't have any infrastructure to
forward vendor commands back to the driver. And we might need to change
that actually.

However at least for now use the headers and constants and not magic
numbers here.

> +static void ath_check_data_len(struct ath_struct *ath, int len)
> +{
> + int room = skb_tailroom(ath->rx_skb);
> +
> + BT_DBG("len %d room %d", len, room);
> +
> + if (len > room) {
> + BT_ERR("Data length is too large");
> + kfree_skb(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + } else {
> + ath->rx_state = HCIATH_W4_DATA;
> + ath->rx_count = len;
> + }
> +}
> +
> +/* Recv data */
> +static int ath_recv(struct hci_uart *hu, void *data, int count)
> +{
> + struct ath_struct *ath = hu->priv;
> + char *ptr = data;
> + struct hci_event_hdr *eh;
> + struct hci_acl_hdr *ah;
> + struct hci_sco_hdr *sh;
> + int len, type, dlen;
> +
> + BT_DBG("hu %p count %d rx_state %d rx_count %d", hu, count,
> + ath->rx_state, ath->rx_count);
> +
> + while (count) {
> + if (ath->rx_count) {
> +
> + len = min_t(unsigned int, ath->rx_count, count);
> + memcpy(skb_put(ath->rx_skb, len), ptr, len);
> + ath->rx_count -= len;
> + count -= len;
> + ptr += len;
> +
> + if (ath->rx_count)
> + continue;
> + switch (ath->rx_state) {
> + case HCIATH_W4_DATA:
> + hci_recv_frame(ath->rx_skb);
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_skb = NULL;
> + ath->rx_count = 0;
> + continue;
> +
> + case HCIATH_W4_EVENT_HDR:
> + eh = hci_event_hdr(ath->rx_skb);
> +
> + BT_DBG("Event header: evt 0x%2.2x plen %d",
> + eh->evt, eh->plen);
> +
> + ath_check_data_len(ath, eh->plen);
> + continue;
> +
> + case HCIATH_W4_ACL_HDR:
> + ah = hci_acl_hdr(ath->rx_skb);
> + dlen = __le16_to_cpu(ah->dlen);
> +
> + BT_DBG("ACL header: dlen %d", dlen);
> +
> + ath_check_data_len(ath, dlen);
> + continue;
> +
> + case HCIATH_W4_SCO_HDR:
> + sh = hci_sco_hdr(ath->rx_skb);
> +
> + BT_DBG("SCO header: dlen %d", sh->dlen);
> +
> + ath_check_data_len(ath, sh->dlen);
> + continue;
> +
> + }
> + }
> +
> + /* HCIATH_W4_PACKET_TYPE */
> + switch (*ptr) {
> + case HCI_EVENT_PKT:
> + BT_DBG("Event packet");
> + ath->rx_state = HCIATH_W4_EVENT_HDR;
> + ath->rx_count = HCI_EVENT_HDR_SIZE;
> + type = HCI_EVENT_PKT;
> + break;
> +
> + case HCI_ACLDATA_PKT:
> + BT_DBG("ACL packet");
> + ath->rx_state = HCIATH_W4_ACL_HDR;
> + ath->rx_count = HCI_ACL_HDR_SIZE;
> + type = HCI_ACLDATA_PKT;
> + break;
> +
> + case HCI_SCODATA_PKT:
> + BT_DBG("SCO packet");
> + ath->rx_state = HCIATH_W4_SCO_HDR;
> + ath->rx_count = HCI_SCO_HDR_SIZE;
> + type = HCI_SCODATA_PKT;
> + break;
> +
> + default:
> + BT_ERR("Unknown HCI packet type %2.2x", (__u8) *ptr);
> + hu->hdev->stat.err_rx++;
> + ptr++;
> + count--;
> + continue;
> +
> + };
> + ptr++;
> + count--;
> +
> + /* Allocate packet */
> + ath->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
> + if (!ath->rx_skb) {
> + BT_ERR("Can't allocate mem for new packet");
> + ath->rx_state = HCIATH_W4_PACKET_TYPE;
> + ath->rx_count = 0;
> +
> + return -ENOMEM;
> + }
> + ath->rx_skb->dev = (void *)hu->hdev;
> + bt_cb(ath->rx_skb)->pkt_type = type;
> + }
> +
> + return count;
> +}

What was the reason that hci_recv_fragment is not good enough here and
can not made work for this case. I really wanna avoid have multiple
implementation of this reassembly support all over the places.

Regards

Marcel



2010-05-20 16:02:54

by Marcel Holtmann

[permalink] [raw]
Subject: Re: buffer starvation with multiple ACL link

Hi Suraj,

please never start a new thread that hangs of an existing thread. I do
will miss these and ignore. You need to fix your mailer setup.

> I am seeing a strange issue with multiple ACL connection with CSR chip.
>
> I am having 2 ACL link, one with FTP going on and another streaming
> A2DP.
> The moment the A2DP link goes out of range ,I see that the FTP also
> stops. It resumes as soon as A2DP comes back in range.
>
> On further analysis I could verify that since the A2DP link is
> blocked( due to remote being OoR) the controller's ACL buffers with A2DP
> data are stuck.
> But at the host level this is not considered and Bluez keeps sending
> A2DP data until it blocks all the ACL buffers which in turns blocks FTP
> also.
>
> I was expecting controller to flush these packets sometime and free the
> A2DP buffers. Not sure, what is the default Flush timeout value.

We don't have anything as of now that could fix this. I would need more
details on this since it might be some outdated firmware or known bug in
the controller. Please start a proper new thread with details about the
hardware you are using and which software versions.

Regards

Marcel



2010-05-20 16:00:56

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v3] hciattach application support for Atheros AR300x Bluetooth Chip

Hi Suraj,

> Implements support for Atheros AR300x Bluetooth chip in hciattach.
> Adds feature to bring up AR300x Bluetooth chip
> with and without enhanced power management enabled.
>
> Signed-off-by: Suraj <[email protected]>

not SOBs for BlueZ userspace. That is kernel only.

> ---
> Makefile.tools | 1 +
> tools/hciattach.8 | 6 +
> tools/hciattach.c | 111 +++++
> tools/hciattach.h | 3 +
> tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 1344 insertions(+), 0 deletions(-)
> create mode 100755 tools/hciattach_ar3k.c

While hciattach is kinda the bad sheep inside BlueZ, I will enforce the
general coding style for it for all new contributions. So could you
please fix that one first. Otherwise it makes no sense for me to go
through such a big patch if I have to complain about the coding style
breakage for every second line. A general rule is if it fails
check-patch.pl from the kernel, then you are doing something wrong.

Regards

Marcel



2010-05-20 13:37:02

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH v3] hciattach application support for Atheros AR300x Bluetooth Chip

Hi,

On Wed, 2010-05-12 at 19:17 +0530, suraj wrote:
> Implements support for Atheros AR300x Bluetooth chip in hciattach.
> Adds feature to bring up AR300x Bluetooth chip
> with and without enhanced power management enabled.
>
> Signed-off-by: Suraj <[email protected]>
>
> ---
> Makefile.tools | 1 +
> tools/hciattach.8 | 6 +
> tools/hciattach.c | 111 +++++
> tools/hciattach.h | 3 +
> tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 1344 insertions(+), 0 deletions(-)
> create mode 100755 tools/hciattach_ar3k.c
>
> diff --git a/Makefile.tools b/Makefile.tools
> index 2735d68..48cf097 100644
> --- a/Makefile.tools
> +++ b/Makefile.tools
> @@ -23,6 +23,7 @@ tools_l2ping_LDADD = lib/libbluetooth.la
> tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
> tools/hciattach_st.c \
> tools/hciattach_ti.c \
> + tools/hciattach_ar3k.c \
> tools/hciattach_tialt.c
> tools_hciattach_LDADD = lib/libbluetooth.la
>
> diff --git a/tools/hciattach.8 b/tools/hciattach.8
> index f750222..ef943ea 100644
> --- a/tools/hciattach.8
> +++ b/tools/hciattach.8
> @@ -49,6 +49,12 @@ specific identifier. Currently supported types are
> .B any
> Unspecified HCI_UART interface, no vendor specific options
> .TP
> +.B ar3kalt
> +Atheros AR300x based serial bluetooth device with power management disabled
> +.TP
> +.B ar3k
> +Atheros AR300x based serial bluetooth device
> +.TP
> .B ericsson
> Ericsson based modules
> .TP
> diff --git a/tools/hciattach.c b/tools/hciattach.c
> index b13db1b..768a3f1 100644
> --- a/tools/hciattach.c
> +++ b/tools/hciattach.c
> @@ -653,6 +653,110 @@ static int csr(int fd, struct uart_t *u, struct termios *ti)
> }
>
> /*
> + * Atheros AR300x specific initialization post callback
> + * with power management dsiabled
> + * Suraj Sumangala <[email protected]>
> + */
> +static int ar3kpost(int fd, struct uart_t *u, struct termios *ti)
> +{
> + return ath_configure_sleep(fd, 0);
> +}
> +
> +/*
> + * Atheros AR300x specific initialization post callback
> + * with power management enabled
> + * Suraj Sumangala <[email protected]>
> + */
> +static int ar3kpmpost(int fd, struct uart_t *u, struct termios *ti)
> +{
> + return ath_configure_sleep(fd, 1);
> +}
> +/*
> + * Atheros AR300x specific initialization
> + * Suraj Sumangala <[email protected]>
> + */
> +static int ar3kinit(int fd, struct uart_t *u, struct termios *ti)
> +{
> + struct timespec tm = { 0, 500000 };
> + unsigned char cmd[14], rsp[100];
> + int r;
> + int baud;
> +
> + /* Download PS and patch */
> + r = ath_ps_download(fd);
> +
> + if (r < 0) {
> + perror("Failed to Download configuration");
> + return -1;
> + }
> +
> + /* Write BDADDR if user has provided any */
> + if (u->bdaddr != NULL) {
> + /* Set BD_ADDR */
> + memset(cmd, 0, sizeof(cmd));
> + memset(rsp, 0, sizeof(rsp));
> + cmd[0] = HCI_COMMAND_PKT;
> + cmd[1] = 0x0B;
> + cmd[2] = 0xfc;
> + cmd[3] = 0x0A;
> + cmd[4] = 0x01;
> + cmd[5] = 0x01;
> + cmd[6] = 0x00;
> + cmd[7] = 0x06;
> + str2ba(u->bdaddr, (bdaddr_t *) (cmd + 8));
> +
> + /* Send command */
> + if (write(fd, cmd, 14) != 14) {
> + fprintf(stderr, "Failed to write BD_ADDR command\n");
> + return -1;
> + }
> +
> + /* Read reply */
> + if (read_hci_event(fd, rsp, 10) < 0) {
> + fprintf(stderr, "Failed to set BD_ADDR\n");
> + return -1;
> + }
> + }
> +
> + /* Send HCI Reset to write the configuration */
> + cmd[0] = HCI_COMMAND_PKT;
> + cmd[1] = 0x03;
> + cmd[2] = 0x0C;
> + cmd[3] = 0x00;
> +
> + r = write(fd, cmd, 4);
> +
> + if (r != 4)
> + return -1;
> +
> + nanosleep(&tm, NULL);
> + if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
> + return -1;
> +
> + /* Set baud rate command,
> + * set controller baud rate to user specified value */
> + cmd[0] = HCI_COMMAND_PKT;
> + cmd[1] = 0x0C;
> + cmd[2] = 0xfc;
> + cmd[3] = 0x02;
> + baud = u->speed/100;
> + cmd[4] = (char)baud;
> + cmd[5] = (char)(baud >> 8);
> +
> + if (write(fd, cmd, 6) != 6) {
> + perror("Failed to write init command");
> + return -1;
> + }
> +
> + /* Wait for the command complete event for Baud rate change Command */
> + nanosleep(&tm, NULL);
> +
> + if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
> + return -1;
> +
> + return 0;
> +}
> +/*
> * Silicon Wave specific initialization
> * Thomas Moser <[email protected]>
> */
> @@ -1071,6 +1175,13 @@ struct uart_t uart[] = {
> /* Broadcom BCM2035 */
> { "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },
>
> + /* ATHEROS AR300x */
> + { "ar3kalt", 0x0000, 0x0000, HCI_UART_ATH, 115200, 115200,
> + FLOW_CTL, NULL, ar3kinit, ar3kpost },
> +
> + { "ar3k", 0x0000, 0x0000, HCI_UART_ATH, 115200, 115200,
> + FLOW_CTL, NULL, ar3kinit, ar3kpmpost },
> +
> { NULL, 0 }
> };
>
> diff --git a/tools/hciattach.h b/tools/hciattach.h
> index 867563b..7719e04 100644
> --- a/tools/hciattach.h
> +++ b/tools/hciattach.h
> @@ -36,6 +36,7 @@
> #define HCI_UART_3WIRE 2
> #define HCI_UART_H4DS 3
> #define HCI_UART_LL 4
> +#define HCI_UART_ATH 5
>
> int read_hci_event(int fd, unsigned char* buf, int size);
> int set_speed(int fd, struct termios *ti, int speed);
> @@ -45,3 +46,5 @@ int texas_post(int fd, struct termios *ti);
> int texasalt_init(int fd, int speed, struct termios *ti);
> int stlc2500_init(int fd, bdaddr_t *bdaddr);
> int bgb2xx_init(int dd, bdaddr_t *bdaddr);
> +int ath_configure_sleep(int fd, int sleep_stat);
> +int ath_ps_download(int fd);
> diff --git a/tools/hciattach_ar3k.c b/tools/hciattach_ar3k.c
> new file mode 100755
> index 0000000..2542161
> --- /dev/null
> +++ b/tools/hciattach_ar3k.c
> @@ -0,0 +1,1223 @@
> +/*
> + * Copyright (c) 2009-2010 Atheros Communications Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <ctype.h>
> +#include <time.h>
> +#include <sys/time.h>
> +#include <sys/types.h>
> +#include <sys/param.h>
> +#include <sys/ioctl.h>
> +
> +#include <bluetooth/bluetooth.h>
> +#include <bluetooth/hci.h>
> +#include <bluetooth/hci_lib.h>
> +
> +#include "hciattach.h"
> +
> +/* The maximum number of bytes possible in a patch entry */
> +#define MAX_PATCH_SIZE 20000
> +
> +#define MAX_BYTE_LENGTH 244
> +
> +/* Maximum HCI packets that will be formed from the Patch file */
> +#define MAX_NUM_PATCH_ENTRY ((MAX_PATCH_SIZE/MAX_BYTE_LENGTH) + 1)
> +
> +#define DEV_REGISTER 0x4FFC
> +
> +#define FW_PATH "/lib/firmware/ar3k/"
> +
> +#define PS_ASIC_FILE "PS_ASIC.pst"
> +#define PS_FPGA_FILE "PS_FPGA.pst"
> +#define PATCH_FILE "RamPatch.txt"
> +#define BDADDR_FILE "ar3kbdaddr.pst"
> +
> +#define HCI_CMD_HEADER_LEN 7
> +
> +/* PS command types */
> +#define PS_RESET 2
> +#define PS_WRITE 1
> +#define WRITE_PATCH 8
> +#define PS_VERIFY_CRC 9
> +#define ENABLE_PATCH 11
> +
> +#define EXTRA_PATCH_SIZE 500
> +
> +/* PS configuration entry time */
> +#define PS_TYPE_HEX 0
> +#define PS_TYPE_DEC 1
> +
> +#define PS_RESET_PARAM_LEN 6
> +#define PS_RESET_CMD_LEN (PS_RESET_PARAM_LEN +\
> + HCI_CMD_HEADER_LEN)
> +
> +#define RAM_PS_REGION (1<<0)
> +#define RAM_PATCH_REGION (1<<1)
> +
> +#define RAMPS_MAX_PS_TAGS_PER_FILE 50
> +#define PS_MAX_LEN 500
> +#define LINE_SIZE_MAX (PS_MAX_LEN * 2)
> +
> +#define BYTES_OF_PS_DATA_PER_LINE 16
> +
> +#define skip_space(str) while (*(str) == (' ')) ((str)++)
> +
> +#define is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
> +
> +#define tohexval(c) (isdigit((c)) ? ((c) - '0') : \
> + (is_between((c), 'A', 'Z') ? \
> + ((c) - 'A' + 10) : ((c) - 'a' + 10)))
> +
> +#define stringtohex(str) (((uint8_t)(tohexval((str)[0]) << 4)) |\
> + ((uint8_t)tohexval((str)[1])))
> +
> +#define set_pst_format(pst, type, array_val) ((pst)->data_type = (type),\
> + (pst)->is_array = (array_val))
> +
> +struct ps_tag_entry {
> + uint32_t tag_id;
> + uint32_t tag_len;
> + uint8_t *tag_data;
> +};
> +
> +struct ps_ram_patch {
> + int16_t Len;
> + uint8_t *Data;
> +};
> +
> +struct ps_data_format {
> + unsigned char data_type;
> + unsigned char is_array;
> +};
> +
> +struct ps_cmd_packet {
> + uint8_t *Hcipacket;
> + int packetLen;
> +};
> +
> +struct st_read_status {
> + unsigned section;
> + unsigned line_count;
> + unsigned char_cnt;
> + unsigned byte_count;
> +};
> +
> +struct ps_tag_entry ps_tag_entry[RAMPS_MAX_PS_TAGS_PER_FILE];
> +struct ps_ram_patch ram_patch[MAX_NUM_PATCH_ENTRY];
> +
> +static void load_hci_header(uint8_t *hci_ps_cmd,
> + uint8_t opcode,
> + int length,
> + int index)
> +{
> + hci_ps_cmd[0] = 0x0B;
> + hci_ps_cmd[1] = 0xFC;
> + hci_ps_cmd[2] = length + 4;
> + hci_ps_cmd[3] = opcode;
> + hci_ps_cmd[4] = (index & 0xFF);
> + hci_ps_cmd[5] = ((index >> 8) & 0xFF);
> + hci_ps_cmd[6] = length;
> +
> +}
> +
> +/*
> + *Create PS download commands from parsed data
> + */
> +static int ath_create_ps_command(uint8_t opcode,
> + uint32_t param_1,
> + struct ps_cmd_packet *ps_patch_packet,
> + uint32_t *index)
> +{
> + uint8_t *hci_ps_cmd;
> + int i;
> +
> + switch (opcode) {
> +
> + case WRITE_PATCH:
> +
> + for (i = 0; i < param_1; i++) {
> +
> + /* Allocate command buffer */
> + hci_ps_cmd = (uint8_t *) malloc(ram_patch[i].Len +
> + HCI_CMD_HEADER_LEN);
> +
> + if (!hci_ps_cmd)
> + return -ENOMEM;
> +
> + /* Update commands to buffer */
> + load_hci_header(hci_ps_cmd,
> + opcode,
> + ram_patch[i].Len,
> + i);
> + memcpy(&hci_ps_cmd[HCI_CMD_HEADER_LEN],
> + ram_patch[i].Data,
> + ram_patch[i].Len);
> +
> + ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
> + ps_patch_packet[*index].packetLen = ram_patch[i].Len +
> + HCI_CMD_HEADER_LEN;
> +
> + (*index)++;
> + }
> +
> + break;
> + case ENABLE_PATCH:
> +
> + hci_ps_cmd = (uint8_t *) malloc(HCI_CMD_HEADER_LEN);
> +
> + if (!hci_ps_cmd)
> + return -ENOMEM;
> +
> + load_hci_header(hci_ps_cmd, opcode, 0, 0x00);
> + ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
> + ps_patch_packet[*index].packetLen = HCI_CMD_HEADER_LEN;
> +
> + (*index)++;
> +
> + break;
> + case PS_RESET:
> +
> + hci_ps_cmd = (uint8_t *) malloc(PS_RESET_CMD_LEN);
> +
> + if (!hci_ps_cmd)
> + return -ENOMEM;
> +
> + load_hci_header(hci_ps_cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
> +
> + hci_ps_cmd[7] = 0x00;
> + hci_ps_cmd[PS_RESET_CMD_LEN - 2] = (param_1 & 0xFF);
> + hci_ps_cmd[PS_RESET_CMD_LEN - 1] = ((param_1 >> 8) & 0xFF);
> +
> + ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
> + ps_patch_packet[*index].packetLen = PS_RESET_CMD_LEN;
> +
> + (*index)++;
> +
> + break;
> + case PS_WRITE:
> +
> + for (i = 0; i < param_1; i++) {
> +
> + hci_ps_cmd =
> + (uint8_t *) malloc(ps_tag_entry[i].tag_len +
> + HCI_CMD_HEADER_LEN);
> + if (!hci_ps_cmd)
> + return -ENOMEM;
> +
> + load_hci_header(hci_ps_cmd,
> + opcode,
> + ps_tag_entry[i].tag_len,
> + ps_tag_entry[i].tag_id);
> +
> + memcpy(&hci_ps_cmd[HCI_CMD_HEADER_LEN],
> + ps_tag_entry[i].tag_data,
> + ps_tag_entry[i].tag_len);
> +
> + ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
> +
> + ps_patch_packet[*index].packetLen =
> + ps_tag_entry[i].tag_len + HCI_CMD_HEADER_LEN;
> +
> + (*index)++;
> + }
> +
> + break;
> + default:
> + break;
> + }
> +
> + return 0;
> +}
> +
> +static int get_ps_type(char *line,
> + int eol_index,
> + unsigned char *type,
> + unsigned char *sub_type)
> +{
> +
> + switch (eol_index) {
> + case 1:
> + return 0;
> + case 2:
> + (*type) = toupper(line[1]);
> + break;
> + case 3:
> + if (line[2] == ':')
> + (*type) = toupper(line[1]);
> + else if (line[1] == ':')
> + (*sub_type) = toupper(line[2]);
> + else
> + return -1;
> +
> + break;
> + case 4:
> + if (line[2] != ':')
> + return -1;
> +
> + (*type) = toupper(line[1]);
> + (*sub_type) = toupper(line[3]);
> +
> + break;
> + case -1:
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int get_input_data_format(char *line, struct ps_data_format *pst_format)
> +{
> + unsigned char type = '\0';
> + unsigned char sub_type = '\0';
> + int eol_index = -1;
> + int i;
> +
> + /* The default values */
> + set_pst_format(pst_format, PS_TYPE_HEX, 1);
> +
> + if (line[0] != '[') {
> + set_pst_format(pst_format, PS_TYPE_HEX, 1);
> + return 0;
> + }
> +
> + for (i = 1; i < 5; i++) {
> + if (line[i] == ']') {
> + eol_index = i;
> + break;
> + }
> + }
> +
> + if (get_ps_type(line, eol_index, &type, &sub_type) < 0)
> + return -1;
> +
> + /* By default Hex array type is assumed */
> + if (type == '\0' && sub_type == '\0')
> + set_pst_format(pst_format, PS_TYPE_HEX, 1);
> +
> + /* Check is data type is of array */
> + if (type == 'A' || sub_type == 'A')
> + pst_format->is_array = 1;
> +
> + if (type == 'S' || sub_type == 'S')
> + pst_format->is_array = 0;
> +
> + switch (type) {
> +
> + case 'D':
> + case 'B':
> +
> + pst_format->data_type = PS_TYPE_DEC;
> + break;
> + default:
> +
> + pst_format->data_type = PS_TYPE_HEX;
> + break;
> +
> + }
> +
> + line += (eol_index + 1);
> +
> + return 0;
> +
> +}
> +
> +static unsigned int read_data_in_section(char *line,
> + struct ps_data_format format_info)
> +{
> + char *token_ptr = line;
> +
> + if (!token_ptr)
> + return 0x0FFF;
> +
> + if (token_ptr[0] == '[') {
> +
> + while (token_ptr[0] != ']' && token_ptr[0] != '\0')
> + token_ptr++;
> +
> + if (token_ptr[0] == '\0')
> + return 0x0FFF;
> +
> + token_ptr++;
> + }
> +
> + if (format_info.data_type == PS_TYPE_HEX) {
> +
> + if (format_info.is_array == 1)
> + return 0x0FFF;
> + else
> + return strtol(token_ptr, NULL, 16);
> +
> + } else
> + return 0x0FFF;
> +
> + return 0x0FFF;
> +
> +}
> +static int ath_parse_file(FILE *stream)
> +{
> + char *buffer;
> + char *line;
> + uint8_t tag_cnt = 0;
> + int16_t byte_count = 0;
> + int read_count;
> + int num_ps_entry;
> + struct ps_data_format stps_data_format;
> + struct st_read_status read_status = { 0, 0, 0, 0 };
> +
> + if (!stream) {
> + perror("Could not open config file .\n");
> + return -1;
> + }
> +
> + buffer = malloc(LINE_SIZE_MAX + 1);
> +
> + if (!buffer)
> + return -ENOMEM;
> +
> + do {
> + line = fgets(buffer, LINE_SIZE_MAX, stream);
> +
> + if (!line)
> + break;
> +
> + skip_space(line);
> +
> + if ((line[0] == '/') && (line[1] == '/'))
> + continue;
> +
> + if ((line[0] == '#')) {
> +
> + if (read_status.section != 0) {
> +
> + if (buffer)
> + free(buffer);
> + return -1;
> +
> + } else {
> + read_status.section = 1;
> + continue;
> + }
> + }
> +
> + if ((line[0] == '/') && (line[1] == '*')) {
> +
> + read_status.section = 0;
> + continue;
> + }
> +
> + if (read_status.section == 1) {
> + skip_space(line);
> +
> + if (get_input_data_format(
> + line, &stps_data_format) < 0) {
> +
> + if (buffer)
> + free(buffer);
> + return -1;
> +
> + }
> +
> + ps_tag_entry[tag_cnt].tag_id = read_data_in_section(
> + line,
> + stps_data_format);
> + read_status.section = 2;
> +
> + } else if (read_status.section == 2) {
> +
> + if (get_input_data_format(
> + line, &stps_data_format) < 0) {
> +
> + if (buffer)
> + free(buffer);
> + return -1;
> + }
> +
> + byte_count =
> + read_data_in_section(line, stps_data_format);
> +
> + read_status.section = 2;
> + if (byte_count > LINE_SIZE_MAX / 2) {
> + if (buffer)
> + free(buffer);
> +
> + return -1;
> + }
> +
> + ps_tag_entry[tag_cnt].tag_len = byte_count;
> + ps_tag_entry[tag_cnt].tag_data = (uint8_t *)
> + malloc(byte_count);
> +
> + read_status.section = 3;
> + read_status.line_count = 0;
> +
> + } else if (read_status.section == 3) {
> +
> + if (read_status.line_count == 0) {
> + if (get_input_data_format(
> + line, &stps_data_format) < 0) {
> + if (buffer)
> + free(buffer);
> + return -1;
> + }
> + }
> +
> + skip_space(line);
> + read_status.char_cnt = 0;
> +
> + if (line[read_status.char_cnt] == '[') {
> +
> + while (line[read_status.char_cnt] != ']' &&
> + line[read_status.char_cnt] != '\0')
> + read_status.char_cnt++;
> +
> + if (line[read_status.char_cnt] == ']')
> + read_status.char_cnt++;
> + else
> + read_status.char_cnt = 0;
> +
> + }
> +
> + read_count = (byte_count > BYTES_OF_PS_DATA_PER_LINE)
> + ? BYTES_OF_PS_DATA_PER_LINE : byte_count;
> +
> + if (stps_data_format.data_type == PS_TYPE_HEX &&
> + stps_data_format.is_array == 1) {
> +
> + while (read_count > 0) {
> +
> + ps_tag_entry[tag_cnt].tag_data
> + [read_status.byte_count] =
> + stringtohex(
> + &line[read_status.char_cnt]);
> +
> + ps_tag_entry[tag_cnt].tag_data
> + [read_status.byte_count + 1] =
> + stringtohex(
> + &line[read_status.char_cnt + 3]);
> +
> + read_status.char_cnt += 6;
> + read_status.byte_count += 2;
> + read_count -= 2;
> +
> + }
> +
> + if (byte_count > BYTES_OF_PS_DATA_PER_LINE)
> + byte_count -=
> + BYTES_OF_PS_DATA_PER_LINE;
> + else
> + byte_count = 0;
> + }
> +
> + read_status.line_count++;
> +
> + if (byte_count == 0) {
> + read_status.section = 0;
> + read_status.char_cnt = 0;
> + read_status.line_count = 0;
> + read_status.byte_count = 0;
> + } else
> + read_status.char_cnt = 0;
> +
> + if (read_status.section == 0) {
> + tag_cnt++;
> +
> + if (tag_cnt == RAMPS_MAX_PS_TAGS_PER_FILE) {
> + if (buffer)
> + free(buffer);
> + return -1;
> + }
> + }
> +
> + }
> +
> + } while (line);
> +
> + num_ps_entry = tag_cnt;
> +
> + if (tag_cnt > RAMPS_MAX_PS_TAGS_PER_FILE) {
> + if (buffer)
> + free(buffer);
> + return -1;
> + }
> +
> + if (buffer)
> + free(buffer);
> +
> + return num_ps_entry;
> +}
> +
> +static int parse_patch_file(FILE *stream)
> +{
> + char byte[3];
> + char line[MAX_BYTE_LENGTH + 1];
> + int byte_cnt, byte_cnt_org;
> + int patch_index;
> + int i, k;
> + int data;
> + int patch_count = 0;
> +
> + byte[2] = '\0';
> +
> + while (fgets(line, MAX_BYTE_LENGTH, stream)) {
> + if (strlen(line) <= 1 || !isxdigit(line[0]))
> + continue;
> + else
> + break;
> + }
> +
> + byte_cnt = strtol(line, NULL, 16);
> + byte_cnt_org = byte_cnt;
> +
> + while (byte_cnt > MAX_BYTE_LENGTH) {
> +
> + /* Handle case when the number of patch buffer is
> + * more than the 20K */
> + if (MAX_NUM_PATCH_ENTRY == patch_count) {
> + for (i = 0; i < patch_count; i++)
> + free(ram_patch[i].Data);
> + return -ENOMEM;
> + }
> +
> + ram_patch[patch_count].Len = MAX_BYTE_LENGTH;
> + ram_patch[patch_count].Data =
> + (uint8_t *) malloc(MAX_BYTE_LENGTH);
> +
> + if (!ram_patch[patch_count].Data)
> + return -ENOMEM;
> +
> + patch_count++;
> + byte_cnt = byte_cnt - MAX_BYTE_LENGTH;
> + }
> +
> + ram_patch[patch_count].Len = (byte_cnt & 0xFF);
> +
> + if (byte_cnt != 0) {
> + ram_patch[patch_count].Data = (uint8_t *) malloc(byte_cnt);
> +
> + if (!ram_patch[patch_count].Data)
> + return -ENOMEM;
> + patch_count++;
> + }
> +
> + while (byte_cnt_org > MAX_BYTE_LENGTH) {
> +
> + k = 0;
> + for (i = 0; i < MAX_BYTE_LENGTH * 2; i += 2) {
> + if (!fgets(byte, 3, stream))
> + return -1;
> + data = strtoul(&byte[0], NULL, 16);
> + ram_patch[patch_index].Data[k] = (data & 0xFF);
> +
> + k++;
> + }
> +
> + patch_index++;
> +
> + byte_cnt_org = byte_cnt_org - MAX_BYTE_LENGTH;
> + }
> +
> + if (patch_index == 0)
> + patch_index++;
> +
> + for (k = 0; k < byte_cnt_org; k++) {
> +
> + if (!fgets(byte, 3, stream))
> + return -1;
> +
> + data = strtoul(byte, NULL, 16);
> + ram_patch[patch_index].Data[k] = (data & 0xFF);
> + }
> +
> + return patch_count;
> +}
> +
> +static int ath_parse_ps(FILE *stream, int *total_tag_len)
> +{
> + int num_ps_tags;
> + int i;
> + unsigned char bdaddr_present = 0;
> +
> + if (stream)
> + num_ps_tags = ath_parse_file(stream);
> +
> + if (num_ps_tags < 0)
> + return -1;
> +
> + if (num_ps_tags == 0)
> + *total_tag_len = 10;
> + else {
> +
> + for (i = 0; i < num_ps_tags; i++) {
> +
> + if (ps_tag_entry[i].tag_id == 1)
> + bdaddr_present = 1;
> + if (ps_tag_entry[i].tag_len % 2 == 1)
> + *total_tag_len = *total_tag_len
> + + ps_tag_entry[i].tag_len + 1;
> + else
> + *total_tag_len =
> + *total_tag_len + ps_tag_entry[i].tag_len;
> +
> + }
> + }
> +
> + if (num_ps_tags > 0 && !bdaddr_present)
> + *total_tag_len = *total_tag_len + 10;
> +
> + *total_tag_len = *total_tag_len + 10 + (num_ps_tags * 4);
> +
> + return num_ps_tags;
> +}
> +
> +static int ath_create_cmd_list(struct ps_cmd_packet **hci_packet_list,
> + uint32_t *num_packets,
> + int tag_count,
> + int patch_count,
> + int total_tag_len)
> +{
> + uint8_t count;
> + uint32_t num_cmd_entry = 0;
> +
> + *num_packets = 0;
> +
> + if (patch_count || tag_count) {
> +
> + /* PS Reset Packet + Patch List + PS List */
> + num_cmd_entry += (1 + patch_count + tag_count);
> + if (patch_count > 0)
> + num_cmd_entry++; /* Patch Enable Command */
> +
> + (*hci_packet_list) =
> + malloc(sizeof(struct ps_cmd_packet) * num_cmd_entry);
> +
> + if (!(*hci_packet_list))
> + return -ENOMEM;
> +
> + if (patch_count > 0) {
> +
> + if (ath_create_ps_command(WRITE_PATCH, patch_count,
> + *hci_packet_list, num_packets) < 0)
> + return -1;
> + if (ath_create_ps_command(ENABLE_PATCH, 0,
> + *hci_packet_list, num_packets) < 0)
> + return -1;
> + if (ath_create_ps_command(PS_RESET,
> + total_tag_len + EXTRA_PATCH_SIZE,
> + *hci_packet_list, num_packets) < 0)
> + return -1;
> +
> + } else {
> +
> + if (ath_create_ps_command(PS_RESET, total_tag_len,
> + *hci_packet_list, num_packets) < 0)
> + return -1;
> + }
> +
> + if (tag_count > 0)
> + ath_create_ps_command(PS_WRITE, tag_count,
> + *hci_packet_list, num_packets);
> + }
> +
> + for (count = 0; count < patch_count; count++)
> + free(ram_patch[patch_count].Data);
> +
> + for (count = 0; count < tag_count; count++)
> + free(ps_tag_entry[count].tag_data);
> +
> + return *num_packets;
> +}
> +
> +static int ath_free_command_list(struct ps_cmd_packet **hci_packet_list,
> + uint32_t num_packets)
> +{
> + int i;
> +
> + if (!(*hci_packet_list))
> + return -1;
> +
> + for (i = 0; i < num_packets; i++)
> + free((*hci_packet_list)[i].Hcipacket);
> +
> + free(*hci_packet_list);
> +
> + return 0;
> +}
> +
> +/*
> + * This API is used to send the HCI command to controller and return
> + * with a HCI Command Complete event.
> + */
> +static int send_hci_cmd_wait_event(int dev,
> + uint8_t *hci_command,
> + int cmd_length,
> + uint8_t **event, uint8_t **buffer_to_free)
> +{
> + int r;
> + uint8_t *hci_event;
> + uint8_t pkt_type = 0x01;
> +
> + if (cmd_length == 0)
> + return -1;
> +
> + if (write(dev, &pkt_type, 1) != 1)
> + return -1;
> +
> + if (write(dev, (unsigned char *)hci_command, cmd_length) != cmd_length)
> + return -1;
> +
> + hci_event = (uint8_t *) malloc(100);
> +
> + if (!hci_event)
> + return -ENOMEM;
> +
> + r = read_hci_event(dev, (unsigned char *)hci_event, 100);
> +
> + if (r > 0) {
> + *event = hci_event;
> + *buffer_to_free = hci_event;
> + } else {
> +
> + /* Did not get an event from controller. return error */
> + free(hci_event);
> + *buffer_to_free = NULL;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int read_ps_event(uint8_t *data)
> +{
> +
> + if (data[5] == 0xFC && data[6] == 0x00) {
> +
> + switch (data[4]) {
> +
> + case 0x0B:/* CRC Check */
> + case 0x0C:/* Change Baudrate */
> + case 0x04:/* Enable sleep */
> + return 0;
> + break;
> + default:
> + return -1;
> + break;
> +
> + }
> + }
> +
> + return -1;
> +}
> +
> +static int get_ps_file_name(int devtype, int rom_version, char *path)
> +{
> + char *filename;
> + int status = 0;
> +
> + if (devtype == 0xdeadc0de) {
> + filename = PS_ASIC_FILE;
> + status = 1;
> + } else {
> + filename = PS_FPGA_FILE;
> + status = 0;
> + }
> +
> + sprintf(path, "%s%x/%s", FW_PATH, rom_version, filename);
> +
> + return status;
> +}
> +
> +static int get_patch_file_name(int dev_type, int rom_version,
> + int build_version, char *path)
> +{
> +
> + if ((dev_type != 0) &&
> + (dev_type != 0xdeadc0de) &&
> + (rom_version == 0x99999999) &&
> + (build_version == 1))
> + path[0] = '\0';
> + else
> + sprintf(path, "%s%x/%s", FW_PATH, rom_version, PATCH_FILE);
> +
> + return 0;
> +}
> +static int get_ar3k_crc(int dev, int tag_count, int patch_count)
> +{
> + uint8_t hci_cmd[7];
> + uint8_t *event;
> + uint8_t *buffer_to_free = NULL;
> + int retval = 1;
> + int crc;
> +
> + if (patch_count > 0)
> + crc |= RAM_PATCH_REGION;
> + if (tag_count > 0)
> + crc |= RAM_PS_REGION;
> +
> + load_hci_header(hci_cmd, PS_VERIFY_CRC, 0, crc);
> +
> + if (send_hci_cmd_wait_event(dev,
> + hci_cmd,
> + sizeof(hci_cmd),
> + &event,
> + &buffer_to_free) == 0) {
> +
> + if (read_ps_event(event) == 0)
> + retval = -1;
> +
> + if (buffer_to_free != NULL)
> + free(buffer_to_free);
> + }
> +
> + return retval;
> +}
> +static int get_device_type(int dev, uint32_t *code)
> +{
> + uint8_t hci_cmd[] = { 0x05, 0xfc, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04 };
> + uint8_t *event;
> + uint8_t *buffer_to_free = NULL;
> + uint32_t reg;
> + int result = -1;
> +
> + *code = 0;
> +
> + hci_cmd[3] = (uint8_t) (DEV_REGISTER & 0xFF);
> + hci_cmd[4] = (uint8_t) ((DEV_REGISTER >> 8) & 0xFF);
> + hci_cmd[5] = (uint8_t) ((DEV_REGISTER >> 16) & 0xFF);
> + hci_cmd[6] = (uint8_t) ((DEV_REGISTER >> 24) & 0xFF);
> +
> + if (send_hci_cmd_wait_event(dev,
> + hci_cmd,
> + sizeof(hci_cmd),
> + &event,
> + &buffer_to_free) == 0) {
> +
> + if (event[5] == 0xFC && event[6] == 0x00) {
> +
> + switch (event[4]) {
> + case 0x05:
> + reg = event[10];
> + reg = ((reg << 8) | event[9]);
> + reg = ((reg << 8) | event[8]);
> + reg = ((reg << 8) | event[7]);
> + *code = reg;
> + result = 0;
> +
> + break;
> +
> + case 0x06:
> + break;
> + }
> + }
> + }
> +
> + if (buffer_to_free)
> + free(buffer_to_free);
> +
> + return result;
> +}
> +
> +static int read_ar3k_version(int pConfig, int *rom_version, int *build_version)
> +{
> + uint8_t hci_cmd[] = { 0x1E, 0xfc, 0x00 };
> + uint8_t *event;
> + uint8_t *buffer_to_free = NULL;
> + int result = -1;
> +
> + if (send_hci_cmd_wait_event(pConfig,
> + hci_cmd,
> + sizeof(hci_cmd),
> + &event,
> + &buffer_to_free) == 0) {
> +
> + if (event[5] == 0xFC &&
> + event[6] == 0x00 &&
> + event[4] == 0x1E) {
> +
> + (*rom_version) = event[10];
> + (*rom_version) = (((*rom_version) << 8) | event[9]);
> + (*rom_version) = (((*rom_version) << 8) | event[8]);
> + (*rom_version) = (((*rom_version) << 8) | event[7]);
> +
> + (*build_version) = event[14];
> + (*build_version) = (((*build_version) << 8) |
> + event[13]);
> + (*build_version) = (((*build_version) << 8) |
> + event[12]);
> + (*build_version) = (((*build_version) << 8) |
> + event[11]);
> +
> + result = 1;
> +
> + }
> +
> + if (buffer_to_free)
> + free(buffer_to_free);
> + }
> +
> + return result;
> +}
> +
> +static int str2bdaddr(char *str_bdaddr, char *bdaddr)
> +{
> + char bdbyte[3];
> + char *str_byte = str_bdaddr;
> + int i, j;
> + unsigned char colon_present = 0;
> +
> + if (strstr(str_bdaddr, ":"))
> + colon_present = 1;
> +
> + bdbyte[2] = '\0';
> +
> + for (i = 0, j = 5; i < 6; i++, j--) {
> +
> + bdbyte[0] = str_byte[0];
> + bdbyte[1] = str_byte[1];
> + bdaddr[j] = strtol(bdbyte, NULL, 16);
> +
> + if (colon_present == 1)
> + str_byte += 3;
> + else
> + str_byte += 2;
> + }
> + return 0;
> +}
> +
> +static int write_bdaddr(int pConfig, char *bdaddr)
> +{
> + uint8_t bdaddr_cmd[] = { 0x0B, 0xFC, 0x0A,
> + 0x01, 0x01, 0x00,
> + 0x06, 0x00, 0x00,
> + 0x00, 0x00, 0x00,
> + 0x00 };
> + uint8_t *event;
> + uint8_t *buffer_to_free = NULL;
> + int result = -1;
> +
> + str2bdaddr(bdaddr, (char *)&bdaddr_cmd[7]);
> +
> + if (send_hci_cmd_wait_event(pConfig,
> + bdaddr_cmd,
> + sizeof(bdaddr_cmd),
> + &event,
> + &buffer_to_free) == 0) {
> +
> + if (event[5] == 0xFC && event[6] == 0x00) {
> + if (event[4] == 0x0B)
> + result = 0;
> + }
> +
> + }
> +
> + if (buffer_to_free)
> + free(buffer_to_free);
> +
> + return result;
> +}
> +
> +int ath_configure_sleep(int fd, int sleep_stat)
> +{
> + int dev_id, dd;
> + struct timespec tm = {0, 50000};
> +
> + dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
> +
> + if (dev_id < 0) {
> + perror("cannot get device id");
> + return -1;
> + }
> +
> + dd = hci_open_dev(dev_id);
> +
> + if (dd < 0) {
> + perror("HCI device open failed");
> + return -1;
> + }
> +
> + sleep(2);
> +
> + /* send vendor specific command with Sleep feature Enabled */
> + if (hci_send_cmd(dd, OGF_VENDOR_CMD, 0x04, 1, &sleep_stat) < 0)
> + perror("Power management Disabled");
> +
> + nanosleep(&tm, NULL);
> + hci_close_dev(dd);
> +
> + return 0;
> +}
> +
> +int ath_ps_download(int hdev)
> +{
> + int i;
> + int status = 0;
> + int tag_count;
> + int patch_count;
> + int total_tag_len = 0;
> + int rom_version = 0, build_version = 0;
> +
> + struct ps_cmd_packet *hci_cmd_list; /* List storing the commands */
> + uint32_t num_cmds;
> + uint8_t *event;
> + uint8_t *buffer_to_free;
> + uint32_t dev_type;
> +
> + char patch_file[PATH_MAX];
> + char ps_file[PATH_MAX];
> + char bdaddr_file[PATH_MAX];
> +
> + FILE *stream;
> + char bdaddr[21];
> +
> + hci_cmd_list = NULL;
> +
> + /*
> + * Verfiy firmware version. depending on it select the PS
> + * config file to download.
> + */
> + if (get_device_type(hdev, &dev_type) == -1) {
> + status = -1;
> + goto download_cmplete;
> + }
> + if (read_ar3k_version(hdev, &rom_version, &build_version) == -1) {
> + status = -1;
> + goto download_cmplete;
> + }
> +
> + get_ps_file_name(dev_type, rom_version, ps_file);
> +
> + get_patch_file_name(dev_type, rom_version, build_version, patch_file);
> +
> + /* Read the PS file to a dynamically allocated buffer */
> + stream = fopen(ps_file, "r");
> +
> + if (!stream) {
> + perror("firmware file open error\n");
> + status = -1;
> + goto download_cmplete;
> + }
> +
> + tag_count = ath_parse_ps(stream, &total_tag_len);
> +
> + fclose(stream);
> +
> + if (tag_count == -1) {
> + status = -1;
> + goto download_cmplete;
> + }
> +
> + /*
> + * It is not necessary that Patch file be available,
> + * continue with PS Operations if.
> + * failed.
> + */
> + if (patch_file[0] == '\0')
> + status = 0;
> +
> + stream = fopen(patch_file, "r");
> +
> + if (!stream) {
> + patch_count = 0;
> + status = 0;
> + } else {
> + /* parse and store the Patch file contents to
> + * a global variables
> + */
> + patch_count = parse_patch_file(stream);
> +
> + fclose(stream);
> +
> + if (patch_count < 0) {
> + status = -1;
> + goto download_cmplete;
> + }
> + }
> +
> + /*
> + * Send the CRC packet,
> + * Continue with the PS operations
> + * only if the CRC check failed
> + */
> + if (get_ar3k_crc(hdev, tag_count, patch_count) < 0) {
> + status = 0;
> + goto download_cmplete;
> + }
> +
> + /* Create an HCI command list
> + * from the parsed PS and patch information
> + */
> + ath_create_cmd_list(&hci_cmd_list,
> + &num_cmds,
> + tag_count,
> + patch_count,
> + total_tag_len);
> +
> + for (i = 0; i < num_cmds; i++) {
> +
> + if (send_hci_cmd_wait_event
> + (hdev,
> + hci_cmd_list[i].Hcipacket,
> + hci_cmd_list[i].packetLen,
> + &event,
> + &buffer_to_free) == 0) {
> +
> + if (read_ps_event(event) < 0) {
> +
> + /* Exit if the status is not success */
> + if (buffer_to_free)
> + free(buffer_to_free);
> +
> + status = -1;
> + goto download_cmplete;
> + }
> + if (buffer_to_free)
> + free(buffer_to_free);
> + } else {
> + status = 0;
> + goto download_cmplete;
> + }
> + }
> + /* Read the PS file to a dynamically allocated buffer */
> + sprintf(bdaddr_file, "%s%x/%s", FW_PATH, rom_version, BDADDR_FILE);
> +
> + stream = fopen(bdaddr_file, "r");
> +
> + if (!stream) {
> + status = 0;
> + goto download_cmplete;
> + }
> +
> + if (fgets(bdaddr, 20, stream))
> + status = write_bdaddr(hdev, bdaddr);
> +
> + fclose(stream);
> +
> +download_cmplete:
> +
> + if (hci_cmd_list)
> + ath_free_command_list(&hci_cmd_list, num_cmds);
> +
> + return status;
> +}

Please spend some time to verify the patch so that I can take it to the
next level.

Regards
Suraj


2010-05-18 11:39:12

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip

Hi Marcel,

On Tue, 2010-05-11 at 13:59 +0530, suraj wrote:
> Hi marcel,
>
> On Wed, 2010-05-05 at 18:03 +0530, suraj wrote:
> > Hi Marcel,
> >
> > Can you take a look at the patch? Your review has been pending for
> > sometime.
> >
> > On Mon, 2010-04-26 at 16:30 +0530, suraj wrote:
> > > Hi marcel,
> > >
> > > On Thu, 2010-04-22 at 14:40 +0530, suraj wrote:
> > > > This implements the Atheros Bluetooth serial protocol to
> > > > support the AR300x Bluetooth chipsets.
> > > > The serial protocol implements enhanced power management
> > > > features for the AR300x chipsets.
> > > >
> > > > Reviewed-by: Luis R. Rodriguez <[email protected]>
> > > > Reviewed-by: Gustavo F. Padovan <[email protected]>
> > > > Signed-off-by: Suraj <[email protected]>
> > > >
> > > > ---
> > > > drivers/bluetooth/Kconfig | 14 ++
> > > > drivers/bluetooth/Makefile | 1 +
> > > > drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++
> > > > drivers/bluetooth/hci_ldisc.c | 6 +
> > > > drivers/bluetooth/hci_uart.h | 8 +-
> > > > 5 files changed, 406 insertions(+), 1 deletions(-)
> > > > create mode 100755 drivers/bluetooth/hci_ath.c
> > > >
> > > Can you verify the patch let me know your comments?
> > >
> > > Regards
> > > Suraj
> > >
> >
> >
>
> your review has been pending for a long time. Please let me know what
> should be done regarding this.
>
> Regards
> Suraj
>
>
This patch has been pending your approval/disapproval for so much time
that it runs the risk of being obsolete. Please do let me know if you
have any plans of doing something about it.

Regards
Suraj

2010-05-12 13:47:39

by Suraj Sumangala

[permalink] [raw]
Subject: [PATCH v3] hciattach application support for Atheros AR300x Bluetooth Chip

Implements support for Atheros AR300x Bluetooth chip in hciattach.
Adds feature to bring up AR300x Bluetooth chip
with and without enhanced power management enabled.

Signed-off-by: Suraj <[email protected]>

---
Makefile.tools | 1 +
tools/hciattach.8 | 6 +
tools/hciattach.c | 111 +++++
tools/hciattach.h | 3 +
tools/hciattach_ar3k.c | 1223 ++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 1344 insertions(+), 0 deletions(-)
create mode 100755 tools/hciattach_ar3k.c

diff --git a/Makefile.tools b/Makefile.tools
index 2735d68..48cf097 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -23,6 +23,7 @@ tools_l2ping_LDADD = lib/libbluetooth.la
tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
tools/hciattach_st.c \
tools/hciattach_ti.c \
+ tools/hciattach_ar3k.c \
tools/hciattach_tialt.c
tools_hciattach_LDADD = lib/libbluetooth.la

diff --git a/tools/hciattach.8 b/tools/hciattach.8
index f750222..ef943ea 100644
--- a/tools/hciattach.8
+++ b/tools/hciattach.8
@@ -49,6 +49,12 @@ specific identifier. Currently supported types are
.B any
Unspecified HCI_UART interface, no vendor specific options
.TP
+.B ar3kalt
+Atheros AR300x based serial bluetooth device with power management disabled
+.TP
+.B ar3k
+Atheros AR300x based serial bluetooth device
+.TP
.B ericsson
Ericsson based modules
.TP
diff --git a/tools/hciattach.c b/tools/hciattach.c
index b13db1b..768a3f1 100644
--- a/tools/hciattach.c
+++ b/tools/hciattach.c
@@ -653,6 +653,110 @@ static int csr(int fd, struct uart_t *u, struct termios *ti)
}

/*
+ * Atheros AR300x specific initialization post callback
+ * with power management dsiabled
+ * Suraj Sumangala <[email protected]>
+ */
+static int ar3kpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ return ath_configure_sleep(fd, 0);
+}
+
+/*
+ * Atheros AR300x specific initialization post callback
+ * with power management enabled
+ * Suraj Sumangala <[email protected]>
+ */
+static int ar3kpmpost(int fd, struct uart_t *u, struct termios *ti)
+{
+ return ath_configure_sleep(fd, 1);
+}
+/*
+ * Atheros AR300x specific initialization
+ * Suraj Sumangala <[email protected]>
+ */
+static int ar3kinit(int fd, struct uart_t *u, struct termios *ti)
+{
+ struct timespec tm = { 0, 500000 };
+ unsigned char cmd[14], rsp[100];
+ int r;
+ int baud;
+
+ /* Download PS and patch */
+ r = ath_ps_download(fd);
+
+ if (r < 0) {
+ perror("Failed to Download configuration");
+ return -1;
+ }
+
+ /* Write BDADDR if user has provided any */
+ if (u->bdaddr != NULL) {
+ /* Set BD_ADDR */
+ memset(cmd, 0, sizeof(cmd));
+ memset(rsp, 0, sizeof(rsp));
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x0B;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x0A;
+ cmd[4] = 0x01;
+ cmd[5] = 0x01;
+ cmd[6] = 0x00;
+ cmd[7] = 0x06;
+ str2ba(u->bdaddr, (bdaddr_t *) (cmd + 8));
+
+ /* Send command */
+ if (write(fd, cmd, 14) != 14) {
+ fprintf(stderr, "Failed to write BD_ADDR command\n");
+ return -1;
+ }
+
+ /* Read reply */
+ if (read_hci_event(fd, rsp, 10) < 0) {
+ fprintf(stderr, "Failed to set BD_ADDR\n");
+ return -1;
+ }
+ }
+
+ /* Send HCI Reset to write the configuration */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x03;
+ cmd[2] = 0x0C;
+ cmd[3] = 0x00;
+
+ r = write(fd, cmd, 4);
+
+ if (r != 4)
+ return -1;
+
+ nanosleep(&tm, NULL);
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -1;
+
+ /* Set baud rate command,
+ * set controller baud rate to user specified value */
+ cmd[0] = HCI_COMMAND_PKT;
+ cmd[1] = 0x0C;
+ cmd[2] = 0xfc;
+ cmd[3] = 0x02;
+ baud = u->speed/100;
+ cmd[4] = (char)baud;
+ cmd[5] = (char)(baud >> 8);
+
+ if (write(fd, cmd, 6) != 6) {
+ perror("Failed to write init command");
+ return -1;
+ }
+
+ /* Wait for the command complete event for Baud rate change Command */
+ nanosleep(&tm, NULL);
+
+ if (read_hci_event(fd, rsp, sizeof(rsp)) < 0)
+ return -1;
+
+ return 0;
+}
+/*
* Silicon Wave specific initialization
* Thomas Moser <[email protected]>
*/
@@ -1071,6 +1175,13 @@ struct uart_t uart[] = {
/* Broadcom BCM2035 */
{ "bcm2035", 0x0A5C, 0x2035, HCI_UART_H4, 115200, 460800, FLOW_CTL, NULL, bcm2035 },

+ /* ATHEROS AR300x */
+ { "ar3kalt", 0x0000, 0x0000, HCI_UART_ATH, 115200, 115200,
+ FLOW_CTL, NULL, ar3kinit, ar3kpost },
+
+ { "ar3k", 0x0000, 0x0000, HCI_UART_ATH, 115200, 115200,
+ FLOW_CTL, NULL, ar3kinit, ar3kpmpost },
+
{ NULL, 0 }
};

diff --git a/tools/hciattach.h b/tools/hciattach.h
index 867563b..7719e04 100644
--- a/tools/hciattach.h
+++ b/tools/hciattach.h
@@ -36,6 +36,7 @@
#define HCI_UART_3WIRE 2
#define HCI_UART_H4DS 3
#define HCI_UART_LL 4
+#define HCI_UART_ATH 5

int read_hci_event(int fd, unsigned char* buf, int size);
int set_speed(int fd, struct termios *ti, int speed);
@@ -45,3 +46,5 @@ int texas_post(int fd, struct termios *ti);
int texasalt_init(int fd, int speed, struct termios *ti);
int stlc2500_init(int fd, bdaddr_t *bdaddr);
int bgb2xx_init(int dd, bdaddr_t *bdaddr);
+int ath_configure_sleep(int fd, int sleep_stat);
+int ath_ps_download(int fd);
diff --git a/tools/hciattach_ar3k.c b/tools/hciattach_ar3k.c
new file mode 100755
index 0000000..2542161
--- /dev/null
+++ b/tools/hciattach_ar3k.c
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (c) 2009-2010 Atheros Communications Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+
+/* The maximum number of bytes possible in a patch entry */
+#define MAX_PATCH_SIZE 20000
+
+#define MAX_BYTE_LENGTH 244
+
+/* Maximum HCI packets that will be formed from the Patch file */
+#define MAX_NUM_PATCH_ENTRY ((MAX_PATCH_SIZE/MAX_BYTE_LENGTH) + 1)
+
+#define DEV_REGISTER 0x4FFC
+
+#define FW_PATH "/lib/firmware/ar3k/"
+
+#define PS_ASIC_FILE "PS_ASIC.pst"
+#define PS_FPGA_FILE "PS_FPGA.pst"
+#define PATCH_FILE "RamPatch.txt"
+#define BDADDR_FILE "ar3kbdaddr.pst"
+
+#define HCI_CMD_HEADER_LEN 7
+
+/* PS command types */
+#define PS_RESET 2
+#define PS_WRITE 1
+#define WRITE_PATCH 8
+#define PS_VERIFY_CRC 9
+#define ENABLE_PATCH 11
+
+#define EXTRA_PATCH_SIZE 500
+
+/* PS configuration entry time */
+#define PS_TYPE_HEX 0
+#define PS_TYPE_DEC 1
+
+#define PS_RESET_PARAM_LEN 6
+#define PS_RESET_CMD_LEN (PS_RESET_PARAM_LEN +\
+ HCI_CMD_HEADER_LEN)
+
+#define RAM_PS_REGION (1<<0)
+#define RAM_PATCH_REGION (1<<1)
+
+#define RAMPS_MAX_PS_TAGS_PER_FILE 50
+#define PS_MAX_LEN 500
+#define LINE_SIZE_MAX (PS_MAX_LEN * 2)
+
+#define BYTES_OF_PS_DATA_PER_LINE 16
+
+#define skip_space(str) while (*(str) == (' ')) ((str)++)
+
+#define is_between(x, lower, upper) (((lower) <= (x)) && ((x) <= (upper)))
+
+#define tohexval(c) (isdigit((c)) ? ((c) - '0') : \
+ (is_between((c), 'A', 'Z') ? \
+ ((c) - 'A' + 10) : ((c) - 'a' + 10)))
+
+#define stringtohex(str) (((uint8_t)(tohexval((str)[0]) << 4)) |\
+ ((uint8_t)tohexval((str)[1])))
+
+#define set_pst_format(pst, type, array_val) ((pst)->data_type = (type),\
+ (pst)->is_array = (array_val))
+
+struct ps_tag_entry {
+ uint32_t tag_id;
+ uint32_t tag_len;
+ uint8_t *tag_data;
+};
+
+struct ps_ram_patch {
+ int16_t Len;
+ uint8_t *Data;
+};
+
+struct ps_data_format {
+ unsigned char data_type;
+ unsigned char is_array;
+};
+
+struct ps_cmd_packet {
+ uint8_t *Hcipacket;
+ int packetLen;
+};
+
+struct st_read_status {
+ unsigned section;
+ unsigned line_count;
+ unsigned char_cnt;
+ unsigned byte_count;
+};
+
+struct ps_tag_entry ps_tag_entry[RAMPS_MAX_PS_TAGS_PER_FILE];
+struct ps_ram_patch ram_patch[MAX_NUM_PATCH_ENTRY];
+
+static void load_hci_header(uint8_t *hci_ps_cmd,
+ uint8_t opcode,
+ int length,
+ int index)
+{
+ hci_ps_cmd[0] = 0x0B;
+ hci_ps_cmd[1] = 0xFC;
+ hci_ps_cmd[2] = length + 4;
+ hci_ps_cmd[3] = opcode;
+ hci_ps_cmd[4] = (index & 0xFF);
+ hci_ps_cmd[5] = ((index >> 8) & 0xFF);
+ hci_ps_cmd[6] = length;
+
+}
+
+/*
+ *Create PS download commands from parsed data
+ */
+static int ath_create_ps_command(uint8_t opcode,
+ uint32_t param_1,
+ struct ps_cmd_packet *ps_patch_packet,
+ uint32_t *index)
+{
+ uint8_t *hci_ps_cmd;
+ int i;
+
+ switch (opcode) {
+
+ case WRITE_PATCH:
+
+ for (i = 0; i < param_1; i++) {
+
+ /* Allocate command buffer */
+ hci_ps_cmd = (uint8_t *) malloc(ram_patch[i].Len +
+ HCI_CMD_HEADER_LEN);
+
+ if (!hci_ps_cmd)
+ return -ENOMEM;
+
+ /* Update commands to buffer */
+ load_hci_header(hci_ps_cmd,
+ opcode,
+ ram_patch[i].Len,
+ i);
+ memcpy(&hci_ps_cmd[HCI_CMD_HEADER_LEN],
+ ram_patch[i].Data,
+ ram_patch[i].Len);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen = ram_patch[i].Len +
+ HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+ }
+
+ break;
+ case ENABLE_PATCH:
+
+ hci_ps_cmd = (uint8_t *) malloc(HCI_CMD_HEADER_LEN);
+
+ if (!hci_ps_cmd)
+ return -ENOMEM;
+
+ load_hci_header(hci_ps_cmd, opcode, 0, 0x00);
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen = HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+
+ break;
+ case PS_RESET:
+
+ hci_ps_cmd = (uint8_t *) malloc(PS_RESET_CMD_LEN);
+
+ if (!hci_ps_cmd)
+ return -ENOMEM;
+
+ load_hci_header(hci_ps_cmd, opcode, PS_RESET_PARAM_LEN, 0x00);
+
+ hci_ps_cmd[7] = 0x00;
+ hci_ps_cmd[PS_RESET_CMD_LEN - 2] = (param_1 & 0xFF);
+ hci_ps_cmd[PS_RESET_CMD_LEN - 1] = ((param_1 >> 8) & 0xFF);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+ ps_patch_packet[*index].packetLen = PS_RESET_CMD_LEN;
+
+ (*index)++;
+
+ break;
+ case PS_WRITE:
+
+ for (i = 0; i < param_1; i++) {
+
+ hci_ps_cmd =
+ (uint8_t *) malloc(ps_tag_entry[i].tag_len +
+ HCI_CMD_HEADER_LEN);
+ if (!hci_ps_cmd)
+ return -ENOMEM;
+
+ load_hci_header(hci_ps_cmd,
+ opcode,
+ ps_tag_entry[i].tag_len,
+ ps_tag_entry[i].tag_id);
+
+ memcpy(&hci_ps_cmd[HCI_CMD_HEADER_LEN],
+ ps_tag_entry[i].tag_data,
+ ps_tag_entry[i].tag_len);
+
+ ps_patch_packet[*index].Hcipacket = hci_ps_cmd;
+
+ ps_patch_packet[*index].packetLen =
+ ps_tag_entry[i].tag_len + HCI_CMD_HEADER_LEN;
+
+ (*index)++;
+ }
+
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int get_ps_type(char *line,
+ int eol_index,
+ unsigned char *type,
+ unsigned char *sub_type)
+{
+
+ switch (eol_index) {
+ case 1:
+ return 0;
+ case 2:
+ (*type) = toupper(line[1]);
+ break;
+ case 3:
+ if (line[2] == ':')
+ (*type) = toupper(line[1]);
+ else if (line[1] == ':')
+ (*sub_type) = toupper(line[2]);
+ else
+ return -1;
+
+ break;
+ case 4:
+ if (line[2] != ':')
+ return -1;
+
+ (*type) = toupper(line[1]);
+ (*sub_type) = toupper(line[3]);
+
+ break;
+ case -1:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int get_input_data_format(char *line, struct ps_data_format *pst_format)
+{
+ unsigned char type = '\0';
+ unsigned char sub_type = '\0';
+ int eol_index = -1;
+ int i;
+
+ /* The default values */
+ set_pst_format(pst_format, PS_TYPE_HEX, 1);
+
+ if (line[0] != '[') {
+ set_pst_format(pst_format, PS_TYPE_HEX, 1);
+ return 0;
+ }
+
+ for (i = 1; i < 5; i++) {
+ if (line[i] == ']') {
+ eol_index = i;
+ break;
+ }
+ }
+
+ if (get_ps_type(line, eol_index, &type, &sub_type) < 0)
+ return -1;
+
+ /* By default Hex array type is assumed */
+ if (type == '\0' && sub_type == '\0')
+ set_pst_format(pst_format, PS_TYPE_HEX, 1);
+
+ /* Check is data type is of array */
+ if (type == 'A' || sub_type == 'A')
+ pst_format->is_array = 1;
+
+ if (type == 'S' || sub_type == 'S')
+ pst_format->is_array = 0;
+
+ switch (type) {
+
+ case 'D':
+ case 'B':
+
+ pst_format->data_type = PS_TYPE_DEC;
+ break;
+ default:
+
+ pst_format->data_type = PS_TYPE_HEX;
+ break;
+
+ }
+
+ line += (eol_index + 1);
+
+ return 0;
+
+}
+
+static unsigned int read_data_in_section(char *line,
+ struct ps_data_format format_info)
+{
+ char *token_ptr = line;
+
+ if (!token_ptr)
+ return 0x0FFF;
+
+ if (token_ptr[0] == '[') {
+
+ while (token_ptr[0] != ']' && token_ptr[0] != '\0')
+ token_ptr++;
+
+ if (token_ptr[0] == '\0')
+ return 0x0FFF;
+
+ token_ptr++;
+ }
+
+ if (format_info.data_type == PS_TYPE_HEX) {
+
+ if (format_info.is_array == 1)
+ return 0x0FFF;
+ else
+ return strtol(token_ptr, NULL, 16);
+
+ } else
+ return 0x0FFF;
+
+ return 0x0FFF;
+
+}
+static int ath_parse_file(FILE *stream)
+{
+ char *buffer;
+ char *line;
+ uint8_t tag_cnt = 0;
+ int16_t byte_count = 0;
+ int read_count;
+ int num_ps_entry;
+ struct ps_data_format stps_data_format;
+ struct st_read_status read_status = { 0, 0, 0, 0 };
+
+ if (!stream) {
+ perror("Could not open config file .\n");
+ return -1;
+ }
+
+ buffer = malloc(LINE_SIZE_MAX + 1);
+
+ if (!buffer)
+ return -ENOMEM;
+
+ do {
+ line = fgets(buffer, LINE_SIZE_MAX, stream);
+
+ if (!line)
+ break;
+
+ skip_space(line);
+
+ if ((line[0] == '/') && (line[1] == '/'))
+ continue;
+
+ if ((line[0] == '#')) {
+
+ if (read_status.section != 0) {
+
+ if (buffer)
+ free(buffer);
+ return -1;
+
+ } else {
+ read_status.section = 1;
+ continue;
+ }
+ }
+
+ if ((line[0] == '/') && (line[1] == '*')) {
+
+ read_status.section = 0;
+ continue;
+ }
+
+ if (read_status.section == 1) {
+ skip_space(line);
+
+ if (get_input_data_format(
+ line, &stps_data_format) < 0) {
+
+ if (buffer)
+ free(buffer);
+ return -1;
+
+ }
+
+ ps_tag_entry[tag_cnt].tag_id = read_data_in_section(
+ line,
+ stps_data_format);
+ read_status.section = 2;
+
+ } else if (read_status.section == 2) {
+
+ if (get_input_data_format(
+ line, &stps_data_format) < 0) {
+
+ if (buffer)
+ free(buffer);
+ return -1;
+ }
+
+ byte_count =
+ read_data_in_section(line, stps_data_format);
+
+ read_status.section = 2;
+ if (byte_count > LINE_SIZE_MAX / 2) {
+ if (buffer)
+ free(buffer);
+
+ return -1;
+ }
+
+ ps_tag_entry[tag_cnt].tag_len = byte_count;
+ ps_tag_entry[tag_cnt].tag_data = (uint8_t *)
+ malloc(byte_count);
+
+ read_status.section = 3;
+ read_status.line_count = 0;
+
+ } else if (read_status.section == 3) {
+
+ if (read_status.line_count == 0) {
+ if (get_input_data_format(
+ line, &stps_data_format) < 0) {
+ if (buffer)
+ free(buffer);
+ return -1;
+ }
+ }
+
+ skip_space(line);
+ read_status.char_cnt = 0;
+
+ if (line[read_status.char_cnt] == '[') {
+
+ while (line[read_status.char_cnt] != ']' &&
+ line[read_status.char_cnt] != '\0')
+ read_status.char_cnt++;
+
+ if (line[read_status.char_cnt] == ']')
+ read_status.char_cnt++;
+ else
+ read_status.char_cnt = 0;
+
+ }
+
+ read_count = (byte_count > BYTES_OF_PS_DATA_PER_LINE)
+ ? BYTES_OF_PS_DATA_PER_LINE : byte_count;
+
+ if (stps_data_format.data_type == PS_TYPE_HEX &&
+ stps_data_format.is_array == 1) {
+
+ while (read_count > 0) {
+
+ ps_tag_entry[tag_cnt].tag_data
+ [read_status.byte_count] =
+ stringtohex(
+ &line[read_status.char_cnt]);
+
+ ps_tag_entry[tag_cnt].tag_data
+ [read_status.byte_count + 1] =
+ stringtohex(
+ &line[read_status.char_cnt + 3]);
+
+ read_status.char_cnt += 6;
+ read_status.byte_count += 2;
+ read_count -= 2;
+
+ }
+
+ if (byte_count > BYTES_OF_PS_DATA_PER_LINE)
+ byte_count -=
+ BYTES_OF_PS_DATA_PER_LINE;
+ else
+ byte_count = 0;
+ }
+
+ read_status.line_count++;
+
+ if (byte_count == 0) {
+ read_status.section = 0;
+ read_status.char_cnt = 0;
+ read_status.line_count = 0;
+ read_status.byte_count = 0;
+ } else
+ read_status.char_cnt = 0;
+
+ if (read_status.section == 0) {
+ tag_cnt++;
+
+ if (tag_cnt == RAMPS_MAX_PS_TAGS_PER_FILE) {
+ if (buffer)
+ free(buffer);
+ return -1;
+ }
+ }
+
+ }
+
+ } while (line);
+
+ num_ps_entry = tag_cnt;
+
+ if (tag_cnt > RAMPS_MAX_PS_TAGS_PER_FILE) {
+ if (buffer)
+ free(buffer);
+ return -1;
+ }
+
+ if (buffer)
+ free(buffer);
+
+ return num_ps_entry;
+}
+
+static int parse_patch_file(FILE *stream)
+{
+ char byte[3];
+ char line[MAX_BYTE_LENGTH + 1];
+ int byte_cnt, byte_cnt_org;
+ int patch_index;
+ int i, k;
+ int data;
+ int patch_count = 0;
+
+ byte[2] = '\0';
+
+ while (fgets(line, MAX_BYTE_LENGTH, stream)) {
+ if (strlen(line) <= 1 || !isxdigit(line[0]))
+ continue;
+ else
+ break;
+ }
+
+ byte_cnt = strtol(line, NULL, 16);
+ byte_cnt_org = byte_cnt;
+
+ while (byte_cnt > MAX_BYTE_LENGTH) {
+
+ /* Handle case when the number of patch buffer is
+ * more than the 20K */
+ if (MAX_NUM_PATCH_ENTRY == patch_count) {
+ for (i = 0; i < patch_count; i++)
+ free(ram_patch[i].Data);
+ return -ENOMEM;
+ }
+
+ ram_patch[patch_count].Len = MAX_BYTE_LENGTH;
+ ram_patch[patch_count].Data =
+ (uint8_t *) malloc(MAX_BYTE_LENGTH);
+
+ if (!ram_patch[patch_count].Data)
+ return -ENOMEM;
+
+ patch_count++;
+ byte_cnt = byte_cnt - MAX_BYTE_LENGTH;
+ }
+
+ ram_patch[patch_count].Len = (byte_cnt & 0xFF);
+
+ if (byte_cnt != 0) {
+ ram_patch[patch_count].Data = (uint8_t *) malloc(byte_cnt);
+
+ if (!ram_patch[patch_count].Data)
+ return -ENOMEM;
+ patch_count++;
+ }
+
+ while (byte_cnt_org > MAX_BYTE_LENGTH) {
+
+ k = 0;
+ for (i = 0; i < MAX_BYTE_LENGTH * 2; i += 2) {
+ if (!fgets(byte, 3, stream))
+ return -1;
+ data = strtoul(&byte[0], NULL, 16);
+ ram_patch[patch_index].Data[k] = (data & 0xFF);
+
+ k++;
+ }
+
+ patch_index++;
+
+ byte_cnt_org = byte_cnt_org - MAX_BYTE_LENGTH;
+ }
+
+ if (patch_index == 0)
+ patch_index++;
+
+ for (k = 0; k < byte_cnt_org; k++) {
+
+ if (!fgets(byte, 3, stream))
+ return -1;
+
+ data = strtoul(byte, NULL, 16);
+ ram_patch[patch_index].Data[k] = (data & 0xFF);
+ }
+
+ return patch_count;
+}
+
+static int ath_parse_ps(FILE *stream, int *total_tag_len)
+{
+ int num_ps_tags;
+ int i;
+ unsigned char bdaddr_present = 0;
+
+ if (stream)
+ num_ps_tags = ath_parse_file(stream);
+
+ if (num_ps_tags < 0)
+ return -1;
+
+ if (num_ps_tags == 0)
+ *total_tag_len = 10;
+ else {
+
+ for (i = 0; i < num_ps_tags; i++) {
+
+ if (ps_tag_entry[i].tag_id == 1)
+ bdaddr_present = 1;
+ if (ps_tag_entry[i].tag_len % 2 == 1)
+ *total_tag_len = *total_tag_len
+ + ps_tag_entry[i].tag_len + 1;
+ else
+ *total_tag_len =
+ *total_tag_len + ps_tag_entry[i].tag_len;
+
+ }
+ }
+
+ if (num_ps_tags > 0 && !bdaddr_present)
+ *total_tag_len = *total_tag_len + 10;
+
+ *total_tag_len = *total_tag_len + 10 + (num_ps_tags * 4);
+
+ return num_ps_tags;
+}
+
+static int ath_create_cmd_list(struct ps_cmd_packet **hci_packet_list,
+ uint32_t *num_packets,
+ int tag_count,
+ int patch_count,
+ int total_tag_len)
+{
+ uint8_t count;
+ uint32_t num_cmd_entry = 0;
+
+ *num_packets = 0;
+
+ if (patch_count || tag_count) {
+
+ /* PS Reset Packet + Patch List + PS List */
+ num_cmd_entry += (1 + patch_count + tag_count);
+ if (patch_count > 0)
+ num_cmd_entry++; /* Patch Enable Command */
+
+ (*hci_packet_list) =
+ malloc(sizeof(struct ps_cmd_packet) * num_cmd_entry);
+
+ if (!(*hci_packet_list))
+ return -ENOMEM;
+
+ if (patch_count > 0) {
+
+ if (ath_create_ps_command(WRITE_PATCH, patch_count,
+ *hci_packet_list, num_packets) < 0)
+ return -1;
+ if (ath_create_ps_command(ENABLE_PATCH, 0,
+ *hci_packet_list, num_packets) < 0)
+ return -1;
+ if (ath_create_ps_command(PS_RESET,
+ total_tag_len + EXTRA_PATCH_SIZE,
+ *hci_packet_list, num_packets) < 0)
+ return -1;
+
+ } else {
+
+ if (ath_create_ps_command(PS_RESET, total_tag_len,
+ *hci_packet_list, num_packets) < 0)
+ return -1;
+ }
+
+ if (tag_count > 0)
+ ath_create_ps_command(PS_WRITE, tag_count,
+ *hci_packet_list, num_packets);
+ }
+
+ for (count = 0; count < patch_count; count++)
+ free(ram_patch[patch_count].Data);
+
+ for (count = 0; count < tag_count; count++)
+ free(ps_tag_entry[count].tag_data);
+
+ return *num_packets;
+}
+
+static int ath_free_command_list(struct ps_cmd_packet **hci_packet_list,
+ uint32_t num_packets)
+{
+ int i;
+
+ if (!(*hci_packet_list))
+ return -1;
+
+ for (i = 0; i < num_packets; i++)
+ free((*hci_packet_list)[i].Hcipacket);
+
+ free(*hci_packet_list);
+
+ return 0;
+}
+
+/*
+ * This API is used to send the HCI command to controller and return
+ * with a HCI Command Complete event.
+ */
+static int send_hci_cmd_wait_event(int dev,
+ uint8_t *hci_command,
+ int cmd_length,
+ uint8_t **event, uint8_t **buffer_to_free)
+{
+ int r;
+ uint8_t *hci_event;
+ uint8_t pkt_type = 0x01;
+
+ if (cmd_length == 0)
+ return -1;
+
+ if (write(dev, &pkt_type, 1) != 1)
+ return -1;
+
+ if (write(dev, (unsigned char *)hci_command, cmd_length) != cmd_length)
+ return -1;
+
+ hci_event = (uint8_t *) malloc(100);
+
+ if (!hci_event)
+ return -ENOMEM;
+
+ r = read_hci_event(dev, (unsigned char *)hci_event, 100);
+
+ if (r > 0) {
+ *event = hci_event;
+ *buffer_to_free = hci_event;
+ } else {
+
+ /* Did not get an event from controller. return error */
+ free(hci_event);
+ *buffer_to_free = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int read_ps_event(uint8_t *data)
+{
+
+ if (data[5] == 0xFC && data[6] == 0x00) {
+
+ switch (data[4]) {
+
+ case 0x0B:/* CRC Check */
+ case 0x0C:/* Change Baudrate */
+ case 0x04:/* Enable sleep */
+ return 0;
+ break;
+ default:
+ return -1;
+ break;
+
+ }
+ }
+
+ return -1;
+}
+
+static int get_ps_file_name(int devtype, int rom_version, char *path)
+{
+ char *filename;
+ int status = 0;
+
+ if (devtype == 0xdeadc0de) {
+ filename = PS_ASIC_FILE;
+ status = 1;
+ } else {
+ filename = PS_FPGA_FILE;
+ status = 0;
+ }
+
+ sprintf(path, "%s%x/%s", FW_PATH, rom_version, filename);
+
+ return status;
+}
+
+static int get_patch_file_name(int dev_type, int rom_version,
+ int build_version, char *path)
+{
+
+ if ((dev_type != 0) &&
+ (dev_type != 0xdeadc0de) &&
+ (rom_version == 0x99999999) &&
+ (build_version == 1))
+ path[0] = '\0';
+ else
+ sprintf(path, "%s%x/%s", FW_PATH, rom_version, PATCH_FILE);
+
+ return 0;
+}
+static int get_ar3k_crc(int dev, int tag_count, int patch_count)
+{
+ uint8_t hci_cmd[7];
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ int retval = 1;
+ int crc;
+
+ if (patch_count > 0)
+ crc |= RAM_PATCH_REGION;
+ if (tag_count > 0)
+ crc |= RAM_PS_REGION;
+
+ load_hci_header(hci_cmd, PS_VERIFY_CRC, 0, crc);
+
+ if (send_hci_cmd_wait_event(dev,
+ hci_cmd,
+ sizeof(hci_cmd),
+ &event,
+ &buffer_to_free) == 0) {
+
+ if (read_ps_event(event) == 0)
+ retval = -1;
+
+ if (buffer_to_free != NULL)
+ free(buffer_to_free);
+ }
+
+ return retval;
+}
+static int get_device_type(int dev, uint32_t *code)
+{
+ uint8_t hci_cmd[] = { 0x05, 0xfc, 0x05, 0x00, 0x00, 0x00, 0x00, 0x04 };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ uint32_t reg;
+ int result = -1;
+
+ *code = 0;
+
+ hci_cmd[3] = (uint8_t) (DEV_REGISTER & 0xFF);
+ hci_cmd[4] = (uint8_t) ((DEV_REGISTER >> 8) & 0xFF);
+ hci_cmd[5] = (uint8_t) ((DEV_REGISTER >> 16) & 0xFF);
+ hci_cmd[6] = (uint8_t) ((DEV_REGISTER >> 24) & 0xFF);
+
+ if (send_hci_cmd_wait_event(dev,
+ hci_cmd,
+ sizeof(hci_cmd),
+ &event,
+ &buffer_to_free) == 0) {
+
+ if (event[5] == 0xFC && event[6] == 0x00) {
+
+ switch (event[4]) {
+ case 0x05:
+ reg = event[10];
+ reg = ((reg << 8) | event[9]);
+ reg = ((reg << 8) | event[8]);
+ reg = ((reg << 8) | event[7]);
+ *code = reg;
+ result = 0;
+
+ break;
+
+ case 0x06:
+ break;
+ }
+ }
+ }
+
+ if (buffer_to_free)
+ free(buffer_to_free);
+
+ return result;
+}
+
+static int read_ar3k_version(int pConfig, int *rom_version, int *build_version)
+{
+ uint8_t hci_cmd[] = { 0x1E, 0xfc, 0x00 };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ int result = -1;
+
+ if (send_hci_cmd_wait_event(pConfig,
+ hci_cmd,
+ sizeof(hci_cmd),
+ &event,
+ &buffer_to_free) == 0) {
+
+ if (event[5] == 0xFC &&
+ event[6] == 0x00 &&
+ event[4] == 0x1E) {
+
+ (*rom_version) = event[10];
+ (*rom_version) = (((*rom_version) << 8) | event[9]);
+ (*rom_version) = (((*rom_version) << 8) | event[8]);
+ (*rom_version) = (((*rom_version) << 8) | event[7]);
+
+ (*build_version) = event[14];
+ (*build_version) = (((*build_version) << 8) |
+ event[13]);
+ (*build_version) = (((*build_version) << 8) |
+ event[12]);
+ (*build_version) = (((*build_version) << 8) |
+ event[11]);
+
+ result = 1;
+
+ }
+
+ if (buffer_to_free)
+ free(buffer_to_free);
+ }
+
+ return result;
+}
+
+static int str2bdaddr(char *str_bdaddr, char *bdaddr)
+{
+ char bdbyte[3];
+ char *str_byte = str_bdaddr;
+ int i, j;
+ unsigned char colon_present = 0;
+
+ if (strstr(str_bdaddr, ":"))
+ colon_present = 1;
+
+ bdbyte[2] = '\0';
+
+ for (i = 0, j = 5; i < 6; i++, j--) {
+
+ bdbyte[0] = str_byte[0];
+ bdbyte[1] = str_byte[1];
+ bdaddr[j] = strtol(bdbyte, NULL, 16);
+
+ if (colon_present == 1)
+ str_byte += 3;
+ else
+ str_byte += 2;
+ }
+ return 0;
+}
+
+static int write_bdaddr(int pConfig, char *bdaddr)
+{
+ uint8_t bdaddr_cmd[] = { 0x0B, 0xFC, 0x0A,
+ 0x01, 0x01, 0x00,
+ 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x00,
+ 0x00 };
+ uint8_t *event;
+ uint8_t *buffer_to_free = NULL;
+ int result = -1;
+
+ str2bdaddr(bdaddr, (char *)&bdaddr_cmd[7]);
+
+ if (send_hci_cmd_wait_event(pConfig,
+ bdaddr_cmd,
+ sizeof(bdaddr_cmd),
+ &event,
+ &buffer_to_free) == 0) {
+
+ if (event[5] == 0xFC && event[6] == 0x00) {
+ if (event[4] == 0x0B)
+ result = 0;
+ }
+
+ }
+
+ if (buffer_to_free)
+ free(buffer_to_free);
+
+ return result;
+}
+
+int ath_configure_sleep(int fd, int sleep_stat)
+{
+ int dev_id, dd;
+ struct timespec tm = {0, 50000};
+
+ dev_id = ioctl(fd, HCIUARTGETDEVICE, 0);
+
+ if (dev_id < 0) {
+ perror("cannot get device id");
+ return -1;
+ }
+
+ dd = hci_open_dev(dev_id);
+
+ if (dd < 0) {
+ perror("HCI device open failed");
+ return -1;
+ }
+
+ sleep(2);
+
+ /* send vendor specific command with Sleep feature Enabled */
+ if (hci_send_cmd(dd, OGF_VENDOR_CMD, 0x04, 1, &sleep_stat) < 0)
+ perror("Power management Disabled");
+
+ nanosleep(&tm, NULL);
+ hci_close_dev(dd);
+
+ return 0;
+}
+
+int ath_ps_download(int hdev)
+{
+ int i;
+ int status = 0;
+ int tag_count;
+ int patch_count;
+ int total_tag_len = 0;
+ int rom_version = 0, build_version = 0;
+
+ struct ps_cmd_packet *hci_cmd_list; /* List storing the commands */
+ uint32_t num_cmds;
+ uint8_t *event;
+ uint8_t *buffer_to_free;
+ uint32_t dev_type;
+
+ char patch_file[PATH_MAX];
+ char ps_file[PATH_MAX];
+ char bdaddr_file[PATH_MAX];
+
+ FILE *stream;
+ char bdaddr[21];
+
+ hci_cmd_list = NULL;
+
+ /*
+ * Verfiy firmware version. depending on it select the PS
+ * config file to download.
+ */
+ if (get_device_type(hdev, &dev_type) == -1) {
+ status = -1;
+ goto download_cmplete;
+ }
+ if (read_ar3k_version(hdev, &rom_version, &build_version) == -1) {
+ status = -1;
+ goto download_cmplete;
+ }
+
+ get_ps_file_name(dev_type, rom_version, ps_file);
+
+ get_patch_file_name(dev_type, rom_version, build_version, patch_file);
+
+ /* Read the PS file to a dynamically allocated buffer */
+ stream = fopen(ps_file, "r");
+
+ if (!stream) {
+ perror("firmware file open error\n");
+ status = -1;
+ goto download_cmplete;
+ }
+
+ tag_count = ath_parse_ps(stream, &total_tag_len);
+
+ fclose(stream);
+
+ if (tag_count == -1) {
+ status = -1;
+ goto download_cmplete;
+ }
+
+ /*
+ * It is not necessary that Patch file be available,
+ * continue with PS Operations if.
+ * failed.
+ */
+ if (patch_file[0] == '\0')
+ status = 0;
+
+ stream = fopen(patch_file, "r");
+
+ if (!stream) {
+ patch_count = 0;
+ status = 0;
+ } else {
+ /* parse and store the Patch file contents to
+ * a global variables
+ */
+ patch_count = parse_patch_file(stream);
+
+ fclose(stream);
+
+ if (patch_count < 0) {
+ status = -1;
+ goto download_cmplete;
+ }
+ }
+
+ /*
+ * Send the CRC packet,
+ * Continue with the PS operations
+ * only if the CRC check failed
+ */
+ if (get_ar3k_crc(hdev, tag_count, patch_count) < 0) {
+ status = 0;
+ goto download_cmplete;
+ }
+
+ /* Create an HCI command list
+ * from the parsed PS and patch information
+ */
+ ath_create_cmd_list(&hci_cmd_list,
+ &num_cmds,
+ tag_count,
+ patch_count,
+ total_tag_len);
+
+ for (i = 0; i < num_cmds; i++) {
+
+ if (send_hci_cmd_wait_event
+ (hdev,
+ hci_cmd_list[i].Hcipacket,
+ hci_cmd_list[i].packetLen,
+ &event,
+ &buffer_to_free) == 0) {
+
+ if (read_ps_event(event) < 0) {
+
+ /* Exit if the status is not success */
+ if (buffer_to_free)
+ free(buffer_to_free);
+
+ status = -1;
+ goto download_cmplete;
+ }
+ if (buffer_to_free)
+ free(buffer_to_free);
+ } else {
+ status = 0;
+ goto download_cmplete;
+ }
+ }
+ /* Read the PS file to a dynamically allocated buffer */
+ sprintf(bdaddr_file, "%s%x/%s", FW_PATH, rom_version, BDADDR_FILE);
+
+ stream = fopen(bdaddr_file, "r");
+
+ if (!stream) {
+ status = 0;
+ goto download_cmplete;
+ }
+
+ if (fgets(bdaddr, 20, stream))
+ status = write_bdaddr(hdev, bdaddr);
+
+ fclose(stream);
+
+download_cmplete:
+
+ if (hci_cmd_list)
+ ath_free_command_list(&hci_cmd_list, num_cmds);
+
+ return status;
+}
--
1.7.0

2010-05-11 09:04:18

by Suraj Sumangala

[permalink] [raw]
Subject: [PATCH v2] ath3k: add support for new firmware

New firmware has few critical bug fixes and shared antenna support.

Signed-off-by: Vikram Kandukuri <[email protected]>
---
drivers/bluetooth/ath3k.c | 9 ++++++---
1 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 128cae4..7bda549 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -122,9 +122,12 @@ static int ath3k_probe(struct usb_interface *intf,

data->udev = udev;

- if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
- kfree(data);
- return -EIO;
+ if (request_firmware(&firmware, "ath3k-2.fw", &udev->dev) < 0) {
+ BT_DBG("requesting old firmware");
+ if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
+ kfree(data);
+ return -EIO;
+ }
}

size = max_t(uint, firmware->size, 4096);
--
1.7.0

2010-05-11 08:29:08

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip

Hi marcel,

On Wed, 2010-05-05 at 18:03 +0530, suraj wrote:
> Hi Marcel,
>
> Can you take a look at the patch? Your review has been pending for
> sometime.
>
> On Mon, 2010-04-26 at 16:30 +0530, suraj wrote:
> > Hi marcel,
> >
> > On Thu, 2010-04-22 at 14:40 +0530, suraj wrote:
> > > This implements the Atheros Bluetooth serial protocol to
> > > support the AR300x Bluetooth chipsets.
> > > The serial protocol implements enhanced power management
> > > features for the AR300x chipsets.
> > >
> > > Reviewed-by: Luis R. Rodriguez <[email protected]>
> > > Reviewed-by: Gustavo F. Padovan <[email protected]>
> > > Signed-off-by: Suraj <[email protected]>
> > >
> > > ---
> > > drivers/bluetooth/Kconfig | 14 ++
> > > drivers/bluetooth/Makefile | 1 +
> > > drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++
> > > drivers/bluetooth/hci_ldisc.c | 6 +
> > > drivers/bluetooth/hci_uart.h | 8 +-
> > > 5 files changed, 406 insertions(+), 1 deletions(-)
> > > create mode 100755 drivers/bluetooth/hci_ath.c
> > >
> > Can you verify the patch let me know your comments?
> >
> > Regards
> > Suraj
> >
>
>

your review has been pending for a long time. Please let me know what
should be done regarding this.

Regards
Suraj

2010-05-10 20:12:50

by Luis R. Rodriguez

[permalink] [raw]
Subject: Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip

On Wed, May 05, 2010 at 05:33:18AM -0700, Suraj Sumangala wrote:
> Hi Marcel,
>
> Can you take a look at the patch? Your review has been pending for
> sometime.

Marcel, new timeline:

----------
02-22-2010 - Marcel responded to your first patch version for UART bluetooth
02-22-2010 - Suarj posted resplies to Marcel's questions
03-01-2010 - Suraj poked Marcel for feedback based on Suraj's comments
----------
03-11-2010 - Suraj posts new V2 patch but its sent busted with tabs/space mixup
03-11-2010 - Marcel asks for a resend
----------
03-14-2010 - Suaraj posts V3 patch with tabs/spaces fixed
03-23-2010 - First poke to Marcel and list
03-29-2010 - Second poke to Marcel and list
03-31-2010 - Patch for userspace hciattach.c changes posted
----------
04-20-2010 - v3 patch posted
04-21-2010 - v4 patch posted
04-22-2010 - v5 patch posted
04-26-2010 - v5 first poke
05-05-2010 - v5 second poke
----------

What else can our team do?

:(

Luis

2010-05-06 07:45:32

by Suraj Sumangala

[permalink] [raw]
Subject: buffer starvation with multiple ACL link

Hi,

I am seeing a strange issue with multiple ACL connection with CSR chip.

I am having 2 ACL link, one with FTP going on and another streaming
A2DP.
The moment the A2DP link goes out of range ,I see that the FTP also
stops. It resumes as soon as A2DP comes back in range.

On further analysis I could verify that since the A2DP link is
blocked( due to remote being OoR) the controller's ACL buffers with A2DP
data are stuck.
But at the host level this is not considered and Bluez keeps sending
A2DP data until it blocks all the ACL buffers which in turns blocks FTP
also.

I was expecting controller to flush these packets sometime and free the
A2DP buffers. Not sure, what is the default Flush timeout value.

Do we have any patch for this issue?

Regards
Suraj


2010-05-05 12:33:18

by Suraj Sumangala

[permalink] [raw]
Subject: Re: [PATCH v5] Add support for the Atheros AR300x Bluetooth Chip

Hi Marcel,

Can you take a look at the patch? Your review has been pending for
sometime.

On Mon, 2010-04-26 at 16:30 +0530, suraj wrote:
> Hi marcel,
>
> On Thu, 2010-04-22 at 14:40 +0530, suraj wrote:
> > This implements the Atheros Bluetooth serial protocol to
> > support the AR300x Bluetooth chipsets.
> > The serial protocol implements enhanced power management
> > features for the AR300x chipsets.
> >
> > Reviewed-by: Luis R. Rodriguez <[email protected]>
> > Reviewed-by: Gustavo F. Padovan <[email protected]>
> > Signed-off-by: Suraj <[email protected]>
> >
> > ---
> > drivers/bluetooth/Kconfig | 14 ++
> > drivers/bluetooth/Makefile | 1 +
> > drivers/bluetooth/hci_ath.c | 378 +++++++++++++++++++++++++++++++++++++++++
> > drivers/bluetooth/hci_ldisc.c | 6 +
> > drivers/bluetooth/hci_uart.h | 8 +-
> > 5 files changed, 406 insertions(+), 1 deletions(-)
> > create mode 100755 drivers/bluetooth/hci_ath.c
> >
> Can you verify the patch let me know your comments?
>
> Regards
> Suraj
>