Dear All,
I would like to create different pages with dynamic tab titles. I would also like to have multiple level of tab. Currenlty I tried the kooltabs but I have problem for instance my last tab is having the final submit button and when my first tab is having the error I can show the contents of the first tab but the tab is not highlighted to reflect its content. Is there any other relevant tabs. Thank you.

Recommended Answers

All 16 Replies

What have you tried?

Dear Twiss,
Here is what I have tried http://183.78.169.54/v3/addTab.php. You can try the Driver Employment tab then you click the Add button the content will be Driver Details but the tab is not highlight accordingly. I have also another problem when I change to the tab method the javascript calendar is appearing at below my not beside the button.

Well, you will need to figure out every class that changes when you click and add / remove those yourself, or get another tab script, or write one yourself, as I couldn't get jQuery to emulate a click on one of those tabs.

It could also help if you have a non-minified version of the script.

Dear Twiss,
If you notice when I press the Tab it works well and show the right contents. But when I call it from here in the validateForm() function it shows the right content but the tab is not highlight that is the only problem I am having actually.

if(gotDriverNameError=="true" || gotDateOfBirthError=="true" || gotDriverNewICNoError=="true")
			{
				showTab("driverDetails");
				return false;
			}
			else if(gotChild1DateOfBirthError=="true" || gotChild2DateOfBirthError=="true" || gotChild3DateOfBirthError=="true" )
			{
				showTab("driverNextOfKin");
				return false;
			}
			else 
				return true;

Yes, I understood the problem, but there isn't a solution without refactoring the script or changing the classes yourself.

Dear Twiss,
What do you mean by refactoring the classes? Which classes do you mean? I dont get you hope I can give you more details.

Not refactoring the classes, changing them.

You have to figure out (and 'inspect element' on chrome can help with that) which classes are given to what elements. Than, you have to do exactly that yourself (with jQuery, for example).

But it could help to find that out easier if you have a non-minified version of kooltabs.

Dear Twiss,
What do you mean by non-minified version of kooltabs. Do you mean to reduce my tabs is it?

The kooltabs script is now very unreadable as you can see, it is on a single line and with no spaces or tabs.

Dear Twiss,
I know this problem I dont know why is like this when I view it on html. Below is my full codes. But the problem is here

if(gotDriverNameError=="true" || gotDateOfBirthError=="true" || gotDriverNewICNoError=="true")
			{
				showTab("driverDetails");
				return false;
			}
			else if(gotChild1DateOfBirthError=="true" || gotChild2DateOfBirthError=="true" || gotChild3DateOfBirthError=="true" )
			{
				showTab("driverNextOfKin");
				return false;
			}
			else 
				return true;
<?php 
session_start(); 
require "KoolTabs/kooltabs.php";
require_once('config.php');
$searchcm=$_POST['searchcm'];
$formType="Add";
$submitTag="Add";
//$driverID=$_GET['driverID'];




?>

<?
    $driverDetails=true;
    $driverLicenses='';
		$driverEmployment='';
		echo "TEst DriverDetails : ".$driverDetails;
    $kts = new KoolTabs("kts");
 
		//Step 3: Set properties for kooltabs
		$kts->styleFolder = "KoolTabs/styles/silver";
		 
		//Step 4: Add tabs for KoolTabs: addTab($parentid,$id,$text,$link)
		$kts->addTab("root","Driver Details","Driver Details","javascript:showTab(\"driverDetails\")",$driverDetails);
		$kts->addTab("root","Driver Licenses","Driver Licenses","javascript:showTab(\"driverLicenses\")",$driverLicenses);
		$kts->addTab("root","Driver Employment","Driver Employment","javascript:showTab(\"driverEmployment\")",$driverEmployment);
		
    echo $kts->Render(); 

?>


