Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
ProofScriptParser
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
24
Issues
24
List
Boards
Labels
Service Desk
Milestones
Merge Requests
4
Merge Requests
4
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
sarah.grebing
ProofScriptParser
Commits
f15159ee
Commit
f15159ee
authored
Jun 26, 2017
by
Sarah Grebing
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Interim (incomplete commit)
parent
444581f3
Pipeline
#11567
failed with stage
in 2 minutes and 23 seconds
Changes
7
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
217 additions
and
45 deletions
+217
-45
src/main/java/edu/kit/formal/gui/controller/DebuggerMainWindowController.java
...t/formal/gui/controller/DebuggerMainWindowController.java
+9
-6
src/main/java/edu/kit/formal/interpreter/ControlFlowNode.java
...main/java/edu/kit/formal/interpreter/ControlFlowNode.java
+5
-3
src/main/java/edu/kit/formal/interpreter/EdgeTypes.java
src/main/java/edu/kit/formal/interpreter/EdgeTypes.java
+1
-1
src/main/java/edu/kit/formal/interpreter/PTreeNode.java
src/main/java/edu/kit/formal/interpreter/PTreeNode.java
+9
-5
src/main/java/edu/kit/formal/interpreter/ProgramFlowVisitor.java
...n/java/edu/kit/formal/interpreter/ProgramFlowVisitor.java
+65
-22
src/main/java/edu/kit/formal/interpreter/ProofTreeController.java
.../java/edu/kit/formal/interpreter/ProofTreeController.java
+41
-8
src/main/java/edu/kit/formal/interpreter/StateGraphVisitor.java
...in/java/edu/kit/formal/interpreter/StateGraphVisitor.java
+87
-0
No files found.
src/main/java/edu/kit/formal/gui/controller/DebuggerMainWindowController.java
View file @
f15159ee
...
...
@@ -4,10 +4,7 @@ import de.uka.ilkd.key.proof.init.ProofInputException;
import
de.uka.ilkd.key.speclang.Contract
;
import
edu.kit.formal.gui.controls.*
;
import
edu.kit.formal.gui.model.RootModel
;
import
edu.kit.formal.interpreter.Interpreter
;
import
edu.kit.formal.interpreter.InterpreterBuilder
;
import
edu.kit.formal.interpreter.KeYProofFacade
;
import
edu.kit.formal.interpreter.ProofTreeController
;
import
edu.kit.formal.interpreter.*
;
import
edu.kit.formal.interpreter.data.KeyData
;
import
edu.kit.formal.interpreter.data.State
;
import
edu.kit.formal.proofscriptparser.Facade
;
...
...
@@ -113,6 +110,7 @@ public class DebuggerMainWindowController implements Initializable {
private
ObservableBooleanValue
executeNotPossible
=
interpreterService
.
runningProperty
().
or
(
facade
.
readyToExecuteProperty
().
not
());
private
ProofTreeController
pc
;
public
static
void
showExceptionDialog
(
String
title
,
String
headerText
,
String
contentText
,
Throwable
ex
)
{
Alert
alert
=
new
Alert
(
Alert
.
AlertType
.
ERROR
);
alert
.
setTitle
(
title
);
...
...
@@ -225,8 +223,11 @@ public class DebuggerMainWindowController implements Initializable {
Interpreter
<
KeyData
>
currentInterpreter
=
ib
.
build
();
if
(
debugMode
)
{
ProofTreeController
pc
=
new
ProofTreeController
(
currentInterpreter
,
scripts
.
get
(
0
));
//blocker.getStepUntilBlock().set(1);
blocker
.
getStepUntilBlock
().
set
(
1
);
//for stepping functionality
StateGraphVisitor
visitor
=
new
StateGraphVisitor
(
currentInterpreter
,
scripts
.
get
(
0
));
pc
=
new
ProofTreeController
(
currentInterpreter
,
scripts
.
get
(
0
),
visitor
);
currentInterpreter
.
getEntryListeners
().
add
(
visitor
);
}
blocker
.
install
(
currentInterpreter
);
...
...
@@ -386,11 +387,13 @@ public class DebuggerMainWindowController implements Initializable {
public
void
stepOver
(
ActionEvent
actionEvent
)
{
blocker
.
getStepUntilBlock
().
addAndGet
(
1
);
blocker
.
unlock
();
pc
.
stepOver
();
}
public
void
stepBack
(
ActionEvent
actionEvent
)
{
System
.
out
.
println
(
blocker
.
getHistoryLogger
());
blocker
.
unlock
();
pc
.
stepBack
();
}
...
...
src/main/java/edu/kit/formal/interpreter/ControlFlowNode.java
View file @
f15159ee
...
...
@@ -5,20 +5,21 @@ import edu.kit.formal.proofscriptparser.ast.ASTNode;
/**
* ControlFlowNode for ControlFlowGraph to look up step-edges for teh debugger.
*/
@Deprecated
public
class
ControlFlowNode
{
ASTNode
scriptstmt
;
edu
.
kit
.
formal
.
proofscriptparser
.
ast
.
ASTNode
scriptstmt
;
public
ControlFlowNode
(
ASTNode
node
)
{
this
.
setScriptstmt
(
node
);
}
public
ASTNode
getScriptstmt
()
{
public
edu
.
kit
.
formal
.
proofscriptparser
.
ast
.
ASTNode
getScriptstmt
()
{
return
scriptstmt
;
}
public
void
setScriptstmt
(
ASTNode
scriptstmt
)
{
public
void
setScriptstmt
(
edu
.
kit
.
formal
.
proofscriptparser
.
ast
.
ASTNode
scriptstmt
)
{
this
.
scriptstmt
=
scriptstmt
;
}
...
...
@@ -34,4 +35,5 @@ public class ControlFlowNode {
return
sb
.
toString
();
}
}
src/main/java/edu/kit/formal/interpreter/EdgeTypes.java
View file @
f15159ee
...
...
@@ -4,5 +4,5 @@ package edu.kit.formal.interpreter;
* Created by sarah on 6/20/17.
*/
public
enum
EdgeTypes
{
STEP_INTO
,
STEP_OVER
,
STEP_BACK
,
STEP_RETURN
;
STEP_INTO
,
STEP_OVER
,
STEP_BACK
,
STEP_RETURN
,
STEP_OVER_COND
,
STATE_FLOW
;
}
src/main/java/edu/kit/formal/interpreter/PTreeNode.java
View file @
f15159ee
package
edu.kit.formal.interpreter
;
import
edu.kit.formal.interpreter.data.GoalNode
;
import
edu.kit.formal.interpreter.data.KeyData
;
import
edu.kit.formal.interpreter.data.State
;
import
edu.kit.formal.proofscriptparser.ast.ASTNode
;
...
...
@@ -10,7 +9,7 @@ import edu.kit.formal.proofscriptparser.ast.ASTNode;
* A node contains a reference to the ASTNode and a reference to the corresponding interpreter state if this state is already interpreted, null otherwise.
*/
public
class
PTreeNode
{
State
<
GoalNode
<
KeyData
>
>
state
;
State
<
KeyData
>
state
;
ASTNode
scriptstmt
;
...
...
@@ -18,11 +17,11 @@ public class PTreeNode {
this
.
setScriptstmt
(
node
);
}
public
State
<
GoalNode
<
KeyData
>
>
getState
()
{
public
State
<
KeyData
>
getState
()
{
return
state
;
}
public
void
setState
(
State
<
GoalNode
<
KeyData
>
>
state
)
{
public
void
setState
(
State
<
KeyData
>
state
)
{
this
.
state
=
state
;
}
...
...
@@ -42,10 +41,15 @@ public class PTreeNode {
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
"Node {"
);
if
(
scriptstmt
!=
null
)
{
sb
.
append
(
scriptstmt
.
toString
()
);
sb
.
append
(
scriptstmt
.
getNodeName
()
+
"\n"
);
}
else
{
sb
.
append
(
"No Stmt"
);
}
if
(
hasState
())
{
sb
.
append
(
"\nState "
+
state
.
getGoals
()
+
"\n"
);
}
else
{
sb
.
append
(
"No State yet"
);
}
sb
.
append
(
"}"
);
return
sb
.
toString
();
}
...
...
src/main/java/edu/kit/formal/interpreter/ProgramFlowVisitor.java
View file @
f15159ee
...
...
@@ -2,50 +2,60 @@ package edu.kit.formal.interpreter;
import
com.google.common.graph.MutableValueGraph
;
import
com.google.common.graph.ValueGraphBuilder
;
import
edu.kit.formal.interpreter.data.KeyData
;
import
edu.kit.formal.interpreter.funchdl.CommandLookup
;
import
edu.kit.formal.interpreter.funchdl.ProofScriptHandler
;
import
edu.kit.formal.proofscriptparser.DefaultASTVisitor
;
import
edu.kit.formal.proofscriptparser.ast.*
;
import
java.util.List
;
/**
* Visitor to create ProgramFlowGraph
*/
public
class
ProgramFlowVisitor
extends
DefaultASTVisitor
<
Void
>
{
/**
* Lookup for names of scripts
*/
private
final
CommandLookup
functionLookup
;
private
ControlFlowNode
lastNode
;
private
MutableValueGraph
<
ControlFlowNode
,
EdgeTypes
>
graph
=
ValueGraphBuilder
.
directed
().
allowsSelfLoops
(
true
).
build
();
/**
* Last visited Node
*/
private
ASTNode
lastNode
;
/**
* Control Flow Graph
*/
private
MutableValueGraph
<
ASTNode
,
EdgeTypes
>
graph
=
ValueGraphBuilder
.
directed
().
allowsSelfLoops
(
true
).
build
();
private
Interpreter
<
KeyData
>
inter
;
public
ProgramFlowVisitor
(
CommandLookup
functionLookup
)
{
this
.
functionLookup
=
functionLookup
;
}
public
MutableValueGraph
<
ControlFlow
Node
,
EdgeTypes
>
getGraph
()
{
public
MutableValueGraph
<
AST
Node
,
EdgeTypes
>
getGraph
()
{
return
graph
;
}
@Override
public
Void
visit
(
ProofScript
proofScript
)
{
ControlFlowNode
scriptNode
=
new
ControlFlowNode
(
proofScript
);
lastNode
=
scriptNode
;
lastNode
=
proofScript
;
return
this
.
visit
(
proofScript
.
getBody
());
}
@Override
public
Void
visit
(
AssignmentStatement
assignment
)
{
ControlFlowNode
node
=
new
ControlFlowNode
(
assignment
);
graph
.
addNode
(
node
);
lastNode
=
node
;
graph
.
addNode
(
assignment
);
lastNode
=
assignment
;
return
null
;
}
@Override
public
Void
visit
(
Statements
statements
)
{
ControlFlow
Node
curLastNode
=
lastNode
;
AST
Node
curLastNode
=
lastNode
;
for
(
Statement
stmnt
:
statements
)
{
stmnt
.
accept
(
this
);
graph
.
putEdgeValue
(
curLastNode
,
lastNode
,
EdgeTypes
.
STEP_OVER
);
...
...
@@ -58,7 +68,7 @@ public class ProgramFlowVisitor extends DefaultASTVisitor<Void> {
@Override
public
Void
visit
(
CallStatement
call
)
{
ControlFlowNode
currentNode
=
new
ControlFlowNode
(
call
)
;
ASTNode
currentNode
=
call
;
graph
.
addNode
(
currentNode
);
graph
.
putEdgeValue
(
lastNode
,
currentNode
,
EdgeTypes
.
STEP_OVER
);
...
...
@@ -73,14 +83,15 @@ public class ProgramFlowVisitor extends DefaultASTVisitor<Void> {
//Annahme: wenn ich zwischendrin keine return kante habe, dann wird solange durchgegangen, bis eine return kante da ist
if
(
atomic
)
{
graph
.
putEdgeValue
(
currentNode
,
lastNode
,
EdgeTypes
.
STEP_INTO
);
// graph.putEdgeValue(lastNode, currentNode, EdgeTypes.STEP_RETURN);
ProofScriptHandler
psh
=
(
ProofScriptHandler
)
functionLookup
.
getBuilder
(
call
);
psh
.
getScript
(
call
.
getCommand
()).
getBody
().
accept
(
this
);
//verbinde letzten knoten aus auruf mi step return zu aktuellem knoten
//verbinde letzten knoten aus auruf mi
t
step return zu aktuellem knoten
graph
.
putEdgeValue
(
lastNode
,
currentNode
,
EdgeTypes
.
STEP_RETURN
);
graph
.
putEdgeValue
(
currentNode
,
lastNode
,
EdgeTypes
.
STEP_INTO
);
}
lastNode
=
currentNode
;
...
...
@@ -90,30 +101,62 @@ public class ProgramFlowVisitor extends DefaultASTVisitor<Void> {
@Override
public
Void
visit
(
ForeachStatement
foreach
)
{
ControlFlowNode
currentNode
=
new
ControlFlowNode
(
foreach
)
;
ASTNode
currentNode
=
foreach
;
graph
.
addNode
(
currentNode
);
graph
.
putEdgeValue
(
lastNode
,
currentNode
,
EdgeTypes
.
STEP_OVER
);
graph
.
putEdgeValue
(
currentNode
,
lastNode
,
EdgeTypes
.
STEP_BACK
);
lastNode
=
currentNode
;
foreach
.
getBody
().
accept
(
this
);
graph
.
putEdgeValue
(
currentNode
,
las
tNode
,
EdgeTypes
.
STEP_RETURN
);
lastNode
=
currentNode
;
graph
.
putEdgeValue
(
lastNode
,
curren
tNode
,
EdgeTypes
.
STEP_RETURN
);
//lastNode = currentNode; ??
return
null
;
}
@Override
public
Void
visit
(
TheOnlyStatement
theOnly
)
{
return
super
.
visit
(
theOnly
);
ASTNode
currentNode
=
theOnly
;
graph
.
addNode
(
currentNode
);
graph
.
putEdgeValue
(
lastNode
,
currentNode
,
EdgeTypes
.
STEP_OVER
);
graph
.
putEdgeValue
(
currentNode
,
lastNode
,
EdgeTypes
.
STEP_BACK
);
lastNode
=
currentNode
;
theOnly
.
getBody
().
accept
(
this
);
graph
.
putEdgeValue
(
lastNode
,
currentNode
,
EdgeTypes
.
STEP_RETURN
);
//lastNode = currentNode; ??
return
null
;
}
@Override
public
Void
visit
(
RepeatStatement
repeatStatement
)
{
return
super
.
visit
(
repeatStatement
);
ASTNode
currentNode
=
repeatStatement
;
graph
.
addNode
(
currentNode
);
graph
.
putEdgeValue
(
lastNode
,
currentNode
,
EdgeTypes
.
STEP_OVER
);
graph
.
putEdgeValue
(
currentNode
,
lastNode
,
EdgeTypes
.
STEP_BACK
);
lastNode
=
currentNode
;
repeatStatement
.
getBody
().
accept
(
this
);
graph
.
putEdgeValue
(
lastNode
,
currentNode
,
EdgeTypes
.
STEP_OVER
);
lastNode
=
currentNode
;
return
null
;
}
@Override
public
Void
visit
(
CasesStatement
casesStatement
)
{
return
super
.
visit
(
casesStatement
);
ASTNode
currentNode
=
casesStatement
;
graph
.
addNode
(
currentNode
);
graph
.
putEdgeValue
(
lastNode
,
currentNode
,
EdgeTypes
.
STEP_OVER
);
graph
.
putEdgeValue
(
currentNode
,
lastNode
,
EdgeTypes
.
STEP_BACK
);
List
<
CaseStatement
>
cases
=
casesStatement
.
getCases
();
for
(
CaseStatement
aCase
:
cases
)
{
ASTNode
caseNode
=
aCase
;
graph
.
addNode
(
caseNode
);
graph
.
putEdgeValue
(
currentNode
,
caseNode
,
EdgeTypes
.
STEP_OVER
);
//??is this right?
graph
.
putEdgeValue
(
caseNode
,
currentNode
,
EdgeTypes
.
STEP_BACK
);
lastNode
=
caseNode
;
aCase
.
getBody
().
accept
(
this
);
graph
.
putEdgeValue
(
lastNode
,
currentNode
,
EdgeTypes
.
STEP_RETURN
);
}
lastNode
=
currentNode
;
return
null
;
}
...
...
@@ -124,9 +167,9 @@ public class ProgramFlowVisitor extends DefaultASTVisitor<Void> {
graph
.
nodes
().
forEach
(
n
->
{
sb
.
append
(
n
.
hashCode
())
.
append
(
" [label=\""
)
.
append
(
n
.
get
Scriptstmt
().
get
NodeName
())
.
append
(
n
.
getNodeName
())
.
append
(
"@"
)
.
append
(
n
.
getS
criptstmt
().
getS
tartPosition
().
getLineNumber
())
.
append
(
n
.
getStartPosition
().
getLineNumber
())
.
append
(
"\"]\n"
);
});
...
...
src/main/java/edu/kit/formal/interpreter/ProofTreeController.java
View file @
f15159ee
...
...
@@ -2,6 +2,7 @@ package edu.kit.formal.interpreter;
import
com.google.common.graph.MutableValueGraph
;
import
edu.kit.formal.interpreter.data.KeyData
;
import
edu.kit.formal.proofscriptparser.ast.ASTNode
;
import
edu.kit.formal.proofscriptparser.ast.ProofScript
;
/**
...
...
@@ -10,30 +11,34 @@ import edu.kit.formal.proofscriptparser.ast.ProofScript;
* @author S. Grebing
*/
public
class
ProofTreeController
{
//TODO Listener auf den Interperter
StateGraphVisitor
stateGraphVisitor
;
/**
* ControlFlowGraph to lookup edges
*/
private
MutableValueGraph
<
ControlFlowNode
,
EdgeTypes
>
controlFlowGraph
;
private
MutableValueGraph
<
ASTNode
,
EdgeTypes
>
controlFlowGraph
;
/**
* Graph that is computed on the fly in order to allow stepping
*/
private
MutableValueGraph
<
PTreeNode
,
EdgeTypes
>
stateGraph
;
/**
* Current interpreter
*/
private
Interpreter
<
KeyData
>
currentInterpreter
;
/**
* Current State in graph
*/
private
PTreeNode
statePointer
;
public
ProofTreeController
(
Interpreter
<
KeyData
>
inter
,
ProofScript
mainScript
)
{
public
ProofTreeController
(
Interpreter
<
KeyData
>
inter
,
ProofScript
mainScript
,
StateGraphVisitor
stateGraphVisitor
)
{
this
.
currentInterpreter
=
inter
;
buildControlFlowGraph
(
mainScript
);
stateGraph
=
stateGraphVisitor
.
getStateGraph
();
statePointer
=
stateGraphVisitor
.
getRootNode
();
this
.
stateGraphVisitor
=
stateGraphVisitor
;
// System.out.println(stateGraph.nodes());
//initializeStateGraph(mainScript);
}
...
...
@@ -48,13 +53,41 @@ public class ProofTreeController {
mainScript
.
accept
(
visitor
);
this
.
controlFlowGraph
=
visitor
.
getGraph
();
System
.
out
.
println
(
visitor
.
asdot
());
// System.out.println(controlFlowGraph);
// System.out.println(visitor.asdot());
}
/* private void initializeStateGraph(ProofScript mainScript){
stateGraph = ValueGraphBuilder.directed().build();
State<KeyData> initState = currentInterpreter.getCurrentState();
System.out.println(initState);
PTreeNode initNode = new PTreeNode(mainScript);
initNode.setState(initState);
stateGraph.addNode(initNode);
// statePointer = initNode;
}*/
public
PTreeNode
stepOver
()
{
PTreeNode
current
=
statePointer
;
ASTNode
stmt
=
current
.
getScriptstmt
();
if
(
controlFlowGraph
.
asGraph
().
nodes
().
contains
(
stmt
))
{
// System.out.println("\n\nAdjacent:{\n"+controlFlowGraph.asGraph().adjacentNodes(stmt)+"}\n\n\n");
Object
[]
nodeArray
=
controlFlowGraph
.
asGraph
().
adjacentNodes
(
stmt
).
toArray
();
ASTNode
firtSucc
=
(
ASTNode
)
nodeArray
[
0
];
for
(
PTreeNode
succ
:
stateGraph
.
successors
(
current
))
{
if
(
succ
.
getScriptstmt
().
equals
(
firtSucc
))
{
statePointer
=
succ
;
}
}
}
//System.out.println(stateGraphVisitor.asdot());
return
null
;
}
...
...
src/main/java/edu/kit/formal/interpreter/StateGraphVisitor.java
0 → 100644
View file @
f15159ee
package
edu.kit.formal.interpreter
;
import
com.google.common.graph.MutableValueGraph
;
import
com.google.common.graph.ValueGraphBuilder
;
import
edu.kit.formal.interpreter.data.KeyData
;
import
edu.kit.formal.interpreter.data.State
;
import
edu.kit.formal.proofscriptparser.DefaultASTVisitor
;
import
edu.kit.formal.proofscriptparser.ast.ASTNode
;
import
edu.kit.formal.proofscriptparser.ast.ProofScript
;
/**
* Created by sarah on 6/26/17.
*/
public
class
StateGraphVisitor
extends
DefaultASTVisitor
<
Void
>
{
Interpreter
currentInterpreter
;
/**
* Graph that is computed on the fly in order to allow stepping
*/
private
MutableValueGraph
<
PTreeNode
,
EdgeTypes
>
stateGraph
;
private
PTreeNode
root
;
private
PTreeNode
lastNode
;
public
StateGraphVisitor
(
Interpreter
inter
,
ProofScript
mainScript
)
{
stateGraph
=
ValueGraphBuilder
.
directed
().
build
();
this
.
currentInterpreter
=
inter
;
State
<
KeyData
>
initState
=
currentInterpreter
.
getCurrentState
();
System
.
out
.
println
(
initState
);
PTreeNode
initNode
=
new
PTreeNode
(
mainScript
);
initNode
.
setState
(
initState
);
stateGraph
.
addNode
(
initNode
);
root
=
initNode
;
lastNode
=
initNode
;
}
public
MutableValueGraph
<
PTreeNode
,
EdgeTypes
>
getStateGraph
()
{
return
stateGraph
;
}
public
PTreeNode
getRootNode
()
{
return
root
;
}
public
PTreeNode
getLastNode
()
{
return
lastNode
;
}
@Override
public
Void
defaultVisit
(
ASTNode
node
)
{
PTreeNode
newStateNode
=
new
PTreeNode
(
node
);
newStateNode
.
setState
(
currentInterpreter
.
getCurrentState
());
stateGraph
.
addNode
(
newStateNode
);
stateGraph
.
putEdgeValue
(
lastNode
,
newStateNode
,
EdgeTypes
.
STATE_FLOW
);
lastNode
=
newStateNode
;
System
.
out
.
println
(
asdot
());
return
null
;
}
public
String
asdot
()
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
"digraph G {\nnode [shape=rect]\n "
);
stateGraph
.
nodes
().
forEach
(
n
->
{
sb
.
append
(
n
.
hashCode
())
.
append
(
" [label=\""
)
.
append
(
n
.
getScriptstmt
().
getNodeName
())
.
append
(
"@"
)
.
append
(
n
.
getScriptstmt
().
getStartPosition
().
getLineNumber
())
.
append
(
"\"]\n"
);
});
stateGraph
.
edges
().
forEach
(
edge
->
{
sb
.
append
(
edge
.
source
().
hashCode
())
.
append
(
" -> "
)
.
append
(
edge
.
target
().
hashCode
())
.
append
(
" [label=\""
)
.
append
(
stateGraph
.
edgeValue
(
edge
.
source
(),
edge
.
target
()).
name
())
.
append
(
"\"]\n"
);
});
sb
.
append
(
"}"
);
return
sb
.
toString
();
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a 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