Solved

Cross Browser Compatibility

Posted on 2010-08-23
18
242 Views
Last Modified: 2014-01-21
I have an application that was built for IE7. It works correctly there. I have  been asked to make it cross browser compatible.

Background:  The application is built using php, javascript, ajax.  The page is created dynamically with php. It includes a javascript file.  There is a window.onload = initPage command.  

Problem:  In Firefox the javascript cannot find the elements.  It is like they have not been created.

Javascript Code:

window.onload = initPage;



function initPage() {
	getContractType();     //populate the ContractType drop down from the Programs.contractType db table
	getPrograms();
} // of initPage




function getContractType() {
//	alert('in getContractType');
	contractTypeRequest = createRequest();
	if (contractTypeRequest == null) {		
		alert("Unable to create request object.");
		return;
	}
	var url = "phpPopulateCategory.php"; 
	contractTypeRequest.open("GET", url, false);
	contractTypeRequest.onreadystatechange = displayContractType;
	contractTypeRequest.send(null);
	return true;
}  //of function getCategories

function displayContractType() {
	if (contractTypeRequest.readyState == 4) {
			//alert('in displayCategory and contractTypeRequest.responseText = ' + contractTypeRequest.responseText);
			document.getElementById('contractTypeSelect').innerHTML = contractTypeRequest.responseText;
	}
} // of function


function getPrograms() {
	var contractType = document.getElementById('contractType').value;
//	alert("getPrograms and contractType = " + contractType);	
	
	programsRequest = createRequest();
	if (programsRequest == null) {		
		alert("Unable to create request object.");
		return;
	}	
	var programSelect = document.getElementById("programSelect");
	var url = "phpPopulatePrograms.php?contractType=" + contractType;
	programsRequest.open("GET", url, true);
	programsRequest.onreadystatechange = displayPrograms;
	programsRequest.send(null);

} // of function getPrograms


function displayPrograms() {
//alert("in displayPrograms");
	
	if(programsRequest.readyState == 4) {
//alert('ResponseText = ' + programsRequest.responseText + ' end of responseText');
		document.getElementById('programSelect').innerHTML = programsRequest.responseText;		
	}
	
} // of function

Open in new window


php code:
<?php 
//Start the session
require_once('startSession.php');
session_start();

//check for logged in status
	if (!isset($_SESSION['username'])) {
		$homeUrl = 'http://' . $_SERVER['HTTP_HOST'] . dirname($_SERVER['PHP_SELF']) . '/logIn.php';
		header('Location: ' . $homeUrl);
	}
	else {
		drawMainLocatorPage();		
	}
	
function drawMainLocatorPage() {
	require_once('connectVars.php');
	$pageTitle = "Sonsio Locator";
	$script = "js/locatorMain.js";

	//Insert the page header
	require_once('header.php');

	//Show the navigation menu
	require_once('navBar.php');

	require_once('footer.php');

		echo '<form name="dummyForm" id="dummyForm" action="destroySession.php" method="POST" style="display:none">';
			echo '<input type="text" value="dummy"/>';
		echo '</form>';
		echo '<div id="formContainer" name="formContainer">';
			echo '<form method="post" action="phpMainLocatorServerCode.php" id="searchForm" name="searchForm">';
				echo '<div id="consumerInfo" class="consumerInfo" name="consumerInfo">';
					echo '<div name="divHeaderReferral">';
						echo '<span class="header2" id="consumerInfoID" name="consumerInfoID">Customer Information</span>';
						echo '<span class="smallPrint" id="rNumber" name="rNumber">Referral Number: </span>';
						echo '<input name="referralNumber" type="text" style="border:0px;" value="' . (isset($_SESSION['referralNumber']) ? $_SESSION['referralNumber'] : '') . '" /></span>';
					echo '</div>';
	
					echo '<div class="row" id="divClaimNum" name="divClaimNum">';
						echo '<span class="label"><span class="required" id="claimNumStar" name="claimNumStar">*</span>Claim Number:</span>';
						
							if($_SESSION['claimNumCkbx'] == 'on') {
								echo '<span class="form2 smallPrint" name="spanClaimNumCkbx"><input type="checkbox" id="claimNumCkbx" name="claimNumCkbx" checked>No associated claim number available</input></span>';
							}
							else {
								echo '<span class="form2 smallPrint" name="spanClaimNumCkbx"><input type="checkbox" id="claimNumCkbx" name="claimNumCkbx" >No associated claim number available</input></span>';
							}
						
						echo '<span class="form1" name="spanClaimNumText">';
						echo '<input type="text" tabindex="1" id="claimNumText" name="claimNumText" size="70" value="' . (isset($_SESSION['claimNumber']) ? $_SESSION['claimNumber'] : '') . '" required="true"></input>';
						echo '</span>';
					echo '</div>';
	
					echo '<div class="row" name="divFirstName" id="divFirstName">';
						echo '<span class="label"><span class="required" id="spanFirstNameAsterisk" name="spanFirstNameAsterisk">*</span>First Name:</span>';
						echo '<span class="form2">&nbsp;</span>';
						echo '<span class="form1" name="spanFirstNameText">';
								echo '<input type="text" tabindex="2" id="firstName" name="firstName" size="70"required="true" value="' . (isset($_SESSION['firstName']) ? $_SESSION['firstName'] : '') . '"></input>';
						echo '</span>';
					echo '</div>';
	
					echo '<div class="row" name="divLastName" id="divLastName">';
						echo '<span class="label"><span class="required" id="spanLastNameAsterisk" name="spanLastNameAsterisk">*</span>Last Name:</span>';
						echo '<span class="form2">&nbsp;</span>';
						echo '<span class="form1" name="spanLastNameText">';
						echo '<input type="text" tabindex="3" id="lastName" name="lastName" size="70" required="true" value="' . (isset($_SESSION['lastName']) ? $_SESSION['lastName'] : '') . '"></input>';
						echo '</span>';
					echo '</div>';
	
					echo '<div class="row" name="divEmail" id="divEmail">';
						echo '<span class="label"><span class="required" id="emailStar" name="emailStar">*</span>Email Address:</span>';
							if($_SESSION['emailCkbx'] == 'on') {
								echo '<span class="form2 smallPrint" name="spanEmailCkbx"><input type="checkbox" id="emailCkbx" name="emailCkbx" checked>Unwilling to provide email address</input></span>';
								//need to update the screen
							}
							else {
								echo '<span class="form2 smallPrint" name="spanEmailCkbx"><input type="checkbox" id="emailCkbx" name="emailCkbx">Unwilling to provide email address</input></span>';
							}
	
						echo '<span class="form1" name="spanEmailText">';
						echo '<input type="text" tabindex="4" id="emailText" name="emailText" size="70" required="true" value="' . (isset($_SESSION['emailAddy']) ? $_SESSION['emailAddy'] : '') . '"></input>';
						echo '</span>';
					echo '</div>';
				echo '</div>'; // of consumerInfo 
				echo '<div id="searchParams" >'; 
				   echo '<div class="header2">Search Parameters</div>';   
					echo '<div>';
						echo '<span class="required" id="spanSearchParamAsterisk" name="spanSearchParamAserisk">*</span>';
						echo 'Enter Address, intersection, City and State or Zip Code:'; 
						echo '<span class="smallPrint">Examples: 5630 Ward Rd CO ';
							echo '<span class="required">OR</span> 52nd & Ward Road CO'; 
							echo '<span class="required">OR</span> Arvada CO ';
							echo '<span class="required">OR</span> 80033';
						echo '</span>';
					echo '</div>';
					echo '<div id="divSearchParam" name="divSearchParam">';
						echo '<input type="text" tabindex="5" size="100" id="searchParam" name="searchParam" required="true" value="' . (isset($_SESSION['searchParam']) ? $_SESSION['searchParam'] : '') . '"></input>';
					echo '</div>';
	
					echo '<div class="divContractProgram">';
						echo '<div class="row">';
							echo '<span class="SPDcolumn1"><span class="required" id="spanContractTypeAsterisk" name="spanContractTypeAsterisk">*</span>Contract Type</span>';
							echo '<span class="SPDcolumn2"><span class="required" id="spanProgramAsterisk" name="spanProgramAsterisk">*</span>Program</span>';
						echo '</div>';
						echo '<div class="row">';
							echo '<span class="SPDcolumn1" id="contractTypeSelect" name="contractTypeSelect"><select id="" name=""><option>Select Contract Type</option></select></span>';
							echo '<span class="SPDcolumn2" id="programSelect" name="programSelect"><select id="programType" name="programType"><option>Select Category First</option></select></span>';
						echo '</div>';
					echo '</div>'; //of dropdowns -->
					echo '<div id="locations" name="divLocationNum"><span class="required" id="spanSearchParamAsterisk" name="spanSearchParamAsterisk">*</span>Nearest ';
							echo '<input type="text" size="3" id="locNum" name="locNum" required="true" value="' . (isset($_SESSION['locNum']) ? $_SESSION['locNum'] : $locations) . '" />';
					echo 'Locations</div>';
					echo '<div id="divDistance" name="divDistance"><span class="required" id="spanDivDistanceAsterisk" name="spanDivDistanceAsterisk">*</span>Within ';
						echo '<input type="text" size="3" id="distance" name="distance" required="true" value="' . (isset($_SESSION['distance']) ? $_SESSION['distance'] : $miles) . '" /> Miles';
					echo '</div>';
					echo '<div class="smallPrint"><span class="required">*</span>Required Fields</div>';
				echo '</div>';  //of searchParams -->
				echo '<div id="buttonsDiv" class="buttonsDiv">';
					echo '<div class="row">';
					
							echo '<span class="BDcolumn1" name="spanBtnReset"><button type="button" id="btnReset" name="btnReset"> Start New Search</button></span>';
				
							echo '<span class="BDcolumn2" name="spanBtnFindLocations"><button type="submit" id="btnFindLocations" name="btnFindLocations">Find Locations!</button></span>';
					echo '</div>';
				echo '</div>'; //of buttonsDIV -->
		  echo '</form>';
		echo '</div>';  //of formContainer -->
	require_once('footer.php');
	
} //of drawMainLocatorPage

?>

Open in new window


Does anyone have suggestions as to why Firefox is not working?

Thank you!
0
Comment
Question by:criggs
  • 8
  • 8
18 Comments
 
LVL 2

Expert Comment

by:arch-itect
ID: 33507189
What does createRequest() look like?
0
 
LVL 2

Expert Comment

by:arch-itect
ID: 33507208
onreadystate doesn't get called in Firefox during synchronous call so

contractTypeRequest.open("GET", url, false); //synchronous

should be

contractTypeRequest.open("GET", url, true);  //asynchronous

That way you have asynchronous (AJAX) communication
0
 
LVL 2

Expert Comment

by:arch-itect
ID: 33507221
If you really want to use synchronous communication then :

var contractTypeRequest = new XMLHttpRequest();  //XMLHttpRequest() for firefox
contractTypeRequest.open("GET", url, false); //synchronous
contractTypeRequest.send(null);  //to flush

if (request.status == 200) { /* the request has been returned */
  alert("request successful")  //you are here immediately because the code executed linear
}
0
Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.

 

Author Comment

by:criggs
ID: 33507422
Thank you for the response arch-itect.  I have left work now, but will try this first thing in the morning.  I'm not sure why synchronous is being used instead of asynchronous, but I will find out!  I'll let you know tomorrow if it works!

Thanks again.
0
 

Author Comment

by:criggs
ID: 33515941
This did not work. The first thing the form does is reset itself and it stumbles there. Any other ideas for why the javascript is not finding the form?
0
 
LVL 2

Expert Comment

by:arch-itect
ID: 33516724
another common problem with window.onload is that the page sometimes hasn't been constructed when the javascript runs, so the javascript looks for objects that doesn't exist yet.  To test that, just put an alert('hello'); as the very first statement of initPage.  That will pause the javascript until you click ok.  If your script is in the header that could be the problem.  Rather put the (window.onload = initPage;) part in the footer of the page.

If that is not the problem please save generated html, by opening the page in the browser and saving it; and post it here.

It would make it much easier to debug.
0
 

Author Comment

by:criggs
ID: 33516979
arch-itect:

I wasn't sure what you meant by putting the window.onload into the footer of the page.  Here is the code that is generated when the program is run in firefox:

[code]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <link rel="stylesheet" type="text/css" href="css/main.css" />
    <script src="js/utils.js" type="text/javascript"></script>
    <script src="js/shared.js" type="text/javascript"></script>
    <link rel="shortcut icon" href="favicon.ico">
    <title>Sonsio Locator</title><link rel="stylesheet" type="text/css" href="" />
    <script src="js/locatorMain.js" type="text/javascript"></script>
</head>

<body>
    <div id="header" name="header">
        <div id="logo" name="logo">
            <img src="images/logo.jpg" width=125px height=75px alt="logo.jpg" name="logo" />
        </div> <!-- of logo -->
        <div id="title" name="title">
            <div class="header1 center">Call Ahead Referral System</div>
            <div class="header2 center">(CARS)</div>

        </div> <!-- of title -->
    </div> <!-- of header -->  

    <div  style="font-weight:bold;margin-bottom:8px;">!!! Do NOT use the Browser BACK Button !!! If you have questions, please see your supervisor!</div>
    <div id="logInInfo" name="logInInfo" class="navBar">
        <a href="destroySession.php" class="navLinks">Home</a>
        <a href="logOut.php" class="navLinks">Log Out (criggs)</a>
        <a href="changePassword.php" class="navLinks">Change Password</a>
        <a href="lookup.php" class="navLinks">Look Up Existing Referral</a><a href="admin.php" class="navLinks">Administrative Tasks</a>
        <a href="phpEmailGenerator.php" class="navLinks">Generate Emails</a>
        <a href="deleteTempFiles.php" class="navLinks">Delete Temp Files</a>
    </div>
    <form name="dummyForm" id="dummyForm" action="destroySession.php" method="POST" style="display:none">
        <input type="text" value="dummy"/>
    </form>
    <div id="formContainer" name="formContainer">
        <form method="post" action="phpMainLocatorServerCode.php" id="searchForm" name="searchForm">
            <div id="consumerInfo" class="consumerInfo" name="consumerInfo">
                <div name="divHeaderReferral" style="margin-top:15px;">
                    <span class="header2" id="consumerInfoID" name="consumerInfoID">Customer Information</span>
                    <span class="smallPrint" id="rNumber" name="rNumber">Referral Number: </span>
                    <input name="referralNumber" type="text" style="border:0px;" value="" />
                </div>
                <div class="row" id="divClaimNum" name="divClaimNum">
                    <span class="label">
                        <span class="required" id="claimNumStar" name="claimNumStar">*</span>Claim Number:
                    </span>
                    <span class="form2 smallPrint" name="spanClaimNumCkbx">
                        <input type="checkbox" id="claimNumCkbx" name="claimNumCkbx" >No associated claim number available</input>
                    </span>
                    <span class="form1" name="spanClaimNumText">
                        <input type="text" tabindex="1" id="claimNumText" name="claimNumText" size="70" value="" required="true"></input>
                    </span>
                   
                </div>
                <div class="row" name="divFirstName" id="divFirstName">
                    <span class="label"><span class="required" id="spanFirstNameAsterisk" name="spanFirstNameAsterisk">*</span>First Name:</span>
                    <span class="form2">&nbsp;</span>
                    <span class="form1" name="spanFirstNameText">
                        <input type="text" tabindex="2" id="firstName" name="firstName" size="70"required="true" value=""></input>
                    </span>
                </div>
                <div class="row" name="divLastName" id="divLastName">
                    <span class="label"><span class="required" id="spanLastNameAsterisk" name="spanLastNameAsterisk">*</span>Last Name:</span><
                    span class="form2">&nbsp;</span>
                    <span class="form1" name="spanLastNameText">
                        <input type="text" tabindex="3" id="lastName" name="lastName" size="70" required="true" value=""></input>
                    </span>
                </div>
                <div class="row" name="divEmail" id="divEmail">
                    <span class="label"><span class="required" id="emailStar" name="emailStar">*</span>Email Address:</span>
                    <span class="form2 smallPrint" name="spanEmailCkbx">
                        <input type="checkbox" id="emailCkbx" name="emailCkbx">Unwilling to provide email address</input>
                    </span>
                    <span class="form1" name="spanEmailText">
                        <input type="text" tabindex="4" id="emailText" name="emailText" size="70" required="true" value=""></input>
                    </span>
                </div>
            </div>
            <div id="searchParams" style="margin-top:35px;width:100%;" >
                <div class="header2">Search Parameters</div>
                <div>
                    <span class="required" id="spanSearchParamAsterisk" name="spanSearchParamAserisk">*</span>Enter Address, intersection, City and State or Zip Code:<span class="smallPrint">Examples: 5630 Ward Rd CO <span class="required">OR</span> 52nd & Ward Road CO <span class="required">OR</span> Arvada CO <span class="required">OR</span> 80033</span>
                </div>
                <div id="divSearchParam" name="divSearchParam">
                    <input type="text" tabindex="5" size="100" id="searchParam" name="searchParam" required="true" value=""></input>
                </div>
                <div class="divContractProgram">
                    <div class="row"><span class="SPDcolumn1">
                        <span class="required" id="spanContractTypeAsterisk" name="spanContractTypeAsterisk">*</span>Contract Type</span>
                        <span class="SPDcolumn2"><span class="required" id="spanProgramAsterisk" name="spanProgramAsterisk">*</span>Program</span>
                    </div>
                <div class="row">
                    <span class="SPDcolumn1" id="contractTypeSelect" name="contractTypeSelect">
                        <select id="" name=""><option>Select Contract Type</option></select>
                    </span>
                    <span class="SPDcolumn2" id="programSelect" name="programSelect">
                        <select id="programType" name="programType">
                            <option>Select Category First</option>
                        </select>
                    </span>
                </div>
            </div>
            <div id="locations" name="divLocationNum">
                <span class="required" id="spanSearchParamAsterisk" name="spanSearchParamAsterisk">*</span>
                Nearest <input type="text" size="3" id="locNum" name="locNum" required="true" value="20" />Locations
            </div>
            <div id="divDistance" name="divDistance">
                <span class="required" id="spanDivDistanceAsterisk" name="spanDivDistanceAsterisk">*</span>
                Within <input type="text" size="3" id="distance" name="distance" required="true" value="50" />
                Miles
            </div>
            <div class="smallPrint">
                <span class="required">*</span>
                Required Fields
            </div>
        </div>
        <div id="buttonsDiv" class="buttonsDiv">
            <div class="row">
                <span class="BDcolumn1" name="spanBtnReset">
                    <button type="button" id="btnReset" name="btnReset"> Start New Search</button>
                </span>
                <span class="BDcolumn2" name="spanBtnFindLocations">
                    <button type="submit" id="btnFindLocations" name="btnFindLocations">Find Locations!</button>
                </span>
            </div>
        </div>
        </form>
    </div>    

<div class="smallPrint" style="text-align:center; width: 100%; margin-top:50px; border:solid 1px gray; background-color:#FDDF71;">Copyright &copy;2010 Sonsio, Inc.</div>

</body>
</html>
[/code]

See above for the init code.  The error message that firefox gives is:

searchForm is not defined      
searchForm.reset();

So....it appears to stumble on the first command in init.

Thank you for your time and help with this.  I really do appreciate it.
0
 
LVL 2

Expert Comment

by:arch-itect
ID: 33517092
If you put the following at the bottom of the page (just above the </body> tag) it works, but if you put it in the

<head></head> section it doesn't work


   <script type="text/javascript">
   alert(document.getElementById('searchForm'));
   </script>


It is because the head loads completely before the body.  So rather put the javascript that deals with initPage at the bottom of your file, or even just this line :

   <script type="text/javascript">
window.onload = initPage;
   </script>


and remove it from the .js file at the top of the page
0
 
LVL 2

Expert Comment

by:arch-itect
ID: 33517113
...I mean just above the </body> tag


...
   <script type="text/javascript">
     window.onload = initPage;
   </script>
</body>
</html>

Open in new window

0
 

Author Comment

by:criggs
ID: 33517252
Great!  I really appreciate your help!  I have left work, but will do this tomorrow.
0
 

Author Comment

by:criggs
ID: 33524756
arch-itect:
I just tried putting the script line just above the </body> and it still doesn't work in firefox. I am going to keep trying other ideas today.

Thanks!
0
 
LVL 2

Expert Comment

by:arch-itect
ID: 33525477
Let's see if we can make the javascript wait for the screen to render:
<script type="text/javascript">
  var i = 0;
  while(document.getElementById('searchForm')) == null && i++ < 10) 
  {
    sleep(100);
  }
</script>
</body>
</html>

Open in new window

0
 

Author Comment

by:criggs
ID: 33526298
I got around the searchForm error by changing the initPage function as follows:


[code]
function initPage() {
//    alert('in initPage');
    var form = document.getElementById("searchForm");
    form.reset();
    getContractType();     //populate the ContractType drop down from the Programs.contractType db table
    getPrograms();
    addHandlers();
    document.getElementById("claimNumText").focus();
    secondTimeIn();

//    fillOutForm();
} // of initPage
[/code]


Now it can't find "contractType" unless the alert is included. That seems to give it enough time to render.

[code]
function getPrograms() {
//    alert("in getPrograms");
//    var i=0;
//    while (document.getElementById('contractType')== null) && (i++ < 10)) {
//        alert('in while');        
//    }
//    if(!document.getElementById('contractType')) {
//        alert('no contractType element');
//        sleep(100);
//    }

    programsRequest = createRequest();
    if (programsRequest == null) {        
        alert("Unable to create request object.");
        return;
    }    
    var programSelect = document.getElementById("programSelect");
    var contractType = document.getElementById("contractType").value;
    var url = "phpPopulatePrograms.php?contractType=" + contractType;
    programsRequest.open("GET", url, true);
    programsRequest.onreadystatechange = displayPrograms;
    programsRequest.send(null);

} // of function getPrograms
[/code]


I was trying the sleep function, but javascript doesn't have a sleep function.  Is there one in a library somewhere that I should include?

Again, thank you so much for your help.  It is really appreciated.

0
 
LVL 2

Expert Comment

by:arch-itect
ID: 33526719
If you don't have a sleep function (which is a bit of a hack in javascript in any case) you can do it this way :



<script type="text/javascript">
  var i = 0;
  var isSet = false;
  function checkPageLoad() {
    if(!isSet && i++ < 10){
      if (document.getElementById('searchForm') == null) {
        setTimeout("checkPageLoad()", 100);  //check again after 100 miliseconds
      } else {
        initPage();  //the page has been loaded so we don't need the window.onload
      }
    }
  }

  checkPageLoad();
</script>
</body>
</html>

Open in new window

0
 

Author Comment

by:criggs
ID: 33531978
arch-itect:

Thank you again!  I am leaving on vacation, but as soon as I get back I will try this.  I will definitely be back with you after the first of September!
0
 

Accepted Solution

by:
criggs earned 0 total points
ID: 33676471
arch-itect:

I had no success in trying to set some sort of a 'timeout'.  Nothing seemed to work.  I was able to solve the problem by moving the function call of getPrograms into the displayContractType function. This way the contractType element is rendered and the rest of the code worked.

Thanks for all your help!
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Today, still in the boom of Apple, PC's and products, nearly 50% of the computer users use Windows as graphical operating systems. If you are among those users who love windows, but are grappling to keep the system's hard drive optimized, then you s…
3 proven steps to speed up Magento powered sites. The article focus is on optimizing time to first byte (TTFB), full page caching and configuring server for optimal performance.
The viewer will learn how to create a basic form using some HTML5 and PHP for later processing. Set up your basic HTML file. Open your form tag and set the method and action attributes.: (CODE) Set up your first few inputs one for the name and …
Google currently has a new report that is in beta and coming soon to Webmaster Tool accounts. This Micro Tutorial will highlight new features for Google Webmaster Tools.

815 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

11 Experts available now in Live!

Get 1:1 Help Now