<html> 
<head> 
<link rel="stylesheet" type="text/css" href="my1.css" media="all"> 
<link rel="stylesheet" type="text/css" href="epoch_styles.css" />
<script type="text/javascript" src="epoch_classes.js"></script>
<script type="text/javascript">
/*You can also place this code in a separate file and link to it like epoch_classes.js*/
	var driverLicenseExpiryCal,driverGDLExpiryCal;
	
	var dp_cal,ms_cal;      
  window.onload = function () {
  
  driverLicenseExpiryCal  = new Epoch('epoch_popup','popup',document.getElementById('driverLicenseExpiryDate'));
	driverGDLExpiryCal  = new Epoch('epoch_popup','popup',document.getElementById('driverGDLExpiryDate'));
	
	
	document.getElementById("driverDetails").className = "show"; 
	document.getElementById("driverLicenses").className = "hide";
	document.getElementById("driverEmployment").className = "hide";

};
</script>
<script type="text/javascript">
function showTab(_id) 
{
	
	var tabID=_id;  
	
	//var class1 = document.getElementById("driverDetails").className; 
	//var class2 = document.getElementById("driverLicenses").className; 
	//var class3 = document.getElementById("driverNextOfKin").className; 
	
	<?php 		 
    $driverDetails=true;
    $driverLicenses='';
		$driverEmployment='';		

		?>
	if(tabID=="driverDetails")
	{
		<?php 		 
    $driverDetails=true;
    $driverLicenses=false;
		$driverEmployment=false;
		?>
		//alert("driverDetails : "+tabID);
		//document.getElementById(tabID).style.display = 'block'; 
		document.getElementById("driverDetails").className = "show"; 
		document.getElementById("driverLicenses").className = "hide";
		document.getElementById("driverEmployment").className = "hide";		
	}
	else if(tabID=="driverLicenses")
	{
		//alert("DD : "+tabID);
		document.getElementById("driverDetails").className = "hide"; 
		document.getElementById("driverLicenses").className = "show";
		document.getElementById("driverEmployment").className = "hide";
		<?php 		 
    $driverDetails='';
    $driverLicenses=true;
		$driverEmployment='';
		
		?>
	}
	
	else if(tabID=="driverEmployment")
	{
		//alert("DD : "+tabID);
		document.getElementById("driverDetails").className = "hide"; 
		document.getElementById("driverLicenses").className = "hide";
		document.getElementById("driverEmployment").className = "show";
		<?		 
    $driverDetails='';
    $driverLicenses='';
		$driverEmployment=true;
		?>
	}
}

