Commit 568e80b5 authored by Thomas Hartmann's avatar Thomas Hartmann

QmlDesigner: get tests compiling and running

105 passing, 1 failing, one test seems flaky
I skip many nodeinstance/puppet related tests,
because the tests/test framework cannot deal with the qml2puppet/emulation
layer being out of process.

Change-Id: I5b254c7e6e944b8fbd8ba490c1e8bb43d0eb38c3
Reviewed-by: default avatarTim Jenssen <tim.jenssen@theqtcompany.com>
parent ec80aa80
......@@ -33,7 +33,9 @@
#include <QCoreApplication>
#include <coreplugin/messagebox.h>
#ifndef QMLDESIGNER_TEST
#include <qmldesignerplugin.h>
#endif
/*!
\defgroup CoreExceptions
......@@ -86,9 +88,13 @@ bool Exception::shouldAssert()
bool Exception::warnAboutException()
{
#ifndef QMLDESIGNER_TEST
static bool warnException = !QmlDesignerPlugin::instance()->settings().value(
DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT).toBool();
DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT).toBool();
return warnException;
#else
return true;
#endif
}
/*!
......
......@@ -56,7 +56,11 @@
#include <nodeinstanceview.h>
#include <import.h>
#include <rewriterview.h>
#ifndef QMLDESIGNER_TEST
#include <qmldesignerplugin.h>
#endif
#include <coreplugin/icore.h>
#include <utils/hostosinfo.h>
......@@ -82,11 +86,13 @@ namespace QmlDesigner {
static void showCannotConnectToPuppetWarningAndSwitchToEditMode()
{
#ifndef QMLDESIGNER_TEST
Core::AsynchronousMessageBox::warning(QCoreApplication::translate("NodeInstanceServerProxy", "Cannot Connect to QML Emulation Layer (QML Puppet)"),
QCoreApplication::translate("NodeInstanceServerProxy", "The executable of the QML emulation layer (QML Puppet) may not be responding. "
"Switching to another kit might help."));
QCoreApplication::translate("NodeInstanceServerProxy", "The executable of the QML emulation layer (QML Puppet) may not be responding. "
"Switching to another kit might help."));
QmlDesignerPlugin::instance()->switchToTextModeDeferred();
#endif
}
......@@ -184,7 +190,9 @@ NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceV
Core::AsynchronousMessageBox::warning(tr("Cannot Start QML Emulation Layer (QML Puppet)"),
tr("The executable of the QML emulation layer (QML Puppet) process cannot be started or does not respond."));
#ifndef QMLDESIGNER_TEST
QmlDesignerPlugin::instance()->switchToTextModeDeferred();
#endif
}
m_localServer->close();
......@@ -197,6 +205,7 @@ NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceV
qDebug() << "file is open: " << isOpen;
}
#ifndef QMLDESIGNER_TEST
DesignerSettings settings = QmlDesignerPlugin::instance()->settings();
int timeOutTime = settings.value(DesignerSettingsKey::PUPPET_KILL_TIMEOUT).toInt();
m_firstTimer.setInterval(timeOutTime);
......@@ -209,6 +218,7 @@ NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceV
connect(&m_secondTimer, SIGNAL(timeout()), this, SLOT(processFinished()));
connect(&m_thirdTimer, SIGNAL(timeout()), this, SLOT(processFinished()));
}
#endif
}
NodeInstanceServerProxy::~NodeInstanceServerProxy()
......
......@@ -25,13 +25,13 @@
#include "puppetcreator.h"
#include <QProcess>
#include <QTemporaryDir>
#include <QCoreApplication>
#include <QCryptographicHash>
#include <QDateTime>
#include <QMessageBox>
#include <QThread>
#include "puppetbuildprogressdialog.h"
#include <model.h>
#ifndef QMLDESIGNER_TEST
#include <qmldesignerplugin.h>
#endif
#include <projectexplorer/kit.h>
#include <projectexplorer/toolchain.h>
......@@ -43,9 +43,13 @@
#include <qtsupport/qtsupportconstants.h>
#include <coreplugin/icore.h>
#include <qmldesignerplugin.h>
#include "puppetbuildprogressdialog.h"
#include <QProcess>
#include <QTemporaryDir>
#include <QCoreApplication>
#include <QCryptographicHash>
#include <QDateTime>
#include <QMessageBox>
#include <QThread>
namespace QmlDesigner {
......@@ -103,16 +107,22 @@ QDateTime PuppetCreator::puppetSourceLastModified() const
bool PuppetCreator::useOnlyFallbackPuppet() const
{
#ifndef QMLDESIGNER_TEST
return m_designerSettings.value(DesignerSettingsKey::USE_ONLY_FALLBACK_PUPPET
).toBool() || m_kit == 0 || !m_kit->isValid();
).toBool() || m_kit == 0 || !m_kit->isValid();
#else
return true;
#endif
}
PuppetCreator::PuppetCreator(ProjectExplorer::Kit *kit, const QString &qtCreatorVersion, const Model *model)
: m_qtCreatorVersion(qtCreatorVersion),
m_kit(kit),
m_availablePuppetType(FallbackPuppet),
m_model(model),
m_designerSettings(QmlDesignerPlugin::instance()->settings())
: m_qtCreatorVersion(qtCreatorVersion)
,m_kit(kit)
,m_availablePuppetType(FallbackPuppet)
,m_model(model)
#ifndef QMLDESIGNER_TEST
,m_designerSettings(QmlDesignerPlugin::instance()->settings())
#endif
{
}
......@@ -152,8 +162,12 @@ QProcess *PuppetCreator::puppetProcess(const QString &puppetPath,
QObject::connect(QCoreApplication::instance(), SIGNAL(aboutToQuit()), puppetProcess, SLOT(kill()));
QObject::connect(puppetProcess, SIGNAL(finished(int,QProcess::ExitStatus)), handlerObject, finishSlot);
#ifndef QMLDESIGNER_TEST
QString forwardOutput = m_designerSettings.value(DesignerSettingsKey::
FORWARD_PUPPET_OUTPUT).toString();
#else
QString forwardOutput(QLatin1String("all"));
#endif
if (forwardOutput == puppetMode || forwardOutput == QLatin1String("all")) {
puppetProcess->setProcessChannelMode(QProcess::MergedChannels);
QObject::connect(puppetProcess, SIGNAL(readyRead()), handlerObject, outputSlot);
......@@ -161,8 +175,12 @@ QProcess *PuppetCreator::puppetProcess(const QString &puppetPath,
puppetProcess->setWorkingDirectory(workingDirectory);
puppetProcess->start(puppetPath, QStringList() << socketToken << puppetMode << QLatin1String("-graphicssystem raster"));
#ifndef QMLDESIGNER_TEST
QString debugPuppet = m_designerSettings.value(DesignerSettingsKey::
DEBUG_PUPPET).toString();
#else
QString debugPuppet(QLatin1String("all"));
#endif
if (debugPuppet == puppetMode || debugPuppet == QLatin1String("all")) {
QMessageBox::information(Core::ICore::dialogParent(),
QStringLiteral("Puppet is starting ..."),
......@@ -281,11 +299,15 @@ QString PuppetCreator::defaultPuppetToplevelBuildDirectory()
QString PuppetCreator::qmlPuppetToplevelBuildDirectory() const
{
#ifndef QMLDESIGNER_TEST
QString puppetToplevelBuildDirectory = m_designerSettings.value(
DesignerSettingsKey::PUPPET_TOPLEVEL_BUILD_DIRECTORY).toString();
DesignerSettingsKey::PUPPET_TOPLEVEL_BUILD_DIRECTORY).toString();
if (puppetToplevelBuildDirectory.isEmpty())
return defaultPuppetToplevelBuildDirectory();
return puppetToplevelBuildDirectory;
#else
return QString();
#endif
}
QString PuppetCreator::qmlPuppetDirectory(PuppetType puppetType) const
......@@ -307,11 +329,15 @@ QString PuppetCreator::defaultPuppetFallbackDirectory()
QString PuppetCreator::qmlPuppetFallbackDirectory() const
{
#ifndef QMLDESIGNER_TEST
QString puppetFallbackDirectory = m_designerSettings.value(
DesignerSettingsKey::PUPPET_FALLBACK_DIRECTORY).toString();
if (puppetFallbackDirectory.isEmpty())
return defaultPuppetFallbackDirectory();
return puppetFallbackDirectory;
#else
return QString();
#endif
}
QString PuppetCreator::qml2PuppetPath(PuppetType puppetType) const
......@@ -333,8 +359,12 @@ QProcessEnvironment PuppetCreator::processEnvironment() const
environment.set(QLatin1String("QML_USE_MOCKUPS"), QLatin1String("true"));
environment.set(QLatin1String("QML_PUPPET_MODE"), QLatin1String("true"));
#ifndef QMLDESIGNER_TEST
const QString controlsStyle = m_designerSettings.value(DesignerSettingsKey::
CONTROLS_STYLE).toString();
#else
const QString controlsStyle;
#endif
if (!controlsStyle.isEmpty())
environment.set(QLatin1String("QT_QUICK_CONTROLS_STYLE"), controlsStyle);
......
......@@ -114,7 +114,9 @@ private:
PuppetType m_availablePuppetType;
static QHash<Core::Id, PuppetType> m_qml2PuppetForKitPuppetHash;
const Model *m_model;
#ifndef QMLDESIGNER_TEST
const DesignerSettings m_designerSettings;
#endif
QString m_qrcMapping;
};
......
......@@ -83,6 +83,7 @@ void MetaInfoPrivate::initialize()
void MetaInfoPrivate::parseItemLibraryDescriptions()
{
#ifndef QMLDESIGNER_TEST
Internal::WidgetPluginManager pluginManager;
foreach (const QString &pluginDir, m_q->s_pluginDirs)
pluginManager.addPath(pluginDir);
......@@ -98,6 +99,7 @@ void MetaInfoPrivate::parseItemLibraryDescriptions()
errorMessage);
}
}
#endif
}
} // namespace Internal
......
......@@ -1958,9 +1958,14 @@ The view is informed that it has been registered within the model by a call to A
void Model::attachView(AbstractView *view)
{
// Internal::WriteLocker locker(d);
RewriterView *rewriterView = qobject_cast<RewriterView*>(view);
if (rewriterView)
RewriterView *castedRewriterView = qobject_cast<RewriterView*>(view);
if (castedRewriterView) {
if (rewriterView() == castedRewriterView)
return;
setRewriterView(castedRewriterView);
return;
}
NodeInstanceView *nodeInstanceView = qobject_cast<NodeInstanceView*>(view);
if (nodeInstanceView)
......
......@@ -84,9 +84,13 @@ bool QmlModelNodeFacade::isValid() const
bool QmlModelNodeFacade::isValidQmlModelNodeFacade(const ModelNode &modelNode)
{
return modelNode.isValid()
#ifndef QMLDESIGNER_TEST //This is a hack to keep tests working without instances
&& nodeInstanceView(modelNode)
&& nodeInstanceView(modelNode)->hasInstanceForModelNode(modelNode)
&& nodeInstanceView(modelNode)->instanceForModelNode(modelNode).isValid();
#else
;
#endif
}
bool QmlModelNodeFacade::isRootNode() const
......
......@@ -35,7 +35,9 @@
#include "bindingproperty.h"
#include "nodelistproperty.h"
#include "nodeinstanceview.h"
#ifndef QMLDESIGNER_TEST
#include <qmldesignerplugin.h>
#endif
namespace QmlDesigner {
......@@ -463,11 +465,16 @@ QVariant QmlObjectNode::instanceValue(const ModelNode &modelNode, const Property
QString QmlObjectNode::generateTranslatableText(const QString &text)
{
#ifndef QMLDESIGNER_TEST
if (QmlDesignerPlugin::instance()->settings().value(
DesignerSettingsKey::USE_QSTR_FUNCTION).toBool())
return QString(QStringLiteral("qsTr(\"%1\")")).arg(text);
else
return QString(QStringLiteral("qsTrId(\"%1\")")).arg(text);
#else
Q_UNUSED(text);
return QString();
#endif
}
TypeName QmlObjectNode::instanceType(const PropertyName &name) const
......
......@@ -25,6 +25,8 @@
#include "viewmanager.h"
#ifndef QMLDESIGNER_TEST
#include <rewriterview.h>
#include <nodeinstanceview.h>
#include <itemlibraryview.h>
......@@ -44,7 +46,6 @@
#include <qmldesigner/qmldesignerplugin.h>
#include <utils/algorithm.h>
namespace QmlDesigner {
class ViewManagerData
......@@ -307,3 +308,5 @@ Model *ViewManager::documentModel() const
}
} // namespace QmlDesigner
#endif //QMLDESIGNER_TEST
......@@ -25,8 +25,13 @@
#include "rewritertransaction.h"
#include <abstractview.h>
#ifndef QMLDESIGNER_TEST
#include <designdocument.h>
#include <qmldesignerplugin.h>
#endif
#include <QDebug>
namespace QmlDesigner {
......@@ -88,8 +93,10 @@ void RewriterTransaction::rollback()
if (m_valid) {
m_valid = false;
view()->emitRewriterEndTransaction();
QmlDesignerPlugin::instance()->currentDesignDocument()->undo();
#ifndef QMLDESIGNER_TEST
QmlDesignerPlugin::instance()->currentDesignDocument()->undo();
#endif
if (m_activeIdentifier) {
qDebug() << "Rollback RewriterTransaction:" << m_identifier << m_identifierNumber;
m_identifierList.removeOne(m_identifier + QByteArrayLiteral("-") + QByteArray::number(m_identifierNumber));
......
......@@ -47,15 +47,15 @@
static ModelNode addNodeListChild(const ModelNode &parentNode, const QString &typeName, int major, int minor, const QString &parentProperty)
{
ModelNode newNode = parentNode.view()->createModelNode(typeName, major, minor);
parentNode.nodeListProperty(parentProperty).reparentHere(newNode);
ModelNode newNode = parentNode.view()->createModelNode(typeName.toUtf8(), major, minor);
parentNode.nodeListProperty(parentProperty.toUtf8()).reparentHere(newNode);
return newNode;
}
static ModelNode addNodeChild(const ModelNode &parentNode, const QString &typeName, int major, int minor, const QString &parentProperty)
{
ModelNode newNode = parentNode.view()->createModelNode(typeName, major, minor);
parentNode.nodeProperty(parentProperty).reparentHere(newNode);
ModelNode newNode = parentNode.view()->createModelNode(typeName.toUtf8(), major, minor);
parentNode.nodeProperty(parentProperty.toUtf8()).reparentHere(newNode);
return newNode;
}
......@@ -104,8 +104,8 @@ static bool compareTree(const ModelNode &node1, const ModelNode &node2)
// Compare list of children
{
const QList<ModelNode> childList1 = node1.allDirectSubModelNodes();
const QList<ModelNode> childList2 = node2.allDirectSubModelNodes();
const QList<ModelNode> childList1 = node1.directSubModelNodes();
const QList<ModelNode> childList2 = node2.directSubModelNodes();
QList<ModelNode>::const_iterator iter1;
QList<ModelNode>::const_iterator iter2;
......
IDE_SOURCE_TREE=$$PWD/../../../../..
IDE_BUILD_TREE=$$OUT_PWD/../../../../..
# can we check that this is a valid build dir?
OUT_PWD_SAVE=$$OUT_PWD
OUT_PWD=IDE_BUILD_TREE
include($$IDE_SOURCE_TREE/src/plugins/qmldesigner/config.pri)
include(../../../qttest.pri)
OUT_PWD=$$OUT_PWD_SAVE
LIBS *= -L$$IDE_PLUGIN_PATH
LIBS *= -L$$IDE_LIBRARY_PATH
QTC_LIB_DEPENDS += \
utils \
qmljs \
qmleditorwidgets \
cplusplus
unix: QMAKE_LFLAGS += \'-Wl,-rpath,$${IDE_LIBRARY_PATH}\' \'-Wl,-rpath,$${IDE_PLUGIN_PATH}\'
QTC_PLUGIN_DEPENDS += \
coreplugin \
qmljseditor
QT += script \
network
include(../../../qttest.pri)
include($$IDE_SOURCE_TREE/src/plugins/qmldesigner/config.pri)
QT += network core-private
greaterThan(QT_MAJOR_VERSION, 4) {
QT += printsupport
......@@ -22,22 +21,26 @@ greaterThan(QT_MAJOR_VERSION, 4) {
contains(QT_CONFIG, webkit): QT += webkit
}
# DEFINES+=QTCREATOR_UTILS_STATIC_LIB QML_BUILD_STATIC_LIB
DEFINES+=QTCREATORDIR=\\\"$$IDE_BUILD_TREE\\\"
DEFINES += QTCREATOR_TEST QMLDESIGNER_TEST
DEFINES += QTCREATOR_TEST
DEFINES += QMLDESIGNER_TEST
DEFINES += QT_RESTRICTED_CAST_FROM_ASCII
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/designercore/include
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/designercore
INCLUDEPATH += $$IDE_SOURCE_TREE//share/qtcreator/qml/qmlpuppet
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/components/integration
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/components/componentcore
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/components/itemlibrary
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/components/navigator
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/components/stateseditor
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/components/formeditor
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/components/propertyeditor
INCLUDEPATH += $$IDE_SOURCE_TREE/src/plugins/qmldesigner/components/debugview
INCLUDEPATH *= $$IDE_SOURCE_TREE/src/libs/3rdparty
include($$IDE_SOURCE_TREE/src/plugins/qmldesigner/designercore/designercore-lib.pri)
include($$IDE_SOURCE_TREE/src/plugins/qmljstools/qmljstools.pri)
include($$IDE_SOURCE_TREE/src/libs/utils/utils.pri)
include($$IDE_SOURCE_TREE/src/libs/qmljs/qmljs.pri)
include($$IDE_SOURCE_TREE/src/libs/cplusplus/cplusplus.pri)
CONFIG += console
CONFIG -= app_bundle
......
@set path=%PATH%;%CD%\..\..\..\..\..\lib\qtcreator\plugins\
@set path=%PATH%;%CD%\..\..\..\..\..\lib\qtcreator\plugins\;%CD%\..\..\..\..\..\lib\qtcreator\;
......@@ -26,6 +26,8 @@
#include "testrewriterview.h"
#include <QObject>
#include <nodeproperty.h>
#include <nodelistproperty.h>
#include <variantproperty.h>
using namespace QmlDesigner;
using namespace QmlDesigner::Internal;
......@@ -82,6 +84,8 @@ TestRewriterView::TestRewriterView(QObject *parent,
DifferenceHandling differenceHandling)
: RewriterView(differenceHandling, parent)
{
//Unit tests do not like the semantic errors
setCheckSemanticErrors(false);
}
bool TestRewriterView::isModificationGroupActive() const
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -23,7 +23,7 @@
**
****************************************************************************/
import Qt 4.7
import QtQuick 1.0
Rectangle {
property string text: "test"
......
......@@ -23,7 +23,7 @@
**
****************************************************************************/
import Qt 4.7
import QtQuick 1.0
Item {
MyButton { }
......
This diff is collapsed.
......@@ -25,12 +25,15 @@
#pragma once
#include <qmlmodelview.h>
#include <abstractview.h>
#include <nodeinstanceview.h>
#include <QVariant>
#include <QStringList>
#include <model.h>
#include <qmlobjectnode.h>
#include <qmlitemnode.h>
class TestView : public QmlDesigner::QmlModelView
class TestView : public QmlDesigner::AbstractView
{
Q_OBJECT
public:
......@@ -52,12 +55,17 @@ public:
void nodeAboutToBeRemoved(const QmlDesigner::ModelNode &removedNode);
void nodeRemoved(const QmlDesigner::ModelNode &removedNode, const QmlDesigner::NodeAbstractProperty &parentProperty, AbstractView::PropertyChangeFlags propertyChange);
void nodeReparented(const QmlDesigner::ModelNode &node, const QmlDesigner::NodeAbstractProperty &newPropertyParent, const QmlDesigner::NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
void nodeAboutToBeReparented(const QmlDesigner::ModelNode &node, const QmlDesigner::NodeAbstractProperty &newPropertyParent, const QmlDesigner::NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange);
void nodeIdChanged(const QmlDesigner::ModelNode& node, const QString& newId, const QString& oldId);
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion);
void bindingPropertiesChanged(const QList<QmlDesigner::BindingProperty>& propertyList, PropertyChangeFlags propertyChange);
void variantPropertiesChanged(const QList<QmlDesigner::VariantProperty>& propertyList, PropertyChangeFlags propertyChange);
void propertiesAboutToBeRemoved(const QList<QmlDesigner::AbstractProperty> &propertyList);
void propertiesRemoved(const QList<QmlDesigner::AbstractProperty>& propertyList);
void signalHandlerPropertiesChanged(const QVector<QmlDesigner::SignalHandlerProperty>& propertyList, PropertyChangeFlags propertyChange);
void importsChanged(const QList<QmlDesigner::Import> &addedImports, const QList<QmlDesigner::Import> &removedImports);
......@@ -67,14 +75,41 @@ public:
void nodeOrderChanged(const QmlDesigner::NodeListProperty &listProperty, const QmlDesigner::ModelNode &movedNode, int oldIndex);
void actualStateChanged(const QmlDesigner::ModelNode &node);
virtual void instancePropertyChange(const QList<QPair<QmlDesigner::ModelNode, QmlDesigner::PropertyName> > &propertyList);
virtual void instancesCompleted(const QVector<QmlDesigner::ModelNode> &completedNodeList);
virtual void instanceInformationsChange(const QMultiHash<QmlDesigner::ModelNode, QmlDesigner::InformationName> &informationChangeHash);
virtual void instancesRenderImageChanged(const QVector<QmlDesigner::ModelNode> &nodeList);
virtual void instancesPreviewImageChanged(const QVector<QmlDesigner::ModelNode> &nodeList);
virtual void instancesChildrenChanged(const QVector<QmlDesigner::ModelNode> &nodeList);
virtual void instancesToken(const QString &tokenName, int tokenNumber, const QVector<QmlDesigner::ModelNode> &nodeVector);
virtual void nodeSourceChanged(const QmlDesigner::ModelNode &modelNode, const QString &newNodeSource);
virtual void rewriterBeginTransaction() {}
virtual void rewriterEndTransaction() {}
void scriptFunctionsChanged(const QmlDesigner::ModelNode &node, const QStringList &scriptFunctionList);
void currentStateChanged(const QmlDesigner::ModelNode &node);
QList<MethodCall> &methodCalls();
QString lastFunction() const;
QmlDesigner::NodeInstanceView *nodeInstanceView() const;
QmlDesigner::NodeInstance instanceForModelNode(const QmlDesigner::ModelNode &modelNode);
QmlDesigner::QmlObjectNode rootQmlObjectNode() const;
void setCurrentState(const QmlDesigner::QmlModelState &node);
QmlDesigner::QmlItemNode rootQmlItemNode() const;
QmlDesigner::QmlModelState baseState() const;
QmlDesigner::QmlObjectNode createQmlObjectNode(const QmlDesigner::TypeName &typeName,
int majorVersion,
int minorVersion,
const QmlDesigner::PropertyListType &propertyList = QmlDesigner::PropertyListType());
private:
QList<MethodCall> m_methodCalls;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment