diff --git a/resources/desktop/com.github.rssguard.appdata.xml b/resources/desktop/com.github.rssguard.appdata.xml
index 33f5b23b6..fad4d8d1a 100644
--- a/resources/desktop/com.github.rssguard.appdata.xml
+++ b/resources/desktop/com.github.rssguard.appdata.xml
@@ -26,7 +26,7 @@
https://github.com/sponsors/martinrotter
-
+
none
diff --git a/src/librssguard/CMakeLists.txt b/src/librssguard/CMakeLists.txt
index ce4a6fd65..203e032f8 100644
--- a/src/librssguard/CMakeLists.txt
+++ b/src/librssguard/CMakeLists.txt
@@ -289,8 +289,6 @@ set(SOURCES
services/gmail/gui/emailrecipientcontrol.h
services/gmail/gui/formaddeditemail.cpp
services/gmail/gui/formaddeditemail.h
- services/gmail/gui/formdownloadattachment.cpp
- services/gmail/gui/formdownloadattachment.h
services/gmail/gui/formeditgmailaccount.cpp
services/gmail/gui/formeditgmailaccount.h
services/gmail/gui/gmailaccountdetails.cpp
@@ -541,7 +539,6 @@ set(UI_FILES
services/abstract/gui/formfeeddetails.ui
services/feedly/gui/feedlyaccountdetails.ui
services/gmail/gui/formaddeditemail.ui
- services/gmail/gui/formdownloadattachment.ui
services/gmail/gui/gmailaccountdetails.ui
services/gmail/gui/emailpreviewer.ui
services/greader/gui/greaderaccountdetails.ui
diff --git a/src/librssguard/gui/webviewers/webengine/webengineviewer.cpp b/src/librssguard/gui/webviewers/webengine/webengineviewer.cpp
index 36d279ace..f6ef11415 100644
--- a/src/librssguard/gui/webviewers/webengine/webengineviewer.cpp
+++ b/src/librssguard/gui/webviewers/webengine/webengineviewer.cpp
@@ -166,6 +166,7 @@ void WebEngineViewer::bindToBrowser(WebBrowser* browser) {
browser->m_actionReload = pageAction(QWebEnginePage::WebAction::Reload);
browser->m_actionStop = pageAction(QWebEnginePage::WebAction::Stop);
+ // NOTE: Just forwar QtWebEngine signals, it's all there.
connect(this, &QWebEngineView::loadStarted, this, &WebEngineViewer::loadStarted);
connect(this, &QWebEngineView::loadProgress, this, &WebEngineViewer::loadProgress);
connect(this, &QWebEngineView::loadFinished, this, &WebEngineViewer::loadFinished);
diff --git a/src/librssguard/network-web/downloadmanager.cpp b/src/librssguard/network-web/downloadmanager.cpp
index c627fbdae..9e1421976 100644
--- a/src/librssguard/network-web/downloadmanager.cpp
+++ b/src/librssguard/network-web/downloadmanager.cpp
@@ -23,10 +23,13 @@
#include
#include
-DownloadItem::DownloadItem(QNetworkReply* reply, QWidget* parent) : QWidget(parent),
- m_ui(new Ui::DownloadItem), m_reply(reply),
- m_bytesReceived(0), m_requestFileName(false), m_startedSaving(false), m_finishedDownloading(false),
- m_gettingFileName(false), m_canceledFileSelect(false) {
+DownloadItem::DownloadItem(QNetworkReply* reply,
+ const QString& preferred_file_name,
+ const std::function& run_on_finish,
+ QWidget* parent) : QWidget(parent),
+ m_ui(new Ui::DownloadItem), m_reply(reply), m_preferredFileName(preferred_file_name),
+ m_runOnFinish(run_on_finish), m_bytesReceived(0), m_requestFileName(false), m_startedSaving(false),
+ m_finishedDownloading(false), m_gettingFileName(false), m_canceledFileSelect(false) {
m_ui->setupUi(this);
m_ui->m_btnTryAgain->hide();
m_requestFileName = qApp->settings()->value(GROUP(Downloads), SETTING(Downloads::AlwaysPromptForFilename)).toBool();
@@ -40,6 +43,7 @@ DownloadItem::DownloadItem(QNetworkReply* reply, QWidget* parent) : QWidget(pare
connect(m_ui->m_btnOpenFile, &QPushButton::clicked, this, &DownloadItem::openFile);
connect(m_ui->m_btnTryAgain, &QPushButton::clicked, this, &DownloadItem::tryAgain);
connect(m_ui->m_btnOpenFolder, &QPushButton::clicked, this, &DownloadItem::openFolder);
+
init();
}
@@ -151,7 +155,10 @@ QString DownloadItem::saveFileName(const QString& directory) const {
}
}
- if (path.isEmpty()) {
+ if (!m_preferredFileName.isEmpty()) {
+ path = m_preferredFileName;
+ }
+ else if (path.isEmpty()) {
path = m_url.path();
}
@@ -181,6 +188,11 @@ QString DownloadItem::saveFileName(const QString& directory) const {
return name;
}
+const QFile& DownloadItem::output() const
+{
+ return m_output;
+}
+
void DownloadItem::stop() {
setUpdatesEnabled(false);
m_ui->m_btnStopDownload->setEnabled(false);
@@ -205,11 +217,11 @@ void DownloadItem::openFolder() {
if (m_output.exists()) {
if (!SystemFactory::openFolderFile(m_output.fileName())) {
MsgBox::show(this,
- QMessageBox::Icon::Warning,
- tr("Cannot open directory"),
- tr("Cannot open output directory. Open it manually."),
- QString(),
- m_output.fileName());
+ QMessageBox::Icon::Warning,
+ tr("Cannot open directory"),
+ tr("Cannot open output directory. Open it manually."),
+ QString(),
+ m_output.fileName());
}
}
}
@@ -413,6 +425,10 @@ void DownloadItem::finished() {
emit statusChanged();
emit downloadFinished();
+ if (m_runOnFinish) {
+ m_runOnFinish(this);
+ }
+
if (downloadedSuccessfully()) {
qApp->showGuiMessage(Notification::Event::GeneralEvent, {
tr("Download finished"),
@@ -487,9 +503,11 @@ int DownloadManager::downloadProgress() const {
}
}
-void DownloadManager::download(const QNetworkRequest& request) {
+void DownloadManager::download(const QNetworkRequest& request,
+ const QString& preferred_file_name,
+ const std::function& run_on_finish) {
if (!request.url().isEmpty()) {
- handleUnsupportedContent(m_networkManager->get(request));
+ handleUnsupportedContent(m_networkManager->get(request), preferred_file_name, run_on_finish);
}
}
@@ -497,7 +515,9 @@ void DownloadManager::download(const QUrl& url) {
download(QNetworkRequest(url));
}
-void DownloadManager::handleUnsupportedContent(QNetworkReply* reply) {
+void DownloadManager::handleUnsupportedContent(QNetworkReply* reply,
+ const QString& preferred_file_name,
+ const std::function& run_on_finish) {
if (reply == nullptr || reply->url().isEmpty()) {
return;
}
@@ -510,7 +530,7 @@ void DownloadManager::handleUnsupportedContent(QNetworkReply* reply) {
return;
}
- auto* item = new DownloadItem(reply, this);
+ auto* item = new DownloadItem(reply, preferred_file_name, run_on_finish, this);
addItem(item);
@@ -660,7 +680,7 @@ void DownloadManager::load() {
bool done = settings->value(GROUP(Downloads), QString(Downloads::ItemDone).arg(i), true).toBool();
if (!url.isEmpty() && !file_name.isEmpty()) {
- auto* item = new DownloadItem(nullptr, this);
+ auto* item = new DownloadItem(nullptr, {}, {}, this);
item->m_output.setFileName(file_name);
item->m_url = url;
@@ -670,6 +690,7 @@ void DownloadManager::load() {
item->m_ui->m_btnTryAgain->setVisible(!done);
item->m_ui->m_btnTryAgain->setEnabled(!done);
item->m_ui->m_progressDownload->setVisible(false);
+
addItem(item);
}
diff --git a/src/librssguard/network-web/downloadmanager.h b/src/librssguard/network-web/downloadmanager.h
index 4e82fadbe..2bf4f0490 100644
--- a/src/librssguard/network-web/downloadmanager.h
+++ b/src/librssguard/network-web/downloadmanager.h
@@ -25,7 +25,10 @@ class DownloadItem : public QWidget {
friend class DownloadModel;
public:
- explicit DownloadItem(QNetworkReply* reply = 0, QWidget* parent = nullptr);
+ explicit DownloadItem(QNetworkReply* reply = nullptr,
+ const QString& preferred_file_name = {},
+ const std::function& run_on_finish = {},
+ QWidget* parent = nullptr);
virtual ~DownloadItem();
bool downloading() const;
@@ -35,6 +38,7 @@ class DownloadItem : public QWidget {
qint64 bytesReceived() const;
double remainingTime() const;
double currentSpeed() const;
+ const QFile& output() const;
private slots:
void stop();
@@ -64,6 +68,8 @@ class DownloadItem : public QWidget {
QUrl m_url;
QFile m_output;
QNetworkReply* m_reply;
+ QString m_preferredFileName;
+ std::function m_runOnFinish;
qint64 m_bytesReceived;
QElapsedTimer m_downloadTime;
QTime m_lastProgressTime;
@@ -113,9 +119,10 @@ class DownloadManager : public TabContent {
static QString dataString(qint64 size);
public slots:
- void download(const QNetworkRequest& request);
+ void download(const QNetworkRequest& request,
+ const QString& preferred_file_name = {},
+ const std::function& run_on_finish = {});
void download(const QUrl& url);
- void handleUnsupportedContent(QNetworkReply* reply);
void cleanup();
private slots:
@@ -133,6 +140,9 @@ class DownloadManager : public TabContent {
void downloadFinished();
private:
+ void handleUnsupportedContent(QNetworkReply* reply,
+ const QString& preferred_file_name,
+ const std::function& run_on_finish);
void addItem(DownloadItem* item);
QScopedPointer m_ui;
diff --git a/src/librssguard/services/gmail/gmailnetworkfactory.cpp b/src/librssguard/services/gmail/gmailnetworkfactory.cpp
index 7285026c6..650d35c4a 100644
--- a/src/librssguard/services/gmail/gmailnetworkfactory.cpp
+++ b/src/librssguard/services/gmail/gmailnetworkfactory.cpp
@@ -147,6 +147,20 @@ void GmailNetworkFactory::setDownloadOnlyUnreadMessages(bool download_only_unrea
m_downloadOnlyUnreadMessages = download_only_unread_messages;
}
+QNetworkRequest GmailNetworkFactory::requestForAttachment(const QString& email_id, const QString& attachment_id) {
+ QString target_url = QSL(GMAIL_API_GET_ATTACHMENT).arg(email_id, attachment_id);
+ QNetworkRequest req(target_url);
+ QByteArray bearer = m_oauth2->bearer().toLocal8Bit();
+
+ if (bearer.isEmpty()) {
+ throw NetworkException(QNetworkReply::NetworkError::AuthenticationRequiredError);
+ }
+
+ req.setRawHeader(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), bearer);
+
+ return req;
+}
+
void GmailNetworkFactory::setOauth(OAuth2Service* oauth) {
m_oauth2 = oauth;
}
@@ -155,29 +169,6 @@ void GmailNetworkFactory::setUsername(const QString& username) {
m_username = username;
}
-Downloader* GmailNetworkFactory::downloadAttachment(const QString& msg_id,
- const QString& attachment_id,
- const QNetworkProxy& custom_proxy) {
- QString bearer = m_oauth2->bearer().toLocal8Bit();
-
- if (bearer.isEmpty()) {
- return nullptr;
- }
- else {
- auto* downloader = new Downloader();
- QString target_url = QSL(GMAIL_API_GET_ATTACHMENT).arg(msg_id, attachment_id);
-
- if (custom_proxy.type() != QNetworkProxy::ProxyType::DefaultProxy) {
- downloader->setProxy(custom_proxy);
- }
-
- downloader->appendRawHeader(QSL(HTTP_HEADERS_AUTHORIZATION).toLocal8Bit(), bearer.toLocal8Bit());
- downloader->downloadFile(target_url);
-
- return downloader;
- }
-}
-
QList GmailNetworkFactory::messages(const QString& stream_id,
const QHash& stated_messages,
Feed::Status& error,
diff --git a/src/librssguard/services/gmail/gmailnetworkfactory.h b/src/librssguard/services/gmail/gmailnetworkfactory.h
index 7f34ce22a..c55aa3697 100644
--- a/src/librssguard/services/gmail/gmailnetworkfactory.h
+++ b/src/librssguard/services/gmail/gmailnetworkfactory.h
@@ -40,8 +40,8 @@ class GmailNetworkFactory : public QObject {
void setDownloadOnlyUnreadMessages(bool download_only_unread_messages);
// API methods.
+ QNetworkRequest requestForAttachment(const QString& email_id, const QString& attachment_id);
QString sendEmail(Mimesis::Message msg, const QNetworkProxy& custom_proxy, Message* reply_to_message = nullptr);
- Downloader* downloadAttachment(const QString& msg_id, const QString& attachment_id, const QNetworkProxy& custom_proxy);
QList messages(const QString& stream_id, const QHash& stated_messages,
Feed::Status& error, const QNetworkProxy& custom_proxy);
QNetworkReply::NetworkError markMessagesRead(RootItem::ReadStatus status,
diff --git a/src/librssguard/services/gmail/gmailserviceroot.cpp b/src/librssguard/services/gmail/gmailserviceroot.cpp
index ac30d08b2..4b62f17c5 100644
--- a/src/librssguard/services/gmail/gmailserviceroot.cpp
+++ b/src/librssguard/services/gmail/gmailserviceroot.cpp
@@ -14,7 +14,6 @@
#include "services/gmail/gmailnetworkfactory.h"
#include "services/gmail/gui/emailpreviewer.h"
#include "services/gmail/gui/formaddeditemail.h"
-#include "services/gmail/gui/formdownloadattachment.h"
#include "services/gmail/gui/formeditgmailaccount.h"
#include
@@ -106,7 +105,7 @@ bool GmailServiceRoot::wantsBaggedIdsOfExistingMessages() const {
CustomMessagePreviewer* GmailServiceRoot::customMessagePreviewer() {
if (m_emailPreview.isNull()) {
- m_emailPreview = new EmailPreviewer();
+ m_emailPreview = new EmailPreviewer(this);
}
return m_emailPreview.data();
diff --git a/src/librssguard/services/gmail/gui/emailpreviewer.cpp b/src/librssguard/services/gmail/gui/emailpreviewer.cpp
index c6446a844..16be2deb8 100644
--- a/src/librssguard/services/gmail/gui/emailpreviewer.cpp
+++ b/src/librssguard/services/gmail/gui/emailpreviewer.cpp
@@ -2,10 +2,19 @@
#include "services/gmail/gui/emailpreviewer.h"
+#include "exceptions/networkexception.h"
+#include "gui/messagebox.h"
#include "miscellaneous/application.h"
#include "miscellaneous/iconfactory.h"
+#include "network-web/oauth2service.h"
+#include "services/gmail/definitions.h"
+#include "services/gmail/gmailnetworkfactory.h"
+#include "services/gmail/gmailserviceroot.h"
-EmailPreviewer::EmailPreviewer(QWidget* parent) : CustomMessagePreviewer(parent), m_webView(new WebBrowser(nullptr, this)) {
+#include
+
+EmailPreviewer::EmailPreviewer(GmailServiceRoot* account, QWidget* parent)
+ : CustomMessagePreviewer(parent), m_account(account), m_webView(new WebBrowser(nullptr, this)) {
m_ui.setupUi(this);
m_ui.m_mainLayout->addWidget(dynamic_cast(m_webView.data()), 3, 0, 1, -1);
@@ -13,22 +22,13 @@ EmailPreviewer::EmailPreviewer(QWidget* parent) : CustomMessagePreviewer(parent)
m_ui.m_btnForward->setIcon(qApp->icons()->fromTheme(QSL("mail-forward")));
m_ui.m_btnReply->setIcon(qApp->icons()->fromTheme(QSL("mail-reply-sender")));
+ QMenu* menu_attachments = new QMenu(this);
+
+ m_ui.m_btnAttachments->setMenu(menu_attachments);
+
m_webView->setNavigationBarVisible(false);
- // TODO: stahovani attachmentu
-
- /*
- if (!file.isEmpty() && parts.size() == 3) {
- Downloader* down = network()->downloadAttachment(parts.at(1), parts.at(2), networkProxy());
- FormDownloadAttachment form(file, down, qApp->mainFormWidget());
-
- form.exec();
- return true;
- }
- else {
- return false;
- }
- */
+ connect(menu_attachments, &QMenu::triggered, this, &EmailPreviewer::downloadAttachment);
}
EmailPreviewer::~EmailPreviewer() {
@@ -40,10 +40,59 @@ void EmailPreviewer::clear() {
}
void EmailPreviewer::loadMessage(const Message& msg, RootItem* selected_item) {
+ Q_UNUSED(selected_item)
+
+ m_message = msg;
m_webView->setHtml(msg.m_contents);
+
m_ui.m_tbFrom->setText(msg.m_author);
m_ui.m_tbSubject->setText(msg.m_title);
-
- // TODO: todo
m_ui.m_tbTo->setText(QSL("-"));
+
+ m_ui.m_btnAttachments->menu()->clear();
+
+ for (const Enclosure& att : msg.m_enclosures) {
+ const QStringList att_id_name = att.m_url.split(QSL(GMAIL_ATTACHMENT_SEP));
+
+ m_ui.m_btnAttachments->menu()->addAction(att.m_mimeType)->setData(att_id_name);
+ }
+
+ m_ui.m_btnAttachments->setDisabled(m_ui.m_btnAttachments->menu()->isEmpty());
+}
+
+void EmailPreviewer::downloadAttachment(QAction* act) {
+ const QString attachment_id = act->data().toStringList().at(1);
+ const QString file_name = act->data().toStringList().at(0);
+
+ try {
+
+ const QNetworkRequest req = m_account->network()->requestForAttachment(m_message.m_customId, attachment_id);
+
+ qApp->downloadManager()->download(req, file_name, [this](DownloadItem* it) {
+ if (it->downloadedSuccessfully()) {
+ const QByteArray raw_json = IOFactory::readFile(it->output().fileName());
+ const QString data = QJsonDocument::fromJson(raw_json).object()[QSL("data")].toString();
+
+ if (!data.isEmpty()) {
+ IOFactory::writeFile(it->output().fileName(),
+ QByteArray::fromBase64(data.toLocal8Bit(),
+ QByteArray::Base64Option::Base64UrlEncoding));
+ }
+ }
+ });
+ }
+ catch (const NetworkException&) {
+ MsgBox::show({},
+ QMessageBox::Icon::Critical,
+ tr("Cannot download attachment"),
+ tr("Attachment cannot be downloaded because you are not logged-in."));
+ }
+ catch (const ApplicationException& ex) {
+ MsgBox::show({},
+ QMessageBox::Icon::Critical,
+ tr("Cannot download attachment"),
+ tr("Attachment cannot be downloaded because some general error happened."),
+ {},
+ ex.message());
+ }
}
diff --git a/src/librssguard/services/gmail/gui/emailpreviewer.h b/src/librssguard/services/gmail/gui/emailpreviewer.h
index a9f037041..b63a5075a 100644
--- a/src/librssguard/services/gmail/gui/emailpreviewer.h
+++ b/src/librssguard/services/gmail/gui/emailpreviewer.h
@@ -9,19 +9,26 @@
#include "ui_emailpreviewer.h"
+class GmailServiceRoot;
+
class EmailPreviewer : public CustomMessagePreviewer {
Q_OBJECT
public:
- explicit EmailPreviewer(QWidget* parent = nullptr);
+ explicit EmailPreviewer(GmailServiceRoot* account, QWidget* parent = nullptr);
virtual ~EmailPreviewer();
virtual void clear();
virtual void loadMessage(const Message& msg, RootItem* selected_item);
+ private slots:
+ void downloadAttachment(QAction* act);
+
private:
Ui::EmailPreviewer m_ui;
+ GmailServiceRoot* m_account;
QScopedPointer m_webView;
+ Message m_message;
};
#endif // EMAILPREVIEWER_H
diff --git a/src/librssguard/services/gmail/gui/emailpreviewer.ui b/src/librssguard/services/gmail/gui/emailpreviewer.ui
index 0892889f9..d6c2ac962 100644
--- a/src/librssguard/services/gmail/gui/emailpreviewer.ui
+++ b/src/librssguard/services/gmail/gui/emailpreviewer.ui
@@ -64,9 +64,6 @@
Qt::ToolButtonTextBesideIcon
-
- Qt::DownArrow
-
-
diff --git a/src/librssguard/services/gmail/gui/formdownloadattachment.cpp b/src/librssguard/services/gmail/gui/formdownloadattachment.cpp
deleted file mode 100644
index 5bec371f6..000000000
--- a/src/librssguard/services/gmail/gui/formdownloadattachment.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-// For license of this file, see /LICENSE.md.
-
-#include "formdownloadattachment.h"
-
-#include "gui/guiutilities.h"
-#include "miscellaneous/application.h"
-#include "miscellaneous/iconfactory.h"
-#include "miscellaneous/iofactory.h"
-#include "network-web/downloader.h"
-
-#include
-#include
-#include
-
-FormDownloadAttachment::FormDownloadAttachment(const QString& target_file, Downloader* downloader, QWidget* parent) : QDialog(parent) {
- m_ui.setupUi(this);
-
- GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("mail-attachment")), tr("Downloading attachment..."));
-
- connect(m_ui.m_btnBox->button(QDialogButtonBox::StandardButton::Abort), &QPushButton::clicked, downloader, &Downloader::cancel);
- connect(downloader,
- &Downloader::completed,
- this,
- [this, downloader, target_file](QNetworkReply::NetworkError status, const QByteArray& contents) {
- if (status == QNetworkReply::NetworkError::NoError) {
- QString data = QJsonDocument::fromJson(contents).object()[QSL("data")].toString();
-
- if (!data.isEmpty()) {
- IOFactory::writeFile(target_file, QByteArray::fromBase64(data.toLocal8Bit(),
- QByteArray::Base64Option::Base64UrlEncoding));
- }
- }
-
- downloader->deleteLater();
- close();
- });
- connect(downloader, &Downloader::progress, this, [this](qint64 bytes_received, qint64 bytes_total) {
- m_ui.m_lblInfo->setText(tr("Downloaded: %1 kB").arg(bytes_received / 1000.0));
-
- if (m_ui.m_progressBar->maximum() == 0) {
- return;
- }
-
- if (bytes_total <= 0) {
- m_ui.m_progressBar->setMinimum(0);
- m_ui.m_progressBar->setMaximum(0);
- m_ui.m_progressBar->setValue(0);
- }
- else {
- m_ui.m_progressBar->setValue(int((bytes_received * 100.0) / bytes_total));
- }
- });
-}
diff --git a/src/librssguard/services/gmail/gui/formdownloadattachment.h b/src/librssguard/services/gmail/gui/formdownloadattachment.h
deleted file mode 100644
index 89815da54..000000000
--- a/src/librssguard/services/gmail/gui/formdownloadattachment.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// For license of this file, see /LICENSE.md.
-
-#ifndef FORMDOWNLOADATTACHMENT_H
-#define FORMDOWNLOADATTACHMENT_H
-
-#include
-
-#include "ui_formdownloadattachment.h"
-
-namespace Ui {
- class FormDownloadAttachment;
-}
-
-class Downloader;
-
-class FormDownloadAttachment : public QDialog {
- Q_OBJECT
-
- public:
- explicit FormDownloadAttachment(const QString& target_file, Downloader* downloader, QWidget* parent = nullptr);
-
- private:
- Ui::FormDownloadAttachment m_ui;
-};
-
-#endif // FORMDOWNLOADATTACHMENT_H
diff --git a/src/librssguard/services/gmail/gui/formdownloadattachment.ui b/src/librssguard/services/gmail/gui/formdownloadattachment.ui
deleted file mode 100644
index 4663d36f3..000000000
--- a/src/librssguard/services/gmail/gui/formdownloadattachment.ui
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
- FormDownloadAttachment
-
-
-
- 0
- 0
- 275
- 106
-
-
-
-
-
-
-
- 0
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 100
-
-
-
-
- -
-
-
- Qt::Horizontal
-
-
- QDialogButtonBox::Abort
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-