function validateForm() 
{
			//alert("TEST");
			//Get the controls
			var driverNameControl = document.getElementById("driverName");
      var dateOfBirthDayControl = document.getElementById("dateOfBirthDay");
      var dateOfBirthMonthControl = document.getElementById("dateOfBirthMonth");
      var dateOfBirthYearControl = document.getElementById("dateOfBirthYear");
      var driverNewICNoControl = document.getElementById("driverNewICNo");
          
      var driverLicenseNoControl = document.getElementById("driverLicenseNo");
      var driverLicenseExpiryDateControl = document.getElementById("driverLicenseExpiryDate");
      var driverGDLNoControl = document.getElementById("driverGDLNo");
      var driverGDLExpiryDateControl = document.getElementById("driverGDLExpiryDate");
     
     
			//Create expressions
			var isNumeric = /^[0-9]+$/;
			var isLetters = /^[a-zA-Z ]+$/;
			var isEmail = /^([\w-]+(?:\.[\w-]+)*)@((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$/i;
			
			//Cheack each one and if it fails, set an appropriate error message
			var gotDriverNameError="false";
			var gotDateOfBirthError="false";
			var gotDriverNewICNoError="false";			
			
			var gotDriverLicenseNoError="false";
			var gotDriverLicenseExpiryDateError="false";
			var gotDriverGDLNoError="false";
			var gotDriverGDLExpiryDateError="false";
			
			//alert("client ID:"+clientNameControl.value+"TEST");
			//If name is empty or invalid
		
		  	
		  if(driverNameControl.value == "")
			{
				driverNameError.innerHTML = " * Driver Name is empty";
				gotDriverNameError="true";
			}
			else if(driverNameControl.value.search(isLetters))
			{
				driverNameError.innerHTML = " * Driver Name must only contain letters";
				gotDriverNameError="true";				
			}
			else
			{
				driverNameError.innerHTML = "";
			  gotDriverNameError="false";
		  }		  
      
      if(dateOfBirthDayControl.value>0 && dateOfBirthMonthControl.value>0 && dateOfBirthYearControl.value >0)
      {
      	  var myDate = new Date();
		      //alert("day : "+ dateOfBirthDayControl.value+"month : "+dateOfBirthMonthControl.value+"year : "+dateOfBirthYearControl.value);
		      myDate.setFullYear( dateOfBirthYearControl.value, dateOfBirthMonthControl.value-1, dateOfBirthDayControl.value );
          //alert("my date : "+myDate+"get month :"+myDate.getMonth());
      	  if ( myDate.getMonth() != dateOfBirthMonthControl.value-1 ) 
      	  {      
            driverDateOfBirthError.innerHTML = "In Valid Date";
			      gotDateOfBirthError="true";
		      }
		      else
		      {
		      	//alert(" valid date");
		      	driverDateOfBirthError.innerHTML = "";
			      gotDateOfBirthError="false";
		      }
      }
      else
      {
      	driverDateOfBirthError.innerHTML = "Select Data Of Birth";
			  gotDateOfBirthError="true";
      }      
      
      if(driverNewICNoControl.value == "")
			{
				driverNewICNoError.innerHTML = " * Driver New IC No is empty";
				gotDriverNewICNoError="true";
			}
			else if(driverNewICNoControl.value.search(isNumeric))
			{
				driverNewICNoError.innerHTML = " * Driver New IC No must only contain numbers";
				gotDriverNewICNoError="true";				
			}
			else
			{
				driverNewICNoError.innerHTML = "";
			  gotDriverNewICNoError="false";
		  }
		  		  
		  if(driverLicenseNoControl.value == "")
			{
				driverLicenseNoError.innerHTML = " * License No. is empty";
				gotDriverLicenseNoError="true";				
			}			
			else
			{
				driverLicenseNoError.innerHTML = "";
			  gotDriverLicenseNoError="false";
		  }
		  
		  if(driverLicenseExpiryDateControl.value == "")
			{
				driverLicenseExpiryDateError.innerHTML = " * License Expiry Date is empty";
				gotDriverLicenseExpiryDateError="true";				
			}			
			else
			{
				driverLicenseExpiryDateError.innerHTML = "";
			  gotDriverLicenseExpiryDateError="false";
		  }
		  
		  
		  
		  if(driverGDLNoControl.value == "")
			{
				driverGDLNoError.innerHTML = " * GDL No. is empty";
				gotDriverGDLNoError="true";				
			}			
			else
			{
				driverGDLNoError.innerHTML = "";
			  gotDriverGDLNoError="false";
		  }
		  
		  if(driverGDLExpiryDateControl.value == "")
			{
				driverGDLExpiryDateError.innerHTML = " * GDL Expiry Date is empty";
				gotDriverGDLExpiryDateError="true";				
			}			
			else
			{
				driverGDLExpiryDateError.innerHTML = "";
			  gotDriverGDLExpiryDateError="false";
		  }
		  
		 
			//If any errors occurred, return false, otherwise true
			if(gotDriverNameError=="true" || gotDateOfBirthError=="true" || gotDriverNewICNoError=="true")
			{
				showTab("driverDetails");
				return false;
			}
			else if(gotChild1DateOfBirthError=="true" || gotChild2DateOfBirthError=="true" || gotChild3DateOfBirthError=="true" )
			{
				showTab("driverNextOfKin");
				return false;
			}
			else 
				return true;
};
</script> 


<script src="http://code.jquery.com/jquery-1.5.1.min.js"></script> 
<script src="jquery.validate.js"></script> 
        
<script> 
        
        $(document).ready(function() {
        	  
            function setupSingleRowValidation(form) {
                function filledFields(array) {
                    // when given ['name', 'age'] this function will return the following string
                    // '[name="name"]:filled, [name="age"]:filled'
                    var selectors = [];
                    $(array).each(function (i, name) {
                        selectors.push('[name="' + name + '"]:filled');
                    });
                    //alert("Selector : "+selectors);
                    return selectors.join(', ');
                }
                function createSingleRowRule(field) {
                    var suffix = /\[.*\]/.exec(field),
                        name = 'name' + suffix,
                        durationOfEmployment = 'durationOfEmployment' + suffix,
                        reasonLeaving = 'reasonLeaving' + suffix;
                        previousRecords = 'previousRecords' + suffix;
                     //alert("sffux:"+suffix);
                    return {
                        required: filledFields([name, durationOfEmployment, reasonLeaving, previousRecords]),
                        number: (field === durationOfEmployment)
                    };
                }
                
                // clean up pre-existing rules before adding new ones
                $('tr td:not(:first) input', form).each(function () {
                    if ($(this.form).validate().currentElements.has(this).length) {
                        $(this).rules('remove');
                    }
                
                    var rule = createSingleRowRule(this.name);
                    $(this).rules('add', rule);
                });
                
                $('tr td:not(:first) textarea', form).each(function () {
                    if ($(this.form).validate().currentElements.has(this).length) {
                        $(this).rules('remove');
                    }
                
                    var rule = createSingleRowRule(this.name);
                    $(this).rules('add', rule);
                });
                
                // prepare single row rules
                var nameField = $('tr td input[name^="name"]', form);
                //var singleRowRules = createSingleRowRules(nameField.attr('name'));
                
                // initialize validation with single row rules
                $(form).validate({
                    /*rules: singleRowRules,*/
                    debug: true
                });
            }
            function setupMultipleRowValidation(form) {
                // clean up fields so that they contain the multiple row validation rules
                /*$(form).validate().currentElements.each(function () {
                    $(this).rules('remove');
                });*/
                
                $('td:not(:first) input', form).each(function () {
                    $(this).rules('add', {required: true});
                });
                $('td:not(:first) textarea', form).each(function () {
                    $(this).rules('add', {required: true});
                });
                $('[name^="durationOfEmployment"]', form).each(function () {
                    $(this).rules('add', {number: true});
                });
            };
            function setupFormValidation(form) {
                $(form).validate().resetForm();
                //alert("LEnght : "+$('tbody tr', form).length);
                if ($('tbody tr', form).length > 1) {
                	  //alert("Call setup multiple row");
                    setupMultipleRowValidation(form);
                } else {
                    $(form).validate().resetForm();
                    setupSingleRowValidation(form);
                }
            }
            
            var form = $("#form2");
            setupFormValidation(form);
 
            var prot = $('tr.prototype').clone().removeClass('prototype');
            $(form).data('prototype', prot);
            
            var id = $(document).data('idCounter') || 0;
 
            // Add button functionality
            $("table.dynatable button.add").click(function() {
                var form = this.form;
                id++;
                
                // Get a new row based on the prototype row
                //var prot = master.find(".prototype").clone();
                var prot = $(form).data('prototype').clone();
                prot.find('[name^="id"]').attr("value", id);
                prot.find('[name^="name"]').attr('name', 'name[' + id + ']');
                prot.find('[name^="name"]').attr('value', '');
                prot.find('[name^="duration"]').attr('name', 'durationOfEmployment[' + id + ']');
                prot.find('[name^="duration"]').attr('value', '');
                prot.find('[name^="reasonLeaving"]').attr('name', 'reasonLeaving[' + id + ']');
                prot.find('[name^="reasonLeaving"]').attr('value', '');                
                prot.find('[name^="previousRecords"]').attr('name', 'previousRecords[' + id + ']');
                prot.find('[name^="previousRecords"]').attr('value', '');                
                
                $(form).find("tbody").append(prot);
 
                setupFormValidation(form);
                return false;
            });
            
            // Remove button functionality
            $("table.dynatable button.remove").live("click", function() {
               
                var form = this.form;
 
                $(this).closest("tr").remove();
                setupFormValidation(form);
            });
            
            jQuery('.dOnly').live('keyup', function () 
            {     
                 this.value = this.value.replace(/[^0-9\.]/g,''); 
            });
        });
</script> 
<style> 
            .dynatable {
                border: solid 1px #000; 
                border-collapse: collapse;
            }
            .dynatable th,
            .dynatable td {
                background-color:#ccc; 
                font-size:14px;
                font-color:#ffffff;
                font-family:Calibri;
            }
            .dynatable .prototype {
                
            }
            label.error 
            { 
            	display: block; 
            	color:red;
            }
            
            td { vertical-align: top; }
            
</style> 

</head> 
<body> 


<div >
	<h2 class="form_desicription">Add Driver (Draft)<?=$status?></h2>
</div>



<form action="<?=$_SERVER['PHP_SELF']?>" method="post"id="form1" name="form1" enctype="multipart/form-data" id=form1 onSubmit="return validateForm();">
<div id="driverDetails" class="show" style="position:relative" >
	<table>
		
		
		
		<tr>
			<td>				
			  <label class=description for=element_1>Name<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text"  id="driverName" name="driverName" value="<?php echo $driverName?>">  
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverNameError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class="description">Date of Birth<font color="red">*</font></label>
			</td>
			<td>
			  <?php
        echo "<select class='select' id='dateOfBirthDay' name='dateOfBirthDay' > ";
        echo "<option value=''>-Day-</option>";
        for($d=1;$d<32;$d++)
        {
	        if($d<10)
	        {
	        	$d="0".$d;
	        }
	        if($d==$dateOfBirthDay)
		      {
		       echo "<option selected value=".$d.">".$d."</option>";
		      }
		      else
		      {
		       echo "<option value=".$d.">".$d."</option>";
		      }
	      }
        echo "</select>";
        ?>
        
        <?php
        echo "<select class='select' id='dateOfBirthMonth' name='dateOfBirthMonth' > ";
        echo "<option value=''>-Month-</option>";
        for($m=1;$m<13;$m++)
        {
	        if($m<10)
	        {
	        	$m="0".$m;
	        }
	        if($m==$dateOfBirthMonth)
		      {
		       echo "<option selected value=".$m.">".$m."</option>";
		      }
		      else
		      {
		       echo "<option value=".$m.">".$m."</option>";
		      }
	      }
        echo "</select>";
        ?>
        <?php
        echo "<select class='select' id='dateOfBirthYear' name='dateOfBirthYear' > ";
        echo "<option value=''>-Year-</option>";
        for($y=1940;$y<1995;$y++)
        {
	        if($y==$dateOfBirthYear)
		      {
		       echo "<option selected value=".$y.">".$y."</option>";
		      }
		      else
		      {
		       echo "<option value=".$y.">".$y."</option>";
		      }
	      }
        echo "</select>";
        ?>
        <label class="description">(dd/mm/yyyy)</label> 
			</td>
		</tr>	
		<tr>
			<td><p class=error id="driverDateOfBirthError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description >New I/C No:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverNewICNo" name="driverNewICNo" value="<?php echo $driverNewIcNo?>"> 	  
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverNewICNoError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description for=element_1>Recent Image</label> 
			</td>
			<td>			
			  <input type="file" class="file" id="driverImage" name="driverImage" value="" size="50px">
			</td>
		</tr>
		
	
		<tr>
			<td>				
			  <label class=description >Address:</label> 
			</td>
			<td>
			  <textarea rows="5" cols="20" class="textarea" id="driverAddress" name="driverAddress"></textarea>
			</td>
		</tr>
		
		
		
		
		<tr>
			<td>				
			  <label class=description for=element_1>Home Tel No:</label> 
			</td>
			<td>
			  <input class="text" id="driverTelHome" name="driverTelHome" value="<?php echo $driverTelHome?>"> 	  
			</td>
		</tr>	
		<tr>
			<td><p class=error id="driverTelHomeError" ></p></td>
		  <td></td>
		</tr>	
		
		<tr>
			<td>				
			  <label class=description for=element_1>Mobile Tel No:</label> 
			</td>
			<td>
			  <input class="text" id="driverTelMobile" name="driverTelMobile" value="<?php echo $driverTelMobile?>"> 	  
			</td>
		</tr>	
		<tr>
			<td><p class=error id="driverTelMobileError" ></p></td>
		  <td></td>
		</tr>
	</table>
</div>	
<div id="driverLicenses" class="show" style="position:relative" >				
  <table>		
		<tr>
			<td>				
			  <label class=description for=element_1>License No:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverLicenseNo" name="driverLicenseNo" value="<?php echo $driverLicenseNo?>"> 	  
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverLicenseNoError" ></p></td>
		  <td></td>
		</tr>
		
		
		<tr>
			<td>				
			  <label class=description for=element_1>License Expiry Date:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverLicenseExpiryDate" name="driverLicenseExpiryDate" value="<?php echo $driverLicenseExpiryDate?>"> 	  
			  <input class="buttons" type="button" value="Pick" onclick="driverLicenseExpiryCal.toggle();"/>
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverLicenseExpiryDateError" ></p></td>
		  <td></td>
		</tr>	
		
		<tr>
			<td>				
			  <label class=description for=element_1>License Image</label> 
			</td>
			<td>			
			  <input type="file" class="file" id="driverLicenseImage" name="driverLicenseImage" value="" size="50px">
			</td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description for=element_1>GDL License No:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverGDLNo" name="driverGDLNo" value="<?php echo $driverGDLNo?>"> 	  
			</td>
		</tr>
		<tr>
			<td><p class=error id="driverGDLNoError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description for=element_1>GDL License Expiry Date:<font color="red">*</font></label> 
			</td>
			<td>
			  <input class="text" id="driverGDLExpiryDate" name="driverGDLExpiryDate" value="<?php echo $driverGDLExpiryDate?>"> 	  
		   <input class="buttons" type="button" value="Pick" onclick="driverGDLExpiryCal.toggle();"/>
			</td>
		</tr>	
		<tr>
			<td><p class=error id="driverGDLExpiryDateError" ></p></td>
		  <td></td>
		</tr>
		
		<tr>
			<td>				
			  <label class=description for=element_1>GDL License Image</label> 
			</td>
			<td>			
			  <input type="file" class="file" id="driverGDLImage" name="driverGDLImage" value="" size="50px">
			</td>
		</tr>	
	</table>
</div>
</form>

<form action="<?=$_SERVER['PHP_SELF']?>" method="post"id="form2" name="form2" enctype="multipart/form-data" id=form1 onSubmit="return validateForm();">
<div id="driverEmployment" class="hide" style="position:relative" >

	<table class="dynatable"> 
		     <thead> 
                <tr> 
                    <th>ID</th> 
                    <th>Name Of Former Emp.</th> 
                    <th>Duration of Emp.</th> 
                    <th>Reason for Leaving Emp.</th> 
                    <th>Previous Incidents or Records</th> 
                    <th><button class="add">Add</button></th> 
                </tr> 
            </thead> 
            <tbody> 
            	  <tr class="prototype"> 
                        <td><input type="text" name="id[]" value="0" /></td> 
                        <td><input type="text" name="name[]" value="" /></td> 
                        <td><input type="text" name="durationOfEmployment[]" value="" /></td> 
                        <td><textarea rows=2 cols=15 name="reasonLeaving[]" /></textarea></td> 
                        <td><textarea rows=2 cols=15 name="previousRecords[]" /></textarea></td> 
                        <td><button class="remove">Remove</button> 
                    </tr> 
            </tbody>
   </table>
 		
			  <input class="buttons" type="Submit" name="<?php echo $submitTag?>" value="<?php echo $submitTag?>">
		
			  <input class="buttons" type="Reset" name="Reset" value="Reset" onclick="location.href='addDriverDraft.php'">			  
			
</div>

</form>



</body> 
</html>

And kooltabs.php?

Dear Twiss,
I saw the kooltabs.php the codes is so jumble up I guess they purposely do this to protect their codes. Do you know of any other similar tab functionality?

Dear Twiss,
Thank you do you know any one which can do nested tabs too? Thank you.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.