summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'Swift/QtUI/QtSwift.cpp')
-rw-r--r--Swift/QtUI/QtSwift.cpp444
1 files changed, 255 insertions, 189 deletions
diff --git a/Swift/QtUI/QtSwift.cpp b/Swift/QtUI/QtSwift.cpp
index 756f530..3f6ce8e 100644
--- a/Swift/QtUI/QtSwift.cpp
+++ b/Swift/QtUI/QtSwift.cpp
@@ -1,54 +1,57 @@
/*
- * Copyright (c) 2010-2015 Isode Limited.
+ * Copyright (c) 2010-2016 Isode Limited.
* All rights reserved.
* See the COPYING file for more information.
*/
#include <Swift/QtUI/QtSwift.h>
-#include <string>
#include <map>
+#include <string>
#include <boost/bind.hpp>
-#include <QFile>
-#include <QMessageBox>
#include <QApplication>
+#include <QFile>
+#include <QFontDatabase>
#include <QMap>
+#include <QMessageBox>
#include <qdebug.h>
#include <Swiften/Base/Log.h>
#include <Swiften/Base/Path.h>
+#include <Swiften/Base/Paths.h>
#include <Swiften/Base/Platform.h>
-#include <Swiften/Elements/Presence.h>
#include <Swiften/Client/Client.h>
-#include <Swiften/Base/Paths.h>
+#include <Swiften/Elements/Presence.h>
#include <Swiften/TLS/TLSContextFactory.h>
#include <SwifTools/Application/PlatformApplicationPathProvider.h>
#include <SwifTools/AutoUpdater/AutoUpdater.h>
#include <SwifTools/AutoUpdater/PlatformAutoUpdaterFactory.h>
-#include <Swift/Controllers/Storages/CertificateFileStorageFactory.h>
-#include <Swift/Controllers/Storages/FileStoragesFactory.h>
-#include <Swift/Controllers/Settings/XMLSettingsProvider.h>
-#include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
-#include <Swift/Controllers/SettingConstants.h>
-#include <Swift/Controllers/MainController.h>
#include <Swift/Controllers/ApplicationInfo.h>
#include <Swift/Controllers/BuildVersion.h>
+#include <Swift/Controllers/MainController.h>
+#include <Swift/Controllers/SettingConstants.h>
+#include <Swift/Controllers/Settings/SettingsProviderHierachy.h>
+#include <Swift/Controllers/Settings/XMLSettingsProvider.h>
#include <Swift/Controllers/StatusCache.h>
+#include <Swift/Controllers/Storages/CertificateFileStorageFactory.h>
+#include <Swift/Controllers/Storages/FileStoragesFactory.h>
-#include <Swift/QtUI/QtLoginWindow.h>
-#include <Swift/QtUI/QtChatTabsBase.h>
#include <Swift/QtUI/QtChatTabs.h>
+#include <Swift/QtUI/QtChatTabsBase.h>
#include <Swift/QtUI/QtChatTabsShortcutOnlySubstitute.h>
-#include <Swift/QtUI/QtSystemTray.h>
+#include <Swift/QtUI/QtChatWindowFactory.h>
+#include <Swift/QtUI/QtLoginWindow.h>
+#include <Swift/QtUI/QtSingleWindow.h>
#include <Swift/QtUI/QtSoundPlayer.h>
#include <Swift/QtUI/QtSwiftUtil.h>
+#include <Swift/QtUI/QtSystemTray.h>
#include <Swift/QtUI/QtUIFactory.h>
-#include <Swift/QtUI/QtChatWindowFactory.h>
-#include <Swift/QtUI/QtSingleWindow.h>
+#include <Swift/QtUI/QtUISettingConstants.h>
+#include <Swift/QtUI/SwiftUpdateFeeds.h>
#if defined(SWIFTEN_PLATFORM_WINDOWS)
#include <Swift/QtUI/WindowsNotifier.h>
@@ -76,212 +79,275 @@
#include <Swift/QtUI/QtDBUSURIHandler.h>
#endif
-namespace Swift{
-
#if defined(SWIFTEN_PLATFORM_MACOSX)
-//#define SWIFT_APPCAST_URL "http://swift.im/appcast/swift-mac-dev.xml"
-#else
-//#define SWIFT_APPCAST_URL ""
+#include <Swift/QtUI/CocoaUIHelpers.h>
#endif
+namespace Swift{
+
po::options_description QtSwift::getOptionsDescription() {
- po::options_description result("Options");
- result.add_options()
- ("debug", "Turn on debug logging")
- ("help", "Show this help message")
- ("version", "Show version information")
- ("netbook-mode", "Use netbook mode display (unsupported)")
- ("no-tabs", "Don't manage chat windows in tabs (unsupported)")
- ("latency-debug", "Use latency debugging (unsupported)")
- ("multi-account", po::value<int>()->default_value(1), "Number of accounts to open windows for (unsupported)")
- ("start-minimized", "Don't show the login/roster window at startup")
- ("enable-jid-adhocs", "Enable AdHoc commands to custom JID's.")
- ("trellis", "Enable support for trellis layout")
+ po::options_description result("Options");
+ result.add_options()
+ ("debug", "Turn on debug logging")
+ ("help", "Show this help message")
+ ("version", "Show version information")
+ ("netbook-mode", "Use netbook mode display (unsupported)")
+ ("no-tabs", "Don't manage chat windows in tabs (unsupported)")
+ ("latency-debug", "Use latency debugging (unsupported)")
+ ("multi-account", po::value<int>()->default_value(1), "Number of accounts to open windows for (unsupported)")
+ ("start-minimized", "Don't show the login/roster window at startup")
+ ("enable-jid-adhocs", "Enable AdHoc commands to custom JID's.")
#if QT_VERSION >= 0x040800
- ("language", po::value<std::string>(), "Use a specific language, instead of the system-wide one")
+ ("language", po::value<std::string>(), "Use a specific language, instead of the system-wide one")
#endif
- ;
- return result;
+ ;
+ return result;
}
XMLSettingsProvider* QtSwift::loadSettingsFile(const QString& fileName) {
- QFile configFile(fileName);
- if (configFile.exists() && configFile.open(QIODevice::ReadOnly)) {
- QString xmlString;
- while (!configFile.atEnd()) {
- QByteArray line = configFile.readLine();
- xmlString += line + "\n";
- }
- return new XMLSettingsProvider(Q2PSTRING(xmlString));
- }
- return new XMLSettingsProvider("");
+ QFile configFile(fileName);
+ if (configFile.exists() && configFile.open(QIODevice::ReadOnly)) {
+ QString xmlString;
+ while (!configFile.atEnd()) {
+ QByteArray line = configFile.readLine();
+ xmlString += line + "\n";
+ }
+ return new XMLSettingsProvider(Q2PSTRING(xmlString));
+ }
+ return new XMLSettingsProvider("");
}
void QtSwift::loadEmoticonsFile(const QString& fileName, std::map<std::string, std::string>& emoticons) {
- QFile file(fileName);
- if (file.exists() && file.open(QIODevice::ReadOnly)) {
- while (!file.atEnd()) {
- QString line = file.readLine();
- line.replace("\n", "");
- line.replace("\r", "");
- QStringList tokens = line.split(" ");
- if (tokens.size() == 2) {
- QString emoticonFile = tokens[1];
- if (!emoticonFile.startsWith(":/") && !emoticonFile.startsWith("qrc:/")) {
- emoticonFile = "file://" + emoticonFile;
- }
- emoticons[Q2PSTRING(tokens[0])] = Q2PSTRING(emoticonFile);
- }
- }
- }
+ QFile file(fileName);
+ if (file.exists() && file.open(QIODevice::ReadOnly)) {
+ while (!file.atEnd()) {
+ QString line = file.readLine();
+ line.replace("\n", "");
+ line.replace("\r", "");
+ QStringList tokens = line.split(" ");
+ if (tokens.size() == 2) {
+ QString emoticonFile = tokens[1];
+ if (!emoticonFile.startsWith(":/") && !emoticonFile.startsWith("qrc:/")) {
+ emoticonFile = "file://" + emoticonFile;
+ }
+ emoticons[Q2PSTRING(tokens[0])] = Q2PSTRING(emoticonFile);
+ }
+ }
+ }
}
-QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMainThreadCaller_), autoUpdater_(NULL), idleDetector_(&idleQuerier_, networkFactories_.getTimerFactory(), 1000) {
- QCoreApplication::setApplicationName(SWIFT_APPLICATION_NAME);
- QCoreApplication::setOrganizationName(SWIFT_ORGANIZATION_NAME);
- QCoreApplication::setOrganizationDomain(SWIFT_ORGANIZATION_DOMAIN);
- QCoreApplication::setApplicationVersion(buildVersion);
-
- qtSettings_ = new QtSettingsProvider();
- xmlSettings_ = loadSettingsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "system-settings.xml")));
- settingsHierachy_ = new SettingsProviderHierachy();
- settingsHierachy_->addProviderToTopOfStack(xmlSettings_);
- settingsHierachy_->addProviderToTopOfStack(qtSettings_);
-
- networkFactories_.getTLSContextFactory()->setDisconnectOnCardRemoval(settingsHierachy_->getSetting(SettingConstants::DISCONNECT_ON_CARD_REMOVAL));
-
- std::map<std::string, std::string> emoticons;
- loadEmoticonsFile(":/emoticons/emoticons.txt", emoticons);
- loadEmoticonsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "emoticons.txt")), emoticons);
-
- if (options.count("netbook-mode")) {
- splitter_ = new QtSingleWindow(qtSettings_);
- } else {
- splitter_ = NULL;
- }
-
- int numberOfAccounts = 1;
- try {
- numberOfAccounts = options["multi-account"].as<int>();
- } catch (...) {
- /* This seems to fail on a Mac when the .app is launched directly (the usual path).*/
- numberOfAccounts = 1;
- }
-
- if (options.count("debug")) {
- Log::setLogLevel(Swift::Log::debug);
- }
-
- bool enableAdHocCommandOnJID = options.count("enable-jid-adhocs") > 0;
- tabs_ = NULL;
- if (options.count("no-tabs") && !splitter_) {
- tabs_ = new QtChatTabsShortcutOnlySubstitute();
- }
- else {
- tabs_ = new QtChatTabs(splitter_ != NULL, settingsHierachy_, options.count("trellis"));
- }
- bool startMinimized = options.count("start-minimized") > 0;
- applicationPathProvider_ = new PlatformApplicationPathProvider(SWIFT_APPLICATION_NAME);
- storagesFactory_ = new FileStoragesFactory(applicationPathProvider_->getDataDir(), networkFactories_.getCryptoProvider());
- certificateStorageFactory_ = new CertificateFileStorageFactory(applicationPathProvider_->getDataDir(), tlsFactories_.getCertificateFactory(), networkFactories_.getCryptoProvider());
- chatWindowFactory_ = new QtChatWindowFactory(splitter_, settingsHierachy_, qtSettings_, tabs_, "", emoticons);
- soundPlayer_ = new QtSoundPlayer(applicationPathProvider_);
-
- // Ugly, because the dock depends on the tray, but the temporary
- // multi-account hack creates one tray per account.
- QtSystemTray* systemTray = new QtSystemTray();
- systemTrays_.push_back(systemTray);
+const std::string& QtSwift::updateChannelToFeed(const std::string& channel) {
+ static const std::string invalidChannel;
+ if (channel == UpdateFeeds::StableChannel) {
+ return UpdateFeeds::StableAppcastFeed;
+ }
+ else if (channel == UpdateFeeds::TestingChannel) {
+ return UpdateFeeds::TestingAppcastFeed;
+ }
+ else if (channel == UpdateFeeds::DevelopmentChannel) {
+ return UpdateFeeds::DevelopmentAppcastFeed;
+ }
+ else {
+ return invalidChannel;
+ }
+}
+
+QtSwift::QtSwift(const po::variables_map& options) : networkFactories_(&clientMainThreadCaller_), autoUpdater_(nullptr), idleDetector_(&idleQuerier_, networkFactories_.getTimerFactory(), 1000) {
+ QCoreApplication::setApplicationName(SWIFT_APPLICATION_NAME);
+ QCoreApplication::setOrganizationName(SWIFT_ORGANIZATION_NAME);
+ QCoreApplication::setOrganizationDomain(SWIFT_ORGANIZATION_DOMAIN);
+ QCoreApplication::setApplicationVersion(buildVersion);
+
+ qtSettings_ = new QtSettingsProvider();
+ xmlSettings_ = loadSettingsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "system-settings.xml")));
+ settingsHierachy_ = new SettingsProviderHierachy();
+ settingsHierachy_->addProviderToTopOfStack(xmlSettings_);
+ settingsHierachy_->addProviderToTopOfStack(qtSettings_);
+
+ networkFactories_.getTLSContextFactory()->setDisconnectOnCardRemoval(settingsHierachy_->getSetting(SettingConstants::DISCONNECT_ON_CARD_REMOVAL));
+
+ std::map<std::string, std::string> emoticons;
+ loadEmoticonsFile(":/emoticons/emoticons.txt", emoticons);
+ loadEmoticonsFile(P2QSTRING(pathToString(Paths::getExecutablePath() / "emoticons.txt")), emoticons);
+
+ if (options.count("netbook-mode")) {
+ splitter_ = new QtSingleWindow(qtSettings_);
+ } else {
+ splitter_ = nullptr;
+ }
+
+ int numberOfAccounts = 1;
+ try {
+ numberOfAccounts = options["multi-account"].as<int>();
+ } catch (...) {
+ /* This seems to fail on a Mac when the .app is launched directly (the usual path).*/
+ numberOfAccounts = 1;
+ }
+
+ if (options.count("debug")) {
+ Log::setLogLevel(Swift::Log::debug);
+ }
+
+ // Load fonts
+ std::vector<std::string> fontNames = {
+ "themes/Default/Lato2OFL/Lato-Black.ttf",
+ "themes/Default/Lato2OFL/Lato-BlackItalic.ttf",
+ "themes/Default/Lato2OFL/Lato-Bold.ttf",
+ "themes/Default/Lato2OFL/Lato-BoldItalic.ttf",
+ "themes/Default/Lato2OFL/Lato-Hairline.ttf",
+ "themes/Default/Lato2OFL/Lato-HairlineItalic.ttf",
+ "themes/Default/Lato2OFL/Lato-Heavy.ttf",
+ "themes/Default/Lato2OFL/Lato-HeavyItalic.ttf",
+ "themes/Default/Lato2OFL/Lato-Italic.ttf",
+ "themes/Default/Lato2OFL/Lato-Light.ttf",
+ "themes/Default/Lato2OFL/Lato-LightItalic.ttf",
+ "themes/Default/Lato2OFL/Lato-Medium.ttf",
+ "themes/Default/Lato2OFL/Lato-MediumItalic.ttf",
+ "themes/Default/Lato2OFL/Lato-Regular.ttf",
+ "themes/Default/Lato2OFL/Lato-Semibold.ttf",
+ "themes/Default/Lato2OFL/Lato-SemiboldItalic.ttf",
+ "themes/Default/Lato2OFL/Lato-Thin.ttf",
+ "themes/Default/Lato2OFL/Lato-ThinItalic.ttf"
+ };
+
+ for (auto&& fontName : fontNames) {
+ std::string fontPath = std::string(":/") + fontName;
+ int error = QFontDatabase::addApplicationFont(P2QSTRING(fontPath));
+ assert((error != -1) && "Failed to load font.");
+ }
+
+ bool enableAdHocCommandOnJID = options.count("enable-jid-adhocs") > 0;
+ tabs_ = nullptr;
+ if (options.count("no-tabs") && !splitter_) {
+ tabs_ = new QtChatTabsShortcutOnlySubstitute();
+ }
+ else {
+ tabs_ = new QtChatTabs(splitter_ != nullptr, settingsHierachy_, true);
+ }
+ bool startMinimized = options.count("start-minimized") > 0;
+ applicationPathProvider_ = new PlatformApplicationPathProvider(SWIFT_APPLICATION_NAME);
+ storagesFactory_ = new FileStoragesFactory(applicationPathProvider_->getDataDir(), networkFactories_.getCryptoProvider());
+ certificateStorageFactory_ = new CertificateFileStorageFactory(applicationPathProvider_->getDataDir(), tlsFactories_.getCertificateFactory(), networkFactories_.getCryptoProvider());
+ chatWindowFactory_ = new QtChatWindowFactory(splitter_, settingsHierachy_, qtSettings_, tabs_, ":/themes/Default/", emoticons);
+ soundPlayer_ = new QtSoundPlayer(applicationPathProvider_);
+
+ // Ugly, because the dock depends on the tray, but the temporary
+ // multi-account hack creates one tray per account.
+ QtSystemTray* systemTray = new QtSystemTray();
+ systemTrays_.push_back(systemTray);
#if defined(HAVE_GROWL)
- notifier_ = new GrowlNotifier(SWIFT_APPLICATION_NAME);
+ notifier_ = new GrowlNotifier(SWIFT_APPLICATION_NAME);
#elif defined(SWIFTEN_PLATFORM_WINDOWS)
- notifier_ = new WindowsNotifier(SWIFT_APPLICATION_NAME, applicationPathProvider_->getResourcePath("/images/logo-icon-32.png"), systemTray->getQSystemTrayIcon());
+ notifier_ = new WindowsNotifier(SWIFT_APPLICATION_NAME, applicationPathProvider_->getResourcePath("/images/logo-icon-32.png"), systemTray->getQSystemTrayIcon());
#elif defined(SWIFTEN_PLATFORM_LINUX)
- notifier_ = new FreeDesktopNotifier(SWIFT_APPLICATION_NAME);
+ notifier_ = new FreeDesktopNotifier(SWIFT_APPLICATION_NAME);
#elif defined(SWIFTEN_PLATFORM_MACOSX)
- notifier_ = new NotificationCenterNotifier();
+ notifier_ = new NotificationCenterNotifier();
#else
- notifier_ = new NullNotifier();
+ notifier_ = new NullNotifier();
#endif
#if defined(SWIFTEN_PLATFORM_MACOSX)
- dock_ = new MacOSXDock(&cocoaApplication_);
+ dock_ = new MacOSXDock(&cocoaApplication_);
#else
- dock_ = new NullDock();
+ dock_ = new NullDock();
#endif
#if defined(SWIFTEN_PLATFORM_MACOSX)
- uriHandler_ = new QtURIHandler();
+ uriHandler_ = new QtURIHandler();
#elif defined(SWIFTEN_PLATFORM_WIN32)
- uriHandler_ = new NullURIHandler();
+ uriHandler_ = new NullURIHandler();
#else
- uriHandler_ = new QtDBUSURIHandler();
+ uriHandler_ = new QtDBUSURIHandler();
#endif
- statusCache_ = new StatusCache(applicationPathProvider_);
-
- if (splitter_) {
- splitter_->show();
- }
-
- for (int i = 0; i < numberOfAccounts; i++) {
- if (i > 0) {
- // Don't add the first tray (see note above)
- systemTrays_.push_back(new QtSystemTray());
- }
- QtUIFactory* uiFactory = new QtUIFactory(settingsHierachy_, qtSettings_, tabs_, splitter_, systemTrays_[i], chatWindowFactory_, networkFactories_.getTimerFactory(), statusCache_, startMinimized, !emoticons.empty(), enableAdHocCommandOnJID);
- uiFactories_.push_back(uiFactory);
- MainController* mainController = new MainController(
- &clientMainThreadCaller_,
- &networkFactories_,
- uiFactory,
- settingsHierachy_,
- systemTrays_[i],
- soundPlayer_,
- storagesFactory_,
- certificateStorageFactory_,
- dock_,
- notifier_,
- uriHandler_,
- &idleDetector_,
- emoticons,
- options.count("latency-debug") > 0);
- mainControllers_.push_back(mainController);
- }
-
-
- // PlatformAutoUpdaterFactory autoUpdaterFactory;
- // if (autoUpdaterFactory.isSupported()) {
- // autoUpdater_ = autoUpdaterFactory.createAutoUpdater(SWIFT_APPCAST_URL);
- // autoUpdater_->checkForUpdates();
- // }
+ statusCache_ = new StatusCache(applicationPathProvider_);
+
+ if (splitter_) {
+ splitter_->show();
+ }
+
+ for (int i = 0; i < numberOfAccounts; i++) {
+ if (i > 0) {
+ // Don't add the first tray (see note above)
+ systemTrays_.push_back(new QtSystemTray());
+ }
+ QtUIFactory* uiFactory = new QtUIFactory(settingsHierachy_, qtSettings_, tabs_, splitter_, systemTrays_[i], chatWindowFactory_, networkFactories_.getTimerFactory(), statusCache_, startMinimized, !emoticons.empty(), enableAdHocCommandOnJID);
+ uiFactories_.push_back(uiFactory);
+ MainController* mainController = new MainController(
+ &clientMainThreadCaller_,
+ &networkFactories_,
+ uiFactory,
+ settingsHierachy_,
+ systemTrays_[i],
+ soundPlayer_,
+ storagesFactory_,
+ certificateStorageFactory_,
+ dock_,
+ notifier_,
+ uriHandler_,
+ &idleDetector_,
+ emoticons,
+ options.count("latency-debug") > 0);
+ mainControllers_.push_back(mainController);
+ }
+
+ connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(handleAboutToQuit()));
+
+ PlatformAutoUpdaterFactory autoUpdaterFactory;
+ if (autoUpdaterFactory.isSupported() && settingsHierachy_->getSetting(QtUISettingConstants::ENABLE_SOFTWARE_UPDATES)
+ && !settingsHierachy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL).empty()) {
+ autoUpdater_ = autoUpdaterFactory.createAutoUpdater(updateChannelToFeed(settingsHierachy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL)));
+ autoUpdater_->checkForUpdates();
+ autoUpdater_->onSuggestRestartToUserToUpdate.connect(boost::bind(&QtSwift::handleRecommendRestartToInstallUpdate, this));
+
+ settingsHierachy_->onSettingChanged.connect([&](const std::string& path) {
+ if (path == QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL.getKey()) {
+ autoUpdater_->setAppcastFeed(updateChannelToFeed(settingsHierachy_->getSetting(QtUISettingConstants::SOFTWARE_UPDATE_CHANNEL)));
+ autoUpdater_->checkForUpdates();
+ }
+ });
+ }
}
QtSwift::~QtSwift() {
- delete autoUpdater_;
- foreach (QtUIFactory* factory, uiFactories_) {
- delete factory;
- }
- foreach (MainController* controller, mainControllers_) {
- delete controller;
- }
- delete notifier_;
- foreach (QtSystemTray* tray, systemTrays_) {
- delete tray;
- }
- delete tabs_;
- delete splitter_;
- delete settingsHierachy_;
- delete qtSettings_;
- delete xmlSettings_;
- delete statusCache_;
- delete uriHandler_;
- delete dock_;
- delete soundPlayer_;
- delete chatWindowFactory_;
- delete certificateStorageFactory_;
- delete storagesFactory_;
- delete applicationPathProvider_;
+ delete autoUpdater_;
+ for (auto* factory : uiFactories_) {
+ delete factory;
+ }
+ for (auto* controller : mainControllers_) {
+ delete controller;
+ }
+ delete notifier_;
+ for (auto* tray : systemTrays_) {
+ delete tray;
+ }
+ delete tabs_;
+ delete splitter_;
+ delete settingsHierachy_;
+ delete qtSettings_;
+ delete xmlSettings_;
+ delete statusCache_;
+ delete uriHandler_;
+ delete dock_;
+ delete soundPlayer_;
+ delete chatWindowFactory_;
+ delete certificateStorageFactory_;
+ delete storagesFactory_;
+ delete applicationPathProvider_;
+}
+
+void QtSwift::handleAboutToQuit() {
+#if defined(SWIFTEN_PLATFORM_MACOSX)
+ // This is required so Sparkle knows about the application shutting down
+ // and can update the application in background.
+ CocoaUIHelpers::sendCocoaApplicationWillTerminateNotification();
+#endif
+}
+
+void QtSwift::handleRecommendRestartToInstallUpdate() {
+ notifier_->showMessage(Notifier::SystemMessage, Q2PSTRING(tr("Swift Update Available")), Q2PSTRING(tr("Restart Swift to update to the new Swift version.")), "", [](){});
}
}