Why does this code work?

X

xmail123

Why does this code work?
I am new to C# and have been studying this piece of code. It loops
through an Adjacency Matrix table to populate a tree view. I have two
questions about why this code works.

1. initTreeView(TreeNode N) creates a new "temp" table to hold
the children for each node. Each time the table is created it has the
same name "temp". Why doesn't the table just get over written each
time?
2. In the foreach (DataRow r3 in temp.Rows) loop, if the temp
table is empty like when Menu11 is reached the call to
initTreeView(tn) is not executed but for all the parent nodes Menu1,
Menu4, Menu5 and Menu6 initTreeView(tn) is executed. There is no code
to indicate that at Menu11 not to execute initTreeView(tn) How does
C# know when to execute initTreeView(tn) and when not to?


namespace DynamicTree
{
public partial class Form1 : Form
{
//Declare the table that will be populated with the Adjacency
Matrix data.
DataTable tbl;
//Declare the coumns that will be populated in the Adjacency
Matrix table.
DataColumn col;

public Form1()
{
InitializeComponent();
//Create the Adjacency Matrix table.
InitTable();
//Populate the Adjacency Matrix table.
initTableData();
}

#region InitTable() - Create the Adjacency Matrix table.

private void InitTable()
{//Create the Adjacency Matrix table.

tbl = new DataTable();

col = new DataColumn("ID");
tbl.Columns.Add(col);
col = new DataColumn("PID");
tbl.Columns.Add(col);
col = new DataColumn("Info");
tbl.Columns.Add(col);

tbl.AcceptChanges();

}

#endregion InitTable() - Create the Adjacency Matrix table.

#region initTableData() - Populate the Adjacency Matrix table.

private void initTableData()
{//Populate the Adjacency Matrix table.
DataRow r;

r = tbl.NewRow();
r["ID"] = "0";
r["PID"] = "-1";
r["Info"] = "Root";
tbl.Rows.Add(r);


r = tbl.NewRow();
r["ID"] = "1";
r["PID"] = "0";
r["Info"] = "Menu1";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "10";
r["PID"] = "0";
r["Info"] = "Menu10";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "2";
r["PID"] = "0";
r["Info"] = "Menu2";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "3";
r["PID"] = "0";
r["Info"] = "Menu3";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "4";
r["PID"] = "1";
r["Info"] = "Menu4";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "5";
r["PID"] = "4";
r["Info"] = "Menu5";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "6";
r["PID"] = "5";
r["Info"] = "Menu6";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "7";
r["PID"] = "2";
r["Info"] = "Menu7";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "11";
r["PID"] = "6";
r["Info"] = "Menu11";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "8";
r["PID"] = "10";
r["Info"] = "Menu8";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "9";
r["PID"] = "3";
r["Info"] = "Menu9";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "12";
r["PID"] = "7";
r["Info"] = "Menu12";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "13";
r["PID"] = "4";
r["Info"] = "Menu13";
tbl.Rows.Add(r);

}

#endregion initTableData() - Populate the Adjacency Matrix
table.

#region Form1_Load() - Create the root tree node.

private void Form1_Load(object sender, EventArgs e)
{
//Create the root tree node.
TreeNode r = new TreeNode();
r.Text = "Root";
initTreeView(r);
tree.Nodes.Add(r);
tree.ExpandAll();
}

#endregion Form1_Load()

//The first pass the root tree node created in ther form load
is passed.
private void initTreeView(TreeNode N)
{//This is the recursive method, calling it's self from the
FOR loop at 201.
//This creates nested tables containing the children for each
node.

//Create a temp table to act as a buffer to hold the
//children of the current node.
DataTable temp = new DataTable();
col = new DataColumn("ID");
temp.Columns.Add(col);
col = new DataColumn("PID");
temp.Columns.Add(col);
col = new DataColumn("Info");
temp.Columns.Add(col);
temp.AcceptChanges();

//Retrieve the child ID of the current node.
string id = getID(N);


foreach (DataRow r1 in tbl.Rows)
{//Step through the Adjacency Matrix table to find
//all the children of the current node.

if (r1["PID"].ToString() == id)
{//This row represents a child of the current node.

//Add a row to the buffer table to contain this
child
//of the of the current node.
DataRow r2 = temp.NewRow();
r2["ID"] = r1["ID"].ToString();
r2["PID"] = r1["PID"].ToString();
r2["Info"] = r1["Info"].ToString();
temp.Rows.Add(r2);
temp.AcceptChanges();
}
}

foreach (DataRow r3 in temp.Rows)
{//Step through the buffer table and create a node for
each row.
//These are the children of the current node.

//If temp is empty control pops ouit and goes to
initTreeView()
//calls it's self, back to 157.

TreeNode tn = new TreeNode();
tn.Text = r3["Info"].ToString();

//This is where initTreeView() calls it's self, back
to 157
//To create a nested table to hold the children of
this node.
initTreeView(tn);

N.Nodes.Add(tn);
}
}

//Return the child ID of the current node.
private string getID(TreeNode N)
{

foreach (DataRow r in tbl.Rows)
{
//Step through the Adjacency Matrix table to find row
//representing the current node. Return the child ID.
if (r["Info"].ToString() == N.Text)
return r["ID"].ToString();
}
return "";
}
}
}
 
C

Christof Nordiek

Why does this code work?
I am new to C# and have been studying this piece of code. It loops
through an Adjacency Matrix table to populate a tree view. I have two
questions about why this code works.

1. initTreeView(TreeNode N) creates a new "temp" table to hold
the children for each node. Each time the table is created it has the
same name "temp". Why doesn't the table just get over written each
time?

temp is a local variable, wich exists once per call of the method. So each
of the recursive call has its own temp, wich refers to its own table.
2. In the foreach (DataRow r3 in temp.Rows) loop, if the temp
table is empty like when Menu11 is reached the call to
initTreeView(tn) is not executed but for all the parent nodes Menu1,
Menu4, Menu5 and Menu6 initTreeView(tn) is executed. There is no code
to indicate that at Menu11 not to execute initTreeView(tn) How does
C# know when to execute initTreeView(tn) and when not to?

initTreeView(tn) is called inside the foreach loop, so it is called once for
each row in temp. If temp has no rows initTree is not called here.

Christof
namespace DynamicTree
{
public partial class Form1 : Form
{
//Declare the table that will be populated with the Adjacency
Matrix data.
DataTable tbl;
//Declare the coumns that will be populated in the Adjacency
Matrix table.
DataColumn col;

public Form1()
{
InitializeComponent();
//Create the Adjacency Matrix table.
InitTable();
//Populate the Adjacency Matrix table.
initTableData();
}

#region InitTable() - Create the Adjacency Matrix table.

private void InitTable()
{//Create the Adjacency Matrix table.

tbl = new DataTable();

col = new DataColumn("ID");
tbl.Columns.Add(col);
col = new DataColumn("PID");
tbl.Columns.Add(col);
col = new DataColumn("Info");
tbl.Columns.Add(col);

tbl.AcceptChanges();

}

#endregion InitTable() - Create the Adjacency Matrix table.

#region initTableData() - Populate the Adjacency Matrix table.

private void initTableData()
{//Populate the Adjacency Matrix table.
DataRow r;

r = tbl.NewRow();
r["ID"] = "0";
r["PID"] = "-1";
r["Info"] = "Root";
tbl.Rows.Add(r);


r = tbl.NewRow();
r["ID"] = "1";
r["PID"] = "0";
r["Info"] = "Menu1";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "10";
r["PID"] = "0";
r["Info"] = "Menu10";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "2";
r["PID"] = "0";
r["Info"] = "Menu2";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "3";
r["PID"] = "0";
r["Info"] = "Menu3";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "4";
r["PID"] = "1";
r["Info"] = "Menu4";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "5";
r["PID"] = "4";
r["Info"] = "Menu5";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "6";
r["PID"] = "5";
r["Info"] = "Menu6";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "7";
r["PID"] = "2";
r["Info"] = "Menu7";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "11";
r["PID"] = "6";
r["Info"] = "Menu11";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "8";
r["PID"] = "10";
r["Info"] = "Menu8";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "9";
r["PID"] = "3";
r["Info"] = "Menu9";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "12";
r["PID"] = "7";
r["Info"] = "Menu12";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "13";
r["PID"] = "4";
r["Info"] = "Menu13";
tbl.Rows.Add(r);

}

#endregion initTableData() - Populate the Adjacency Matrix
table.

#region Form1_Load() - Create the root tree node.

private void Form1_Load(object sender, EventArgs e)
{
//Create the root tree node.
TreeNode r = new TreeNode();
r.Text = "Root";
initTreeView(r);
tree.Nodes.Add(r);
tree.ExpandAll();
}

#endregion Form1_Load()

//The first pass the root tree node created in ther form load
is passed.
private void initTreeView(TreeNode N)
{//This is the recursive method, calling it's self from the
FOR loop at 201.
//This creates nested tables containing the children for each
node.

//Create a temp table to act as a buffer to hold the
//children of the current node.
DataTable temp = new DataTable();
col = new DataColumn("ID");
temp.Columns.Add(col);
col = new DataColumn("PID");
temp.Columns.Add(col);
col = new DataColumn("Info");
temp.Columns.Add(col);
temp.AcceptChanges();

//Retrieve the child ID of the current node.
string id = getID(N);


foreach (DataRow r1 in tbl.Rows)
{//Step through the Adjacency Matrix table to find
//all the children of the current node.

if (r1["PID"].ToString() == id)
{//This row represents a child of the current node.

//Add a row to the buffer table to contain this
child
//of the of the current node.
DataRow r2 = temp.NewRow();
r2["ID"] = r1["ID"].ToString();
r2["PID"] = r1["PID"].ToString();
r2["Info"] = r1["Info"].ToString();
temp.Rows.Add(r2);
temp.AcceptChanges();
}
}

foreach (DataRow r3 in temp.Rows)
{//Step through the buffer table and create a node for
each row.
//These are the children of the current node.

//If temp is empty control pops ouit and goes to
initTreeView()
//calls it's self, back to 157.

TreeNode tn = new TreeNode();
tn.Text = r3["Info"].ToString();

//This is where initTreeView() calls it's self, back
to 157
//To create a nested table to hold the children of
this node.
initTreeView(tn);

N.Nodes.Add(tn);
}
}

//Return the child ID of the current node.
private string getID(TreeNode N)
{

foreach (DataRow r in tbl.Rows)
{
//Step through the Adjacency Matrix table to find row
//representing the current node. Return the child ID.
if (r["Info"].ToString() == N.Text)
return r["ID"].ToString();
}
return "";
}
}
}
 
I

IfThenElse

Recursion, a function calling itself. keeps everything in a stack, same
table name but different instance and references are kept.
Once a Node does not have any more child nodes the foreach is not executed
you can not in recursion target a specific node, like Menu11, and check on
it.

you have to examine everyone Node and return to the calling function (
itself ) to continue with the previous sibling Node, if any, that might
have many children Nodes.


Why does this code work?
I am new to C# and have been studying this piece of code. It loops
through an Adjacency Matrix table to populate a tree view. I have two
questions about why this code works.

1. initTreeView(TreeNode N) creates a new "temp" table to hold
the children for each node. Each time the table is created it has the
same name "temp". Why doesn't the table just get over written each
time?
2. In the foreach (DataRow r3 in temp.Rows) loop, if the temp
table is empty like when Menu11 is reached the call to
initTreeView(tn) is not executed but for all the parent nodes Menu1,
Menu4, Menu5 and Menu6 initTreeView(tn) is executed. There is no code
to indicate that at Menu11 not to execute initTreeView(tn) How does
C# know when to execute initTreeView(tn) and when not to?


namespace DynamicTree
{
public partial class Form1 : Form
{
//Declare the table that will be populated with the Adjacency
Matrix data.
DataTable tbl;
//Declare the coumns that will be populated in the Adjacency
Matrix table.
DataColumn col;

public Form1()
{
InitializeComponent();
//Create the Adjacency Matrix table.
InitTable();
//Populate the Adjacency Matrix table.
initTableData();
}

#region InitTable() - Create the Adjacency Matrix table.

private void InitTable()
{//Create the Adjacency Matrix table.

tbl = new DataTable();

col = new DataColumn("ID");
tbl.Columns.Add(col);
col = new DataColumn("PID");
tbl.Columns.Add(col);
col = new DataColumn("Info");
tbl.Columns.Add(col);

tbl.AcceptChanges();

}

#endregion InitTable() - Create the Adjacency Matrix table.

#region initTableData() - Populate the Adjacency Matrix table.

private void initTableData()
{//Populate the Adjacency Matrix table.
DataRow r;

r = tbl.NewRow();
r["ID"] = "0";
r["PID"] = "-1";
r["Info"] = "Root";
tbl.Rows.Add(r);


r = tbl.NewRow();
r["ID"] = "1";
r["PID"] = "0";
r["Info"] = "Menu1";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "10";
r["PID"] = "0";
r["Info"] = "Menu10";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "2";
r["PID"] = "0";
r["Info"] = "Menu2";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "3";
r["PID"] = "0";
r["Info"] = "Menu3";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "4";
r["PID"] = "1";
r["Info"] = "Menu4";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "5";
r["PID"] = "4";
r["Info"] = "Menu5";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "6";
r["PID"] = "5";
r["Info"] = "Menu6";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "7";
r["PID"] = "2";
r["Info"] = "Menu7";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "11";
r["PID"] = "6";
r["Info"] = "Menu11";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "8";
r["PID"] = "10";
r["Info"] = "Menu8";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "9";
r["PID"] = "3";
r["Info"] = "Menu9";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "12";
r["PID"] = "7";
r["Info"] = "Menu12";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "13";
r["PID"] = "4";
r["Info"] = "Menu13";
tbl.Rows.Add(r);

}

#endregion initTableData() - Populate the Adjacency Matrix
table.

#region Form1_Load() - Create the root tree node.

private void Form1_Load(object sender, EventArgs e)
{
//Create the root tree node.
TreeNode r = new TreeNode();
r.Text = "Root";
initTreeView(r);
tree.Nodes.Add(r);
tree.ExpandAll();
}

#endregion Form1_Load()

//The first pass the root tree node created in ther form load
is passed.
private void initTreeView(TreeNode N)
{//This is the recursive method, calling it's self from the
FOR loop at 201.
//This creates nested tables containing the children for each
node.

//Create a temp table to act as a buffer to hold the
//children of the current node.
DataTable temp = new DataTable();
col = new DataColumn("ID");
temp.Columns.Add(col);
col = new DataColumn("PID");
temp.Columns.Add(col);
col = new DataColumn("Info");
temp.Columns.Add(col);
temp.AcceptChanges();

//Retrieve the child ID of the current node.
string id = getID(N);


foreach (DataRow r1 in tbl.Rows)
{//Step through the Adjacency Matrix table to find
//all the children of the current node.

if (r1["PID"].ToString() == id)
{//This row represents a child of the current node.

//Add a row to the buffer table to contain this
child
//of the of the current node.
DataRow r2 = temp.NewRow();
r2["ID"] = r1["ID"].ToString();
r2["PID"] = r1["PID"].ToString();
r2["Info"] = r1["Info"].ToString();
temp.Rows.Add(r2);
temp.AcceptChanges();
}
}

foreach (DataRow r3 in temp.Rows)
{//Step through the buffer table and create a node for
each row.
//These are the children of the current node.

//If temp is empty control pops ouit and goes to
initTreeView()
//calls it's self, back to 157.

TreeNode tn = new TreeNode();
tn.Text = r3["Info"].ToString();

//This is where initTreeView() calls it's self, back
to 157
//To create a nested table to hold the children of
this node.
initTreeView(tn);

N.Nodes.Add(tn);
}
}

//Return the child ID of the current node.
private string getID(TreeNode N)
{

foreach (DataRow r in tbl.Rows)
{
//Step through the Adjacency Matrix table to find row
//representing the current node. Return the child ID.
if (r["Info"].ToString() == N.Text)
return r["ID"].ToString();
}
return "";
}
}
}
 
