Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
KDevelop
KDevelop
Commits
8c1619e7
Commit
8c1619e7
authored
Aug 28, 2022
by
Milian Wolff
Browse files
Port qmakemanager away from Qt foreach
parent
54f66a0a
Pipeline
#224245
passed with stage
in 24 minutes and 34 seconds
Changes
11
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
plugins/qmakemanager/CMakeLists.txt
View file @
8c1619e7
add_definitions
(
-DTRANSLATION_DOMAIN=\"kdevqmakemanager\"
)
remove_definitions
(
-DQT_NO_FOREACH
)
declare_qt_logging_category
(
qmakecommon_LOG_SRCS
TYPE PLUGIN
...
...
plugins/qmakemanager/parser/qmakeastdefaultvisitor.cpp
View file @
8c1619e7
...
...
@@ -15,7 +15,7 @@ ASTDefaultVisitor::~ASTDefaultVisitor()
void
ASTDefaultVisitor
::
visitProject
(
ProjectAST
*
node
)
{
for
each
(
StatementAST
*
stmt
,
node
->
statements
)
{
for
(
StatementAST
*
stmt
:
std
::
as_const
(
node
->
statements
)
)
{
visitNode
(
stmt
);
}
}
...
...
@@ -24,7 +24,7 @@ void ASTDefaultVisitor::visitAssignment(AssignmentAST* node)
{
visitNode
(
node
->
identifier
);
visitNode
(
node
->
op
);
for
each
(
ValueAST
*
value
,
node
->
values
)
{
for
(
ValueAST
*
value
:
std
::
as_const
(
node
->
values
)
)
{
visitNode
(
value
);
}
}
...
...
@@ -36,7 +36,7 @@ void ASTDefaultVisitor::visitValue(ValueAST*)
void
ASTDefaultVisitor
::
visitFunctionCall
(
FunctionCallAST
*
node
)
{
visitNode
(
node
->
identifier
);
for
each
(
ValueAST
*
value
,
node
->
args
)
{
for
(
ValueAST
*
value
:
std
::
as_const
(
node
->
args
)
)
{
visitNode
(
value
);
}
visitNode
(
node
->
body
);
...
...
@@ -44,17 +44,17 @@ void ASTDefaultVisitor::visitFunctionCall(FunctionCallAST* node)
void
ASTDefaultVisitor
::
visitScopeBody
(
ScopeBodyAST
*
node
)
{
for
each
(
StatementAST
*
stmt
,
node
->
ifStatements
)
{
for
(
StatementAST
*
stmt
:
std
::
as_const
(
node
->
ifStatements
)
)
{
visitNode
(
stmt
);
}
for
each
(
StatementAST
*
stmt
,
node
->
elseStatements
)
{
for
(
StatementAST
*
stmt
:
std
::
as_const
(
node
->
elseStatements
)
)
{
visitNode
(
stmt
);
}
}
void
ASTDefaultVisitor
::
visitOr
(
OrAST
*
node
)
{
for
each
(
ScopeAST
*
scope
,
node
->
scopes
)
{
for
(
ScopeAST
*
scope
:
std
::
as_const
(
node
->
scopes
)
)
{
visitNode
(
scope
);
}
visitNode
(
node
->
body
);
...
...
plugins/qmakemanager/parser/tests/assignmenttest.cpp
View file @
8c1619e7
...
...
@@ -66,7 +66,7 @@ BEGINTESTFUNCIMPL(AssignmentTest, quotedValEscapeQuote, 1)
QMake
::
AssignmentAST
*
assignment
;
assignment
=
dynamic_cast
<
QMake
::
AssignmentAST
*>
(
ast
->
statements
.
first
());
qDebug
()
<<
assignment
->
values
.
count
();
for
each
(
QMake
::
ValueAST
*
v
,
assignment
->
values
)
for
(
QMake
::
ValueAST
*
v
:
std
::
as_const
(
assignment
->
values
)
)
qDebug
()
<<
v
->
value
;
TESTASSIGNMENT
(
assignment
,
"VARIABLE"
,
"+="
,
1
)
ENDTESTFUNCIMPL
...
...
plugins/qmakemanager/qmakecache.cpp
View file @
8c1619e7
...
...
@@ -21,7 +21,8 @@ void QMakeCache::setMkSpecs(QMakeMkSpecs* specs)
bool
QMakeCache
::
read
()
{
foreach
(
const
QString
&
var
,
m_mkspecs
->
variables
())
{
const
auto
vars
=
m_mkspecs
->
variables
();
for
(
const
auto
&
var
:
vars
)
{
m_variableValues
[
var
]
=
m_mkspecs
->
variableValues
(
var
);
}
return
QMakeFile
::
read
();
...
...
plugins/qmakemanager/qmakeconfig.cpp
View file @
8c1619e7
...
...
@@ -116,7 +116,7 @@ QString QMakeConfig::findBasicMkSpec(const QHash<QString, QString>& qmakeVars)
if
(
qmakeVars
.
contains
(
QStringLiteral
(
"QMAKE_MKSPECS"
)))
{
// qt4
const
auto
mkspecDirs
=
qmakeVars
[
QStringLiteral
(
"QMAKE_MKSPECS"
)].
split
(
QDir
::
listSeparator
());
for
each
(
const
QString
&
dir
,
mkspecDirs
)
{
for
(
const
auto
&
dir
:
mkspecDirs
)
{
paths
<<
dir
+
QLatin1String
(
"/default/qmake.conf"
);
}
}
else
if
(
!
qmakeVars
.
contains
(
QStringLiteral
(
"QMAKE_MKSPECS"
))
&&
qmakeVars
.
contains
(
QStringLiteral
(
"QMAKE_SPEC"
)))
{
...
...
@@ -141,7 +141,7 @@ QString QMakeConfig::findBasicMkSpec(const QHash<QString, QString>& qmakeVars)
paths
<<
path
;
}
for
each
(
const
QString
&
path
,
paths
)
{
for
(
const
auto
&
path
:
std
::
as_const
(
paths
)
)
{
QFileInfo
fi
(
path
);
if
(
fi
.
exists
())
return
fi
.
absoluteFilePath
();
...
...
plugins/qmakemanager/qmakefile.cpp
View file @
8c1619e7
...
...
@@ -33,8 +33,9 @@ QStringList resolveShellGlobbingInternal(const QStringList& segments, QDir& dir,
pathPattern
.
contains
(
QLatin1Char
(
'?'
))
||
pathPattern
.
contains
(
QLatin1Char
(
'['
)))
{
// pattern contains globbing chars
foreach
(
const
QFileInfo
&
match
,
dir
.
entryInfoList
(
QStringList
()
<<
pathPattern
,
QDir
::
AllEntries
|
QDir
::
NoDotAndDotDot
,
QDir
::
Unsorted
))
{
const
auto
dirEntries
=
dir
.
entryInfoList
(
QStringList
()
<<
pathPattern
,
QDir
::
AllEntries
|
QDir
::
NoDotAndDotDot
,
QDir
::
Unsorted
);
for
(
const
auto
&
match
:
dirEntries
)
{
resolveShellGlobbingInternal
(
entries
,
segments
,
match
,
dir
,
offset
);
}
}
else
{
...
...
plugins/qmakemanager/qmakefilevisitor.cpp
View file @
8c1619e7
...
...
@@ -94,7 +94,8 @@ void QMakeFileVisitor::visitFunctionCall(QMake::FunctionCallAST* node)
ifDebug
(
qCDebug
(
KDEV_QMAKE
)
<<
"successfully read:"
<<
read
;)
if
(
read
)
{
// TODO: optimize by using variableMap and iterator, don't compare values
foreach
(
const
QString
&
var
,
includefile
.
variables
())
{
const
auto
vars
=
includefile
.
variables
();
for
(
const
auto
&
var
:
vars
)
{
if
(
m_variableValues
.
value
(
var
)
!=
includefile
.
variableValues
(
var
))
{
m_variableValues
[
var
]
=
includefile
.
variableValues
(
var
);
}
...
...
@@ -167,14 +168,15 @@ QStringList QMakeFileVisitor::resolveVariables(const QString& var) const
qCWarning
(
KDEV_QMAKE
)
<<
"Couldn't parse"
<<
var
<<
"to replace variables in it"
;
return
QStringList
()
<<
var
;
}
if
(
parser
.
variableReferences
().
isEmpty
())
{
const
auto
variableReferences
=
parser
.
variableReferences
();
if
(
variableReferences
.
isEmpty
())
{
return
QStringList
()
<<
var
;
}
/// TODO: multiple vars in one place will make the offsets go bonkers
QString
value
=
var
;
for
each
(
const
QString
&
variable
,
parser
.
variableReferences
()
)
{
VariableInf
o
vi
=
parser
.
variableInfo
(
variable
);
for
(
const
auto
&
variable
:
variableReferences
)
{
const
aut
o
vi
=
parser
.
variableInfo
(
variable
);
QString
varValue
;
switch
(
vi
.
type
)
{
...
...
@@ -200,7 +202,7 @@ QStringList QMakeFileVisitor::resolveVariables(const QString& var) const
case
VariableInfo
::
FunctionCall
:
{
QStringList
arguments
;
arguments
.
reserve
(
vi
.
positions
.
size
());
for
each
(
const
VariableInfo
::
Position
&
pos
,
vi
.
positions
)
{
for
(
const
auto
&
pos
:
vi
.
positions
)
{
int
start
=
pos
.
start
+
3
+
variable
.
length
();
QString
args
=
value
.
mid
(
start
,
pos
.
end
-
start
);
varValue
=
resolveVariables
(
args
).
join
(
QLatin1Char
(
' '
));
...
...
@@ -214,7 +216,7 @@ QStringList QMakeFileVisitor::resolveVariables(const QString& var) const
continue
;
}
for
each
(
const
VariableInfo
::
Position
&
pos
,
vi
.
positions
)
{
for
(
const
auto
&
pos
:
vi
.
positions
)
{
value
.
replace
(
pos
.
start
,
pos
.
end
-
pos
.
start
+
1
,
varValue
);
}
}
...
...
plugins/qmakemanager/qmakemanager.cpp
View file @
8c1619e7
...
...
@@ -104,7 +104,8 @@ Path QMakeProjectManager::buildDirectory(ProjectBaseItem* item) const
dir
=
QMakeConfig
::
buildDirFromSrc
(
qmakeItem
->
project
(),
qmakeItem
->
path
());
}
else
{
// build sub-item
foreach
(
QMakeProjectFile
*
pro
,
qmakeItem
->
projectFiles
())
{
const
auto
proFiles
=
qmakeItem
->
projectFiles
();
for
(
QMakeProjectFile
*
pro
:
proFiles
)
{
if
(
QDir
(
pro
->
absoluteDir
())
==
QFileInfo
(
qmakeItem
->
path
().
toUrl
().
toLocalFile
()
+
QLatin1Char
(
'/'
)).
absoluteDir
()
||
pro
->
hasSubProject
(
qmakeItem
->
path
().
toUrl
().
toLocalFile
()))
{
// get path from project root and it to buildDir
...
...
@@ -195,7 +196,8 @@ ProjectFolderItem* QMakeProjectManager::buildFolderItem(IProject* project, const
// TODO: multiple includes by different .pro's
QMakeProjectFile
*
parentPro
=
nullptr
;
foreach
(
QMakeProjectFile
*
p
,
qmakeParent
->
projectFiles
())
{
const
auto
proFiles
=
qmakeParent
->
projectFiles
();
for
(
QMakeProjectFile
*
p
:
proFiles
)
{
if
(
p
->
hasSubProject
(
absFile
))
{
parentPro
=
p
;
break
;
...
...
@@ -258,15 +260,18 @@ void QMakeProjectManager::slotFolderAdded(ProjectFolderItem* folder)
}
qCDebug
(
KDEV_QMAKE
)
<<
"adding targets for"
<<
folder
->
path
();
foreach
(
QMakeProjectFile
*
pro
,
qmakeParent
->
projectFiles
())
{
foreach
(
const
QString
&
s
,
pro
->
targets
())
{
const
auto
proFiles
=
qmakeParent
->
projectFiles
();
for
(
QMakeProjectFile
*
pro
:
proFiles
)
{
const
auto
targets
=
pro
->
targets
();
for
(
const
auto
&
s
:
targets
)
{
if
(
!
isValid
(
Path
(
folder
->
path
(),
s
),
false
,
folder
->
project
()))
{
continue
;
}
qCDebug
(
KDEV_QMAKE
)
<<
"adding target:"
<<
s
;
Q_ASSERT
(
!
s
.
isEmpty
());
auto
target
=
new
QMakeTargetItem
(
pro
,
folder
->
project
(),
s
,
folder
);
foreach
(
const
QString
&
path
,
pro
->
filesForTarget
(
s
))
{
const
auto
files
=
pro
->
filesForTarget
(
s
);
for
(
const
auto
&
path
:
files
)
{
new
ProjectFileItem
(
folder
->
project
(),
Path
(
path
),
target
);
/// TODO: signal?
}
...
...
@@ -314,9 +319,11 @@ void QMakeProjectManager::slotDirty(const QString& path)
}
bool
finished
=
false
;
foreach
(
ProjectFolderItem
*
folder
,
project
->
foldersForPath
(
IndexedString
(
KIO
::
upUrl
(
url
))))
{
const
auto
folders
=
project
->
foldersForPath
(
IndexedString
(
KIO
::
upUrl
(
url
)));
for
(
ProjectFolderItem
*
folder
:
folders
)
{
if
(
auto
*
qmakeFolder
=
dynamic_cast
<
QMakeFolderItem
*>
(
folder
))
{
foreach
(
QMakeProjectFile
*
pro
,
qmakeFolder
->
projectFiles
())
{
const
auto
proFiles
=
qmakeFolder
->
projectFiles
();
for
(
QMakeProjectFile
*
pro
:
proFiles
)
{
if
(
pro
->
absoluteFile
()
==
path
)
{
// TODO: children
// TODO: cache added
...
...
@@ -366,7 +373,8 @@ Path::List QMakeProjectManager::collectDirectories(ProjectBaseItem* item, const
Path
::
List
list
;
QMakeFolderItem
*
folder
=
findQMakeFolderParent
(
item
);
if
(
folder
)
{
foreach
(
QMakeProjectFile
*
pro
,
folder
->
projectFiles
())
{
const
auto
proFiles
=
folder
->
projectFiles
();
for
(
QMakeProjectFile
*
pro
:
proFiles
)
{
if
(
pro
->
files
().
contains
(
item
->
path
().
toLocalFile
()))
{
const
QStringList
directories
=
collectIncludes
?
pro
->
includeDirectories
()
:
pro
->
frameworkDirectories
();
for
(
const
QString
&
dir
:
directories
)
{
...
...
@@ -379,7 +387,8 @@ Path::List QMakeProjectManager::collectDirectories(ProjectBaseItem* item, const
}
if
(
list
.
isEmpty
())
{
// fallback for new files, use all possible include dirs
foreach
(
QMakeProjectFile
*
pro
,
folder
->
projectFiles
())
{
const
auto
proFiles
=
folder
->
projectFiles
();
for
(
QMakeProjectFile
*
pro
:
proFiles
)
{
const
QStringList
directories
=
collectIncludes
?
pro
->
includeDirectories
()
:
pro
->
frameworkDirectories
();
for
(
const
QString
&
dir
:
directories
)
{
Path
path
(
dir
);
...
...
@@ -416,8 +425,10 @@ QHash<QString, QString> QMakeProjectManager::defines(ProjectBaseItem* item) cons
// happens for bad qmake configurations
return
d
;
}
foreach
(
QMakeProjectFile
*
pro
,
folder
->
projectFiles
())
{
foreach
(
QMakeProjectFile
::
DefinePair
def
,
pro
->
defines
())
{
const
auto
proFiles
=
folder
->
projectFiles
();
for
(
QMakeProjectFile
*
pro
:
proFiles
)
{
const
auto
defines
=
pro
->
defines
();
for
(
const
auto
&
def
:
defines
)
{
d
.
insert
(
def
.
first
,
def
.
second
);
}
}
...
...
@@ -433,7 +444,8 @@ QString QMakeProjectManager::extraArguments(KDevelop::ProjectBaseItem *item) con
}
QStringList
d
;
foreach
(
QMakeProjectFile
*
pro
,
folder
->
projectFiles
())
{
const
auto
proFiles
=
folder
->
projectFiles
();
for
(
QMakeProjectFile
*
pro
:
proFiles
)
{
d
<<
pro
->
extraArguments
();
}
return
d
.
join
(
QLatin1Char
(
' '
));
...
...
plugins/qmakemanager/qmakeprojectfile.cpp
View file @
8c1619e7
...
...
@@ -71,17 +71,16 @@ bool QMakeProjectFile::read()
}
Q_ASSERT
(
m_mkspecs
);
foreach
(
const
QString
&
var
,
m_mkspecs
->
variables
())
{
if
(
!
m_variableValues
.
contains
(
var
))
{
m_variableValues
[
var
]
=
m_mkspecs
->
variableValues
(
var
);
}
}
if
(
m_cache
)
{
foreach
(
const
QString
&
var
,
m_cache
->
variables
())
{
if
(
!
m_variableValues
.
contains
(
var
))
{
m_variableValues
[
var
]
=
m_cache
->
variableValues
(
var
);
auto
addVars
=
[
&
](
const
auto
&
vars
)
{
for
(
auto
it
=
vars
.
begin
(),
end
=
vars
.
end
();
it
!=
end
;
++
it
)
{
if
(
!
m_variableValues
.
contains
(
it
.
key
()))
{
m_variableValues
.
insert
(
it
.
key
(),
it
.
value
());
}
}
};
addVars
(
m_mkspecs
->
variableMap
());
if
(
m_cache
)
{
addVars
(
m_cache
->
variableMap
());
}
/// TODO: more special variables
...
...
@@ -143,7 +142,8 @@ QStringList QMakeProjectFile::subProjects() const
bool
QMakeProjectFile
::
hasSubProject
(
const
QString
&
file
)
const
{
foreach
(
const
QString
&
sub
,
subProjects
())
{
const
auto
subs
=
subProjects
();
for
(
const
auto
&
sub
:
subs
)
{
if
(
sub
==
file
)
{
return
true
;
}
else
if
(
QFileInfo
(
file
).
absoluteDir
()
==
sub
)
{
...
...
@@ -189,7 +189,7 @@ QStringList QMakeProjectFile::includeDirectories() const
}
// TODO: This is all very fragile, should rather read QMake module .pri files (e.g. qt_lib_core_private.pri)
for
each
(
const
QString
&
module
,
modules
)
{
for
(
const
auto
&
module
:
std
::
as_const
(
modules
)
)
{
QString
pattern
=
module
;
bool
isPrivate
=
false
;
...
...
@@ -259,7 +259,8 @@ QStringList QMakeProjectFile::frameworkDirectories() const
QStringList
fwDirs
;
for
(
const
auto
&
var
:
variablesToCheck
)
{
bool
storeArg
=
false
;
foreach
(
const
auto
&
arg
,
variableValues
(
var
))
{
const
auto
values
=
variableValues
(
var
);
for
(
const
auto
&
arg
:
values
)
{
if
(
arg
==
fOption
||
arg
==
iframeworkOption
)
{
// detached -F/-iframework arg; set a warrant to store the next argument
storeArg
=
true
;
...
...
@@ -288,7 +289,8 @@ QStringList QMakeProjectFile::extraArguments() const
const
auto
prefixes
=
{
"-F"
,
"-iframework"
,
"-I"
,
"-D"
};
QStringList
args
;
for
(
const
auto
&
var
:
variablesToCheck
)
{
foreach
(
const
auto
&
arg
,
variableValues
(
var
))
{
const
auto
values
=
variableValues
(
var
);
for
(
const
auto
&
arg
:
values
)
{
auto
argHasPrefix
=
[
&
arg
](
const
char
*
prefix
)
{
return
arg
.
startsWith
(
QLatin1String
(
prefix
));
};
...
...
@@ -305,8 +307,9 @@ QStringList QMakeProjectFile::files() const
ifDebug
(
qCDebug
(
KDEV_QMAKE
)
<<
"Fetching files"
;)
QStringList
list
;
foreach
(
const
QString
&
variable
,
QMakeProjectFile
::
FileVariables
)
{
foreach
(
const
QString
&
value
,
variableValues
(
variable
))
{
for
(
const
auto
&
variable
:
QMakeProjectFile
::
FileVariables
)
{
const
auto
values
=
variableValues
(
variable
);
for
(
const
auto
&
value
:
values
)
{
list
+=
resolveFileName
(
value
);
}
}
...
...
@@ -325,8 +328,9 @@ QStringList QMakeProjectFile::filesForTarget(const QString& s) const
}
}
if
(
!
variableValues
(
QStringLiteral
(
"INSTALLS"
)).
contains
(
s
)
||
s
==
QLatin1String
(
"target"
))
{
foreach
(
const
QString
&
variable
,
QMakeProjectFile
::
FileVariables
)
{
foreach
(
const
QString
&
value
,
variableValues
(
variable
))
{
for
(
const
QString
&
variable
:
QMakeProjectFile
::
FileVariables
)
{
const
auto
values
=
variableValues
(
variable
);
for
(
const
QString
&
value
:
values
)
{
list
+=
QStringList
(
resolveFileName
(
value
));
}
}
...
...
plugins/qmakemanager/tests/test_qmakefile.cpp
View file @
8c1619e7
...
...
@@ -300,7 +300,7 @@ void TestQMakeFile::replaceFunctions()
QCOMPARE
(
file
.
variableValues
(
it
.
key
()),
it
.
value
());
++
it
;
}
for
each
(
const
QString
&
var
,
undefinedVariables
)
{
for
(
const
auto
&
var
:
std
::
as_const
(
undefinedVariables
)
)
{
QVERIFY
(
!
file
.
containsVariable
(
var
));
}
}
...
...
@@ -347,7 +347,7 @@ void TestQMakeFile::qtIncludeDirs_data()
<<
QStringLiteral
(
"qaxserver"
)
<<
QStringLiteral
(
"dbus"
)
<<
QStringLiteral
(
"declarative"
);
for
each
(
const
QString
&
module
,
modules
)
{
for
(
const
auto
&
module
:
std
::
as_const
(
modules
)
)
{
QStringList
expected
;
expected
<<
module
;
if
(
module
!=
QLatin1String
(
"core"
))
{
...
...
@@ -414,7 +414,7 @@ void TestQMakeFile::qtIncludeDirs()
if
(
shouldBeIncluded
)
{
shouldBeIncluded
=
modules
.
contains
(
it
.
key
());
if
(
!
shouldBeIncluded
)
{
for
each
(
const
QString
&
module
,
modules
)
{
for
(
const
auto
&
module
:
std
::
as_const
(
modules
)
)
{
if
(
module
!=
it
.
key
()
&&
moduleMap
.
value
(
module
)
==
it
.
value
())
{
shouldBeIncluded
=
true
;
break
;
...
...
@@ -569,7 +569,7 @@ void TestQMakeFile::globbing()
QDir
tempDirDir
(
tempDir
.
path
());
QVERIFY
(
tempDir
.
isValid
());
for
each
(
const
QString
&
file
,
files
)
{
for
(
const
auto
&
file
:
std
::
as_const
(
files
)
)
{
QVERIFY
(
tempDirDir
.
mkpath
(
QFileInfo
(
file
).
path
()));
QFile
f
(
tempDir
.
path
()
+
'/'
+
file
);
QVERIFY
(
f
.
open
(
QIODevice
::
WriteOnly
));
...
...
@@ -590,7 +590,8 @@ void TestQMakeFile::globbing()
QVERIFY
(
pro
.
read
());
QStringList
actual
;
foreach
(
QString
path
,
pro
.
files
())
{
const
auto
proFiles
=
pro
.
files
();
for
(
auto
path
:
proFiles
)
{
actual
<<
path
.
remove
(
tempDir
.
path
()
+
'/'
);
}
std
::
sort
(
actual
.
begin
(),
actual
.
end
());
...
...
plugins/qmakemanager/tests/test_qmakeproject.cpp
View file @
8c1619e7
...
...
@@ -96,7 +96,8 @@ void TestQMakeProject::testBuildDirectory()
QFETCH
(
QString
,
target
);
QFETCH
(
QString
,
expected
);
foreach
(
IProject
*
p
,
ICore
::
self
()
->
projectController
()
->
projects
())
{
const
auto
projects
=
ICore
::
self
()
->
projectController
()
->
projects
();
for
(
IProject
*
p
:
projects
)
{
ICore
::
self
()
->
projectController
()
->
closeProject
(
p
);
}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment