Skip to content
Snippets Groups Projects
Commit 254fb7f9 authored by Emma Söderberg's avatar Emma Söderberg
Browse files

Updates handler states and dumping of listeners.

- Adds inc_EMPTY: for handlers of decached values
- Adds inc_COMPUTED: for handlers of cached values
- Adds inc_AST: for handlers of editable AST values
- Changes the dependency dump to show listeners and handler state
- Removes the changeState method from the handler class
- Adds the attribute handler directly on the evaluation stack for plain lazy attributes

Note that all changes are focused on the incremental/param configuration and changes
may not be complete for other incremental configurations.

Tested on incremental/param/Test120-121.
parent 8f22ce2a
No related branches found
No related tags found
No related merge requests found
...@@ -33,9 +33,9 @@ aspect IncrementalState { ...@@ -33,9 +33,9 @@ aspect IncrementalState {
tt.expand("ASTDecl.incStateFields", out); tt.expand("ASTDecl.incStateFields", out);
tt.bind("ChangeStateTokens", emitChangeStateTokensString()); //tt.bind("ChangeStateTokens", emitChangeStateTokensString());
tt.bind("ChangeStateAttributes", emitChangeStateAttributesString()); //tt.bind("ChangeStateAttributes", emitChangeStateAttributesString());
tt.expand("ASTDecl.incChangeStateMethod", out); //tt.expand("ASTDecl.incChangeStateMethod", out);
tt.bind("ThrowAwayTokens", emitThrowAwayTokensString()); tt.bind("ThrowAwayTokens", emitThrowAwayTokensString());
tt.bind("ThrowAwayAttributes", emitThrowAwayAttributesString()); tt.bind("ThrowAwayAttributes", emitThrowAwayAttributesString());
...@@ -43,6 +43,7 @@ aspect IncrementalState { ...@@ -43,6 +43,7 @@ aspect IncrementalState {
} }
/*
public String ASTDecl.emitChangeStateTokensString() { public String ASTDecl.emitChangeStateTokensString() {
StringBuffer res = new StringBuffer(); StringBuffer res = new StringBuffer();
TemplateContext tt = templateContext(); TemplateContext tt = templateContext();
...@@ -69,6 +70,7 @@ aspect IncrementalState { ...@@ -69,6 +70,7 @@ aspect IncrementalState {
} }
return res.toString(); return res.toString();
} }
*/
public String ASTDecl.emitThrowAwayTokensString() { public String ASTDecl.emitThrowAwayTokensString() {
StringBuffer res = new StringBuffer(); StringBuffer res = new StringBuffer();
......
...@@ -51,11 +51,13 @@ if (!state().IN_CONSTRUCTION && !(state().IN_COMPUTATION > 0)) { ...@@ -51,11 +51,13 @@ if (!state().IN_CONSTRUCTION && !(state().IN_COMPUTATION > 0)) {
} }
} }
$endif $endif
/*
if (node != null) { if (node != null) {
inc_changeState(node.inc_state); inc_changeState(node.inc_state);
} else { } else {
inc_changeState(inc_GARBAGE); inc_changeState(inc_GARBAGE);
} }
*/
$endif $endif
]] ]]
...@@ -78,7 +80,7 @@ if (!state().IN_CONSTRUCTION && !state().IN_ATTR_STORE_EVAL) { ...@@ -78,7 +80,7 @@ if (!state().IN_CONSTRUCTION && !state().IN_ATTR_STORE_EVAL) {
if (getChild_handler[i] != null) { if (getChild_handler[i] != null) {
getChild_handler[i].notifyDependencies(); getChild_handler[i].notifyDependencies();
} else { } else {
getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i)); getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i));
} }
} }
$endif $endif
...@@ -241,7 +243,7 @@ $if(IncrementalEnabled) ...@@ -241,7 +243,7 @@ $if(IncrementalEnabled)
$if(IncrementalLevelParam) $if(IncrementalLevelParam)
getChild_handler = new $DDGNodeName[i + 1]; getChild_handler = new $DDGNodeName[i + 1];
getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i)); getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i));
$endif $endif
$endif $endif
......
...@@ -37,20 +37,35 @@ $if (IncrementalLevelParam) ...@@ -37,20 +37,35 @@ $if (IncrementalLevelParam)
public String fAttrID; public String fAttrID;
protected Object fParams; protected Object fParams;
public $DDGNodeName($ASTNode node, String attrID, Object params) { public static $DDGNodeName createAttrHandler($ASTNode node, String attrID, Object params) {
return new $DDGNodeName(node, attrID, params, $ASTNode.inc_EMPTY);
}
public static $DDGNodeName createAttrHandler($DDGNodeName handler, $ASTNode node) {
return new $DDGNodeName(handler, node, $ASTNode.inc_EMPTY);
}
public static $DDGNodeName createAstHandler($ASTNode node, String attrID, Object params) {
return new $DDGNodeName(node, attrID, params, $ASTNode.inc_AST);
}
public static $DDGNodeName createAstHandler($DDGNodeName handler, $ASTNode node) {
return new $DDGNodeName(handler, node, $ASTNode.inc_AST);
}
private $DDGNodeName($ASTNode node, String attrID, Object params, int state) {
fNode = node; fNode = node;
fAttrID = attrID; fAttrID = attrID;
fParams = params; fParams = params;
fState = node.inc_state; fState = state;
//createdHandlers.add(this);
} }
public $DDGNodeName($DDGNodeName handler, $ASTNode node) { private $DDGNodeName($DDGNodeName handler, $ASTNode node, int state) {
fNode = node; fNode = node;
fAttrID = handler.fAttrID; fAttrID = handler.fAttrID;
fParams = handler.fParams; fParams = handler.fParams;
fState = node.inc_state; fState = state;
//createdHandlers.add(this);
} }
public void setParams(Object params) { public void setParams(Object params) {
...@@ -260,11 +275,9 @@ $endif ...@@ -260,11 +275,9 @@ $endif
// React to change // React to change
private boolean visitedChange = false;
public void dependencyChanged() { public void dependencyChanged() {
if (!visitedChange) { if (isComputed()) {
visitedChange = true; setEmpty();
$if (IncrementalTrack) $if (IncrementalTrack)
trackedFlushes++; trackedFlushes++;
System.out.println("not(" + this + ")"); System.out.println("not(" + this + ")");
...@@ -305,17 +318,12 @@ $if (IncrementalLevelRegion) ...@@ -305,17 +318,12 @@ $if (IncrementalLevelRegion)
$endif $endif
} }
$endif $endif
visitedChange = false;
} }
} }
// State // State
protected int fState = $ASTNode.inc_CREATED; protected int fState = $ASTNode.inc_EMPTY;
public void changeState(int newState) {
fState = newState;
}
public void throwAway() { public void throwAway() {
fState = $ASTNode.inc_GARBAGE; fState = $ASTNode.inc_GARBAGE;
...@@ -325,6 +333,14 @@ $endif ...@@ -325,6 +333,14 @@ $endif
fState = $ASTNode.inc_LIVE; fState = $ASTNode.inc_LIVE;
} }
public void setComputed() {
fState = $ASTNode.inc_COMPUTED;
}
public void setEmpty() {
fState = $ASTNode.inc_EMPTY;
}
public boolean isGarbage() { public boolean isGarbage() {
return fState == $ASTNode.inc_GARBAGE; return fState == $ASTNode.inc_GARBAGE;
} }
...@@ -341,6 +357,10 @@ $endif ...@@ -341,6 +357,10 @@ $endif
return fState == $ASTNode.inc_LIVE; return fState == $ASTNode.inc_LIVE;
} }
public boolean isComputed() {
return fState == $ASTNode.inc_COMPUTED;
}
$if (IncrementalDebug) $if (IncrementalDebug)
// Debugging // Debugging
...@@ -379,8 +399,19 @@ $if (IncrementalDebug) ...@@ -379,8 +399,19 @@ $if (IncrementalDebug)
for ($DDGNodeName node : fListenerSet) { for ($DDGNodeName node : fListenerSet) {
sorted.add(node.toString()); sorted.add(node.toString());
} }
for (String s : sorted) { System.out.println(this + " listeners: " + sorted);
System.out.println("dep(" + s + " -> " + this + ")"); }
public String state() {
switch (fState) {
case ASTNode.inc_LIVE: return "LIVE";
case ASTNode.inc_COMPUTED: return "COMPUTED";
case ASTNode.inc_EMPTY: return "EMPTY";
case ASTNode.inc_AST: return "AST";
case ASTNode.inc_GARBAGE: return "GARBAGE";
case ASTNode.inc_CREATED: return "CREATED";
case ASTNode.inc_CLONED: return "CLONED";
default: return "UNKNOWN";
} }
} }
...@@ -388,7 +419,7 @@ $if (IncrementalDebug) ...@@ -388,7 +419,7 @@ $if (IncrementalDebug)
$if (IncrementalLevelParam) $if (IncrementalLevelParam)
return fNode.relativeNodeID() + ":" + fAttrID + (fParams != null ? return fNode.relativeNodeID() + ":" + fAttrID + (fParams != null ?
("[" + (fParams instanceof $ASTNode ? (($ASTNode) fParams).relativeNodeID() : fParams) + "]") ("[" + (fParams instanceof $ASTNode ? (($ASTNode) fParams).relativeNodeID() : fParams) + "]")
: ""); : "") + " (" + state() + ")";
$endif $endif
$if (IncrementalLevelAttr) $if (IncrementalLevelAttr)
return fNode.relativeNodeID() + ":" + fAttrID; return fNode.relativeNodeID() + ":" + fAttrID;
...@@ -463,9 +494,9 @@ $if(IncrementalEnabled) ...@@ -463,9 +494,9 @@ $if(IncrementalEnabled)
$if (!#isNTA) $if (!#isNTA)
$if (IncrementalLevelParam) $if (IncrementalLevelParam)
$if (IncrementalPropLimit) $if (IncrementalPropLimit)
protected $DDGNodeName $Host.get$(Id)_handler = new $DDGNodeName(this, "get$Id", null, true); protected $DDGNodeName $Host.get$(Id)_handler = $DDGNodeName.createAstHandler(this, "get$Id", null, true);
$else $else
protected $DDGNodeName $Host.get$(Id)_handler = new $DDGNodeName(this, "get$Id", null); protected $DDGNodeName $Host.get$(Id)_handler = $DDGNodeName.createAstHandler(this, "get$Id", null);
$endif $endif
$endif $endif
$if (IncrementalLevelAttr) $if (IncrementalLevelAttr)
...@@ -479,11 +510,11 @@ $endif ...@@ -479,11 +510,11 @@ $endif
ASTDecl.createASTHandlers = [[ ASTDecl.createASTHandlers = [[
$if (IncrementalLevelParam) $if (IncrementalLevelParam)
$if (IncrementalPropLimit) $if (IncrementalPropLimit)
protected $DDGNodeName $ASTNode.getParent_handler = new $DDGNodeName(this, "getParent", null, true); protected $DDGNodeName $ASTNode.getParent_handler = $DDGNodeName.createAstHandler(this, "getParent", null, true);
protected $DDGNodeName $ASTNode.numChildren_handler = new $DDGNodeName(this, "numChildren", null, true); protected $DDGNodeName $ASTNode.numChildren_handler = $DDGNodeName.createAstHandler(this, "numChildren", null, true);
$else $else
protected $DDGNodeName $ASTNode.getParent_handler = new $DDGNodeName(this, "getParent", null); protected $DDGNodeName $ASTNode.getParent_handler = $DDGNodeName.createAstHandler(this, "getParent", null);
protected $DDGNodeName $ASTNode.numChildren_handler = new $DDGNodeName(this, "numChildren", null); protected $DDGNodeName $ASTNode.numChildren_handler = $DDGNodeName.createAstHandler(this, "numChildren", null);
$endif $endif
protected $DDGNodeName[] $ASTNode.getChild_handler; protected $DDGNodeName[] $ASTNode.getChild_handler;
$endif $endif
......
...@@ -34,11 +34,11 @@ $if (IncrementalLevelParam) ...@@ -34,11 +34,11 @@ $if (IncrementalLevelParam)
if (getChild_handler != null) { if (getChild_handler != null) {
copy.getChild_handler = ($DDGNodeName[])getChild_handler.clone(); copy.getChild_handler = ($DDGNodeName[])getChild_handler.clone();
} }
copy.numChildren_handler = new $DDGNodeName(numChildren_handler, copy); copy.numChildren_handler = $DDGNodeName.createAstHandler(numChildren_handler, copy);
copy.getParent_handler = new $DDGNodeName(getParent_handler, copy); copy.getParent_handler = $DDGNodeName.createAstHandler(getParent_handler, copy);
for (int i = 0; getChild_handler != null && i < getChild_handler.length; i++) { for (int i = 0; getChild_handler != null && i < getChild_handler.length; i++) {
if (getChild_handler[i] != null) { if (getChild_handler[i] != null) {
copy.getChild_handler[i] = new $DDGNodeName(getChild_handler[i], copy); copy.getChild_handler[i] = $DDGNodeName.createAttrHandler(getChild_handler[i], copy);
} }
} }
$endif $endif
...@@ -82,7 +82,7 @@ $endif ...@@ -82,7 +82,7 @@ $endif
# Copy token DDG node # Copy token DDG node
TokenComponent.copyTokenHandler = [[ TokenComponent.copyTokenHandler = [[
if (get$(Id)_handler != null) { if (get$(Id)_handler != null) {
copy.get$(Id)_handler = new $DDGNodeName(get$(Id)_handler, copy); copy.get$(Id)_handler = $DDGNodeName.createAstHandler(get$(Id)_handler, copy);
} }
]] ]]
...@@ -95,7 +95,7 @@ $if (IsParameterized) ...@@ -95,7 +95,7 @@ $if (IsParameterized)
} }
$else $else
if ($(AttributeName)_handler != null) { if ($(AttributeName)_handler != null) {
copy.$(AttributeName)_handler = new $DDGNodeName($(AttributeName)_handler, copy); copy.$(AttributeName)_handler = $DDGNodeName.createAttrHandler($(AttributeName)_handler, copy);
} }
$endif $endif
$endif $endif
......
...@@ -67,15 +67,16 @@ $if(IncrementalTrack) ...@@ -67,15 +67,16 @@ $if(IncrementalTrack)
$endif $endif
// if (!IN_REWRITE_EVAL) { // if (!IN_REWRITE_EVAL) {
IN_ATTR_STORE_EVAL = true; IN_ATTR_STORE_EVAL = true;
//System.out.println("attr eval stack enter: " + handler.fAttrID); //System.out.println("attr eval stack enter: " + handler);
pushHandler(handlerAttrStack, handler); pushHandler(handlerAttrStack, handler);
handler.setComputed();
// } // }
} }
public void exitAttrStoreEval($ASTNode$$DepGraphNode handler) { public void exitAttrStoreEval($ASTNode$$DepGraphNode handler) {
// if (!IN_REWRITE_EVAL) { // if (!IN_REWRITE_EVAL) {
popHandler(handlerAttrStack, handler); popHandler(handlerAttrStack, handler);
//System.out.println("attr eval stack exit: " + handler.fAttrID); //System.out.println("attr eval stack exit: " + handler);
IN_ATTR_STORE_EVAL = !handlerAttrStack.isEmpty(); IN_ATTR_STORE_EVAL = !handlerAttrStack.isEmpty();
// } // }
} }
...@@ -380,6 +381,9 @@ public static final int $ASTNode.inc_CREATED = 0; ...@@ -380,6 +381,9 @@ public static final int $ASTNode.inc_CREATED = 0;
public static final int $ASTNode.inc_CLONED = 1; public static final int $ASTNode.inc_CLONED = 1;
public static final int $ASTNode.inc_LIVE = 2; public static final int $ASTNode.inc_LIVE = 2;
public static final int $ASTNode.inc_GARBAGE = 3; public static final int $ASTNode.inc_GARBAGE = 3;
public static final int $ASTNode.inc_EMPTY = 4;
public static final int $ASTNode.inc_COMPUTED = 5;
public static final int $ASTNode.inc_AST = 6;
public int $ASTNode.inc_state = inc_CREATED; public int $ASTNode.inc_state = inc_CREATED;
$endif $endif
]] ]]
...@@ -58,9 +58,9 @@ $if(IncrementalLevelParam) ...@@ -58,9 +58,9 @@ $if(IncrementalLevelParam)
int i = getNumChildNoTransform() - 1; int i = getNumChildNoTransform() - 1;
if (getChild_handler[i] == null) { if (getChild_handler[i] == null) {
$if(IncrementalPropLimit) $if(IncrementalPropLimit)
getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i), !node.mayHaveRewrite()); getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i), !node.mayHaveRewrite());
$else $else
getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i)); getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i));
$endif $endif
} }
state().addHandlerDepTo(getChild_handler[i]); state().addHandlerDepTo(getChild_handler[i]);
...@@ -160,9 +160,9 @@ $if(IncrementalEnabled) ...@@ -160,9 +160,9 @@ $if(IncrementalEnabled)
$if(IncrementalLevelParam) $if(IncrementalLevelParam)
if (this.getChild_handler[i] == null) { if (this.getChild_handler[i] == null) {
$if(IncrementalPropLimit) $if(IncrementalPropLimit)
this.getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i), !node.mayHaveRewrite()); this.getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i), !node.mayHaveRewrite());
$else $else
this.getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i)); this.getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i));
$endif $endif
} }
this.state().addHandlerDepTo(this.getChild_handler[i]); this.state().addHandlerDepTo(this.getChild_handler[i]);
...@@ -251,9 +251,9 @@ $if(IncrementalEnabled) ...@@ -251,9 +251,9 @@ $if(IncrementalEnabled)
$if(IncrementalLevelParam) $if(IncrementalLevelParam)
if (this.getChild_handler[i] == null) { if (this.getChild_handler[i] == null) {
$if(IncrementalPropLimit) $if(IncrementalPropLimit)
this.getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i), !node.mayHaveRewrite()); this.getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i), !node.mayHaveRewrite());
$else $else
this.getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i)); this.getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i));
$endif $endif
} }
this.state().addHandlerDepTo(this.getChild_handler[i]); this.state().addHandlerDepTo(this.getChild_handler[i]);
...@@ -300,9 +300,9 @@ $if(IncrementalEnabled) ...@@ -300,9 +300,9 @@ $if(IncrementalEnabled)
$if(IncrementalLevelParam) $if(IncrementalLevelParam)
if (getChild_handler[i] == null) { if (getChild_handler[i] == null) {
$if(IncrementalPropLimit) $if(IncrementalPropLimit)
getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i), !child.mayHaveRewrite()); getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i), !child.mayHaveRewrite());
$else $else
getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i)); getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i));
$endif $endif
} }
state().addHandlerDepTo(getChild_handler[i]); state().addHandlerDepTo(getChild_handler[i]);
...@@ -335,9 +335,9 @@ $if(IncrementalEnabled) ...@@ -335,9 +335,9 @@ $if(IncrementalEnabled)
$if(IncrementalLevelParam) $if(IncrementalLevelParam)
if (getChild_handler[i] == null) { if (getChild_handler[i] == null) {
$if(IncrementalPropLimit) $if(IncrementalPropLimit)
getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i), !child.mayHaveRewrite()); getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i), !child.mayHaveRewrite());
$else $else
getChild_handler[i] = new $DDGNodeName(this, "getChild", Integer.valueOf(i)); getChild_handler[i] = $DDGNodeName.createAttrHandler(this, "getChild", Integer.valueOf(i));
$endif $endif
} }
state().addHandlerDepTo(getChild_handler[i]); state().addHandlerDepTo(getChild_handler[i]);
...@@ -432,12 +432,12 @@ $if(IncrementalEnabled) ...@@ -432,12 +432,12 @@ $if(IncrementalEnabled)
$if(IncrementalLevelParam) $if(IncrementalLevelParam)
$if(!#isParameterized) $if(!#isParameterized)
if (#(signature)_handler == null) { if (#(signature)_handler == null) {
#(signature)_handler = new $DDGNodeName(this, "#(signature)", null); #(signature)_handler = $DDGNodeName.createAttrHandler(this, "#(signature)", null);
} }
state().addHandlerDepTo(#(signature)_handler); state().addHandlerDepTo(#(signature)_handler);
$else $else
if (!#(signature)_handler.containsKey(_parameters)) { if (!#(signature)_handler.containsKey(_parameters)) {
#(signature)_handler.put(_parameters, new $DDGNodeName(this, "#(signature)", _parameters)); #(signature)_handler.put(_parameters, $DDGNodeName.createAttrHandler(this, "#(signature)", _parameters));
} }
state().addHandlerDepTo(($DDGNodeName)#(signature)_handler.get(_parameters)); state().addHandlerDepTo(($DDGNodeName)#(signature)_handler.get(_parameters));
$endif $endif
...@@ -487,8 +487,13 @@ $if(IncrementalEnabled) ...@@ -487,8 +487,13 @@ $if(IncrementalEnabled)
$if(#isMemoized) $if(#isMemoized)
$if(IncrementalLevelParam) $if(IncrementalLevelParam)
$DDGNodeName tmpHandler = new $DDGNodeName(this, "", null); //$DDGNodeName tmpHandler = $DDGNodeName.createAttrHandler(this, "", null);
state().enterAttrStoreEval(tmpHandler); //state().enterAttrStoreEval(tmpHandler);
$if(!#isParameterized)
state().enterAttrStoreEval(#(signature)_handler);
$else
state().enterAttrStoreEval(($DDGNodeName)#(signature)_handler.get(_parameters));
$endif
$endif $endif
$if(IncrementalLevelAttr) $if(IncrementalLevelAttr)
...@@ -558,7 +563,13 @@ $if(IncrementalEnabled) ...@@ -558,7 +563,13 @@ $if(IncrementalEnabled)
$if(#isMemoized) $if(#isMemoized)
$if(IncrementalLevelParam) $if(IncrementalLevelParam)
state().exitAttrStoreEval(tmpHandler); //state().exitAttrStoreEval(tmpHandler);
$if(!#isParameterized)
state().exitAttrStoreEval(#(signature)_handler);
$else
state().exitAttrStoreEval(($DDGNodeName)#(signature)_handler.get(_parameters));
$endif
$endif $endif
$if(IncrementalLevelAttr) $if(IncrementalLevelAttr)
...@@ -639,9 +650,9 @@ $if(#isMemoized) ...@@ -639,9 +650,9 @@ $if(#isMemoized)
$if(IncrementalLevelParam) $if(IncrementalLevelParam)
$if(!#isParameterized) $if(!#isParameterized)
#(signature)_handler.transferDependenciesFrom(tmpHandler); //#(signature)_handler.transferDependenciesFrom(tmpHandler);
$else $else
(($DDGNodeName)#(signature)_handler.get(_parameters)).transferDependenciesFrom(tmpHandler); //(($DDGNodeName)#(signature)_handler.get(_parameters)).transferDependenciesFrom(tmpHandler);
$endif $endif
$endif $endif
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment