Solved

Visual Basic Search and Replace through large text file

Posted on 2009-04-06
39
945 Views
Last Modified: 2013-11-26
Hello.  A few months ago an expert helped me develop visual basic code to perform a search and replace in a data file.  At the time the file was about 100mb.  The file has grown to over 200mb and the program does not work anymore.  Is there a way to modify the code so that it won't bomb on files over 200mb?  Any help would be greatly appreciated.  

Thank you
Diammond
Imports System.Text.RegularExpressions

Module Module1

    Public strNewPhoneNumber As String = """2126420001"""

    Public intRepCount As Integer = 0

    Sub Main()

        If IO.File.Exists("c:\reports\replaced.log") Then

            IO.File.Delete("c:\reports\replaced.log")

        End If

        Dim srDataFile As New System.IO.StreamReader("c:\reports\data.txt")

        Dim strDataFile As String = srDataFile.ReadToEnd

        srDataFile.Close()

 

        Dim srPhoneNumbers As New System.IO.StreamReader("c:\realPhoneNumbers.txt")

        Dim strPhoneNumbers As String = srPhoneNumbers.ReadToEnd

        srDataFile.Close()

 

        Dim reNumbers As Regex = New Regex("(?<=#PhoneNumber\r\n"")\d+(?="")")

        Dim mcNumbers As MatchCollection = reNumbers.Matches(strPhoneNumbers)

        Dim strPhoneNumbersToExclude As String = ""

        For Each mNumber As Match In mcNumbers

            strPhoneNumbersToExclude = strPhoneNumbersToExclude & mNumber.Groups(0).Value & "|"

        Next

        strPhoneNumbersToExclude = Left(strPhoneNumbersToExclude, Len(strPhoneNumbersToExclude) - 1)

 

        Dim matchpattern As String = "(?<=#PhoneNumber\r\n)""(?:(?!" & strPhoneNumbersToExclude & ")\d+)"""

        Dim myEval As MatchEvaluator = New MatchEvaluator(AddressOf ReplaceMatch)

 

        Dim swNewDataFile As New System.IO.StreamWriter("c:\reports\data.txt")

        swNewDataFile.Write(Regex.Replace(strDataFile, matchpattern, myEval))

        swNewDataFile.Close()

        Console.WriteLine(intRepCount & " replacements, finished at " & Now())

    End Sub

    Public Function ReplaceMatch(ByVal m As Match) As String

        Dim swLogFile As New System.IO.StreamWriter("c:\reports\replaced.log", True)

        Dim strLogLine As String = "Replaced " & m.Groups(0).Value & " with " & strNewPhoneNumber & " " & Now()

        Console.WriteLine(strLogLine)

        swLogFile.WriteLine(strLogLine)

        swLogFile.Close()

        intRepCount = intRepCount + 1

        Return strNewPhoneNumber

    End Function

End Module

Open in new window

0
Comment
Question by:Diammond
  • 18
  • 15
  • 3
  • +1
39 Comments
 
LVL 19

Expert Comment

by:daveamour
ID: 24077150
In what context is this code being run? Eg through a WinForms app for example?
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24077808
The problem is because you are reading the entire file all at once and you're running out of memory:

    Dim strPhoneNumbers As String = srPhoneNumbers.ReadToEnd

Instead, you need to read it LINE-BY-LINE and process the lines:

        Dim srDataFile As New System.IO.StreamReader("c:\reports\data.txt")
        Dim strDataFileLine As String = srDataFile.ReadLine
        While Not IsNothing(strDataFileLine)

            ' ...do something with "strDataFile"...

            strDataFileLine = srDataFile.ReadLine
        End While
        srDataFile.Close()

I can see, however, that your Regular Expressions are looking for data that spans MULTIPLE lines:

    Dim reNumbers As Regex = New Regex("(?<=#PhoneNumber\r\n"")\d+(?="")")

So you're going to need a COMPLETELY DIFFERENT algorithm to deal with this.

Can you please explain in PLAIN ENGLISH the format of the two files (some small data examples would be excellent) and also what you are trying to do?  Then we can recommend a different approach that won't run out of memory...

0
 

Author Comment

by:Diammond
ID: 24077839
It is being called by a scheduled task on a  Windows 2003 server.
0
 

Author Comment

by:Diammond
ID: 24078226
I have tried the ReadLine method as well.  The code still chokes.  I am attaching sample data.
data.txt
RealPhoneNumbers.txt
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24078320
Yes...as I said before, it will choke because the Regular Expressions are looking for data on multiple lines and it won't find any matches since we are now reading line by line.

I can work with the data but I need to know WHAT to do with it.  Are you trying to take the values in RealPhoneNumbers.txt and remove them from data.txt?

Please explain in PLAIN ENGLISH what needs to be done...


0
 

Author Comment

by:Diammond
ID: 24078441
The code compares the phone numbers in data.txt to the phone number list in realphonenumbers.txt.  If the phone numbers in data.txt do not match any of the phone numbers found in realphonenumber.txt, then replace the phone numbers in data.txt that don't match with any of the phone numbers in realphonenumber.txt with the standard phone number 2126420001.  Hope this makes sense.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24079422
Try this out...
Public Class Form1
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim Path As String = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Downloads")

        Dim DataInFile As String = System.IO.Path.Combine(Path, "Data.txt")

        Dim DataOutFile As String = System.IO.Path.Combine(Path, "Data2.txt")

        Dim PhoneFile As String = System.IO.Path.Combine(path, "RealPhoneNumbers.txt")

        Dim AllowedNumber As String = Chr(34) & "2126420001" & Chr(34)
 

        Dim Phones As New Dictionary(Of String, String)

        Using sr As New System.IO.StreamReader(PhoneFile)

            Dim line As String = sr.ReadLine

            While Not IsNothing(line)

                If line.StartsWith(Chr(34)) Then

                    Phones.Add(line, Nothing)

                End If

                line = sr.ReadLine

            End While

        End Using
 

        Using sr As New System.IO.StreamReader(DataInFile)

            Using sw As New System.IO.StreamWriter(DataOutFile, False)

                Dim line As String = sr.ReadLine

                While Not IsNothing(line)

                    If line.StartsWith(Chr(34)) Then

                        If Not Phones.ContainsKey(line) Then

                            line = AllowedNumber

                        End If

                    End If

                    sw.WriteLine(line)

                    line = sr.ReadLine

                End While

            End Using

        End Using

    End Sub
 

End Class

Open in new window

0
 

Author Comment

by:Diammond
ID: 24079967
Ok.  I will try and get back to you.  Thank you!
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24079993
*Obviously you need to change the first line so that "Path" points to the correct folder on your system...
0
 

Author Comment

by:Diammond
ID: 24080683
I think it worked.  However, the file is too big for me to browse through.
Can you modify the original code to allow the replacements to get written to a log file?  
Log file name = replaced.log
Format of the file =
Replaced "origninal phone number" with "standard phone number" 4/6/2009 8:25:55 AM

Can you also modify the new code to make the changes within the same file (data.txt as opposed to data2.txt)?

Thank you
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24081114
To make the changes in the original file you perform the operation, delete the original, and then rename Data2.txt to Data,txt.

I find it hard to believe that you REALLY can't see how one would make a log file using the code I already posted!...  =\

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24081163
Like this:
Public Class Form1
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim Path As String = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Downloads")

        Dim DataInFile As String = System.IO.Path.Combine(Path, "Data.txt")

        Dim DataOutFile As String = System.IO.Path.Combine(Path, "Data2.txt")

        Dim PhoneFile As String = System.IO.Path.Combine(Path, "RealPhoneNumbers.txt")

        Dim LogFile As String = System.IO.Path.Combine(Path, "Replaced.log")

        Dim AllowedNumber As String = Chr(34) & "2126420001" & Chr(34)
 

        Dim Phones As New Dictionary(Of String, String)

        Using sr As New System.IO.StreamReader(PhoneFile)

            Dim line As String = sr.ReadLine

            While Not IsNothing(line)

                If line.StartsWith(Chr(34)) Then

                    Phones.Add(line, Nothing)

                End If

                line = sr.ReadLine

            End While

        End Using
 

        Using sr As New System.IO.StreamReader(DataInFile)

            Using sw As New System.IO.StreamWriter(DataOutFile, False)

                Using log As New System.IO.StreamWriter(LogFile, False)

                    Dim line As String = sr.ReadLine

                    While Not IsNothing(line)

                        If line.StartsWith(Chr(34)) Then

                            If Not Phones.ContainsKey(line) Then

                                log.WriteLine("Replaced " & line & " with " & AllowedNumber & " on " & DateTime.Now.ToString)

                                line = AllowedNumber

                            End If

                        End If

                        sw.WriteLine(line)

                        line = sr.ReadLine

                    End While

                End Using

            End Using

        End Using
 

        My.Computer.FileSystem.DeleteFile(DataInFile)

        My.Computer.FileSystem.RenameFile(DataOutFile, DataInFile)

    End Sub
 

End Class

Open in new window

0
 

Author Comment

by:Diammond
ID: 24087819
Before you added the log file, I noticed that the original file data.txt and the new data2.txt file were significantly different in size (this shouldn't be happening).  After you implemented the log, the code chokes while writing to the log and the data2.txt file never gets renamed back to data.txt.  I managed to open the log file which is extremely huge and discovered that the code is replacing a lot more than it should; hence the difference is size between the two data files and the large size of the log file.  
The code for the actual search for the phone number seems to be grabbing more than it should including text.  The format of the data.txt file contains other fields as well.  The code needs to only find the entries that look like this:
#PhoneNumber
"8602338905"

#PhoneNumber
"9525679000"

I think this where regular expressions might be beneficial.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24088749
"The format of the data.txt file contains other fields as well."

Good grief...don't you think that was KEY IMPORTANT INFORMATION that I should have known about?!   =\

You never mentioned any other data fields and the SAMPLE data files didn't show any.

"I think this where regular expressions might be beneficial."

Yes...but for the RegExs to work they have to be able to "see" the whole file at once so it can span multiple lines to find matches.  You do NOT have that luxury anymore since your file is so big.

Can you show me some ACTUAL data file samples so we can get something working for you?  Honestly, how do you expect to get good answers if you don't provide good information?!
0
 

Author Comment

by:Diammond
ID: 24090390
I assumed you knew that from my original code.  If the data file only had one type of field, there would be no need for regular expressions.  Attached is another sample.  

Thanks for your help.
data.txt
0
 

Author Comment

by:Diammond
ID: 24132049
Idle,
Did you decide to stop helping me with the code?

Thanks
Diammond
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 24164038
What may I help you with?
0
 

Author Comment

by:Diammond
ID: 24168629
Can you help me find a solution for searching and replacing text in a very large file?  The code I am currently using bombs on files over 100mb.  The code is noted at the top.

Thank you
0
What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

 
LVL 96

Expert Comment

by:Bob Learned
ID: 24169633
I see a lot of comments and help from one of our resident experts (Idle_Mind), and I would like to know where you are and what I can help with?

Are you using a StreamReader and a StreamWriter combination?  Have you stopped loading the entire file into memory with a ReadToEnd call?
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24169774
Hey Bob,

Here's the rundown:

(1) Huge file originally being read into one string and a RegEx was being used to find certain MULTI-LINE entires to replace them.

(2) It needs to be read line by line to eliminate the out of memory error.  Since the values he is looking to replace span multiple lines...it required a different approach to find them (can't use the RegEx anymore since we only see one line at a time).

(3) I asked for sample data so I could show a different algorithm.

(4) Got sample data and proposed a solution.

(5) Was told the solution I proposed doesn't work.

(6) Determined that the "sample data" was NOT representative of the actual data.  He removed (omitted) the fact that there were other types of lines in the original file.

(7) New Data has been posted.

(8) Idle_Mind has a short attention span and hasn't gotten back to the question...

(9) This is the THIRD question (iteration) from Diammond on the subject:
http://www.experts-exchange.com/Programming/Languages/Visual_Basic/Q_24181353.html
http://www.experts-exchange.com/Programming/Languages/Visual_Basic/VB_Script/Q_23657940.html
0
 
LVL 96

Expert Comment

by:Bob Learned
ID: 24170191
Mike,

It looks like you have a handle on this, and I can move on to other things, and not concern myself here.

Bob
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24170874
Does this work?
Public Class Form1
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim Path As String = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Downloads")

        Dim DataInFile As String = System.IO.Path.Combine(Path, "Data.txt")

        Dim DataOutFile As String = System.IO.Path.Combine(Path, "Data2.txt")

        Dim PhoneFile As String = System.IO.Path.Combine(Path, "RealPhoneNumbers.txt")

        Dim LogFile As String = System.IO.Path.Combine(Path, "Replaced.log")

        Dim AllowedNumber As String = Chr(34) & "2126420001" & Chr(34)

        Dim PreviousLine As String = Nothing
 

        Dim Phones As New Dictionary(Of String, String)

        Using sr As New System.IO.StreamReader(PhoneFile)

            Dim line As String = sr.ReadLine

            While Not IsNothing(line)

                If line.StartsWith(Chr(34)) Then

                    Phones.Add(line, Nothing)

                End If

                line = sr.ReadLine

            End While

        End Using
 

        Using sr As New System.IO.StreamReader(DataInFile)

            Using sw As New System.IO.StreamWriter(DataOutFile, False)

                Using log As New System.IO.StreamWriter(LogFile, False)

                    Dim line As String = sr.ReadLine

                    While Not IsNothing(line)

                        If Not IsNothing(PreviousLine) Then

                            If PreviousLine.StartsWith("#PhoneNumber") Then

                                If line.StartsWith(Chr(34)) Then

                                    If Not Phones.ContainsKey(line) Then

                                        log.WriteLine("Replaced " & line & " with " & AllowedNumber & " on " & DateTime.Now.ToString)

                                        line = AllowedNumber

                                    End If

                                End If

                            End If

                        End If
 

                        sw.WriteLine(line)

                        PreviousLine = line

                        line = sr.ReadLine

                    End While

                End Using

            End Using

        End Using
 

        My.Computer.FileSystem.DeleteFile(DataInFile)

        My.Computer.FileSystem.RenameFile(DataOutFile, DataInFile)

    End Sub
 

End Class

Open in new window

0
 

Author Comment

by:Diammond
ID: 24171378
I will try and get back to you.  Thanks for coming back!
0
 

Author Comment

by:Diammond
ID: 24185140
The code is failing (even on the 100mb file).  The data2.txt is created and then it bombs writing to data2.txt file.  It never gets to the point of deleting and renaming the file back to data.txt.  Also, even though the code fails during the creation of data2.txt, the data2.txt is still bigger than the data.txt file.  

Here is what the replaced.log file is reporting:

Replaced "" with "2126420001" on 4/20/2009 10:00:00 AM
Replaced "8606795433" with "2126420001" on 4/20/2009 10:00:00 AM

Can you modify the code not to replace the following?
#PhoneNumber
""
The code should only replace phone numbers that have an actual number between the quotes.....
#PhoneNumber
"8606795433"

I think this should fix the difference in the size of the 2 files.  Maybe it will allow the script to continue to run since the replace criteria won't be as big.

Thanks again for your help.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24185194
To filter out the blank phone numbers...

Change:

                            If PreviousLine.StartsWith("#PhoneNumber") Then
                                If line.StartsWith(Chr(34)) Then

To:

                            If PreviousLine.StartsWith("#PhoneNumber") Then
                                If line.StartsWith(Chr(34)) AndAlso line.Length > 2 Then

I'm not sure that will fix the "never gets to the point of deleting and renaming the file back to data.txt" part though.  If it's still not doing that part then post the current version of the code so I can take a look.
0
 

Author Comment

by:Diammond
ID: 24185582
The data.txt and data2.txt are now the same size.  So we know the search and replace is working as it should.  The replaced.log file is not being written to fully or not at all.  Sometimes it's zero bytes, sometimes it's not.  Therefore, the script is still not progressing to the delete and rename of the data file.  Here is the current code:

 
   Sub Main()
   
        Dim DataInFile As String = ("c:\Data.txt")
        Dim DataOutFile As String = ("c:\Data2.txt")
        Dim PhoneFile As String = ("C:\RealPhoneNumbers.txt")
        Dim LogFile As String = ("C:\Replaced.log")
        Dim AllowedNumber As String = Chr(34) & "2126420001" & Chr(34)
        Dim PreviousLine As String = Nothing
 
        Dim Phones As New Dictionary(Of String, String)
        Using sr As New System.IO.StreamReader(PhoneFile)
            Dim line As String = sr.ReadLine
            While Not IsNothing(line)
                If line.StartsWith(Chr(34)) Then
                    Phones.Add(line, Nothing)
                End If
                line = sr.ReadLine
            End While
        End Using
 
        Using sr As New System.IO.StreamReader(DataInFile)
            Using sw As New System.IO.StreamWriter(DataOutFile, False)
                Using log As New System.IO.StreamWriter(LogFile, False)
                    Dim line As String = sr.ReadLine
                    While Not IsNothing(line)
                        If Not IsNothing(PreviousLine) Then
                            If PreviousLine.StartsWith("#PhoneNumber") Then
                                If line.StartsWith(Chr(34)) AndAlso line.Length > 2 Then
                                    If Not Phones.ContainsKey(line) Then
                                        log.WriteLine("Replaced " & line & " with " & AllowedNumber & " on " & DateTime.Now.ToString)
                                        line = AllowedNumber
                                    End If
                                End If
                            End If
                        End If
 
                        sw.WriteLine(line)
                        PreviousLine = line
                        line = sr.ReadLine
                    End While
                End Using
            End Using
        End Using
 
        My.Computer.FileSystem.DeleteFile(DataInFile)
        My.Computer.FileSystem.RenameFile(DataOutFile, DataInFile)
    End Sub
 
0
 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 500 total points
ID: 24185652
We could try "flushing" the streams before continuing...and place a hard-coded pause before attempting the delete/rename to allow the operating system time to catch up with writing/releasing the file handles:
        Using sr As New System.IO.StreamReader(DataInFile)

            Using sw As New System.IO.StreamWriter(DataOutFile, False)

                Using log As New System.IO.StreamWriter(LogFile, False)

                    Dim line As String = sr.ReadLine

                    While Not IsNothing(line)

                        If Not IsNothing(PreviousLine) Then

                            If PreviousLine.StartsWith("#PhoneNumber") Then

                                If line.StartsWith(Chr(34)) AndAlso line.Length > 2 Then

                                    If Not Phones.ContainsKey(line) Then

                                        log.WriteLine("Replaced " & line & " with " & AllowedNumber & " on " & DateTime.Now.ToString)

                                        line = AllowedNumber

                                    End If

                                End If

                            End If

                        End If
 

                        sw.WriteLine(line)

                        PreviousLine = line

                        line = sr.ReadLine

                    End While
 

                    sw.Flush() ' <----------------- flush the streams

                    log.Flush()

                End Using

            End Using

        End Using
 

        ' <----------------- hard-coded pause ----------------->

        System.Threading.Thread.Sleep(TimeSpan.FromSeconds(10).TotalMilliseconds) ' let the OS do it's thing before we continue
 

        My.Computer.FileSystem.DeleteFile(DataInFile)

        My.Computer.FileSystem.RenameFile(DataOutFile, DataInFile)

Open in new window

0
 

Author Comment

by:Diammond
ID: 24186103
The code is still getting stuck on log file update.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24186677
I don't see any reason why it would get "stuck" on the log file...

Are you getting any exceptions?  Is the log file being written to from anywhere else (internally or externally)?

By "stuck", do you mean the code literally stops?...or is the log file not being updated?...or only some of the data is being written?  How are you viewing the log file?  How BIG is the log file?

etc...
0
 

Author Comment

by:Diammond
ID: 24187174
The log file is only being written to via the code.  Getting an exception at the following line....
My.Computer.FileSystem.RenameFile(DataOutFile, DataInFile)

ArgumentException was unhandled
Argument 'newName' must be a name, and not a relative or absolute path: 'c:\data.txt'.  Parameter name: newName

The code runs on a server.  However I've been testing the code on the c: drive of my laptop as well.  When it executes from the server, the log file doesn't get written to at all.  The code stops with an error "script encountered a problem and needs to close.  we are sorry for the inconvenience."

On my laptop I get the same error.  However, the log file is being written to partially.  The logs grows to about 9 mb and then the error pops up (using notepad to view log).  Since I have Visual Basic Express on my laptop I was able to capture the exception.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24187349
For the rename problem, try this line instead:

    My.Computer.FileSystem.RenameFile(DataOutFile, System.IO.Path.GetFilename(DataInFile))
0
 

Author Comment

by:Diammond
ID: 24187870
With the modified line, the script completes on my laptop (log file is updated and data file delete and rename runs successfully).  However, it is not working correctly on the server which is where it needs to work.  
On the server, the script runs without the previous error.  The file delete and rename also occurs.  But the log file is not getting written to.  The only difference is that the path to the files (data.txt, RealPhoneNumbers.txt, and replaced.log) is pointing to a folder structure on the d: drive (as opposed to the c: drive on my laptop).
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24187916
Just make sure the path for the log is accessible on your server:

    Dim LogFile As String = ("C:\Replaced.log")

The log is being written to in the same manner as the data file so it's got to be an access issue...
0
 

Author Comment

by:Diammond
ID: 24188505
It's weird.  The log file gets created but not written to.  I have modified the path to point to c: instead of d: but the file is still empty.  I have admin rights to the server so I'm a little confused.
0
 

Author Comment

by:Diammond
ID: 24197537
That particular server is having disk problems.  I tried another server and the code worked perfectly!  Thanks for taking the time to help me.

Diammond
0
 

Author Closing Comment

by:Diammond
ID: 31566995
Thanks again for hanging in there with me!
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 24198513
Glad you finally got it all sorted out!...   =)
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

In my previous article (http://www.experts-exchange.com/Programming/Languages/.NET/.NET_Framework_3.x/A_4362-Serialization-in-NET-1.html) we saw the basics of serialization and how types/objects can be serialized to Binary format. In this blog we wi…
Many of us here at EE write code. Many of us write exceptional code; just as many of us write exception-prone code. As we all should know, exceptions are a mechanism for handling errors which are typically out of our control. From database errors, t…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

18 Experts available now in Live!

Get 1:1 Help Now