From b33b22bf166005ab89c74619facbfea55cc52691 Mon Sep 17 00:00:00 2001 From: Barry <870709864@qq.com> Date: Wed, 19 Jun 2019 14:33:20 +0800 Subject: [PATCH] =?UTF-8?q?add:=E5=AE=9E=E7=8E=B0=E5=89=AA=E5=88=87?= =?UTF-8?q?=E6=9D=BF=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- QtScrcpy/inputcontrol/controlevent.cpp | 73 +++++++++++------- QtScrcpy/inputcontrol/controlevent.h | 28 ++++--- QtScrcpy/inputcontrol/controller.cpp | 12 ++- QtScrcpy/inputcontrol/controller.h | 3 + QtScrcpy/inputcontrol/deviceevent.cpp | 69 +++++++++++++++++ QtScrcpy/inputcontrol/deviceevent.h | 42 ++++++++++ QtScrcpy/inputcontrol/inputcontrol.pri | 8 +- QtScrcpy/inputcontrol/receiver.cpp | 53 +++++++++++++ QtScrcpy/inputcontrol/receiver.h | 25 ++++++ QtScrcpy/util/bufferutil.cpp | 51 ++++++++++++ QtScrcpy/util/bufferutil.h | 15 ++++ QtScrcpy/util/util.pri | 6 +- QtScrcpy/videoform.cpp | 41 +++++++++- QtScrcpy/videoform.h | 5 +- .../com/genymobile/scrcpy/ControlEvent.java | 18 ++++- .../genymobile/scrcpy/ControlEventReader.java | 28 ++++++- .../genymobile/scrcpy/DesktopConnection.java | 8 ++ .../java/com/genymobile/scrcpy/Device.java | 12 +++ .../com/genymobile/scrcpy/DeviceEvent.java | 27 +++++++ .../genymobile/scrcpy/DeviceEventWriter.java | 34 ++++++++ .../genymobile/scrcpy/EventController.java | 16 +++- .../com/genymobile/scrcpy/EventSender.java | 34 ++++++++ .../java/com/genymobile/scrcpy/Server.java | 23 +++++- .../com/genymobile/scrcpy/StringUtils.java | 23 ++++++ .../scrcpy/wrappers/ClipboardManager.java | 44 +++++++++++ .../scrcpy/wrappers/ServiceManager.java | 8 ++ third_party/scrcpy-server.jar | Bin 72408 -> 52352 bytes 27 files changed, 650 insertions(+), 56 deletions(-) create mode 100644 QtScrcpy/inputcontrol/deviceevent.cpp create mode 100644 QtScrcpy/inputcontrol/deviceevent.h create mode 100644 QtScrcpy/inputcontrol/receiver.cpp create mode 100644 QtScrcpy/inputcontrol/receiver.h create mode 100644 QtScrcpy/util/bufferutil.cpp create mode 100644 QtScrcpy/util/bufferutil.h create mode 100644 server/src/main/java/com/genymobile/scrcpy/DeviceEvent.java create mode 100644 server/src/main/java/com/genymobile/scrcpy/DeviceEventWriter.java create mode 100644 server/src/main/java/com/genymobile/scrcpy/EventSender.java create mode 100644 server/src/main/java/com/genymobile/scrcpy/StringUtils.java create mode 100644 server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java diff --git a/QtScrcpy/inputcontrol/controlevent.cpp b/QtScrcpy/inputcontrol/controlevent.cpp index 1de03b4..0e4c1da 100644 --- a/QtScrcpy/inputcontrol/controlevent.cpp +++ b/QtScrcpy/inputcontrol/controlevent.cpp @@ -1,6 +1,7 @@ #include #include "controlevent.h" +#include "bufferutil.h" ControlEvent::ControlEvent(ControlEventType controlEventType) : QScrcpyEvent(Control) @@ -8,6 +9,19 @@ ControlEvent::ControlEvent(ControlEventType controlEventType) m_data.type = controlEventType; } +ControlEvent::~ControlEvent() +{ + if (CET_SET_CLIPBOARD == m_data.type + && Q_NULLPTR != m_data.setClipboardEvent.text) { + delete m_data.setClipboardEvent.text; + m_data.setClipboardEvent.text = Q_NULLPTR; + } else if (CET_TEXT == m_data.type + && Q_NULLPTR != m_data.textEvent.text){ + delete m_data.textEvent.text; + m_data.textEvent.text = Q_NULLPTR; + } +} + void ControlEvent::setKeycodeEventData(AndroidKeyeventAction action, AndroidKeycode keycode, AndroidMetastate metastate) { m_data.keycodeEvent.action = action; @@ -15,16 +29,17 @@ void ControlEvent::setKeycodeEventData(AndroidKeyeventAction action, AndroidKeyc m_data.keycodeEvent.metastate = metastate; } -void ControlEvent::setTextEventData(QString text) +void ControlEvent::setTextEventData(QString& text) { // write length (2 byte) + string (non nul-terminated) - if (TEXT_MAX_CHARACTER_LENGTH < text.length()) { + if (CONTROL_EVENT_TEXT_MAX_LENGTH < text.length()) { // injecting a text takes time, so limit the text length - text = text.left(TEXT_MAX_CHARACTER_LENGTH); + text = text.left(CONTROL_EVENT_TEXT_MAX_LENGTH); } QByteArray tmp = text.toUtf8(); - memset(m_data.textEvent.text, 0, sizeof (m_data.textEvent.text)); + m_data.textEvent.text = new char[tmp.length() + 1]; memcpy(m_data.textEvent.text, tmp.data(), tmp.length()); + m_data.textEvent.text[tmp.length()] = '\0'; } void ControlEvent::setMouseEventData(AndroidMotioneventAction action, AndroidMotioneventButtons buttons, QRect position) @@ -48,26 +63,27 @@ void ControlEvent::setScrollEventData(QRect position, qint32 hScroll, qint32 vSc m_data.scrollEvent.vScroll = vScroll; } -void ControlEvent::write32(QBuffer &buffer, quint32 value) +void ControlEvent::setSetClipboardEventData(QString &text) { - buffer.putChar(value >> 24); - buffer.putChar(value >> 16); - buffer.putChar(value >> 8); - buffer.putChar(value); -} + if (text.isEmpty()) { + return; + } + if (CONTROL_EVENT_CLIPBOARD_TEXT_MAX_LENGTH < text.length()) { + text = text.left(CONTROL_EVENT_CLIPBOARD_TEXT_MAX_LENGTH); + } -void ControlEvent::write16(QBuffer &buffer, quint32 value) -{ - buffer.putChar(value >> 8); - buffer.putChar(value); + QByteArray tmp = text.toUtf8(); + m_data.setClipboardEvent.text = new char[tmp.length() + 1]; + memcpy(m_data.setClipboardEvent.text, tmp.data(), tmp.length()); + m_data.setClipboardEvent.text[tmp.length()] = '\0'; } void ControlEvent::writePosition(QBuffer &buffer, const QRect& value) { - write16(buffer, value.left()); - write16(buffer, value.top()); - write16(buffer, value.width()); - write16(buffer, value.height()); + BufferUtil::write16(buffer, value.left()); + BufferUtil::write16(buffer, value.top()); + BufferUtil::write16(buffer, value.width()); + BufferUtil::write16(buffer, value.height()); } QByteArray ControlEvent::serializeData() @@ -80,18 +96,16 @@ QByteArray ControlEvent::serializeData() switch (m_data.type) { case CET_KEYCODE: buffer.putChar(m_data.keycodeEvent.action); - write32(buffer, m_data.keycodeEvent.keycode); - write32(buffer, m_data.keycodeEvent.metastate); + BufferUtil::write32(buffer, m_data.keycodeEvent.keycode); + BufferUtil::write32(buffer, m_data.keycodeEvent.metastate); break; case CET_TEXT: - { - write16(buffer, strlen(m_data.textEvent.text)); + BufferUtil::write16(buffer, strlen(m_data.textEvent.text)); buffer.write(m_data.textEvent.text, strlen(m_data.textEvent.text)); - } break; case CET_MOUSE: buffer.putChar(m_data.mouseEvent.action); - write32(buffer, m_data.mouseEvent.buttons); + BufferUtil::write32(buffer, m_data.mouseEvent.buttons); writePosition(buffer, m_data.mouseEvent.position); break; case CET_TOUCH: @@ -101,12 +115,17 @@ QByteArray ControlEvent::serializeData() break; case CET_SCROLL: writePosition(buffer, m_data.scrollEvent.position); - write32(buffer, m_data.scrollEvent.hScroll); - write32(buffer, m_data.scrollEvent.vScroll); + BufferUtil::write32(buffer, m_data.scrollEvent.hScroll); + BufferUtil::write32(buffer, m_data.scrollEvent.vScroll); + break; + case CET_SET_CLIPBOARD: + BufferUtil::write16(buffer, strlen(m_data.setClipboardEvent.text)); + buffer.write(m_data.setClipboardEvent.text, strlen(m_data.setClipboardEvent.text)); break; case CET_BACK_OR_SCREEN_ON: case CET_EXPAND_NOTIFICATION_PANEL: - case CET_COLLAPSE_NOTIFICATION_PANEL: + case CET_COLLAPSE_NOTIFICATION_PANEL: + case CET_GET_CLIPBOARD: break; default: qDebug() << "Unknown event type:" << m_data.type; diff --git a/QtScrcpy/inputcontrol/controlevent.h b/QtScrcpy/inputcontrol/controlevent.h index 02688e1..67f99a0 100644 --- a/QtScrcpy/inputcontrol/controlevent.h +++ b/QtScrcpy/inputcontrol/controlevent.h @@ -9,43 +9,48 @@ #include "input.h" #include "keycodes.h" -#define TEXT_MAX_CHARACTER_LENGTH 300 +#define CONTROL_EVENT_TEXT_MAX_LENGTH 300 +#define CONTROL_EVENT_CLIPBOARD_TEXT_MAX_LENGTH 4093 // ControlEvent class ControlEvent : public QScrcpyEvent { public: enum ControlEventType { + CET_NULL = -1, CET_KEYCODE = 0, CET_TEXT, - CET_MOUSE, - CET_SCROLL, - CET_TOUCH, + CET_MOUSE, + CET_SCROLL, CET_BACK_OR_SCREEN_ON, CET_EXPAND_NOTIFICATION_PANEL, CET_COLLAPSE_NOTIFICATION_PANEL, + CET_GET_CLIPBOARD, + CET_SET_CLIPBOARD, + + CET_TOUCH, }; ControlEvent(ControlEventType controlEventType); + virtual ~ControlEvent(); void setKeycodeEventData(AndroidKeyeventAction action, AndroidKeycode keycode, AndroidMetastate metastate); - void setTextEventData(QString text); + void setTextEventData(QString& text); void setMouseEventData(AndroidMotioneventAction action, AndroidMotioneventButtons buttons, QRect position); // id 代表一个触摸点,最多支持10个触摸点[0,9] // action 只能是AMOTION_EVENT_ACTION_DOWN,AMOTION_EVENT_ACTION_UP,AMOTION_EVENT_ACTION_MOVE // position action动作对应的位置 void setTouchEventData(quint32 id, AndroidMotioneventAction action, QRect position); void setScrollEventData(QRect position, qint32 hScroll, qint32 vScroll); + void setSetClipboardEventData(QString& text); QByteArray serializeData(); -private: - void write32(QBuffer& buffer, quint32 value); - void write16(QBuffer& buffer, quint32 value); +private: void writePosition(QBuffer& buffer, const QRect& value); private: struct ControlEventData { - ControlEventType type; + ControlEventType type = CET_NULL; union { struct { AndroidKeyeventAction action; @@ -53,7 +58,7 @@ private: AndroidMetastate metastate; } keycodeEvent; struct { - char text[TEXT_MAX_CHARACTER_LENGTH + 1]; + char* text = Q_NULLPTR; } textEvent; struct { AndroidMotioneventAction action; @@ -70,6 +75,9 @@ private: qint32 hScroll; qint32 vScroll; } scrollEvent; + struct { + char *text = Q_NULLPTR; + } setClipboardEvent; }; ControlEventData(){} diff --git a/QtScrcpy/inputcontrol/controller.cpp b/QtScrcpy/inputcontrol/controller.cpp index 53f030a..dcd867e 100644 --- a/QtScrcpy/inputcontrol/controller.cpp +++ b/QtScrcpy/inputcontrol/controller.cpp @@ -3,10 +3,11 @@ #include "controller.h" #include "videosocket.h" #include "controlevent.h" +#include "receiver.h" Controller::Controller(QObject* parent) : QObject(parent) { - + m_receiver = new Receiver(this); } Controller::~Controller() @@ -16,7 +17,16 @@ Controller::~Controller() void Controller::setControlSocket(QTcpSocket* controlSocket) { + if (m_controlSocket || !controlSocket) { + return; + } m_controlSocket = controlSocket; + connect(controlSocket, &QTcpSocket::readyRead, m_receiver, &Receiver::onReadyRead); +} + +QTcpSocket *Controller::getControlSocket() +{ + return m_controlSocket; } void Controller::postControlEvent(ControlEvent *controlEvent) diff --git a/QtScrcpy/inputcontrol/controller.h b/QtScrcpy/inputcontrol/controller.h index 2fb4c2f..1522f3c 100644 --- a/QtScrcpy/inputcontrol/controller.h +++ b/QtScrcpy/inputcontrol/controller.h @@ -6,6 +6,7 @@ class QTcpSocket; class ControlEvent; +class Receiver; class Controller : public QObject { Q_OBJECT @@ -14,6 +15,7 @@ public: virtual ~Controller(); void setControlSocket(QTcpSocket* controlSocket); + QTcpSocket* getControlSocket(); void postControlEvent(ControlEvent* controlEvent); void test(QRect rc); @@ -25,6 +27,7 @@ private: private: QPointer m_controlSocket; + QPointer m_receiver; }; #endif // CONTROLLER_H diff --git a/QtScrcpy/inputcontrol/deviceevent.cpp b/QtScrcpy/inputcontrol/deviceevent.cpp new file mode 100644 index 0000000..668fbcf --- /dev/null +++ b/QtScrcpy/inputcontrol/deviceevent.cpp @@ -0,0 +1,69 @@ +#include + +#include "deviceevent.h" +#include "bufferutil.h" + +DeviceEvent::DeviceEvent(QObject *parent) : QObject(parent) +{ + +} + +DeviceEvent::~DeviceEvent() +{ + if (DET_GET_CLIPBOARD == m_data.type + && Q_NULLPTR != m_data.clipboardEvent.text) { + delete m_data.clipboardEvent.text; + m_data.clipboardEvent.text = Q_NULLPTR; + } +} + +DeviceEvent::DeviceEventType DeviceEvent::type() +{ + return m_data.type; +} + +void DeviceEvent::getClipboardEventData(QString& text) +{ + text = QString::fromUtf8(m_data.clipboardEvent.text); +} + +qint32 DeviceEvent::deserialize(QByteArray& byteArray) +{ + QBuffer buf(&byteArray); + buf.open(QBuffer::ReadOnly); + + qint64 len = buf.size(); + char c = 0; + qint32 ret = 0; + + if (len < 3) { + // at least type + empty string length + return 0; // not available + } + + buf.getChar(&c); + m_data.type = (DeviceEventType)c; + switch (m_data.type) { + case DET_GET_CLIPBOARD: { + quint16 clipboardLen = BufferUtil::read16(buf); + if (clipboardLen > len - 3) { + ret = 0; // not available + break; + } + + QByteArray text = buf.readAll(); + m_data.clipboardEvent.text = new char[text.length() + 1]; + memcpy(m_data.clipboardEvent.text, text.data(), text.length()); + m_data.clipboardEvent.text[text.length()] = '\0'; + + ret = 3 + clipboardLen; + break; + } + default: + qWarning("Unsupported device event type: %d", (int) m_data.type); + ret = -1; // error, we cannot recover + } + + buf.close(); + return ret; +} diff --git a/QtScrcpy/inputcontrol/deviceevent.h b/QtScrcpy/inputcontrol/deviceevent.h new file mode 100644 index 0000000..7f0be20 --- /dev/null +++ b/QtScrcpy/inputcontrol/deviceevent.h @@ -0,0 +1,42 @@ +#ifndef DEVICEEVENT_H +#define DEVICEEVENT_H + +#include + +#define DEVICE_EVENT_QUEUE_SIZE 64 +#define DEVICE_EVENT_TEXT_MAX_LENGTH 4093 +#define DEVICE_EVENT_SERIALIZED_MAX_SIZE (3 + DEVICE_EVENT_TEXT_MAX_LENGTH) + +class DeviceEvent : public QObject +{ + Q_OBJECT +public: + enum DeviceEventType { + DET_NULL = -1, + // 和服务端对应 + DET_GET_CLIPBOARD = 0, + }; + explicit DeviceEvent(QObject *parent = nullptr); + virtual ~DeviceEvent(); + + DeviceEvent::DeviceEventType type(); + void getClipboardEventData(QString& text); + + qint32 deserialize(QByteArray& byteArray); + +private: + struct DeviceEventData { + DeviceEventType type = DET_NULL; + union { + struct { + char* text = Q_NULLPTR; + } clipboardEvent; + }; + DeviceEventData(){} + ~DeviceEventData(){} + }; + + DeviceEventData m_data; +}; + +#endif // DEVICEEVENT_H diff --git a/QtScrcpy/inputcontrol/inputcontrol.pri b/QtScrcpy/inputcontrol/inputcontrol.pri index 1445e3e..af7fc9c 100644 --- a/QtScrcpy/inputcontrol/inputcontrol.pri +++ b/QtScrcpy/inputcontrol/inputcontrol.pri @@ -3,12 +3,16 @@ HEADERS += \ $$PWD/controller.h \ $$PWD/inputconvertbase.h \ $$PWD/inputconvertgame.h \ - $$PWD/inputconvertnormal.h + $$PWD/inputconvertnormal.h \ + $$PWD/deviceevent.h \ + $$PWD/receiver.h SOURCES += \ $$PWD/controlevent.cpp \ $$PWD/controller.cpp \ $$PWD/inputconvertbase.cpp \ $$PWD/inputconvertgame.cpp \ - $$PWD/inputconvertnormal.cpp + $$PWD/inputconvertnormal.cpp \ + $$PWD/deviceevent.cpp \ + $$PWD/receiver.cpp diff --git a/QtScrcpy/inputcontrol/receiver.cpp b/QtScrcpy/inputcontrol/receiver.cpp new file mode 100644 index 0000000..51c8cc0 --- /dev/null +++ b/QtScrcpy/inputcontrol/receiver.cpp @@ -0,0 +1,53 @@ +#include +#include +#include + +#include "receiver.h" +#include "controller.h" +#include "deviceevent.h" + +Receiver::Receiver(Controller* controller) : QObject(controller) +{ + m_controller = controller; + Q_ASSERT(controller); +} + +Receiver::~Receiver() +{ + +} + +void Receiver::onReadyRead() +{ + QTcpSocket* controlSocket = m_controller->getControlSocket(); + if (!controlSocket) { + return; + } + + while (controlSocket->bytesAvailable()) { + QByteArray byteArray = controlSocket->peek(controlSocket->bytesAvailable()); + DeviceEvent deviceEvent; + qint32 consume = deviceEvent.deserialize(byteArray); + if (0 >= consume) { + break; + } + controlSocket->read(consume); + processEvent(&deviceEvent); + } +} + +void Receiver::processEvent(DeviceEvent *deviceEvent) +{ + switch (deviceEvent->type()) { + case DeviceEvent::DET_GET_CLIPBOARD: + { + QClipboard *board = QApplication::clipboard(); + QString text; + deviceEvent->getClipboardEventData(text); + board->setText(text); + break; + } + default: + break; + } +} diff --git a/QtScrcpy/inputcontrol/receiver.h b/QtScrcpy/inputcontrol/receiver.h new file mode 100644 index 0000000..ba9bc4c --- /dev/null +++ b/QtScrcpy/inputcontrol/receiver.h @@ -0,0 +1,25 @@ +#ifndef RECEIVER_H +#define RECEIVER_H + +#include + +class Controller; +class DeviceEvent; +class Receiver : public QObject +{ + Q_OBJECT +public: + explicit Receiver(Controller *controller); + virtual ~Receiver(); + +public slots: + void onReadyRead(); + +protected: + void processEvent(DeviceEvent *deviceEvent); + +private: + QPointer m_controller; +}; + +#endif // RECEIVER_H diff --git a/QtScrcpy/util/bufferutil.cpp b/QtScrcpy/util/bufferutil.cpp new file mode 100644 index 0000000..65f62d2 --- /dev/null +++ b/QtScrcpy/util/bufferutil.cpp @@ -0,0 +1,51 @@ +#include "bufferutil.h" + +void BufferUtil::write32(QBuffer &buffer, quint32 value) +{ + buffer.putChar(value >> 24); + buffer.putChar(value >> 16); + buffer.putChar(value >> 8); + buffer.putChar(value); +} + +void BufferUtil::write16(QBuffer &buffer, quint32 value) +{ + buffer.putChar(value >> 8); + buffer.putChar(value); +} + +quint16 BufferUtil::read16(QBuffer &buffer) +{ + char c; + quint16 ret = 0; + buffer.getChar(&c); + ret |= (c << 8); + buffer.getChar(&c); + ret |= c; + + return ret; +} + +quint32 BufferUtil::read32(QBuffer &buffer) +{ + char c; + quint32 ret = 0; + buffer.getChar(&c); + ret |= (c << 24); + buffer.getChar(&c); + ret |= (c << 16); + buffer.getChar(&c); + ret |= (c << 8); + buffer.getChar(&c); + ret |= c; + + return ret; +} + +quint64 BufferUtil::read64(QBuffer &buffer) +{ + quint32 msb = read32(buffer); + quint32 lsb = read32(buffer); + + return ((quint64) msb << 32) | lsb;; +} diff --git a/QtScrcpy/util/bufferutil.h b/QtScrcpy/util/bufferutil.h new file mode 100644 index 0000000..39152ac --- /dev/null +++ b/QtScrcpy/util/bufferutil.h @@ -0,0 +1,15 @@ +#ifndef BUFFERUTIL_H +#define BUFFERUTIL_H +#include + +class BufferUtil +{ +public: + static void write32(QBuffer& buffer, quint32 value); + static void write16(QBuffer& buffer, quint32 value); + static quint16 read16(QBuffer& buffer); + static quint32 read32(QBuffer& buffer); + static quint64 read64(QBuffer& buffer); +}; + +#endif // BUFFERUTIL_H diff --git a/QtScrcpy/util/util.pri b/QtScrcpy/util/util.pri index 366d5c5..720d7e6 100644 --- a/QtScrcpy/util/util.pri +++ b/QtScrcpy/util/util.pri @@ -1,4 +1,8 @@ include ($$PWD/mousetap/mousetap.pri) HEADERS += \ - $$PWD/compat.h + $$PWD/compat.h \ + $$PWD/bufferutil.h + +SOURCES += \ + $$PWD/bufferutil.cpp diff --git a/QtScrcpy/videoform.cpp b/QtScrcpy/videoform.cpp index d8c2364..fcc455f 100644 --- a/QtScrcpy/videoform.cpp +++ b/QtScrcpy/videoform.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "videoform.h" #include "recorder.h" @@ -365,7 +366,35 @@ void VideoForm::collapseNotificationPanel() m_inputConvert.sendControlEvent(controlEvent); } -void VideoForm::postTextInput(const QString& text) +void VideoForm::requestDeviceClipboard() +{ + ControlEvent* controlEvent = new ControlEvent(ControlEvent::CET_GET_CLIPBOARD); + if (!controlEvent) { + return; + } + m_inputConvert.sendControlEvent(controlEvent); +} + +void VideoForm::setDeviceClipboard() +{ + QClipboard *board = QApplication::clipboard(); + QString text = board->text(); + ControlEvent* controlEvent = new ControlEvent(ControlEvent::CET_SET_CLIPBOARD); + if (!controlEvent) { + return; + } + controlEvent->setSetClipboardEventData(text); + m_inputConvert.sendControlEvent(controlEvent); +} + +void VideoForm::clipboardPaste() +{ + QClipboard *board = QApplication::clipboard(); + QString text = board->text(); + postTextInput(text); +} + +void VideoForm::postTextInput(QString& text) { ControlEvent* controlEvent = new ControlEvent(ControlEvent::CET_TEXT); if (!controlEvent) { @@ -468,6 +497,16 @@ void VideoForm::keyPressEvent(QKeyEvent *event) && isFullScreen()) { switchFullScreen(); } + if (event->key() == Qt::Key_C && (event->modifiers() & Qt::ControlModifier)) { + requestDeviceClipboard(); + } + if (event->key() == Qt::Key_V && (event->modifiers() & Qt::ControlModifier)) { + if (event->modifiers() & Qt::ShiftModifier) { + setDeviceClipboard(); + } else { + clipboardPaste(); + } + } //qDebug() << "keyPressEvent" << event->isAutoRepeat(); m_inputConvert.keyEvent(event, ui->videoWidget->frameSize(), ui->videoWidget->size()); diff --git a/QtScrcpy/videoform.h b/QtScrcpy/videoform.h index c8c1c89..1b229c7 100644 --- a/QtScrcpy/videoform.h +++ b/QtScrcpy/videoform.h @@ -39,7 +39,10 @@ public: void postTurnOn(); void expandNotificationPanel(); void collapseNotificationPanel(); - void postTextInput(const QString& text); + void requestDeviceClipboard(); + void setDeviceClipboard(); + void clipboardPaste(); + void postTextInput(QString& text); void staysOnTop(bool top = true); diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java b/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java index b368d31..1196ea1 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlEvent.java @@ -9,10 +9,13 @@ public final class ControlEvent { public static final int TYPE_TEXT = 1; public static final int TYPE_MOUSE = 2; public static final int TYPE_SCROLL = 3; - public static final int TYPE_TOUCH = 4; - public static final int TYPE_BACK_OR_SCREEN_ON = 5; - public static final int TYPE_EXPAND_NOTIFICATION_PANEL = 6; - public static final int TYPE_COLLAPSE_NOTIFICATION_PANEL = 7; + public static final int TYPE_BACK_OR_SCREEN_ON = 4; + public static final int TYPE_EXPAND_NOTIFICATION_PANEL = 5; + public static final int TYPE_COLLAPSE_NOTIFICATION_PANEL = 6; + public static final int TYPE_GET_CLIPBOARD = 7; + public static final int TYPE_SET_CLIPBOARD = 8; + + public static final int TYPE_TOUCH = 9; private int type; @@ -72,6 +75,13 @@ public final class ControlEvent { return event; } + public static ControlEvent createSetClipboardControlEvent(String text) { + ControlEvent event = new ControlEvent(); + event.type = TYPE_SET_CLIPBOARD; + event.text = text; + return event; + } + public static ControlEvent createSimpleControlEvent(int type) { ControlEvent event = new ControlEvent(); event.type = type; diff --git a/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java b/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java index 6b9e8ea..f4688c0 100644 --- a/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java +++ b/server/src/main/java/com/genymobile/scrcpy/ControlEventReader.java @@ -14,11 +14,12 @@ public class ControlEventReader { private static final int SCROLL_PAYLOAD_LENGTH = 16; public static final int TEXT_MAX_LENGTH = 300; + public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4093; private static final int RAW_BUFFER_SIZE = 1024; private final byte[] rawBuffer = new byte[RAW_BUFFER_SIZE]; private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer); - private final byte[] textBuffer = new byte[TEXT_MAX_LENGTH]; + private final byte[] textBuffer = new byte[CLIPBOARD_TEXT_MAX_LENGTH]; public ControlEventReader() { // invariant: the buffer is always in "get" mode @@ -66,9 +67,13 @@ public class ControlEventReader { case ControlEvent.TYPE_SCROLL: controlEvent = parseScrollControlEvent(); break; + case ControlEvent.TYPE_SET_CLIPBOARD: + controlEvent = parseSetClipboardEvent(); + break; case ControlEvent.TYPE_BACK_OR_SCREEN_ON: case ControlEvent.TYPE_EXPAND_NOTIFICATION_PANEL: case ControlEvent.TYPE_COLLAPSE_NOTIFICATION_PANEL: + case ControlEvent.TYPE_GET_CLIPBOARD: controlEvent = ControlEvent.createSimpleControlEvent(type); break; default: @@ -94,8 +99,8 @@ public class ControlEventReader { return ControlEvent.createKeycodeControlEvent(action, keycode, metaState); } - private ControlEvent parseTextControlEvent() { - if (buffer.remaining() < 1) { + private String parseString() { + if (buffer.remaining() < 2) { return null; } int len = toUnsigned(buffer.getShort()); @@ -103,7 +108,14 @@ public class ControlEventReader { return null; } buffer.get(textBuffer, 0, len); - String text = new String(textBuffer, 0, len, StandardCharsets.UTF_8); + return new String(textBuffer, 0, len, StandardCharsets.UTF_8); + } + + private ControlEvent parseTextControlEvent() { + String text = parseString(); + if (text == null) { + return null; + } return ControlEvent.createTextControlEvent(text); } @@ -137,6 +149,14 @@ public class ControlEventReader { return ControlEvent.createScrollControlEvent(position, hScroll, vScroll); } + private ControlEvent parseSetClipboardEvent() { + String text = parseString(); + if (text == null) { + return null; + } + return ControlEvent.createSetClipboardControlEvent(text); + } + private static Position readPosition(ByteBuffer buffer) { int x = toUnsigned(buffer.getShort()); int y = toUnsigned(buffer.getShort()); diff --git a/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java b/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java index e7237fa..99aa9d2 100644 --- a/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java +++ b/server/src/main/java/com/genymobile/scrcpy/DesktopConnection.java @@ -8,6 +8,7 @@ import java.io.Closeable; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.nio.charset.StandardCharsets; public final class DesktopConnection implements Closeable { @@ -21,14 +22,17 @@ public final class DesktopConnection implements Closeable { private final LocalSocket controlSocket; private final InputStream controlInputStream; + private final OutputStream controlOutputStream; private final ControlEventReader reader = new ControlEventReader(); + private final DeviceEventWriter writer = new DeviceEventWriter(); private DesktopConnection(LocalSocket videoSocket, LocalSocket controlSocket) throws IOException { this.videoSocket = videoSocket; this.controlSocket = controlSocket; controlInputStream = controlSocket.getInputStream(); + controlOutputStream = controlSocket.getOutputStream(); videoFd = videoSocket.getFileDescriptor(); } @@ -109,4 +113,8 @@ public final class DesktopConnection implements Closeable { } return event; } + + public void sendDeviceEvent(DeviceEvent event) throws IOException { + writer.writeTo(event, controlOutputStream); + } } diff --git a/server/src/main/java/com/genymobile/scrcpy/Device.java b/server/src/main/java/com/genymobile/scrcpy/Device.java index c74844e..93b0302 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Device.java +++ b/server/src/main/java/com/genymobile/scrcpy/Device.java @@ -180,6 +180,18 @@ public final class Device { serviceManager.getStatusBarManager().collapsePanels(); } + public String getClipboardText() { + CharSequence s = serviceManager.getClipboardManager().getText(); + if (s == null) { + return null; + } + return s.toString(); + } + + public void setClipboardText(String text) { + serviceManager.getClipboardManager().setText(text); + } + static Rect flipRect(Rect crop) { return new Rect(crop.top, crop.left, crop.bottom, crop.right); } diff --git a/server/src/main/java/com/genymobile/scrcpy/DeviceEvent.java b/server/src/main/java/com/genymobile/scrcpy/DeviceEvent.java new file mode 100644 index 0000000..97bcbfc --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/DeviceEvent.java @@ -0,0 +1,27 @@ +package com.genymobile.scrcpy; + +public final class DeviceEvent { + + public static final int TYPE_GET_CLIPBOARD = 0; + + private int type; + private String text; + + private DeviceEvent() { + } + + public static DeviceEvent createGetClipboardEvent(String text) { + DeviceEvent event = new DeviceEvent(); + event.type = TYPE_GET_CLIPBOARD; + event.text = text; + return event; + } + + public int getType() { + return type; + } + + public String getText() { + return text; + } +} diff --git a/server/src/main/java/com/genymobile/scrcpy/DeviceEventWriter.java b/server/src/main/java/com/genymobile/scrcpy/DeviceEventWriter.java new file mode 100644 index 0000000..e183a22 --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/DeviceEventWriter.java @@ -0,0 +1,34 @@ +package com.genymobile.scrcpy; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; + +public class DeviceEventWriter { + + public static final int CLIPBOARD_TEXT_MAX_LENGTH = 4093; + private static final int MAX_EVENT_SIZE = CLIPBOARD_TEXT_MAX_LENGTH + 3; + + private final byte[] rawBuffer = new byte[MAX_EVENT_SIZE]; + private final ByteBuffer buffer = ByteBuffer.wrap(rawBuffer); + + @SuppressWarnings("checkstyle:MagicNumber") + public void writeTo(DeviceEvent event, OutputStream output) throws IOException { + buffer.clear(); + buffer.put((byte) DeviceEvent.TYPE_GET_CLIPBOARD); + switch (event.getType()) { + case DeviceEvent.TYPE_GET_CLIPBOARD: + String text = event.getText(); + byte[] raw = text.getBytes(StandardCharsets.UTF_8); + int len = StringUtils.getUtf8TruncationIndex(raw, CLIPBOARD_TEXT_MAX_LENGTH); + buffer.putShort((short) len); + buffer.put(raw, 0, len); + output.write(rawBuffer, 0, buffer.position()); + break; + default: + Ln.w("Unknown device event: " + event.getType()); + break; + } + } +} diff --git a/server/src/main/java/com/genymobile/scrcpy/EventController.java b/server/src/main/java/com/genymobile/scrcpy/EventController.java index 34f555a..0bf6055 100644 --- a/server/src/main/java/com/genymobile/scrcpy/EventController.java +++ b/server/src/main/java/com/genymobile/scrcpy/EventController.java @@ -13,11 +13,11 @@ import android.view.MotionEvent; import java.io.IOException; import java.util.Vector; - public class EventController { private final Device device; private final DesktopConnection connection; + private final EventSender sender; private final KeyCharacterMap charMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); @@ -28,6 +28,7 @@ public class EventController { public EventController(Device device, DesktopConnection connection) { this.device = device; this.connection = connection; + sender = new EventSender(connection); } private int getPointer(int id) { @@ -97,6 +98,10 @@ public class EventController { } } + public EventSender getSender() { + return sender; + } + public void control() throws IOException { // on start, turn screen on turnScreenOn(); @@ -133,6 +138,13 @@ public class EventController { case ControlEvent.TYPE_COLLAPSE_NOTIFICATION_PANEL: device.collapsePanels(); break; + case ControlEvent.TYPE_GET_CLIPBOARD: + String clipboardText = device.getClipboardText(); + sender.pushClipboardText(clipboardText); + break; + case ControlEvent.TYPE_SET_CLIPBOARD: + device.setClipboardText(controlEvent.getText()); + break; default: // do nothing } @@ -144,7 +156,7 @@ public class EventController { private boolean injectChar(char c) { String decomposed = KeyComposition.decompose(c); - char[] chars = decomposed != null ? decomposed.toCharArray() : new char[] {c}; + char[] chars = decomposed != null ? decomposed.toCharArray() : new char[]{c}; KeyEvent[] events = charMap.getEvents(chars); if (events == null) { return false; diff --git a/server/src/main/java/com/genymobile/scrcpy/EventSender.java b/server/src/main/java/com/genymobile/scrcpy/EventSender.java new file mode 100644 index 0000000..9f50b16 --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/EventSender.java @@ -0,0 +1,34 @@ +package com.genymobile.scrcpy; + +import java.io.IOException; + +public final class EventSender { + + private final DesktopConnection connection; + + private String clipboardText; + + public EventSender(DesktopConnection connection) { + this.connection = connection; + } + + public synchronized void pushClipboardText(String text) { + clipboardText = text; + notify(); + } + + public void loop() throws IOException, InterruptedException { + while (true) { + String text; + synchronized (this) { + while (clipboardText == null) { + wait(); + } + text = clipboardText; + clipboardText = null; + } + DeviceEvent event = DeviceEvent.createGetClipboardEvent(text); + connection.sendDeviceEvent(event); + } + } +} diff --git a/server/src/main/java/com/genymobile/scrcpy/Server.java b/server/src/main/java/com/genymobile/scrcpy/Server.java index 479e6b6..ed8a40f 100644 --- a/server/src/main/java/com/genymobile/scrcpy/Server.java +++ b/server/src/main/java/com/genymobile/scrcpy/Server.java @@ -20,8 +20,11 @@ public final class Server { try (DesktopConnection connection = DesktopConnection.open(device, tunnelForward)) { ScreenEncoder screenEncoder = new ScreenEncoder(options.getSendFrameMeta(), options.getBitRate()); + EventController controller = new EventController(device, connection); + // asynchronous - startEventController(device, connection); + startEventController(controller); + startEventSender(controller.getSender()); try { // synchronous @@ -33,12 +36,12 @@ public final class Server { } } - private static void startEventController(final Device device, final DesktopConnection connection) { + private static void startEventController(final EventController controller) { new Thread(new Runnable() { @Override public void run() { try { - new EventController(device, connection).control(); + controller.control(); } catch (IOException e) { // this is expected on close Ln.d("Event controller stopped"); @@ -47,6 +50,20 @@ public final class Server { }).start(); } + private static void startEventSender(final EventSender sender) { + new Thread(new Runnable() { + @Override + public void run() { + try { + sender.loop(); + } catch (IOException | InterruptedException e) { + // this is expected on close + Ln.d("Event sender stopped"); + } + } + }).start(); + } + @SuppressWarnings("checkstyle:MagicNumber") private static Options createOptions(String... args) { if (args.length != 5) { diff --git a/server/src/main/java/com/genymobile/scrcpy/StringUtils.java b/server/src/main/java/com/genymobile/scrcpy/StringUtils.java new file mode 100644 index 0000000..199fc8c --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/StringUtils.java @@ -0,0 +1,23 @@ +package com.genymobile.scrcpy; + +public final class StringUtils { + private StringUtils() { + // not instantiable + } + + @SuppressWarnings("checkstyle:MagicNumber") + public static int getUtf8TruncationIndex(byte[] utf8, int maxLength) { + int len = utf8.length; + if (len <= maxLength) { + return len; + } + len = maxLength; + // see UTF-8 encoding + while ((utf8[len] & 0x80) != 0 && (utf8[len] & 0xc0) != 0xc0) { + // the next byte is not the start of a new UTF-8 codepoint + // so if we would cut there, the character would be truncated + len--; + } + return len; + } +} diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java new file mode 100644 index 0000000..a058a8b --- /dev/null +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ClipboardManager.java @@ -0,0 +1,44 @@ +package com.genymobile.scrcpy.wrappers; + +import android.content.ClipData; +import android.os.IInterface; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class ClipboardManager { + private final IInterface manager; + private final Method getPrimaryClipMethod; + private final Method setPrimaryClipMethod; + + public ClipboardManager(IInterface manager) { + this.manager = manager; + try { + getPrimaryClipMethod = manager.getClass().getMethod("getPrimaryClip", String.class); + setPrimaryClipMethod = manager.getClass().getMethod("setPrimaryClip", ClipData.class, String.class); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + public CharSequence getText() { + try { + ClipData clipData = (ClipData) getPrimaryClipMethod.invoke(manager, "com.android.shell"); + if (clipData == null || clipData.getItemCount() == 0) { + return null; + } + return clipData.getItemAt(0).getText(); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new AssertionError(e); + } + } + + public void setText(CharSequence text) { + ClipData clipData = ClipData.newPlainText(null, text); + try { + setPrimaryClipMethod.invoke(manager, clipData, "com.android.shell"); + } catch (InvocationTargetException | IllegalAccessException e) { + throw new AssertionError(e); + } + } +} diff --git a/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java b/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java index 3bcdc0e..0b625c9 100644 --- a/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java +++ b/server/src/main/java/com/genymobile/scrcpy/wrappers/ServiceManager.java @@ -15,6 +15,7 @@ public final class ServiceManager { private InputManager inputManager; private PowerManager powerManager; private StatusBarManager statusBarManager; + private ClipboardManager clipboardManager; public ServiceManager() { try { @@ -68,4 +69,11 @@ public final class ServiceManager { } return statusBarManager; } + + public ClipboardManager getClipboardManager() { + if (clipboardManager == null) { + clipboardManager = new ClipboardManager(getService("clipboard", "android.content.IClipboard")); + } + return clipboardManager; + } } diff --git a/third_party/scrcpy-server.jar b/third_party/scrcpy-server.jar index 4637040d3dc39973767c20324a51ea9a8d185dd1..5f8ad87d76fe5bd3ef596e621f2d34b49344f4c8 100644 GIT binary patch delta 26377 zcmcbym8D@O^Mo32R?T(E6^l#eQ zKMUiINxzveAxLXSiV#D9H#3U}0|NsG0|@+oX})-JSCCTu*}NtPiPndv2YV+#a{jgP1ml5Y(BGaRRwSA zr4PGSiaD^#cq<%RX*^+n_*BXE-~ZOFP};N1h1)`nXUoLQnbTISIK?;r;r6_GyEEU; zgs4U-9Ilg+wmX}@Ke&D^_pb91$Et+(1ihEtJ7>Iio}WCj_0`jjyk8Eo9-G-e z@BfP_iHZ(0SZ=v*dVkyY(&;5Rm&y*ex%wUI{XLDJujrwgg-_RNUO8RO-7Wt;_!i|= zR5=@pzg!&U;wsaqP;9>>o1L#+IsM`($+ekVUrFvt`!N912;nmV{%SnadB#~UP@|(>CFH}#*L2tjP-N&awf!t{`_D2Zm;oV+nGL> zbW3LHi_-wC--{nr}{^0+@F2f8}RS+rqlD+RPFlE->-dj{ghj~3mrKY+5c?uExGfd zoAYPjvY`0(eKXfy@x9QkreT_*xixuHkg)oh)S@x;Lu}jKe+XQ zTY+(fj16NQQyfb@)5`WKrJ=f^@H(^?}bjWYB|VSh<<5S z+#p}WBf}!z*93#Q)(mp%w9;I9z* zBk@Oa4^JHH`sVEi>KjUD2GtqV%ZW5(CRokjeb)3dK`?{)_rb3Z;y$QU$fm^h=|pgr zHGDqs_JQID;}78r)&*nIBU572(4Is(f$HQS%de1dhr9o z4?+d@xviXhkg>r0hwX{oVJk%wBJzwbH|UpUUNC39Qb!I)G*pG)v?4e9Ivkxie=S4u<`*@0qYNu3XU4-KQe##_HZ3D z+~9q{X# zv@?OtLN26v>I0JkF$<177XIe@4c8C+R`@G+i%*8%kD+t{XGxRogQ5cI9n3YNHhlZo z=dsz>v)QxnXRT+@Z`^)h_k-F8yQda4+5|8xYZNk&KEvF7uyX;UN#oW8<_z}O1bz!) zaD+E%AKdyttw4K+Y>nU@=6CG;4ebZdH+;?f#kr;F?E{?xi8~B=jOC5%oAR6G8{(Vn zoA)!8sF*%-ce4E>Gb2Yx@;alZbNeS%m7!?fnB4@xeue`{cVkW^s1 zgY^#MJ|;P~{s#2}{0G+`?0&%eLC#}u?>FYn4y+L@vkpWFFuqM-zrnqZ!Mrj30QUpg zguClP>}D`NYh1cOa1Pr!2ImJc1-d_&Dg^$>SMdE|+rzWw{6(<@s~P;W9NBO1uVXE5 zY(IGZz-@(!diG#(4ff9mls3qiH1a+$G2q~9@;*@dfbWCo2aXD+KO%oP{|K+Jo?7I< zHiN0_K#l>w4x4F$umn?h^Xr4l59B^L{owTj!4D!oEGq=}u*9*xXL$bE>uJN|10@FH zYZ#;tnq6Q&$9lbC_rdK4j32Om;QGOkQqx$-wXC6NgN#YjWygB{8_egJ!<%LwocqA> zgUS!yAI3k_e=xA@@7T+v-cWUc$?BlM4~ZQtcUbJ$-?80iv}dqqu4n(x)~J8+eS+2s zhVBDF0sPmRFFTrdG$s}Z#4zcxZ*SOrF#G^B*j21Qv^TszWY_Ezz_;q4)&|BLHtPd< z1q?A<>)6a2tq)-~T;z@)=+b%C5oKh%Ec{V=SM`@^`0?ZhtrSk~js zS{FF3HT6Cy*&r{&BHn!Xfm?y}53L_^KUgc|{>c4d-ow0ReL%W_;2DOg36>GOQ3uru z*lw_&W1Ze0eNgv--Uo#WE*tjxdyF@~8^<@eE|4>64n8RPz^6cThwL3@IcERH`HlA* zuQ&eEdd$(o9_+vw!8PmP%LVLT8aE$Y`ar6{c86q**d5+|d~(e9+0QrKZ`|K-{b2Qh z|E6!)POt|%a?aq-I_R~5FNf6-lpXb0=d+YI{65h9!0>}g1>YaOJuLSa-Z%HuufHs& zATQEkJbN6`qj zYt3&H*k3TFH_Tli{)Wl$0{gFn3=%BP2@*XGcN6$;aDQtwK3G>EW+7d}Gl!Y4q4=O< zft-bW41*p^`vKPnNd=rcL}J+V*u(1^v=4?pF!*7yLn?-O9qaYR*Nms_k6!ZISQ4yr z{EOY|G>y~pM~z(Xa?N-rdU;3Eu27$uU7G%ey_&{fHO}llq@#Ui)uBI{K2s01XteE2 zI-%7z#VK`aptbAvm$i49FR&kUejxoI@q_ON-47fUJT`p)_-n*#_-z>X@y}!NZ(M$m zzy5&ngZ2mR4~{>G{2=^6=7;7F$sd+KSbwPg5dC5LgSSHNkJul+JskfS{;~XHT^4mi zYy+1`9L*B_Pj|D1W}HRpH6pIe$4CTuEo z3_ei2!@qSI)6Wuy!vDuwmOq^4&o1y?p0j`V(m6ur%qNyJcSIjDciwzJ+f9vqdyQ4Y zj>mc(Z(d$lO`ovsuHR13SF=mkC=4TyRU2xj{m*1VBXMT_08T|CxF=gTDmiGpQ*&j~3 zzlva9(l=@Pi{6?evFl^kRkt43wbGKG7`ZZb-R_f*^SGV%I?4KqU6na;*7sj{kKD|Rv?*yQ&Hc|Sd@ z9!)D*qNnU&cggS3JGGdUBf9lQm)IWdn_RN!m~QfZ<#%c^C7~%PZ@g#yZm2o3Z|>UI zb#s5uC=`!+_ec4qxa4={CBZp&4!2B~_^!QUx%BtNC(anWTV8nH8EP=-&Op29^B?7{BMK$J7Kx+{WkATPtZ61wEsiP`VUuJOHAjz_dapt z_aoCg#lCm`KkA$A_@>~_+ua3Q*3PnhICI{Inmg+CGfIx|=@`8`*`jauPUz0Z8rSyc zGd^(nTP3Nd&a*rI;)BuSX&ZOm+2K0h-z4wiZK=m%d)J!23%XN!EY|ne*JHZBZf4wB zZS(MT;d+CI%c~Aq7nsi|n5q2erN`{!mj!wpU6qFJ`v=I}o7R z-{M{AHDSKbjtlmV>685AUUJATe`#5@Ppp3HH|s2^m)-U}x~g$~3mxm7i+On^XQgNC zTlknqHva{Sv%1u-lNSV?i#4Y|QGP12>%@gLU-8v~zU8apXMWf(`OB(A>=Wyh=ocs3 z{$0Ib&Rcu@LdhrLoj$(qUt*8zY=!vdHtn0?`}hCimu#iBpEh50D{Wq8 z`AT@!xuEcjpJ89~eT%PD&pH&e?eVDD*vjCEWDu%A>RP z$MZ^Bt;t-vi$BV9-*biV%tyKj*R1;fhzZ2+@4Ks3&dwKA{wDQgwZ`$~9P5Kj zU+uq;74>cYh14tWcwcm0d4B&%u=6kBkK9``I;_g(*Z)_olUPy~oMpDccGkL(^I5l+ z$eh|dsYK5y?!|Z0($ibJMDMA5$~AhKe`r4M{?iv?Ux{4xwW_}1=&xks;2HE``HBU< ztpACmuB^|PwK|Hk-aoZ{o_AH|n!cE-wuRI3=9`plOg*tw(Epa^-4m$+>sEWHH^=^8 zJ8RmC^I5OL<1c6YdGDBpqmCW{99P6TY_X5ugm!e+5YO3;#Cj* zkLJB;v7ahDF?QCmr+2D+g4gYzFuAqf{-Az{>noQ_nvcG?e$q61DY}{YhtxyWWA?Ir zSBlx{UT&XxLE)2=YFuX1xsdG>^EChGnSUvsbuOqp%PP7y?y}@7?qmO5eRaPEJJ%<^ zi07%jdEq+G-{s4uzKZp|o^7k=${(yb{X)qLo#1(qufk0Ie=lF%+xE_6%k>MfZO3@t zUal|M`^x+uqpyDO^en6R*mWz{{#%gQwrumwS`X_pYVj9$-;9X8xclZDsT2kC*)x;7 zmtDR(bynQkch|nyl=6S6c*fXSzvtzA%eHA7ttNgj(s{{tN&9e9-j$L*E7!{_td_jw ze8uHEeU-NFkMAb3%j*_ocK@2V?Df@rp4!06Hea_bPTe?^@XC#`<{B#wN*TQvGm5|qRafny!CpsJAJ)ZZ^XQ--o2Ceftwbki2|7zw7KbOUQ zwzTwF8u!`KR%BO0fh50^>OH0~-P|kAFYJ7GUs>MsU(UJM!~e&A(=VbgoF<=hdNXgy z<_X_!tvalI<@T(5>;JLZ9z4M*x>I);b-d zk75)5ou3%r()xStvT0SZm!o%1nD`<3s*~^bmFu%_EtfO-=We<;u=e@|^@ZJ*7pH#G zd8TrGY5B_Ip81B_kLojbxzsLLx%61(&#$jsUkC-yTRLZ%*Pf+wR_rQqIIr%ldHm{; z=v8VfW}D7klXtOX(yuMcc3=HF>)uMat5@o`7JFMN{!@FY|5W8?^(?s%`>S7)raJ8p zExe@jGbHf;^UiQrPosz77eCqkxVomjCEoX^o%atTzX?b8pZPI;c9H&bmmi@&)TRD+ zW_*%eQm(Z8V6Ropo>v#YOxP8Cnfpq=$=-m!5tmo|vfgs+%x=>;Y~H)CUa;4foVE04 z-tMab=VsS$wU6JsVCC(;t!n?HrmnoivHo#M%&F+~XTPodcJBAD*vq*-{m8$@FX0mZ zx%`%-{xO%RZ{Ene=-Z=9iS}uawOEwR+jiau1ia{ zPbxVQ$63p?i%aXV+lnc{FC1mpy0$6c$L9~EA1Q+cuWmE8|PzxS#&%-X%)6K;3xo%*w4@vg|r!4vGeKLqa- z6xivzSw7u~%*wawXIX_`UfVWr9beXe zvC?_VWM9?z>Xy!3HuseO{{9tfXT39hyU~B`#h>pVr#W1*o;+JpvOj&(r8CF(-#_uz z-ToHm{q?i9{;B(tvhJDrYH5?LU+VJg#oPBEuAkOfUN2^DW3PNK@{U67)DPTOvPv2D z&)FNz`2A1m!OA;RAJqQ{yk^Y*=z(&zYUcO1j~*HyRLzq66Wf2{m-0R+y|ZRdjm6gbgWEOLYkp2? ztf=|e{fFy^G*A4wPxX6iCQd*9x6NLB`}P_odBuO5KfG6|xBUP8n0V#SKUa^;Z@(=a z|Bk7uGr!(>Ns66+-+qbzz8~6o>;DP+-|ttv^L2g8f7?^n3t0Y}9{%6odB1|?{xXBTSMB#2oHKA(%=C;`%J?r*8zU7>^2UEw z{?MI2+ilK&)gSwt{_}i|)~ZqXtDpY)z2ko7|Gq!Y9~7@vkoR=AGuro`yWZI5=M5{f z?>5hOeXrj!F=3frzRe#s;kX66bXT_LCdIf~r1^hk7oS+Wdur!g-UFW}-&^}(NgVU7 zs?=3Xt8aI;p1!a-qJr;p{t~mvwoV%P8%meW67OTZYm`Tj`xw><= zcVzvsrp=n^R;AHy_bhj%%3Rvn|K-wxzXyf9G*!DoLxQ*E9MWknc8{6K^mUT0z!a(F zn}z0Qq}-8;Z|K?5eEZnV`d#OQ{%^he?rx#Vo(`ju7ds{%I=afBylz4m$Fy5PQZMDV z_ug}<6R1zwd*Za7$z0>}s!OJ4?@XM1$0Vxde%8%5C;GRirifbZeG+%NF|hHy#jBeM zS1-4J4Kpn2ZAr6YKIrbTe9IF16MN2d=DpnVFJby?EeVcw)9W^P9skNcbL~;l`ZxS# zJJ$95OSn?X`l~s5OE=F|p(@o&UY3V)m(2HeUgB-=Tlr@8u3y%|Q6(%c_tls#+P`d8 zy%PCE$#ikb0%FoyHWaD$PyOI({l^Jm$WhwoPJ1#M-8^Wy;Tg zeEi~Xm-Q?1|Ncwz9C_2fDgJ$C`11RNeLdavPd+XG&;N4!t54o@AAOZLn|^ji4c{dH zk27kTJb!xBr0wO;oWHfRBsJ#JidU1D%w~PdU-o+A4i;a&$eq_50(45$^vZd<-(2t4 ztS)j2D~UYz>hXzl4ab_Kb?s}-1l}B+F86(MUH`i64~@4~ov^=aR`+Eq`(KapuA1)9 z`q#my!e`WR^TY3?08Pp!=7_GzVSS6Q!BGVc91*Jsr_H7V~v@4C{6Ig6^_M))o? z)ti&o`pr? zShYFxebW(Ej+>``e3`xflG|@Br!1fH>CDxa$4mciKanmsv2K;${=0h4L0>#x{p2cI z=~*->Yh51e!~NX$%ANA3Nh`Trd2uZ~%JjfrG+4`jqFVyzmz5| zqxUYNE7!QyNpC!&9>bmY^7W->nP2Ah*Z;0R@!I51cW}SDeV*YO?l=EFxI|uNQTNPR z6MIPLe40pm_k~hnJ=UYT*&;uuh@~WUt0`Mvp7yn`<@^?|E36T#;_l2`6Edmhh(D+J z&CQ|pMc8aDtP4ZgXOi&v+l-gQ^OK}v|j1C za#}xX`l_1g_xJa?#D7R#7PpTn{K2R9ALa_}T;?YFi#^M3eU0wTCt0t{v=_-4y;FW@ zC91h(o9Oh)1;rvIDhZcI(cqh-<&PM-WxPe`qgip`N8AD)c)Hmr?ynT4Pn#O{`lYN|89TXjl8xTUW~1Vq`|KHYcM z=vL(2r8TMFZ7)s}{PVn z_%>};R=wrS8@fyGXRV&r(f`%WfmQoxp4F~5!M@S1O}&%$zndS?n%pXTQ+%gclY^sqhX24Z`|g{p~M(+4>6`|MfC%U0}Mj zt}tuuJ$*iw^J!<&mK{5^vg_mf=tt2jx@y+3{SIl|&vN==!#!RWd$ppv>){XlO&@N2 zuzSh;m*RHT^I7aw59X&t&wnW#`+Z`O)T|fBrv~L$Np`RMec3)>W4!AnqgvOxcXnBE z0o=O(^%=-JM%MGs(4y*XHQl?ya-4&Mx`?xb|`T`)^MTa<|R-@ci$;@_GC$ z_ae6#?u+J$4C}r+_4)6;p*xG1!alf{Jw2uKA}Ri(L%Q|f zf;stHUw@HT?tAg%@r9Dr`yctF7JFTitIu0-?)YXe$&kcTRg9&RH%e?jcz(jNHx+k3 zPV>x~L<*u7F>IK4xU zf9*D&CpzzEGmG!c)MY~Q`)4{_lfC_V(y?!A)%K|F2)oU5(XF#^t>Z4`_5 zzL#WPzm#uh`mX8+jSuc7v4?7yr|74-b+Bf4%zHWISNG?0p|3B?S{I$Iy0xk8rtRd3 zrzRJbB{rKTKRlLmb;cv^FYW7}uUz%zifYWCXE*k9u&lXczQpzM-yJPAcYf}4O+^sdwT8>&K-qH<|~|XYY%@&i8p3=FO;Eme##BYV4Z#B3 zqC&EcnMA#c$(wF;dHRR?1>SyXM{YTEzdKUmbx!C~{Kw3%8M|8Ca~{6kl)@exQ(|YB z9HzKfSv1&2_j^rH%CoJ?ax*`>r8=ExITyTE%+fl~s;9+4BRA&5fzHRD_~y)*e!e2b zaF+Q!zGuD*?CX;DPMtMrbx^RgR%z0%O_w7@(^#g?ow@waY<|+M7tvcLM*I(%x6A17jMcZ5mpg1f z{#wg;wy~ky%`=L7A3gfK@uX_cbGAq8KU#)m&08!r*CzY&o|@@leZfa{?sUybTJq}R z3)8;brA1e-WIT^nOb;&XE9))ho3mr3#ftj7v%88-bAK|Y&-`pI+TL^i(mtEFrx&Nc zUGwgg`C)X1 zLwVkrTPpQa_De)XhA(istR1bUa<*gg*I9hA2h@zMlj_}{Z zMYnR}&z{WKb$?djp1%q|r=06pvcu|7mEqE&idnyEyX?Pa@Al@Nbog`0k9=m$#!G8b z{1nc8bPu{ve5~=s&;2jL@2>9C-a9!`%Qn@pU+9U&qUQ&5F4p_zdmXKgv6Vk`$fx+i zN0Abnt5-jUtnv8hx~@+?Xr|^$;h-y9IG-Oi)jFCH7Nv4{t#_N(`7_BK&kS>WxMf{m zzf{joKeg$K=S?ls*>)!v&TopC6rXu?i=%ZXW|`XQ%P+g1+SlC@-BE6*7rEEi{Mr<& zN~`_;2}dvKZk(U={iq-NxuW{zBAk84BAcG}oKBAPXfACLPEr-S^gR8erLsp%`MDb_ zK2Nn~@%-%gtgR}eBiMbr?om5k9;x~tJa0nP(toM0QZJ7=R+pObqw?rPxsHr)1qvuNZw{H)Yd`6Xxrv=03l(x8rJIeF6L4D{^-xJn7ybou6o4XS8tYly7FC zjc44R-Th&w)@i&##k67|7rDO^J^fiIE7QDRn@tVPu z$qY_rF9hn({cb6GRj6fh`Q`ebQ%v$#dw1t+sjS1@%SsJBr_|6Ww4n67K|{PZ3D z+A`tC*uQ*{k%)6#wM5z|6{1-q-dH8>|+)uTqKQy${`cKRW-J&US=x9x=w*T{! zfgN)D_p6@&`OzkI%goUF=5^EMYTd77|C;z!>b%GFTRqQarY~RJ9Q$sLdhvsUir3$+ zn;y$Osej$6T^jq^Y^DZH+?4nBF9`8YHUF{hhjZBPJ;7H(@>ulT z*lJhXOufVIaz8GK|LKlu4M|bf4|g{jdM?*~=ek5Uog+9xe7@5zZ;8ys%eCv3-uH>m zD>5ytT-I&D6CWIA`MB`*y8eR5dcKgHty;Bn>RaBc_?aaKlpG7ve%O6>;_iJ6+e##_ zl_-!ZvzTlMrUQ)?dqM6Ws|+tl5>{N zGk=uIrC6OZ^OK#@-%j^Vl50Am9K&Y&_Y}=#JDckN@^Vc4ysuw0u3ulWbIp!FvtFOyJWuxN zuj`q5#l8;3%$3*l-FG(f&N^K)dC^YI%4_f4cWTa^b$XR@XmRl8HPhX8t_(c;ltsn2 z`0}SU;ch!KZD*aH8NTb;vgeWiWu7kko~dWOo9FD=6PxeJ);~?_$*eI z-R9Bfe^<`THZ>1UP0P#^D|Fu(X?XVRrviQ--y>(ORL`BgR=D}|nqv2zH>*v|qf?({ z&cf3+0)Hlb$!+@lSB3BItOtJ-I-TdM zS=f6%x-g&f-1#QU$UA$ zzgOY2o%LYP^dk$;3eRa+ZvHgnxAz)#_nn$@dDkW03Gr{QI{ zhigwCzH8Su+iKO<$otZVeLolcH)@N1_;8)v;knNrzLPl|`|jbXxh_Teb6z}rCv~{D zV#n*_1?Cky{wD8Ww~g5-Z*{*V)hd6=Y|U@Vk;QV#DtXNBgrp~Qd`}T#m!9yzX7Z7P zY$_J#RSP#Ta-Lg1+2Te6%k!fue9E>5e`ePUwNIS);E!$RVGsX;dp?g0E(y>1uTr>Y zn{{c(Y@<}0`>M&>g8F94QjDCuq!b8&0RyLT+%77@Q)q~Ci! zO2`(Tv%22qmbRJ7PLp=qn2m}j?;PjseEn^&=dQnxS&q+LYgzc^$89T^;x+PHhHmPg z_}octb?c_(Ce^E2tNc|nxu3+jr)>KawlJb#g2K)6o%=UW+PnQtu9t`VJF#w$fWojw65IDD&_o|yVa^yX=m%LQ+p>(N##quSh{vbHtXAq)&FB#PFJS)h#x9^ z=CmsC?X<~9S?8&zKhE7HQCYcewfDy3$J}z4>McDNmcd{B{^I9NuPW+(MZWm)vpHyM z%jutUj!1LVaZjJq?Dx>-pDw-qEv^*XSs50xitGNw%5(oG z*ogn$;m>PUJW0QD$8)VEb5~ps^OyTrb=KZ%Z&LCM~ke^?p$kQKmTP& zSW!_~%&BXccMiHmRXS~LxmsBveO_m&b@yDILqB|@IIUN?NPOCMG_(HCI)_(wzux$) zf5&}MQ}gcUDURoIogOCDIm*u5F3hc@Y-hASyw&N^Bh3_+r*UR=*FG~9c6C0st^d`2 z&1Bwd?K_>>tdEy91lL!6_t6Tvk$vdXn$3k*56apu6pEcNrBYx1<*CY;KR$)({%l__ zP5M;LcyW65!_yTSPG0lYuKXYxX}aTHfI9mx?Rn4kh_p62ImwM3%`?A=7 zOs|u)@9(p4ox9lbgor|~&w>NHE}q-YA9HWrzDq@UfoszC)E#r*5;(y-E+~GZ_rg1k z1$J*A*>2u_`-8Ggs+xb<*Td86CX~N8A^XeehYbJade@?ES)b)?8y}p{SYM*I(P^J* zneOuS>Z?Bf9Yz^&fS=EoS7tIGHVbZ|CFqGk2c_N%O8b5xR8W zrA154$|D}i%xgYfV%GB}w0o!fl+6Ko>3{y3?hn5{Uq^kJcSrNqqQ^DXrzO9hEqSt? z?@8eN$1R%6U(DH(%aQf*O52xJH!j=Hd%ewBZvWJ?lV{EOBV)ed({8byKOe|${m|dM z>$|S&pL($k_BYrU+wN%Jz0N1+npI8Ff1@>K?cY}URyJn^|C?~jB+un__m-(ok}t;@ z<+tsa+co!0r}mv4XEmDD|Jn=4xJSJ+ZZZ3}UO?~j?sv_1A}Si}1Z1Zer>yk1uUU6t z=Ktfu`3g2CwN(B#&gz^NYA-PFz{;BprA`eIk;iO>=fBuo|7Ch>$)B0)KYMzg+s3^^ zL*(zqH%#{w7sd8HnYr-y-Q{vle)A%8Ee%#gos$jHWw+eC`p42gVh#VSj{LTAzSdAD zt?IAw$~@?laqcfki+Oof6aPHf8T$75&a3tT;`1gy+Nn8xnd4>VPha>=QWrehzDhY& z;ZN`_1Fyv94n; zn(-~7!9K{?XWb{A6mRw@zxLCw5^eU&Y4C2n_9pCcZmoUt>0Xy?_pU5upN#tKyLn#= zEP~wMbY0e+Eo~6<@bVhRclxTXm3eV7i{4&-dHjcsSp7aVp*zcSSKV3I#rK!{wz251 zJ)fd~@rD04%5Z)=b5CsFec6Pqt33SA>6}+{TPC~mzQ5l4fZ&}=s~gpMi%te=_e#yR zzH@*1?x^GMRZcq3Gw!;5s`kdIzge4=_t)<(&DX#1wSVWYdwC~2Cf@HpdOc;@sRs4) zH(U;-PyBwoaO$#@#McqMZ1PI^FPVRy;MlT;!#=RwJ7j{#=QoC#e%?zur}E$P%P~JI z+&68REN6+a#N)^Q^VWX9mA#R-WV)8R@6OYo&zX9^ko~?cxi!?$@7c@HYbmC??kv(a zy2mdNUjI(8^4tuGtJfH#e7>{q4Q-I^ZS~)BLvy8*c1U>S30uC^x0KRkemW4j-`sFf@4SfVrHDt9e;*AfRK7g>#}hy6 zEej^{iOBE&{ov#wlhV)w8`pV#y!m%I%aud#V(Ph4r&sAOuYc2f;li&&=e%-~1Ye(G z%3e9i=IM7u*E<#8*yTkzi>3!hn}2_<`+9D~56)}1gZdm6$!z>k9vb19$uz}np0i(h z(nIyo)=5UJ8kg_K?iTnbw^kx6;|qI5TalW!;Jm9m_4DKTpQ-)I;!OSgZE8ka#%qR$ zpXS61T2K1-;IxoXPLpB%f`2RTu2)dK_DlYU%l;+vQ`mkeeSA{4qvL8oeT9qcg4X~2 z7w6{jwj^J1nfF%zldkF)YoV^SzqSQD`!j!q$AS~~{$Imop6O~bAH43NE4HUCf9K)) zxrOIyHQvsY>@7a* zeRVoxd`8U-7T(Y4timC(Yk; zys_8ZS64OlmzR|5D*m~vmz}E*YOPtnC_VY$SMc=4_H`E|*iD!zBc1=ZJA z8cjbnN8@$K#%$M&#M3q^+WZ%G=NoL_x&L|N)D4}w2a6?+=G|4b$?K19VlUaT#PjM^ zom1N7^(Ws+ZBM<&_^Vzq*>rNcM@p;qPZg)Wjn8zIdy_7GxTQG%9xH38x1v<`ypE^h zg}2PMip)zsWLI-`w&$+J+4p>JtnmG2`DOnb?We^|e?DF~)Fqsi(w}g3P12ixCf^y( z|4sXJEu($Ajm@fkQ4x_ZrqBG>eChh#`1f9WSB71(nEL!ey({~60lnXSCw>)&K6%m{ z(UtU1C$O=2rRb-RCUf<}HctDydyeUe$ww8d!cI-f(^cGl=}W|oMfp!Ot1gyRCWY6< z&uCSf-*wD)d2G7Zvzo4l(cd2Q^hpM}-&BuY)wyT-fyqBL7Tnq{f2HcMrt-ZU;w%hF1^q*01^Ro4-`9&^P=YuD%-NIEV6SRfHzpL#N_n+xe*?;=-W;=<5 z)}2@U{x2wb=i2F8zV5mvH|NShC--@F6Mn^c|1x5Ct$4YtM<8;!SVX;n>D~HQzmEu- z_VUbGzr_5Eu@~Q8N9`Sd6CZ8fy&`?B$#JbIu}KxZs-JxtgO?wEwy|x3!N&Kj`=U!C z)~@-^QT%)k*Sx+}7n8Ht{2#?GT(mFd|3uxT6|>v7T%K0?vGRY>E5+>RKdK(rL>;Kz zcQGLNyNljT%)ICnU9@*XjQa0G8O=|0*1mq$6}RC0 z+bQoOsti4^mq*{&>O9TMTH(FYQa{n@8?^ULiQRbRWxf9XdAe^82C%c;v{l}8C40*J zg$qu(Plb!uF-#d|K(JvFtzXQX6btC$L{-S)<3-mHn~z5Q3R zE?WQfuFbw}a#P;J`mDtPWBnF)zLZMNP@OzQ)_IW$_1-Bm-p6_+3kQd*hDXo%Oq~3SVFTILiAtKyuEYBw%`PJ+d}S=JN?4p_u9m^e}3Et>-G` zyd}GGXW12|TkUHe*@SODoOFMpmhaTR?Q0hAca*wmmA2$vlxmckl-RaAre~fUk#Z}s z?|37UA*GuZef!w$W@GCkZbwcR{&3hMb6sYujK54^U$&2>j=$x)#O-F=WNhB&Ukj2C zL;l&T~w!#kjLW-^_iv?N?s?gPlcbhGDBBv~Q`TbRLbIoV1xwe`;;l z8Pee?pv3sK?CoW%ea?3=azgAV1&vrhYDWBhLIc0ghN#MNvzRc#6`y`KF zd1<<`FxIXr?(&^IT(Qy5R!n^o>K`}p>vi=t9R8oS?Xa`;wtOFXbkDokS0^veDO>Wj zDs;~KTYMk=H}CGSoGW3J7_P1SFoe2p-#%XOM>wTk_o*2?RQ{(FDy4Q2FM zc{b(0$<|}Z#mgGoSZm_m&${xB2VWUhQSHo@F}W*U5V+GGAx2@jhN&xAoh$mC;%C z!5u;jiBn_G>hsj6+CTW+sK5Jc;Qi9H(CJgBu4HZ5o4bFm$hI>(Z@OpL7`IkFGa z=D#mHe(9pgW3RI>3PpmJd?}oJ$=)*TKTFTmzF%ASZ(lQK@~JnsmruNFUc1lvGT%x? z{@0hMeO)%U_C#PfTTQ!%!@jrrzkinP^DrupzIOXxPTarMoi>kS7H(QU+pTT>=ilcF z-h^N1YSPlSKmM+M{-#?S*OjM<{#<*N@$}zq<^C7#s^@#FXU_kf>pv$b;@-JuFSz%; znb&>G<6~9q_U=FXUUh%l_VM41?|;p$Zgzj47a4Z#^5w(#uT`9zcCYfx@%W8vH|&4* z=j!~}ZRZ2;e|u_TeeL(Z2d>$&zunX=EMshM`sZxg!fbOg*Zx&WNc-Pu_4n_+3IEM> ztuB1kg?wwSk7mdB-Ljl_Yv1$rwP)`cw@!DuS(m5M_Z45YcKg=vkUID5>Y1A%Y^*xBcl*EHw(oVy`%vLE;g#q_|9vd z`r7$+hqX?>tiAIw&~5A0p9ku1xVLOFih3N|vfS!g^sF29pMNg1Jm+6yXZ`tjYU;Or zmZ_=1Z}$d2vCcmAYGvR1@Vfg~Hr(G{l{I63e!|_OjdgQNXZ+jixn;6>d0PDPcNg#T zfAH(`q3U*xx@yootp{e12DAIqnledccb(x_^)uydB4 zbC!_dvBr?8v6m0;d%pYJe985;&EMj(Ctb{LJ9f10rO?aHdE4rLci&m}_~^0oKk~n( z8~>Sk|LCHW&*r@Qp2fUPxt$(1SM$}D>Gq$BHtSb&aUE!=__HI*UUu!h@4ou0^W5e0 z%Dh&EPv3gdKyYnI+D*yp`_kH%#iYNV-^3(SP<6ZD=h|(axsz9^?`>PQ*DO=t#HMvR zTlD`;OKZMc?mcgHZud9GQ_t&v&nuo6dTfU0&vn6fis#rbZJX}V6}RI2ZHYzef9HKk z-V$aVx&O=0wS|rs=O)D&=hohxUYk*UGo^H~sCmvS)50!W>yx7E*Xh|mS#tTu(}&&5 zLZcVTsDH1$&pOS*$=v#R^y;;D*4+N{@|=r{-j{UC$tNE9weLyaV){8PC;7{>HD&ch zi84i-1f#=#?3k?HxhAf5|788nEnnB%-2MIA`N-Cr|8ml0l*C_(R5Wiak#v6gyzYLh z%+%itR?Gh1pEEl?@Tt${@8>`Meto5Rn&EcqyaPTyyG1&qYxb@5d!Tl_{L{j%?QbUf zw!fJ(`OcZUStnj}g(o*nc~GWppUpngU#VEzUZtMba&gW~*_%(w|J0r92>v7dXR=3Z zoZjreI~E(P_|q%8YsR68H${$LlC|Bs;9P#__K)Aff2WyzTM?6^@b~_;zNow<532ku zqO{hWDvF&M2UB`sIF(-TL+FF+_JSZIU?aI}&skd0d{Znt$T%UQnt?SdFi3)Gc zmaeH1D>M%MW>g;+_-o4NIm%hZd+&$$y_} zchdIA$IWwmAIF@XA6s$jd-Q(3)0)xe;-kDcWYTN9SEMdxtP7erdxMbytIwvm&6`jE zIP7}E^w>UCv!Jt^-zCorXr1OG9#b7F`J>{&>3{maHqU?R`#%52yCUABA+N*ty?K>c zzv9~Ex7@qa3wa7{JdJL4mOher9aXQ^5xvFW*vUit-aKWv(!O+_TK!ke=(B-0my7yL z&P;Z;)}AS>l9Q>l#`(~<+xx%Rze?$zmo#PCO19UjIY*Da?W?-D{fAZir(e_FmcF^3 zbN|y`zRR~6x!1qfQWUWi$9W&R&=;~VPi->t44Z0HZM zdszSYc4Ck^r&_65(HVz`o$D+$cb^;gr5|My(Jsp@~-DuD~3A5I>~ z`h0sb^R~P8$DgGJFTJKd_l!v~FvMq&Hb|DJzkG5_IMv)o(7rw#u3U-N|N;_t~A_vR`}Ff4Afk(SKRE zYl$1z+qksee)Y=>m(}0;{yWlo-?IvvJ0`04d3m_n3X0w6x8VP|Y3-xH&d0U=7WH3h>kog|Rhst1 zCjHavfU6zY96vvTsGK4qte z0#1HP{laUdQ#wAiEzkL8d{bn8woWW$N_7sk$OKI?=j*@sr5g;b(vEeg8Q*{M#y_`4)AL?i}&T^S^pe z`=;3x!-u!Ut?Y|7-M*q~^eBJIdTpKKCk*dBc$=GTeWlJ?-)Q^3gJ%wKAJ8wESCsOp z@{VOfZraDR^gHL0p6T1&fBxo;Z0ffYo~dX1icj3!`|Hfpy5%`L@6Qw2u==`T&$|sZ z_ZJA(%a>%_Nxiyyx@WIl^2GgeRk^uY{F?hy_dhv(?~d{DK=~hkF8_HI@cCK8q^B!i zh<%%&_VQux%J|7n8;&e)P~Y@o=Y^9ghTnP9?q-mJdy0p%ADiEK6wlMLjM3BmQ}6V~{dbmBekutwn~<*5 zQf-&dBc$~^Z{a(8^L0z=)jvM{{^4WEDIcpMaka{mZyPQMDwIyxZpW$nSp1mKxsQ97 zJ(~96>=oY^W&d`5nXt@yW$%yjPv!zHVdoaK$T0}%t=#oID39~5!On?7_bj)(&6xXW ztAN&@kkDrDQ(=owDbv(*1r%DY)(Q(zRB5?zBuVKCD{wx#5DBv$&&coR`kitfgrmKW)7vC8YI9 zy5WLZgX&UKS>B0Le=PER)E8`i=BoWgy^r4=Re3L(ew^>jvvP63PxU0n&y^m9Re zFLk1lrfJO-efO@LuQj>$@WXjG3Q7tzZkfuw>wEX^WmjAKF1E!NBWBotF{`$$FU|I= zaNm;tyYFGDR(9XRt>5NI#xB#D=2yJiy50Kuw{NAT-_FV2yJ|muN9^CvfoQLbmi69y|x?YJ$$Ma@HS}nmCf1L*XQT0THkB3HhTBc%+^h>LaOez zEqf*!tu*_Z`HDxoCg$E=)ci14dGFrhLn)V}`&_^CO+UxQ|GjnhuOw&X-9J_fmnz%t zz5BIxW3KJ(lSSprA6*QtuPx5aUOg-1{+%uR@?vwjInCxs)!*E-?AsOHv%J~iZec6u z{3^}9wmv)eQsnxTvFo*7StsW;zj=3Cl6QL$`>e(5iVJ+x*A!b{efjG3+qZAzyVkw$ zajkC8IJZ<@RC(9-{l?e!Zp+`19_=6gyntWz+QiP;`H%XJWK5fzxc%sr9l!3)`?t1s zZu8xbKBcWiEAM_th|fR#u0A8@#@fd$`2pTrHb-wapE^I{zWJrwxx2pcyu7|nc5d^- ziH}25|0cxOS6n|K;JD=aO<`#+eUA6<-pD$Nwk`TQw|Va2i|;;MtKCqo`RY=^M6OpB z%_^5AZ{L%4)&8R`^~!8bh~_LE-qjbn+K%1gJv&jiS9fc+)V3{G+@!7?sfd`&S)Usv zotfb%8~UrO?b@$t%f3!5)m7TMapk_m(@~w*Z(MO$KYO3#ekH3d#XHu|w>oxWR#~z3 z+>K7FSG?xjCFeg|z;~BV`y8Vi&2h(7tJ{86TYon_y6x*u#Y*iv6PAR1GY>c;_B1~u zb76_*tbl_nt!(e6lsM|Yvbb`6tFf2zw{N_z^}DYg*;vzck6-=%Qy$mkFMbsonpaBX zPtG*Tx*4YXs_lvSo3~xxyq_NaBY)4(L%sd#kG8#kFR5&N`>-|f<)+v`$^ECYLK=@f zyVX18PF7G^uxv(-SrGUxzH{%+Io3n)%j~_v=Jm z-|Xx89XXlxH*Rd07PvXj_3*S?*L<^IUpI+O<>e!htR8f9pO}UpeR5WWTIM6KBtol74tWbj$W; zdC$9|m;U{@ov@|JEc8atL5Vl7U(Q?IJ29_s=UU~zf158ZT$q+qI(61Gfr)`Vjx)5~ zl3Ck!EXlOkwc1NmCU}9Dug{12ZTw~5-oJP$HEZ`ie|76bo#m{qtAj2J_rzX&H}Ble z>?gbTt+&1v`e;_VWZ1o!ev#Ed$7M}B57z!Y>|&#}d1HP-czRH3^2LWc&l+9qNbKX= z_R26~sha8}IZ=Z(A2vp8y?gi4oKP)&#f#=9+t<0bt=z68q*3gB@>tunu(TCgqF(h~ z3O4`lO)+1iIqy_P@g%R{$v&HITkT%t{$%IA;tkrjqL->wU(V=!_e#1?&29ho%O0ys z?+fgWIX`Fj<<;EIRuy@NA0(_fFI>8%%`HLps@z#!!46BQLr3@z%dUNVqQGB2ci&#G zvwltDWEAGA1k{o+IBg5Hyr*Ci&s>&}eplw-Yk@YlY52lJ#7&$)XA-TwFDL4m)> z%Zq}`jlV33UV2P@`4y|AFAH|;T%CXY&fAMO_QlplS63}gd;26y=I+5Pw_BfHIHi3v zxH{{vy~j@P7Oi^I*AknO)9z@A+AUjgW|QjYRafrtPw%+>`I%gZnObu8t9G{)LC3R1 z&L8=g7;2I9?f--?ZsIJVSx{PfiVt|ynisWRSv@_}`gkgk!eO#R%etG4s&q0-{NddndujP z^?TW=De-?2jj|UVw*EEa(sDW16`gBOEbv_NLF13<#n|ZH1|QDgKBY^yHru)_=2;ZR z>YnIc#`Ep1;;Q)mLNWDC-)G;x-2QFD#TR#OdGGnyd7!PdcV4BPwcx!IF-qQT6)7K+ z>+kGltB%MuG&rtm;rrT#v!W?=nd{!gbJwW4e~vacdc!F%8h_rxqeFa0=l4yKbE2(H zR6Z*Uzj?4ACFj-R%F^1}y%+s*rfM$do8r00)XG4p_oUUyClemLc)8c>X;qQIUPHAN zvrK2M+b11qwJ++NQCA;NYWlq!=0dN(ZE?P!d|9AgdLd^Y&q_b7S?a6If2x^v-L|gI z-n}a#qbkMA=H&5Iw(Z3|g3{kSMEj;rdiW$(xGFk0Y`RQ9hoQ{cZE;0>eP1>&{l4VQ z+B37xJ(LZ7W8wCA&D(6*m$x4FG5If<;GS|f%rbaI(9(GuroGq}cXRT)zIBIhy|nFC z-?m*p$}Pz-d}6(N_2d2{ZPjI!+0V~j+`7d`y;tlC@8#~|mF1Im#BqeLd~ExuN5|~E zs&rE9TxFS5Rj%z_XQ$1(xtDXtp_5!I+LuKa>rS}%QeyG_yD6%t7B_$6b$@(NO_Xz5bNxKUZJtIG79_nX z;fs^25_$cs=H!WlydJfeNB^xlw@|iR$XN~b>f!04_|Sb+&y9N zCGEv3;iU$)3ykk{7W zufKB4|IrGUw`!s`MS|;oY`kG{?!h%vbNR}GNtbpdnf3|>O0J!AZQ`q6QG8y;QP;1o z&+B-RY-M^e_F3T!)z8gyoR0Qyb@JqP2zD~h`Ep11aBRuWJ64;QNyIAmSSIm)-_d@> zr^R-!(Z4&34V-p=4V<4PH~ZK|{#bjXtu~XRE_nvm&yp$Mt$I%2`9E9RyN9i(UF>jQ zQxG$A!Ri;%DXA~oetapcnRoN&%&Wbpi9%G0mzRe>fBdv}>AG!oU&Z>KzWCV2cClFW+QYA3 z>fct0)V$s05uE&|o};ezZB$78s%aS(qW8NNe{`O;Uudp}%=*9HsfpC)y4MDOZYD={cM4ez1%wH zLx+F=TAcSnV0mh7bJ3(;-b3$%tn!${SwCKw_wHNQCe`JFIk_P-pJk-ick7iMQg^>} z>fVXOm&ca5{d{z!Z@t>n>G`r}4&FVs%xvn$z`h@M_zhJ;`o8}VO58U)ltJkGsml9q zmi2cv)YsQ!Y98+W&C?xxus7FZTc^+Ll-Jfvx23M-I$?g4Usbn0wslj-m1Bu2g*8@P z@%v)^Hy={2ykYb3=@w7JpNougQ!?s{IdirbPq`VlUTvHCaeu{r3x}DdEXRv46+Yqg zy6N6s)gQohyMN;i`MaOnZrNV$jQsty^6;bV$x9rJ-)sCAdv>3zBPMd?nR9Dr7>K0k zvcJ%}aMEgReZ*33St+fRD^`5i@pH11T8-R8$#uIoZZG~l!9_$g_}{s86CY|6-M!1Z zH?ThP>`I+GADg3(E!n?$`b>wVMeVAu8&_x<`1YK=ynM$~-_G6gp;FHcCzic`Dbq8p zd^fw;Q{R)fokES=Hn~rG|8$OpQ;%%0@Z+Fb=cm5+EZuxR6-?@#KT9aRlW&TA<&))o z-f8MD9|@jGIqkl9qh?>?vKJE+r(UzPxUqBn>h<;Vz4gXVE~nKERTu4hvv{TO_PR-(`=0pDd$@%4%Z!QKT(W_B?xIs=_Ns;|KEBM%sC=Nv z_32E5_iu6 zlrpoR{K2HHeaYvJzxw7nW4*>kz7l=w`YSBgw;Nf-$cM|s_TOyS<#xmlh`l3!lpqebM)==2fNJHyw0?+6v$FM3k&r=(BuLP?uQi#0b~I90lo38&0>~^>yk> zm~g?Zw@d2itv?6r)V6d@8HVY{t(f zs~4`boEV!qYw7j%D~xhYg8e1>wl3n1t4^C!k$S%6)wRhN9YyswzuZ#4-i+7d`MIpx zHn*P-U)-uP?OsvPkXF$u8|v_SbJn_pY3~j8cP-!hB<+1@WT=<+9l;|`(@qxOR)1j; z6Tdz9dipIVy(=5j`!k=L`AbY)lr|;(hTr7K-Rm~$HVf-;?)6?4k<*s6F^g+%YUi@E z?{@elPF!$MBuQ)b8t?5J%Y%!%zSf(WeObK1hs%v$Y~saNB8E|SiX)GnI=SR!$jn%Y zxh45;jKt2q+8THN>c{x|9hOa8mxTN7uBkU(JTLr+$0`K78VC{p|MHIX16eMd=v++$higGe9bI!^NtQrk66) zme>1;$KHyVe(;z9-`j*sYhzwWg?3C>Ebt}be$djEja%OGGe5gC?T~VV=ttFMysr<+ zsn-?Mx;~%%ZqkbKM_*5g_d8EoD$~kxbbImK_fj18tBzbylM{7YtiAf-8QbZ}r#IdC zu=j3wsM+G{dl!BE`YXiv$h@HBXHOSge7R=(wJ!-rPdL`sB|K@!*_Uxkd!v9*2Fu%^`nxACe z{l2R+!a3}xkc7#f`c8?m?+uSmR)p>B6ye$$G=E)kY8(5nlx8hMoyD5oOSWyuyd}5n zN|vu}v-k^{X3yd!4m;P_Uzimu|J2*bk5m11*}Bf$`%O`t%$K8CCeL7fct)Bh{Z|i% zM^4|1z(c-CJH^gDoH_f-*L>^cfe+tq4AYlVxUMQNOYaCr$*#y`C6RijT;=1NYqT1S z%Rjc6Jw2=v@9Fh3X!f>M4q3wImou81B&Y_5)>TeaZW0aER?`-b{&@SUj#K~f$Vh|K zG8@MwuOCk+4E5CVof*45rln<<2t&eLE%O^&WJ@jza%{ACl4|8YXY;8eZ&oeh%APA% z>NLwmIq2%FO}6exY8do2=7Yq&&fYzu z`kHnIri>!m}pc+tOfU^eKoT=d+BsQc~HP(4DG#qTVF82XPf#Jy&sz zM@;aAjptUTlES;q{%$8?SdvnGPWS)M*Y-TSP*z!U-O2AiSz}Dh`_{aful2d?tx#u@ zPeks~Q$p8lPrjB@kiUi1KDd5YqQUiKrZ&b2|JLcB z@?cxf?R?uvmZx%;?WL-Z5)sofbIv81%LxhI&f2-$G*q_L-SBjO@eYZbe`e;$E?I9W z^)hJ7*{;d&x@@KkZkn@bGm93F^@D_sOmdH7bWa7J|1eSFis_44U!CSn>}-~_P8aK0 zIbq6d4#Q6_9JYy?wLe7g;uG+E%o0 z((E`Xa#HE0NZ8Dchx^M|g3mA-b1hrhGVkSYiIV|kX$MX%+b9t_O?Q%#*UrL}Acl>H zpLT8IGEo;UJ#o(K)NI%4=~_vBee3&Gr9w2nRbG^jm-knB6rr2d*0HKdcUwmNX~hS+ z_j1BGW*iiJm8;F!+;{zT(zj-pB~4OmkNyb}_FxHj*uXwD;Gx*M(%QxASYId4YH7)? zu+rzrytUqJ+oP^6THCks9gVwos(EjmZpgndU2gWMubO-_vfh|pzI3g^EdTn`of119 zsLj^8u5tf~vKzl8Uv|f=G<&<-i_b_TEUSO2IxDkVXNBojP0-UAYe{7hqCRQ;g>bX_Hs_7Qla{|)~Eea0x{yV<8WMeUN?(ap*7yVuw zT6wmAVf{rptE*eDer@ZoK6~-w3+{`;^IW$_XkTpLe90vo^p&gSi}d;P3tu?y*j%{# z&QH6hx%Mk{cP$it$8`9|l?DELR@`swp6KKACHQf#@LAWxY7Gs@EbCKW%deQFwMR8#t6-s3?E7NAJBsI2uAJaMD!D@V`2n@Ub9rLv z1(Ss>_j)Qh&sH_s_Oq;h=8cXEdHkOBXE=AgEBf&*_bvb5NBP=GHd9NKf}`ht_+fVZ zrEl)!$+u-Cy{(EeW-HtNs*4h^>sd{3@G0c}~Kt2N&!bE`Mk2 zd2pBM`43x$c7BEuTb2v|3=Vv;WiqL$w|9~_pzD3)Nm`1Z{$b1C2KU$|ymM!nb>WHf z4)v#pRXtT!Z;w{7aWlA~%NV0}`@vL$5BjWE*ZuWec+}Zp;!1Z$K6|zczb)=gd}YI7 z;9*c1@Mp)m(&NJ1PnUNTHCB05w{*|_u;R65;UVS^x;EcbmR-JfYyy2pE!H>uWnS)n0pD+ttfBD+u<_Zq) zn%rG3_6pD682;2gbTnJhsE%jB?-?2ktoe2R1l+oPcV7MUC(08Wr<)XiZ)}yHZ25E2 z959ODb46(`#ds&pP@LhiJg@dW=N;=Py=cP~H{@`53 zb$Tcu7m)leHXFZwSRR3k#-(}LTmYm+5Y4vg2 zo8l#pbB}RtWZ&KVW?y;Ae&xlBE4of{E_nAiJhe;kdvoT(=eBpu-v8VD=g7o=<$^C% z9PdjcTeEfVtuTx{_J7ghpB;t&80Px!SLe6-^y9aItx4Y*?$yUr{yFn$U9DG~!ga}< zPsGl<;0JTV<9g-NE}N!Ke#T|?Nx$Ya2YqGP`^Hw;zWB+P;~$L5+tl_2Juecw)uyeo zow1fJNVf4JuP|_7S5LcncchQ zW_!}dqmSHV%3aUa9cQdJ{KuK-cvdFGfJ_D5E(JRWcP z_-DPM`KF?yS2y3$kJ&f9b=Q)86}KK-XgE0az@EjH@;|btZ9nozTW8;~N2Ox-(+Uqg ziaoH${}yA7{1wO3?^&1K-_P`J`xkE3FNWU6afcUl-rw@WHer`7vkj-~e|zQkl6UsE zE{Zh$z#1T|@6_D??q@7#>8VdEzW?A|u$=2hO?J=yFpc_8mDgv@_|NKa#`?|?&2Gze zf%^|X%Dm7TuMxiD^yRo8-cj4*GPQp#e=RHi zGA~*`Zhk|d`kN1Pi;mT=XD)f@zE_<6lYH|lruEWY^V7HSn4JC^(09k?zx4v{)3eLx z{oKoY^uxW4KVrM@Z?CxXNZC^0$DRVC1uy0AS3Y_Ev2%5x;9l#C-yQ6m_S+=hb=e#g z{Pfwn3jP=8Rs{99v-L@Re3r-Xr8VG{(vR%{n#WYz-5F~Z#Ix=dpZ?_Iixr;xHvc_a zs}cM`GVFB!L-iM|8xC(B`-+d)4pnoUvB>l1w(2QWW5)_TYy};ngzX>e<4rj}Q4z`2G2>sZmq?C!sEj48HEO zznrHf6{t6g`Y^ovw_xT4gF%~RUJ)>o9o-?y)5 zSYnm4y>nj2o-cW?^r!oBG8!ms47j)XV2Iqh^_m=0FRqB({Z;h3$N8C?0%tARAsI63 zi0SsZoQ!`N>jO?mJTl*H7yij(-bsZ|KaQPHSj-|Cn>($QiAk7Qbf(G$wqEmjYv1v_ z3k_bn&ZFk0u{clrl*Y-jb3NVl-rbA1<#Xi9*+mb|gg!jQ+W%2b|3jvAN638n1t%Bg zocX-0#Qp4d|49o?k4c5O__r5#K8&rH#a*FzVU_%^%T+~pmjB9PUAKsVfnjrs$RF$|ktDa9Dc_VpA<6ad1mz6AgP delta 24147 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 Dk-{G9