X

xmail123

Thank you for the answers I understand what is happening now.

:)

Why does this code work?
I am new to C# and have been studying this piece of code. It loops
through an Adjacency Matrix table to populate a tree view. I have two
questions about why this code works.

1. initTreeView(TreeNode N) creates a new "temp" table to hold
the children for each node. Each time the table is created it has the
same name "temp". Why doesn't the table just get over written each
time?
2. In the foreach (DataRow r3 in temp.Rows) loop, if the temp
table is empty like when Menu11 is reached the call to
initTreeView(tn) is not executed but for all the parent nodes Menu1,
Menu4, Menu5 and Menu6 initTreeView(tn) is executed. There is no code
to indicate that at Menu11 not to execute initTreeView(tn) How does
C# know when to execute initTreeView(tn) and when not to?


namespace DynamicTree
{
public partial class Form1 : Form
{
//Declare the table that will be populated with the Adjacency
Matrix data.
DataTable tbl;
//Declare the coumns that will be populated in the Adjacency
Matrix table.
DataColumn col;

public Form1()
{
InitializeComponent();
//Create the Adjacency Matrix table.
InitTable();
//Populate the Adjacency Matrix table.
initTableData();
}

#region InitTable() - Create the Adjacency Matrix table.

private void InitTable()
{//Create the Adjacency Matrix table.

tbl = new DataTable();

col = new DataColumn("ID");
tbl.Columns.Add(col);
col = new DataColumn("PID");
tbl.Columns.Add(col);
col = new DataColumn("Info");
tbl.Columns.Add(col);

tbl.AcceptChanges();

}

#endregion InitTable() - Create the Adjacency Matrix table.

#region initTableData() - Populate the Adjacency Matrix table.

private void initTableData()
{//Populate the Adjacency Matrix table.
DataRow r;

r = tbl.NewRow();
r["ID"] = "0";
r["PID"] = "-1";
r["Info"] = "Root";
tbl.Rows.Add(r);


r = tbl.NewRow();
r["ID"] = "1";
r["PID"] = "0";
r["Info"] = "Menu1";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "10";
r["PID"] = "0";
r["Info"] = "Menu10";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "2";
r["PID"] = "0";
r["Info"] = "Menu2";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "3";
r["PID"] = "0";
r["Info"] = "Menu3";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "4";
r["PID"] = "1";
r["Info"] = "Menu4";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "5";
r["PID"] = "4";
r["Info"] = "Menu5";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "6";
r["PID"] = "5";
r["Info"] = "Menu6";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "7";
r["PID"] = "2";
r["Info"] = "Menu7";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "11";
r["PID"] = "6";
r["Info"] = "Menu11";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "8";
r["PID"] = "10";
r["Info"] = "Menu8";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "9";
r["PID"] = "3";
r["Info"] = "Menu9";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "12";
r["PID"] = "7";
r["Info"] = "Menu12";
tbl.Rows.Add(r);

r = tbl.NewRow();
r["ID"] = "13";
r["PID"] = "4";
r["Info"] = "Menu13";
tbl.Rows.Add(r);

}

#endregion initTableData() - Populate the Adjacency Matrix
table.

#region Form1_Load() - Create the root tree node.

private void Form1_Load(object sender, EventArgs e)
{
//Create the root tree node.
TreeNode r = new TreeNode();
r.Text = "Root";
initTreeView(r);
tree.Nodes.Add(r);
tree.ExpandAll();
}

#endregion Form1_Load()

//The first pass the root tree node created in ther form load
is passed.
private void initTreeView(TreeNode N)
{//This is the recursive method, calling it's self from the
FOR loop at 201.
//This creates nested tables containing the children for each
node.

//Create a temp table to act as a buffer to hold the
//children of the current node.
DataTable temp = new DataTable();
col = new DataColumn("ID");
temp.Columns.Add(col);
col = new DataColumn("PID");
temp.Columns.Add(col);
col = new DataColumn("Info");
temp.Columns.Add(col);
temp.AcceptChanges();

//Retrieve the child ID of the current node.
string id = getID(N);


foreach (DataRow r1 in tbl.Rows)
{//Step through the Adjacency Matrix table to find
//all the children of the current node.

if (r1["PID"].ToString() == id)
{//This row represents a child of the current node.

//Add a row to the buffer table to contain this
child
//of the of the current node.
DataRow r2 = temp.NewRow();
r2["ID"] = r1["ID"].ToString();
r2["PID"] = r1["PID"].ToString();
r2["Info"] = r1["Info"].ToString();
temp.Rows.Add(r2);
temp.AcceptChanges();
}
}

foreach (DataRow r3 in temp.Rows)
{//Step through the buffer table and create a node for
each row.
//These are the children of the current node.

//If temp is empty control pops ouit and goes to
initTreeView()
//calls it's self, back to 157.

TreeNode tn = new TreeNode();
tn.Text = r3["Info"].ToString();

//This is where initTreeView() calls it's self, back
to 157
//To create a nested table to hold the children of
this node.
initTreeView(tn);

N.Nodes.Add(tn);
}
}

//Return the child ID of the current node.
private string getID(TreeNode N)
{

foreach (DataRow r in tbl.Rows)
{
//Step through the Adjacency Matrix table to find row
//representing the current node. Return the child ID.
if (r["Info"].ToString() == N.Text)
return r["ID"].ToString();
}
return "";
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top