March 27, 2014 at 4:58 pm
Click on the attachment, save as text file (default option).
Then open it and choose File, Save As, Save as type: All Files, add .sql extension to filename (1_Script.sql), click Save.
You only need to save and download the following script, it will create the database, tables,
stored procedure (collation is 'SQL_Latin1_General_CP1_CI_AS') : 1_Script.txt
Below is a copy of the stored procedure:
............................................................
ALTER PROC [dbo].[usp_HierarchyCTE]
@SRID nvarchar(max)
AS
-- exec usp_HierarchyCTE 'SR49931' -- returns 27 records
-- exec usp_HierarchyCTE 'SR43648' -- returns 11 records
-- exec usp_HierarchyCTE 'SR49931,SR43648' -- should return 38 records, currently returns null
DECLARE @tableID TABLE (value nvarchar(256))
INSERT @tableID (value)
SELECT * FROM dbo.fn_CSVToTableString(ISNULL(@SRID,''))
-- get the specified SR only (lists all the anchor objects)
SELECT distinct
ad.Id AS ad_Id
,CASE WHEN workitem.Id in (@SRID) THEN ad.SequenceId ELSE NULL END AS ad_SequenceId
,ad.Title AS ad_Title
,workitem.Id AS workitem_Id
INTO #SUMMARY
FROM dbo.ActivityDimvw ad
left JOIN dbo.WorkItemContainsActivityFactvw wicaf ON wicaf.WorkItemContainsActivity_ActivityDimKey = ad.ActivityDimKey
left join dbo.WorkItemDimvw workitem ON wicaf.WorkItemDimKey = workitem.WorkItemDimKey
join dbo.RelationshipView RV ON RV.TargetEntityId = ad.BaseManagedEntityId AND RV.SourceEntityId = workitem.BaseManagedEntityId
Where
workitem.Id in (@SRID)
UNION
-- get everything except the specified SR (everything else is child objects of anchor objects)
SELECT distinct
ad.Id AS ad_Id
,CASE WHEN workitem.Id in (@SRID) THEN ad.SequenceId ELSE NULL END AS ad_SequenceId
,ad.Title AS ad_Title
,workitem.Id AS workitem_Id
FROM dbo.ActivityDimvw ad
left join dbo.WorkItemContainsActivityFactvw wicaf ON wicaf.WorkItemContainsActivity_ActivityDimKey = ad.ActivityDimKey
left join dbo.WorkItemDimvw workitem ON wicaf.WorkItemDimKey = workitem.WorkItemDimKey
join dbo.RelationshipView RV ON RV.TargetEntityId = ad.BaseManagedEntityId AND RV.SourceEntityId = workitem.BaseManagedEntityId
Where
workitem.Id not in (@SRID)
ORDER BY workitem.Id desc, ad_SequenceId
------------------------------------------------------------------------------------------
DECLARE @lvl_limit AS int = 2; -- the highest level reached is 1, therefore I used 2.
;WITH EmpCTE1([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 0 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE1 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
--------------------------------------------------------------
,EmpCTE2([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 1 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE2 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
--------------------------------------------------------------
,EmpCTE3([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 2 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE3 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
--------------------------------------------------------------
,EmpCTE4([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 3 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE4 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
--------------------------------------------------------------
,EmpCTE5([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 4 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE5 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
--------------------------------------------------------------
,EmpCTE6([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 5 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE6 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
--------------------------------------------------------------
,EmpCTE7([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 6 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE7 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
--------------------------------------------------------------
,EmpCTE8([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 7 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE8 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
--------------------------------------------------------------
,EmpCTE9([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 8 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE9 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
--------------------------------------------------------------
,EmpCTE10([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 9 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE10 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
---------------------------------------------------------------
SELECT * FROM EmpCTE1
UNION ALL
SELECT * FROM EmpCTE2
UNION ALL
SELECT * FROM EmpCTE3
UNION ALL
SELECT * FROM EmpCTE4
UNION ALL
SELECT * FROM EmpCTE5
UNION ALL
SELECT * FROM EmpCTE6
UNION ALL
SELECT * FROM EmpCTE7
UNION ALL
SELECT * FROM EmpCTE8
UNION ALL
SELECT * FROM EmpCTE9
UNION ALL
SELECT * FROM EmpCTE10
--------------------------------------------------------------
DROP TABLE #SUMMARY
--------------------------------------------------------------
/*
Explanation:
................
The result displayed via column ad_SequenceId is:
0 for 1st (top) anchor
1 for 2nd anchor
(NULL) then 3 children belonging to 2nd anchor
2 for 3rd anchor
3 for 4th anchor
(NULL) then 4 children belonging to 4th anchor
and so forth
Currently the query works fine if workitem.Id in ('SR49931') or workitem.Id in ('SR43648')
(view the where clause of first query).
How do I get it working with both 'SR49931' and 'SR43648' .
i.e. It should return 27 records if 'SR49931' is specified,
and return 11 records if 'SR43648' is specified,
and return 38 records if both 'SR49931' and 'SR43648' is specified.
You can remove @lvl_limit from the stored procedure / query if you want.
*/
March 28, 2014 at 7:41 am
Can you post ddl and sample data in a consumable format? I am not a big fan of opening up rar files from the internet. You can post the information inside of code blocks and it will keep the formatting pretty decently.
_______________________________________________________________
Need help? Help us help you.
Read the article at http://www.sqlservercentral.com/articles/Best+Practices/61537/ for best practices on asking questions.
Need to split a string? Try Jeff Modens splitter http://www.sqlservercentral.com/articles/Tally+Table/72993/.
Cross Tabs and Pivots, Part 1 – Converting Rows to Columns - http://www.sqlservercentral.com/articles/T-SQL/63681/
Cross Tabs and Pivots, Part 2 - Dynamic Cross Tabs - http://www.sqlservercentral.com/articles/Crosstab/65048/
Understanding and Using APPLY (Part 1) - http://www.sqlservercentral.com/articles/APPLY/69953/
Understanding and Using APPLY (Part 2) - http://www.sqlservercentral.com/articles/APPLY/69954/
March 28, 2014 at 11:53 am
Hi Sean Lange, I listed the full query.
Unfortunately there is no way around the table scripts (includes both schema and data scripts),
I tried limiting the records for 'SR49931' only - so I could copy and paste the scripts onto this post, only to find that in the end the first part of the query (containing union) gave same result as entire query, thus bypassing the rest of query, which of course defeats the purpose. If someone can
download the table scripts and use it to create a sample to use for testing and paste it onto this post I would be happy, I tried and failed to achieve that with the data I had (I guess the anchor nature of it had something to do with it). I you don't like WinRAR compressed files, I can always try the compression functionality that comes with Windows 7 (work similar to WinZip).
(I use Kaspersky Internet Security, so the attached files are free from any form of virus).
March 28, 2014 at 12:22 pm
The point is to make it easy for us volunteers to help. I really don't want to download several zip files and do a bunch of stuff setting up the problem. Are you having issues posting code on the site? I have heard of other people having those issues as well.
_______________________________________________________________
Need help? Help us help you.
Read the article at http://www.sqlservercentral.com/articles/Best+Practices/61537/ for best practices on asking questions.
Need to split a string? Try Jeff Modens splitter http://www.sqlservercentral.com/articles/Tally+Table/72993/.
Cross Tabs and Pivots, Part 1 – Converting Rows to Columns - http://www.sqlservercentral.com/articles/T-SQL/63681/
Cross Tabs and Pivots, Part 2 - Dynamic Cross Tabs - http://www.sqlservercentral.com/articles/Crosstab/65048/
Understanding and Using APPLY (Part 1) - http://www.sqlservercentral.com/articles/APPLY/69953/
Understanding and Using APPLY (Part 2) - http://www.sqlservercentral.com/articles/APPLY/69954/
March 28, 2014 at 1:20 pm
Sean, if I had issue posting stuff how did I get my query posted ?
Secondly, if you download the files, open SQL Server, create a new database, paste the files (unzipped) into SSMS query window and press F5, et voila. you're done. Then simply run the query I posted. When you then reduce the number of records in each of those tables - you will find that the query no longer works as it was supposed to (unless I missed something). I limited the records to the 2 SRID's I mentioned (to reduce the records), scripted the schema and data, WinRAR them to reduce the file size before uploading to this website.
Anyways, will try again to reduce the number of records in each of those tables - so there is only a few records in each table (making it easy to create script and paste onto this post).
March 28, 2014 at 4:26 pm
Hi Sean, I managed to create scripts which only includes the very minimum records, therefore no need to compress them. Attached the 3 scripts. First script is to create a database called TEST, second script will create 4 tables and populate them with data, third script is same as the one I posted.
Saving the scripts and running them should take less than one minute (I tested it).
March 29, 2014 at 9:19 am
kevin_nikolai (3/28/2014)
Hi Sean, I managed to create scripts which only includes the very minimum records, therefore no need to compress them. Attached the 3 scripts. First script is to create a database called TEST, second script will create 4 tables and populate them with data, third script is same as the one I posted.Saving the scripts and running them should take less than one minute (I tested it).
I would suggest testing a little further. Not everyone uses case insensitive collations. For what ever reason I actually like using case sensitive collations and I write my code with that in mind even when working with databses and servers where the collation is case insensitive. If I name a column Lvl in a table or CTE that is how I will reference it further down in the code. You won't see me call it Lvl in a declaration or column alias then refer to it later as lvl.
March 29, 2014 at 9:27 am
Here is where I am going to start you. Since you have declared the input parameter to the stored procedure as NVARCHAR(MAX) I would not use a T-SQL CSV splitter for this but instead look at the CLR version that I believe is also contained in the resources for the article you should read.
March 29, 2014 at 3:27 pm
Hi Lynn,
Since the highest level reached is 1, for simplicity sake, you can remove the following:
DECLARE @lvl_limit AS int = 2;
and
WHERE lvl < @lvl_limit
----------------------------------
You can use the following:
@SRID varchar(10)
----------------------------------
I updated the query posted above.
Also, you mentioned 'case insensitive collations' , if you use the '1_Create DB script.txt' file,
it will create a database called TEST, your other databases or SQL server won't be affected.
The reason the '1_Create DB script.txt' uses the collation mentioned is because the tables
I use has that collation, so instead of someone trying to figure out which line their query is
asking for the collate function to be added, I decided to improvise (just to help).
March 29, 2014 at 4:07 pm
kevin_nikolai (3/29/2014)
Hi Lynn,Since the highest level reached is 1, for simplicity sake, you can remove the following:
DECLARE @lvl_limit AS int = 2;
and
WHERE lvl < @lvl_limit
----------------------------------
You can use the following:
@SRID varchar(10)
----------------------------------
I updated the query posted above.
Also, you mentioned 'case insensitive collations' , if you use the '1_Create DB script.txt' file,
it will create a database called TEST, your other databases or SQL server won't be affected.
The reason the '1_Create DB script.txt' uses the collation mentioned is because the tables
I use has that collation, so instead of someone trying to figure out which line their query is
asking for the collate function to be added, I decided to improvise (just to help).
Your create database script failed to run on my development system, and no I don't really want to rerun the script to find the error nor did I even bother to debug the script. Bottom line, the point I was trying to make is that you should try to be consistent in writing code so that it will work properly when run regardless of collation used in the database.
March 29, 2014 at 8:47 pm
Lynn Pettis (3/29/2014)
kevin_nikolai (3/28/2014)
Hi Sean, I managed to create scripts which only includes the very minimum records, therefore no need to compress them. Attached the 3 scripts. First script is to create a database called TEST, second script will create 4 tables and populate them with data, third script is same as the one I posted.Saving the scripts and running them should take less than one minute (I tested it).
I would suggest testing a little further. Not everyone uses case insensitive collations. For what ever reason I actually like using case sensitive collations and I write my code with that in mind even when working with databses and servers where the collation is case insensitive. If I name a column Lvl in a table or CTE that is how I will reference it further down in the code. You won't see me call it Lvl in a declaration or column alias then refer to it later as lvl.
Just a sidebar... I hate case sensitive servers mostly because no one seems to follow a decent standard (Pascal casing is the one I like). Even MS has used every type of casing known to man in their tables and it makes code look like a rookie with a nervous twitch wrote it.
I do agree with you on one great point though... If I type something as "Lvl" in one spot, I'll type it the same way throughout my code. I just want the choice of which way I'm going to case things instead of being compelled to type database, table, and column names according to the screwed up mixed standard that someone else has used.
--Jeff Moden
Change is inevitable... Change for the better is not.
March 29, 2014 at 9:01 pm
Jeff Moden (3/29/2014)
Lynn Pettis (3/29/2014)
kevin_nikolai (3/28/2014)
Hi Sean, I managed to create scripts which only includes the very minimum records, therefore no need to compress them. Attached the 3 scripts. First script is to create a database called TEST, second script will create 4 tables and populate them with data, third script is same as the one I posted.Saving the scripts and running them should take less than one minute (I tested it).
I would suggest testing a little further. Not everyone uses case insensitive collations. For what ever reason I actually like using case sensitive collations and I write my code with that in mind even when working with databses and servers where the collation is case insensitive. If I name a column Lvl in a table or CTE that is how I will reference it further down in the code. You won't see me call it Lvl in a declaration or column alias then refer to it later as lvl.
Just a sidebar... I hate case sensitive servers mostly because no one seems to follow a decent standard (Pascal casing is the one I like). Even MS has used every type of casing known to man in their tables and it makes code look like a rookie with a nervous twitch wrote it.
I do agree with you on one great point though... If I type something as "Lvl" in one spot, I'll type it the same way throughout my code. I just want the choice of which way I'm going to case things instead of being compelled to type database, table, and column names according to the screwed up mixed standard that someone else has used.
You know what they say, standards are great and everyone has their own. Using a case sensitive collation forces me to be consistent in the use of object names in my code. It has gotten to the point where it is almost reflex now since I have been doing for so long. I do have to admit, however, even I slip some times especially on a one off ad hoc query where I just need a quick answer. Production code however I still strive for consistency.
March 29, 2014 at 9:19 pm
True enough. And definitely to each their own. The thing I find ironic is that, like you, I've become much more consistent in my coding over the years but it's been for exactly the opposite reason.
--Jeff Moden
Change is inevitable... Change for the better is not.
March 29, 2014 at 11:50 pm
Hi Jeff / Lynn, I updated the query I posted.
Added '1_Script.txt' , collation is 'SQL_Latin1_General_CP1_CI_AS'.
Added function to cater for multiple SRID's via the parameter ( @SRID nvarchar(max) ).
Added stored procedure 'usp_HierarchyCTE'
So there is nothing else to do except run the script, view and run the stored procedure.
--------------------------------------------------------------------
It seems the issue is related to the following - you cannot add more than one SRID - so I might need to use a while loop or cursor to loop through the below EmpCTE1 to EmpCTE10 for every SRID.
Guess you and Jeff might say I must be crazy, which is exactly why I posted my issue - to find a better solution / improve performance of the stored procedure.
;WITH EmpCTE1([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 0 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE1 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
March 30, 2014 at 6:36 am
kevin_nikolai (3/29/2014)
Hi Jeff / Lynn, I updated the query I posted.Added '1_Script.txt' , collation is 'SQL_Latin1_General_CP1_CI_AS'.
Added function to cater for multiple SRID's via the parameter ( @SRID nvarchar(max) ).
Added stored procedure 'usp_HierarchyCTE'
So there is nothing else to do except run the script, view and run the stored procedure.
--------------------------------------------------------------------
It seems the issue is related to the following - you cannot add more than one SRID - so I might need to use a while loop or cursor to loop through the below EmpCTE1 to EmpCTE10 for every SRID.
Guess you and Jeff might say I must be crazy, which is exactly why I posted my issue - to find a better solution / improve performance of the stored procedure.
;WITH EmpCTE1([ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], Lvl)
AS
(
SELECT [ad_Id], [ad_SequenceId], [ad_Title], [workitem_Id], 0 AS Lvl
FROM #SUMMARY AS E
WHERE [ad_Id] = (SELECT [ad_Id] FROM #SUMMARY WHERE [ad_SequenceId] = 0 and workitem_Id = @SRID)
UNION ALL
SELECT E.[ad_Id], E.[ad_SequenceId], E.[ad_Title], E.[workitem_Id], Lvl + 1
FROM #SUMMARY AS E
JOIN EmpCTE1 AS M ON E.[workitem_Id] = M.[ad_Id]
WHERE Lvl < @lvl_limit
)
First, once again your CREATE DATABASE code fails for me:
Msg 5133, Level 16, State 1, Line 2
Directory lookup for the file "C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\HierarchyCTE.mdf" failed with the operating system error 3(The system cannot find the path specified.).
Msg 1802, Level 16, State 1, Line 2
CREATE DATABASE failed. Some file names listed could not be created. Check related errors.
Your code assumes the same directory structure for everyone. Some people setup different default locations for the data and log files. Sorry, don't feel like modifying your code to fit my installation so no HierarchyCTE database to work in, so I'll just continue to use my Sandbox databse.
Back in bit to regarding your other issue, but I will make a few changes to fit what I have.
Viewing 15 posts - 1 through 15 (of 27 total)
You must be logged in to reply to this topic. Login to reply