//---------------------------------------------------------------------------------------------------------------------
function getXMLHTTP()								// Retourne un objet xmlHttpRequest
	{
	var xhr = false ; 
         
	if (window.XMLHttpRequest)						// Firefox et autres
		xhr = new XMLHttpRequest() ; 
	else	if (window.ActiveXObject)
		{										// Internet Explorer 
		try
			{
			xhr = new ActiveXObject ("Msxml2.XMLHTTP") ;
			}
                 
		catch (e)
			{
			xhr = new ActiveXObject ("Microsoft.XMLHTTP") ;
			}
		}
	else											// XMLHttpRequest non supporté par le navigateur
		{
		alert ("Votre navigateur ne supporte pas les objets XMLHTTPRequest !") ; 
           
		xhr = false ; 
		}
        
	return xhr ;
	}

//---------------------------------------------------------------------------------------------------------------------
var _base = null ;									// Nom de la base
var _documentForm = null ;							// Nom du formulaire
var _inputField   = null ;							// Nom du champ de saisie
var _submitButton = null ;							// Nom du bouton de validation

function initAutoComplete (form, field, submit)			// Mise en place du script pour le formulaire
	{
	_documentForm = form ;
	_inputField   = field ;
	_submitButton = submit ;
	
	_base = document.forms["Modifier"].elements["base"].value ;

	_inputField.autocomplete = "off" ;
     
	creeAutocompletionDiv() ;
	_currentInputFieldValue = _inputField.value ;
	_oldInputFieldValue = _currentInputFieldValue ;

	cacheResults ("", new Array()) ;
     
	document.onkeydown = onKeyDownHandler ;
	_inputField.onkeyup = onKeyUpHandler ;
	_inputField.onblur  = onBlurHandler ;
	window.onresize    = onResizeHandler ;

	setTimeout ("mainLoop()", 200) ;					// Premier déclenchement de la fonction dans 200ms
	}

//---------------------------------------------------------------------------------------------------------------------
var _oldInputFieldValue = "" ;						// Valeur précédente du champ de saisie
var _currentInputFieldValue = "" ;						// Valeur actuelle du champ de saisie
var _resultCache = new Object() ;						// Mécanisme de cache des requêtes

												// _resultCache est un objet qui permettra de constituer
												// un cache des requêtes pour éviter de les renvoyer
												// systématiquement (très utile, par exemple en cas de
												// backspace)

												// Comme dans Google Suggest, mise en place d'une
												// méthode qui vérifiera périodiquement les changements
												// survenus dans le champ de saisie et exécutera une
												// requête vers le serveur si nécessaire
function mainLoop ()
	{
	if (_oldInputFieldValue != _currentInputFieldValue)
		{
		var valeur = escapeURI (_currentInputFieldValue) ;
		var suggestions = _resultCache[_currentInputFieldValue] ;
            
		if (suggestions)
			{									// La réponse était encore dans le cache
			metsEnPlace (valeur, suggestions) ;
			}
		else
			{
			callSuggestions (valeur) ;				// Appel distant
			}
                 
		_inputField.focus() ;
		}
           
	_oldInputFieldValue = _currentInputFieldValue ;

	setTimeout ("mainLoop()", 200) ;					// La fonction se redéclenchera dans 200ms
      
	return true ;
	}

//---------------------------------------------------------------------------------------------------------------------
												// Méthode toute simple, permettant d'échapper les
												// caractères spéciaux du champ de saisie avant d'envoyer
												// la requête au serveur. Cette méthode se base sur des
												// méthodes JavaScript natives des navigateurs
function escapeURI(La)
	{
	if (encodeURIComponent) return encodeURIComponent(La) ;
           
	if(escape) return escape(La) ;
	}

//---------------------------------------------------------------------------------------------------------------------
												// Appel au serveur pour récupérer au plus 10 suggestions
												// pour le texte entré dans le champ de saisie

var _xmlHttp = null ;								// Objet xmlHttpRequest utilisé pour contacter le serveur

// Cette fonction utilise l'objet xmlHttpRequest en mode asynchrone, comme le montre le troisième paramètre de la
// méthode open() qui vaut true. Lorsque la réponse du serveur reviendra, le listener lié à l'évènement
// readyStateChange sera déclenché. Concrètement, cela signifie que quand la requête sera terminée (readyState==4),
// la fonction traiteXmlSuggestions transformera le document XML en une liste de suggestions (Array de string) et
// la méthode metsEnPlace sera déclenchée, avec comme argument le texte dans le champ utilisateur et les
// possibilités de complétion

function callSuggestions (valeur)
	{
	if (_xmlHttp && _xmlHttp.readyState != 0) _xmlHttp.abort() ;

	_xmlHttp=getXMLHTTP() ;
     
	if (_xmlHttp)
		{
												// Appel à l'url distante
		var champ = _inputField.name ;
		var lg = valeur.length ;
		
//		_xmlHttp.open ("GET", "ajaxFormulaire.php?champ="+champ+"&debut="+valeur, true) ;
		_xmlHttp.open ("GET", "ajaxFormulaire.php?base=" + _base + "&champ=" + champ + "&debut=" + valeur, true) ;

		_xmlHttp.onreadystatechange = function ()
			{
			if (_xmlHttp.readyState==4 && _xmlHttp.responseXML)
				{
				var liste = traiteXmlSuggestions (_xmlHttp.responseXML) ;

				cacheResults (valeur,liste) ;
				metsEnPlace (valeur,liste) ;
				}
			}

		_xmlHttp.send(null) ;						// Envoi de la requete
		}
	}

//---------------------------------------------------------------------------------------------------------------------
												// La méthode cacheResults permet de garder les
												// demandes précédentes faites au serveur
function cacheResults (debut, suggestions)
	{
	_resultCache[debut] = suggestions ;
	}

//---------------------------------------------------------------------------------------------------------------------
												// Transformation de la réponse du serveur au format
												// XML en une liste de suggestions sous forme de
												// tableau de chaînes de caractères 
function traiteXmlSuggestions (xmlDoc)
	{
	var options = xmlDoc.getElementsByTagName ('option') ;
	var optionsListe = new Array () ;

	for (var i=0; i<options.length; ++i) optionsListe.push(options[i].firstChild.data) ;

	return optionsListe ;
	}

//---------------------------------------------------------------------------------------------------------------------
												// Initialisation de l'ensemble des styles 
												// Insertion d'une règle avec son nom dans la feuille
												// de style, de façon indépendante du navigateur

												// Cette fonction ne fonctionne pas dans Opera car le
												// tableau styleSheets n'existe pas 
function insereCSS (nom, regle)
	{
	if (document.styleSheets)
		{
		var I = document.styleSheets[0] ;

		if (I.addRule)								// Méthode Internet Explorer
			{
			I.addRule (nom, regle) ;
			}
		else	if (I.insertRule)						// Méthode DOM
			{
			I.insertRule (nom + " { "+regle+" }", I.cssRules.length) ;
			}
		}
	}

//---------------------------------------------------------------------------------------------------------------------
function initStyle()
	{
	var AutoCompleteDivListeStyle = "font-size: 13px; font-family: arial,sans-serif; word-wrap:break-word; " ;
	var AutoCompleteDivStyle      = "display: block; padding-left: 3; padding-right: 3; height: 16px; overflow: hidden; background-color: white;" ;
	var AutoCompleteDivActStyle   = "background-color: #3366cc; color: white ! important; " ;

	insereCSS (".AutoCompleteDivListeStyle", AutoCompleteDivListeStyle) ;
	insereCSS (".AutoCompleteDiv", AutoCompleteDivStyle) ;
	insereCSS (".AutoCompleteDivAct", AutoCompleteDivActStyle) ;
	}

//---------------------------------------------------------------------------------------------------------------------
function setStylePourElement (c, name)					// Application d'une classe de style à un élément
	{
	c.className = name ;
	}

//---------------------------------------------------------------------------------------------------------------------
// Mise en place des méthodes permettant de gérer dynamique le placement de la liste de suggestions. Comme il est
// naturel pour une liste de suggestions, celles-ci doivent apparaître directement en dessous du champ de saisie
//---------------------------------------------------------------------------------------------------------------------

function calculateOffsetLeft (r)						// Calcul du décalage à gauche
	{
	return calculateOffset (r, "offsetLeft") ;
	}

function calculateOffsetTop (r)						// Calcule du décalage vertical
	{
	return calculateOffset (r, "offsetTop") ;
	}

function calculateOffset (r, attr)
	{
	var kb = 0 ;

	while (r)
		{
		kb += r[attr] ;
		r = r.offsetParent ;
		}
           
	return kb ;
	}


function calculateWidth ()							// Calcul de la largeur du champ
	{
//	return _inputField.offsetWidth-2*1 ;
	return _inputField.offsetWidth-2*1 + 200 ;			// FGH : pour offrir plus de caractères à l'affichage
	}

function setCompleteDivSize()
	{
	if (_completeDiv)
		{
		_completeDiv.style.left  = calculateOffsetLeft (_inputField) + "px" ;
		_completeDiv.style.top   = calculateOffsetTop  (_inputField) + _inputField.offsetHeight-1 + "px" ;
		_completeDiv.style.width = calculateWidth () + "px" ;
           }
	}

//---------------------------------------------------------------------------------------------------------------------
												// Création de la div qui recevra les éléments prenant
												// la forme de span contenu dans des div, eux-mêmes
												// rajoutés à la div créée
function creeAutocompletionDiv ()
	{
	initStyle() ;

	_completeDiv    = document.createElement("DIV") ;
	_completeDiv.id = "completeDiv" ;

	var borderLeftRight = 1 ;
	var borderTopBottom = 1 ;

	_completeDiv.style.borderRight   = "black " + borderLeftRight + "px solid" ;
	_completeDiv.style.borderLeft    = "black " + borderLeftRight + "px solid" ;
	_completeDiv.style.borderTop     = "black " + borderTopBottom + "px solid" ;
	_completeDiv.style.borderBottom  = "black " + borderTopBottom + "px solid" ;
	_completeDiv.style.zIndex        = "1" ;
	_completeDiv.style.paddingRight  = "0" ;
	_completeDiv.style.paddingLeft   = "0" ;
	_completeDiv.style.paddingTop    = "0" ;
	_completeDiv.style.paddingBottom = "0" ;
   
	setCompleteDivSize () ;

	_completeDiv.style.visibility      = "hidden" ;
	_completeDiv.style.position        = "absolute" ;
	_completeDiv.style.backgroundColor = "white" ;
 
	document.body.appendChild (_completeDiv) ;

	setStylePourElement (_completeDiv, "AutoCompleteDivListeStyle") ;
	}

//---------------------------------------------------------------------------------------------------------------------
function metsEnPlace (valeur, liste)					// Mise en place des suggestions
	{
	while (_completeDiv.childNodes.length>0)
	{
	_completeDiv.removeChild (_completeDiv.childNodes[0]) ;
	}
           
	for (var f=0; f<liste.length; ++f)
		{
		var nouveauDiv = document.createElement("DIV") ;

		nouveauDiv.onmousedown = divOnMouseDown ;
		nouveauDiv.onmouseover = divOnMouseOver ;
		nouveauDiv.onmouseout  = divOnMouseOut ;
            
		setStylePourElement (nouveauDiv, "AutoCompleteDiv") ;
            
		var nouveauSpan = document.createElement("SPAN") ;

		nouveauSpan.innerHTML = liste[f] ;				// Texte de la suggestion
		nouveauDiv.appendChild (nouveauSpan);

		_completeDiv.appendChild(nouveauDiv) ;
		}
           
	PressAction() ;
      
	if  (_completeDivRows>0)
		_completeDiv.height = 16*_completeDivRows+4 ;
	else  hideCompleteDiv() ;
     }

//---------------------------------------------------------------------------------------------------------------------
												// Evénement clavier sur le onkeydown du document
var _lastKeyCode = null ;

var onKeyDownHandler = function(event)
	{
	if (!event && window.event) event = window.event ;	// Accès événement compatible IE/Firefox
  
	if(event) _lastKeyCode=event.keyCode ;				// On enregistre la touche ayant déclenché l'événement
	}

//---------------------------------------------------------------------------------------------------------------------
												// Evénement sur le onkeyup du champ de saisie
var _eventKeycode = null ;

var onKeyUpHandler = function (event)
	{
	if (!event && window.event) event=window.event ;		// Accès événement compatible IE/Firefox

	_eventKeycode = event.keyCode ;
     

	if (_eventKeycode==40 || _eventKeycode==38)			// Cas des touches haute (38) ou basse (40)
		{    
		blurThenGetFocus () ;						// On autorise le blur du champ (traitement dans onblur)
		}
           
	var N = rangeSize (_inputField) ;					// Taille de la sélection
	var v = beforeRangeSize (_inputField) ;				// Taille du texte avant la sélection
												// (sélection = suggestion d'autocomplétion)

	var V = _inputField.value ;						// Contenu du champ de saisie

	if (_eventKeycode != 0)
		{
		if (N>0 && v!=-1)
			{
			V = V.substring (0, v) ;					// On récupère uniquement le texte saisi
			}
                 
		if (_eventKeycode==13 || _eventKeycode==3)		// 13 = touche entrée
			{
			var d = _inputField ;

			if (_inputField.createTextRange)			// Mise en place de l'ensemble du champ de saisie
				{								// en repoussant la sélection
				var t = _inputField.createTextRange () ;

				t.moveStart ("character", _inputField.value.length) ;
				_inputField.select () ;
				}
			else	if (d.setSelectionRange)
				{
				_inputField.setSelectionRange (_inputField.value.length, _inputField.value.length) ;
				}
			}
		else
			{									// Si on n'a pas pu agrandir le champ non selectionné,
												// on le mets en place violemment                  
			if (_inputField.value != V)
				{
				_inputField.value = V ;
				}
			}
		}           
												// Si la touche n'est ni haut, ni bas, on stocke la
												// valeur utilisateur du champ

	if (_eventKeycode!=40 && _eventKeycode!=38)
		{
		_currentInputFieldValue = V ;					// Champ courant inchangé si key Up ou key Down
		}

	if (handleCursorUpDownEnter(_eventKeycode) && _eventKeycode!=0)
		{
		PressAction () ;							// On a pressé une touche autre que haut/bas/enter
		}
	}

//---------------------------------------------------------------------------------------------------------------------
function handleCursorUpDownEnter (eventCode)				// Cette méthode traite les touches haut, bas et enter
	{
	if (eventCode == 40)
		{
		highlightNewValue (_highlightedSuggestionIndex+1) ;
		return false ;
		}
	else	if (eventCode == 38)
		{
		highlightNewValue (_highlightedSuggestionIndex-1) ;
		return false ;
		}
	else	if(eventCode==13 || eventCode==3)
		{
		return false ;
		}
	return true ;
	}

//---------------------------------------------------------------------------------------------------------------------
// 1. Suppression de l'index de la suggestion précédemment sélectionnée, et recopie du div contenant les
//    suggestions dans la variable globale _completeDivDivList.
// 2. Si le champ est vide ou qu'on n'a aucune suggestion, on cache les possibilités de suggestions, sinon,
//    on les affiche.
// 3. On recherche si le texte utilisateur entré correspond à un début de suggestion (_currentInputFieldValue
//    contient l'entrée utilisateur).
// 4. On désélectionne toutes les suggestions et éventuellement on resélectionne celle qui correspond à notre
//    début de texte.
// 5. On filtre les touches spéciales (comme page up/page down et autres) qui ont pour effet d'arrêter les
//    suggestions.
// 6. Si on n'est pas dans le cas d'une touche spéciale et qu'on a trouvé une suggestion possible, on met en
//    place dans le champ texte cette suggestion en sélectionnant la partie suggérée.

var _completeDivRows = 0 ;							// Traite les touches autres que haut/bas/enter
var _completeDivDivList = null ;
var _highlightedSuggestionIndex = -1 ;
var _highlightedSuggestionDiv = null ;

function PressAction ()
	{
	_highlightedSuggestionIndex = -1 ;

	var suggestionList     =_completeDiv.getElementsByTagName("div") ;
	var suggestionLongueur = suggestionList.length ;
												// On stocke les valeurs précédentes
												// Nombre de possibilités de complétion
	_completeDivRows = suggestionLongueur ;
												// Possiblités de complétion
	_completeDivDivList = suggestionList ;
												// Si le champ est vide, on cache les propositions de complétion
	if (_currentInputFieldValue=="" || suggestionLongueur==0)
		hideCompleteDiv () ;
	else showCompleteDiv () ;

	var trouve = false ;      
												// Si on a du texte sur lequel travailler
	if (_currentInputFieldValue.length>0)
		{
		var indice ;
												// T vaut true si on a dans la liste de suggestions
												// un mot commencant comme l'entrée utilisateur
		for(indice=0; indice<suggestionLongueur; indice++)
			{
			if (getSuggestion(suggestionList.item(indice)).toUpperCase().indexOf(_currentInputFieldValue.toUpperCase())==0)
				{
				trouve = true ;
				break ;
				}
			}
		}           
												// On désélectionne toutes les suggestions
	for (var i=0; i<suggestionLongueur; i++)
		{
		setStylePourElement (suggestionList.item(i), "AutoCompleteDiv") ;
		}
												// Si l'entrée utilisateur (n) est le début d'une suggestion (n-1)
												// on sélectionne cette suggestion avant de continuer
	if (trouve)
		{
		_highlightedSuggestionIndex = indice ;
		_highlightedSuggestionDiv   = suggestionList.item (_highlightedSuggestionIndex) ;
		}
	else 
		{
		_highlightedSuggestionIndex = -1 ;
		_highlightedSuggestionDiv   = null ;
		}
           
	var supprSelection = false ;
      
	switch (_eventKeycode)
		{
		case 8 :									// Cursor left, cursor right, page up, page down, others ??
		case 33:
		case 34:
		case 35:
		case 35:
		case 36:
		case 37:
		case 39:
		case 45:
		case 46:	supprSelection = true ;				// On supprime la suggestion du texte utilisateur
				break ;
		default:	break ;
		}
           
	if (!supprSelection && _highlightedSuggestionDiv)		// Si on a une suggestion (n-1) sélectionnée
		{
		setStylePourElement (_highlightedSuggestionDiv, "AutoCompleteDivAct") ;
 
		var z ;
 
		if (trouve)
			z = getSuggestion (_highlightedSuggestionDiv).substr(0) ;
		else	z=_currentInputFieldValue ;

		if (z != _inputField.value)
			{
			if (_inputField.value != _currentInputFieldValue)
				{
				return ;
				}

			if (_inputField.createTextRange || _inputField.setSelectionRange)
				{
				_inputField.value = z ;				// Si on peut créer des range dans le document
				}
                       
			if (_inputField.createTextRange)			// On sélectionne la fin de la suggestion      
				{
				var t = _inputField.createTextRange () ;
                        
				t.moveStart ("character", _currentInputFieldValue.length) ;
        
				t.select () ;
				}
			else	if (_inputField.setSelectionRange)
				{
				_inputField.setSelectionRange (_currentInputFieldValue.length, _inputField.value.length) ;
				}
			}
		}
	else
		{
		_highlightedSuggestionIndex = -1 ;				// Sinon, plus aucune suggestion de sélectionnée
		}
	}

//---------------------------------------------------------------------------------------------------------------------
var _cursorUpDownPressed = null ;						// La méthode blurThenGetFocus est déclenchée après
												// l'appui sur la touche haut/bas. Elle effectue un blur
												// sur le champ de saisie pour que l'utilisateur voit
												// bien le changement de suggestion dans la liste des
												// suggestions, et récupère le focus du champ de saisie

												// Le focus est récupéré après traitement (via le timeout)
function blurThenGetFocus ()
	{
	_cursorUpDownPressed = true ;

	_inputField.blur () ;

	setTimeout ("_inputField.focus();", 10) ;

	return ;
	}

//---------------------------------------------------------------------------------------------------------------------
function rangeSize (n)								// Recherche la taille du texte sélectionné dans un champ
	{
	var N = -1 ;
      
	if (n.createTextRange)
		{
		var fa = document.selection.createRange().duplicate() ;

		N = fa.text.length ;
		}
	else	if (n.setSelectionRange)
		{
		N = n.selectionEnd - n.selectionStart ;
		}

	return N ;
	}

//---------------------------------------------------------------------------------------------------------------------
function beforeRangeSize (n)							// Recherche la taille du texte placé avant la
     {											// sélection dans un champ
	var v = 0 ;
      
	if (n.createTextRange)
		{
		var fa = document.selection.createRange().duplicate() ;

		fa.moveEnd ("textedit", 1) ;
            
		v = n.value.length - fa.text.length ;
		}
	else	if (n.setSelectionRange)
		{
		v = n.selectionStart ;
		}
	else
		{
		v = -1 ;
		}

	return v ;
	}

//---------------------------------------------------------------------------------------------------------------------
function cursorAfterValue (n)							// Place le curseur à la fin du champ
	{
	if (n.createTextRange)
		{
		var t = n.createTextRange () ;

		t.moveStart ("character", n.value.length) ;
             
		t.select () ;
		}
	else	if (n.setSelectionRange)
		{
		n.setSelectionRange (n.value.length,n.value.length) ;
		}
	}


//---------------------------------------------------------------------------------------------------------------------
function getSuggestion (uneDiv)						// Retourne la valeur de la possibilite (texte) contenu
	{											// dans une div de possibilite
	if(!uneDiv) return null ;

	return trimCR (uneDiv.getElementsByTagName('span')[0].firstChild.data)
	}

//---------------------------------------------------------------------------------------------------------------------
function trimCR (chaine)								// Supprime les caractères CR et LF
	{
	for (var f=0, nChaine="", zb="\n\r"; f<chaine.length; f++)
		{
		if (zb.indexOf(chaine.charAt(f)) == -1)
			{
			nChaine += chaine.charAt(f) ;
			}
		}

	return nChaine ;
	}

//---------------------------------------------------------------------------------------------------------------------
function hideCompleteDiv ()							// Cache complètement les choix de completion
	{
	_completeDiv.style.visibility = "hidden" ;
	}

//---------------------------------------------------------------------------------------------------------------------
function showCompleteDiv ()							// Rend les choix de complétion visibles
	{
	_completeDiv.style.visibility = "visible" ;
	setCompleteDivSize () ;
	}

//---------------------------------------------------------------------------------------------------------------------
function highlightNewValue (C)						// Change la suggestion en surbrillance
	{
	if (!_completeDivDivList || _completeDivRows<=0)
		{
		return ;
		}
           
	showCompleteDiv () ;

	if (C >= _completeDivRows)
		{
		C = _completeDivRows-1 ;
		}

	if (_highlightedSuggestionIndex!=-1 && C!=_highlightedSuggestionIndex)
		{
		setStylePourElement (_highlightedSuggestionDiv, "AutoCompleteDiv") ;

		_highlightedSuggestionIndex = -1 ;
		}
           
	if (C < 0)
		{
		_highlightedSuggestionIndex = -1 ;
		_inputField.focus () ;
		return ;
		}
           
	_highlightedSuggestionIndex = C ;
	_highlightedSuggestionDiv   = _completeDivDivList.item (C) ;
     
	setStylePourElement (_highlightedSuggestionDiv, "AutoCompleteDivAct") ;
      
	_inputField.value = getSuggestion (_highlightedSuggestionDiv) ;
	}

//---------------------------------------------------------------------------------------------------------------------
var onResizeHandler = function (event)					// Handler de resize de la fenetre
	{
	setCompleteDivSize () ;							// Recalcule la taille des suggestions
	}

//---------------------------------------------------------------------------------------------------------------------
var onBlurHandler = function (event)					// Handler de blur sur le champ texte
	{
	if (!_cursorUpDownPressed)
		{
		hideCompleteDiv () ;						// Si le blur n'est pas causé par la touche haut/bas

		if (_lastKeyCode == 9)						// Si la dernière touche pressée est TAB, on passe
			{ 									// au bouton de validation
// FGH		_submitButton.focus() ;
// FGH		_lastKeyCode = -1 ;
			}
		}

	_cursorUpDownPressed = false ;
	}

//---------------------------------------------------------------------------------------------------------------------
var divOnMouseDown = function ()						// Déclenchée quand on clique sur une div contenant
     {											// une possibilité
	_inputField.value = getSuggestion (this) ;

//	_documentForm.submit () ;						//////// FGH
	}

//---------------------------------------------------------------------------------------------------------------------
var divOnMouseOver = function ()						// Déclenchée quand on passe sur une div de possibilité
	{											// La div précédente est passée en style normal
	if (_highlightedSuggestionDiv)
		{
		setStylePourElement (_highlightedSuggestionDiv, "AutoCompleteDiv") ;
		}

	setStylePourElement (this, "AutoCompleteDivAct") ;
	}

//---------------------------------------------------------------------------------------------------------------------
var divOnMouseOut = function ()						// Déclenchée quand la souris quitte une div de
	{											// possiblité. La div repasse à l'état normal
	setStylePourElement (this, "AutoCompleteDiv") ;
	}
