//
// utilitaires rev 1.66 du 20080304
//
// (C) Quid.fr
//
//

	pops = [1, 2 ,3 ,4];

	var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

	var	doc_sections	= false;

	var MAX_DUMP_DEPTH 	= 10;
	var	GEO_DELTA		= 2000;
	var GURI 			= new Uri(location.href);
	var	SERVER_NAME		= GURI.authority;
	var	map;
	var	encs 		= new Array;											// encadrés
	var	savedims	= new Array;											// dimensions éléments
	var	user_toggles =new Array;											// toggle utilisateur
	var	reg			= '';													// regexp emphase
	var	spaces_only	= new RegExp("^[\s\t\n\r]+$", "");						// regexp pour parse_nodes
	var isIE 		= (window.navigator.userAgent.indexOf("MSIE") > 0);		// un classique, beurk ;-)
	var menu_shown	= new Array;											// les menus
	var	flash_pub	= false;												// indique la presence de la pub en flash
	var	flash_fix	= true;													// indique si on doit gerer les collisions avec les dropmenus
	var	menus		= new Array;											// les handles de menu

	if (! isIE) {
		HTMLElement.prototype.__defineGetter__("innerText", function () { return(this.textContent); });
		HTMLElement.prototype.__defineSetter__("innerText", function (txt) { this.textContent = txt; });
	}

/**
 * Callback de FCKeditor
 */
function FCKeditor_OnComplete( editorInstance )
{
	document.forms['fck-editor'].first_datas.value =  editorInstance.GetXHTML(true);
}

function grunt(o, dm) {
	var dw=document.body.clientWidth;
	var dh=document.body.clientHeight;
	var ww = self.innerWidth  || (document.documentElement.clientWidth  || document.body.clientWidth);
	var wh = self.innerHeight || (document.documentElement.clientHeight || document.body.clientHeight);
	var iebody=(document.compatMode && document.compatMode != "BackCompat")? document.documentElement : document.body
	var ox=document.all? iebody.scrollLeft : window.pageXOffset;
	var oy=document.all? iebody.scrollTop : window.pageYOffset;
	var x=o.offsetLeft;
	var y=o.offsetTop;

	for (var opa = o.offsetParent; opa ; opa = opa.offsetParent) {
		x = x + opa.offsetLeft;
		y = y + opa.offsetTop;
	}

	var	ck_grunt;
 	var id;
	var	ref = escape(GURI.base());

	if (ck_grunt = GetCookie('grunt')) {
		var ol1=decode64(ck_grunt).split("&");
		var old=new Array();
		for(var i=0 ; i< ol1.length;i++) {
			var e = ol1[i].split("="); 
			old[e[0]] = e[1];
		}
		id = old['id'];
	}

	if (!id) {	
		id = new Date().getTime();
	}

	if (!dm) {
		dm = '0';
	}

	var q = "x="+x+"&y="+y+"&dw="+dw+"&dh="+dh+"&ox="+ox+"&oy="+oy+"&ww="+ww+"&wh="+wh+"&id="+id+"&ref="+ref+"&dm="+dm;	
	document.cookie = 'grunt=' +  encode64(q) + ';  path=/';	

	return true;
}

/**
 * Selectionne onglets
 */
function select_onglet(onglet) {	
	
	if (! onglet) {
		return;
	}

	var father	= onglet.parentNode;
	var divs 	= father.getElementsByTagName('div');
	var litosel = document.getElementById('tab-'+onglet.id);

	if (! litosel) {
		// pas d'onglet pour ça
		return;
	}

	// la liste d'onglets correspondant
	var	ul 		= litosel.parentNode;

	// on cherche le div
	for(i=0; i< divs.length; i++) {
		if (divs[i].className != "minichand"
		||	divs[i].parentNode != ul.parentNode)
		{
			// ce n'est pas une minichand ou son parent
			// n'est pas le meme que la liste d'onglets
			continue;
		}

		// item de liste courant
		var	li = document.getElementById('tab-'+divs[i].id);

		if (! li) {
			// cette minichand n'est pas ongletable
			continue;
		}

		if (divs[i].id == onglet.id) {
			divs[i].style.display="block";
			li.className = "selected"
		}
		else {
			divs[i].style.display="none";
			li.className= "";
		}
	}
}

/**
 * Recupere la selection d'onglets
 */
function get_onglets() {
	var	selecteds = new Object();

	var chdroite = document.getElementById('chdroite');
	if (! chdroite) {
		return;
	}

	var uls = chdroite.getElementsByTagName('ul');

	for(var i=0; i< uls.length; i++) {
		if (uls[i].className != "onglets") {
			continue;
		}
		// items de liste
		var lis= uls[i].getElementsByTagName('li');
		for (var j= 0; j< lis.length; j++) {
			if ( lis[j].className == "selected") {

				selecteds[uls[i].parentNode.id] = lis[j].id.replace(/^tab-/, '')  ;
			}
		}
	}
	return selecteds;
}

function equilibre() {
	var featured = document.getElementById('quidzoom-featured');

	if (! featured) {
		return;
	}

	var divs = featured.getElementsByTagName('div');
	
	var fblocs = new Array();	
	for(j=0, i=0; i< divs.length; i++) {
		if (divs[i].className == "fbloc") {
			fblocs[j++] = divs[i];
			var p 	= (divs[i].getElementsByTagName('p'))[0];
			var a = document.createElement('a');
			a.setAttribute('href', (divs[i].getElementsByTagName('a'))[0].getAttribute('href'));
			a.className="biglink";
			p.appendChild(a);
		}
	}

	// on part du 2eme
	var contenu;
	for (i=1; i < fblocs.length ; i+=2) {
		var h1 = fblocs[i].offsetHeight;
		var	h2 = fblocs[i+1].offsetHeight;

		if (h1 <= h2) {
			contenu = (fblocs[i].getElementsByTagName('div'))[0];
		}
		else {
			contenu = (fblocs[i+1].getElementsByTagName('div'))[0];
		}
		// compense le manque de padding du contenu	(c'est imparfait - les 3px sont ceux du style de base dans la css)
		contenu.style.paddingBottom = Math.abs(h1-h2) + 3 + "px";
	}
}

/**
 * Fait passer derriere notre contenu
 * les eventuels contenus flash
 */
function fix_flash() {	
	var objs = document.getElementsByTagName('object');

	if (objs) {
		flash_pub = true;
	}

	for(i=0; i< objs.length; i++) {	
		// de toute façon, objet à plat
		objs[i].style.position="relative";
		objs[i].style.zIndex="0";
		// traitement de l'embed si présent
		var embed = (objs[i].getElementsByTagName('embed'))[0];
		if (embed) {
			embed.setAttribute('wmode', "transparent");	
			embed.style.position="relative";
			embed.style.zIndex="0";
		}
		// traiement des params si présents
		var params = objs[i].getElementsByTagName('param');
		if (params) {
			for(var wmode_found=false, j=0; j<params.length;j++) {
				if ( "wmode" == params[j].getAttribute('name') ) {
					wmode_found = true;
					params[j].setAttribute('value', "transparent");
				}
			}
			// il faut crée l'élément wmode
			if (! wmode_found) {
				var wmode = document.createElement("param");
				wmode.setAttribute('name', "wmode");
				wmode.setAttribute('value',"transparent");
				// qui devient fils de l'object
				objs[i].appendChild(wmode);
			}
		}
	}
}

/**
 * Affiche un menu deroulant
 */
function show_menu(from, maxwidth, maxheight) {
	// identifiant du menu
	var id		= from.id.replace(/^item-/, '');
	var	menu_id = "menu-" + id;

	if (menu_shown[menu_id]) {
		return;
	}
	
	// le pere
	var father = from.parentNode;
	// déja créé ?
	var menu = document.getElementById(menu_id);
	
	// non, le charge
	if (! menu) {
		menu = load_menu(id);
	}

	// decidemment, ca veut pas
	if (! menu) {
		return;
	}

	// ses dimensions sont-elles deja définies
	if (! menu.style.width) {
		menu.style.left	 = from.offsetLeft+"px";
		menu.style.width = (maxwidth ? maxwidth : from.offsetWidth) + "px";
		// offset global par rapport au pere
		menu.style.top	 = (from.offsetTop +from.offsetHeight)+"px";

		if (maxheight) {
			menu.style.height = maxheight+"px";
		}
	}
	
	menu.style.zIndex= (father.id == 'mainmenu' ? "15" : "10");
	menu_shown[menu_id] = true;	
	addEvent(menu, 'mouseout', listen_menu);
	menu.style.display = "block";

	// efface ses éventuels copains sauf lui
	hide_all_menus(father.id, menu_id);

	// cache temporairement la pub si c'est du flash
	if (flash_fix
	&&	flash_pub)
	{
		var ad = document.getElementById('ad');
		if ( ad
		&&	father.id=="mainmenu") 
		{
			ad.style.visibility = "hidden";
		}
	}
}

/**
 * Charge un menu à partir d'une
 * partie designee de la page
 */
function load_menu(id) {
	// déja chargé
	if (menus[id]) {
		return;
	}

	// il n'a pas deja été créé
	var	source_id = "source-"+id;
	var content = document.getElementById(source_id);

	if (!content) {
		// pas de source
		return false;
	}

	// les listes
	var ul = content.getElementsByTagName('ul');
	// cree le menu
	var menu = document.createElement("div");
	// son id
	menu.id 	= "menu-"+ id;		

	// au départ il est caché
	menu.style.display="none";
	menu_shown[menu.id] = false;

	// le lien apparente
	var item_id 	= "item-"+ id;
	var	from		= document.getElementById(item_id);
	menu.className	= "dropmenu"; 

	// ajoute les listes et les éventuels titres
	for (i=0; i< ul.length; i++) {
		t = getPrevSibling(ul[i]);
		if (t && t.nodeName=='H4') { // IE ne connait pas localname
			menu.appendChild(t.cloneNode(true));
		}
		
		var new_ul = ul[i].cloneNode(true);		
		var lis = new_ul.getElementsByTagName('a');

		// ajout des appels grunt si possible
		for(var j=0; j< lis.length; j++) {		
			var on_click = "grunt(this,'1');";
			// si il y a deja un attribut onclick (eg. f1();), IE6 ne saurait pas chainer
			// un deuxieme appel concaténé f1(); f2(); (alors que firefox sait)
			// on ne cherche donc pas à ajouter grunt dans ce cas
			if (! lis[j].getAttribute('onclick')) {
				lis[j].setAttribute('onclick', on_click);				
			}
		}
		menu.appendChild(new_ul);
	}

	// le rend fils du menu "principal" et frère droit du lien apparenté
	from.parentNode.insertBefore(menu, getNextSibling(from));
	// le memorise ce qui permettra de ne pas le charger une 2eme fois
	menus[id] = menu;
	/* enregistre le mouse out du lien apparenté */
 	from.onmouseout=leave_menu;

	return menu;
}
/**
 * cree les dropmenus d'un element d'id
 */
function preload_menus(father_id) {	
	// enumere les liens fils
	var father = document.getElementById(father_id);
	if (! father) {
		return;
	}

	var items = father.getElementsByTagName('a');
	for(var i=0; i< items.length; i++) {
		load_menu(items[i].id.replace(/^item-/,''));
	}
}	

/**
 * Teste si on est en train de quitter
 * effectivement le lien du menu pour
 * l'exterieur
 */
function leave_menu(e) {

	if (!e) {
		e = window.event;
	}

	var tg = (window.event) ? e.srcElement : e.target;
	// le menu en rapport
	var related_menu = getNextSibling(this);

	// il n'y a pas de menu en rapport immediat, donc on 
	// n'est pas sense faire qq chose
	if (related_menu.className != 'dropmenu') {		
		return false;
	}

	var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
	if (! reltg) {
		return false;
	}

	// si la target est le menu relatif (ou un fils du menu relatif) 
	// c'est qu'on reste dans le menu
	if (reltg.id == related_menu.id
	||	has_ancestor(reltg, related_menu))
	{
		// on reste dans le contexte menu deplié
		return false;
	}

	// on quitte effectivement le menu
	hide_menu(related_menu.id);
}

/**
 * Teste si on quitte le menu deroulant
 * pour l'exterieur 
 */
function listen_menu(e) {	
	// inspiré de http://www.quirksmode.org/js/events_mouse.html
	if (!e) {
		e = window.event;
	}

	var tg = (window.event) ? e.srcElement : e.target;

	if (this.className != 'dropmenu') { 
		// c'est pas pour nous
		return;
	}

	var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
	if (! reltg) {
		return;
	}
	// cherche si l'element dans lequel on entre est un de nos fils	ou nous même
	if (reltg.id == this.id 
	||	has_ancestor(reltg, this))
	{
		// on y reste
		return;
	}

	// on cache
	hide_menu(this.id);
}

/**
 * verifie si ancetre
 */
function has_ancestor(node, ancestor) {
	
	var daddy = node.parentNode;
	
	while (daddy) {
		if( daddy == ancestor) {
			return true;
		}
		daddy = daddy.parentNode;
	} 	
	return false;
}

/**
 * Cache le menu deroulant
 */
function hide_menu(id) {
	
	var menu = document.getElementById(id);

	if (! menu) {
		return;
	}

	menu.style.display="none";
	menu_shown[menu.id] = false;
	// si menu principal et pub en flash on fait réapparaitre la pub
	if (flash_fix
	&&	flash_pub)
	{
		var ad = document.getElementById('ad');
		if ( ad
		&&	 menu.parentNode.id == "mainmenu" ) 
		{
			ad.style.visibility="visible";
		}
	}
	return;
}

/**
 * Cache tous les menus deroulants
 */
function hide_all_menus(father_id, but_id) {

	var father = document.getElementById(father_id);

	if (! father) {
		return;
	}

	var m1 = father.getElementsByTagName('div');

	if (! m1) {
		return;
	}
	for(i=0; i< m1.length;i++) {
		if (m1[i].className == "dropmenu"
		// eventuellement, celui a ne pas cacher
		&&	but_id != m1[i].id
		// et s'il est marque comme visible ou est visible
		&& (menu_shown[m1[i].id] || m1[i].style.display=="block")) 
		{
			// cache par l'id
			hide_menu(m1[i].id);
		}
	}
}

/**
 * Google maps
 */
function gmapload(latitude, longitude, my_maptype, gmzf, opt_tk ) {
	// extension google maps pas chargée
	if (typeof(GBrowserIsCompatible) == 'undefined'
	// latitude indéfinie ?	
	||	typeof(latitude) == 'undefined'	
	// browser incompatible	
	||	! GBrowserIsCompatible() )
	{
		return false;
	}
	
	var wqm = true;
	var whm = true;;

	var	point	 	= new GLatLng(latitude,longitude);
	var	first_move	= true;

	// les params de l'url
	get_query_params();

	var bounds;	// rect(sw,ne)
	var	sw;
	var	ne;
	var center;

	var	active_markers = new Array;								// marqueurs actifs
	var	last_time	= 0;										// dernier mouvement
	var	delayer		= false;									// retardateur requète
	var	tk			= (opt_tk ? opt_tk : location.url['tk']);	// ticket

	var Quid_icon	= quid_icon(); 
	var	Hotel_icon	= hotel_icon();

	// elements dom
	var infobar 		= document.getElementById("infobar");
	var divc 			= document.getElementById("entitieslist");
	var	entitiescount 	= document.getElementById("entitiescount");
	var	colatitude		= document.getElementById("colatitude");
	var	colongitude		= document.getElementById("colongitude");
	var	cowidth			= document.getElementById("cowidth");
	var	coheight		= document.getElementById("coheight");
	var	list			= (divc.getElementsByTagName("ul"))[0];

	// réactions
	addEvent(document.getElementById("wqm") , 'click' , function() { change_marker_option(this);});
	addEvent(document.getElementById("whm") , 'click' , function() { change_marker_option(this);});

	// les états
	set_marker_option(document.getElementById("wqm"), wqm);
	set_marker_option(document.getElementById("whm"), whm);

	// par défaut, affiche la liste 
	user_toggles["entitieslist"] = true;

	map = new GMap2(document.getElementById("gmap"));

	GEvent.addListener(map, "moveend", move_listener);

	// controls
	map.addControl(new GLargeMapControl());
	map.addControl(new GMapTypeControl());
	map.addControl(new GScaleControl());

	// positionne et zoom
	map.setCenter(point, gmzf);

	// type de carte
	switch(my_maptype) {
	default:
	case 1:
		map.setMapType(G_NORMAL_MAP);
		break;	
	case 2:
		map.setMapType(G_HYBRID_MAP);
	}

	function change_marker_option(dom_input) {
		// positionne l'etat de la variable correpondant
		eval(dom_input.id+"="+dom_input.checked);
		// rafraichi la carte
		handle_move();
	}

	function set_marker_option(dom_input, value) {
		dom_input.checked = value;
	}

	/**
	 * Listener des mouvements carte
	 */
	function move_listener() {
		// elapsed depuis la derniere requète
		var l = (new Date()).getTime();

		var	delta = l - last_time;
		last_time = l;		

		// r.a.z des élements d'info
		list.innerHTML 	= "";
		entitiescount.innerHTML	= "";

		if (delta < GEO_DELTA) {
			if (delayer) {
				// deja une préparation de requète en cours
				clearTimeout(delayer);
				// que l'on annule
				delayer = false;
			}
			// on en lance une nouvelle
			var delay = GEO_DELTA-delta;
			// positionne
			delayer = setTimeout(handle_move, delay);
		}
		else {	
			// délai respecté on peut la lancer
			handle_move();
		}
	}
	
	/**
	 * handler m.a.j carte
	 */
	function handle_move() {
		// ne prend pas en compte le tout premier
		if (first_move) {
			first_move = false;
			return;
		}

		// clear un éventuel delayer en cours
		if (delayer) {
			clearTimeout(delayer);
			delayer = false;
		}

		center	= map.getCenter();
		bounds	= map.getBounds();	
		sw 		= bounds.getSouthWest();
		ne 		= bounds.getNorthEast();
		
		colatitude.innerHTML 	= center.y;
		colongitude.innerHTML	= center.x;
		cowidth.innerHTML		= (Math.abs(ne.x - sw.x));
		coheight.innerHTML		= (Math.abs(ne.y - sw.y));
		
		// reset l'infobar
		infobar.innerHTML = '';

		// interrogation base si ticket
		if (! tk) {
			return;
		}

		default_info_elements();

		// prepare affichage - en fonction du toggle
		divc.style.display	= (divc.style.display == false ? "block" : divc.style.display);

		var params 	=  "swx=" + sw.x.toString() + "&swy=" + sw.y.toString() 
					+ "&nex=" + ne.x.toString() + "&ney=" + ne.y.toString()
					+ "&lat=" + center.y.toString() + "&long=" + center.x.toString()
					+ "&wqm=" + (wqm+0)
					+ "&whm=" + (whm+0)
					+ "&tk="  + tk;

		GDownloadUrl("http://"+SERVER_NAME+"/geoget.php?"+params, 

			function (data, responseCode) {
				
				var xml 	= GXml.parse(data);		

				var	hotels			= (xml.documentElement.getElementsByTagName("hotels"))[0];
				var	cnt_hotels		= parseInt(hotels.getAttribute("count"));				

				var	ents			= (xml.documentElement.getElementsByTagName("entities"))[0];
				var	cnt_ents		= parseInt(ents.getAttribute("count"));				
				var	info			= ents.getAttribute("info");
				var	suggest			= ents.getAttribute("suggest");
				var	maxcount		= Math.max(40 ,parseInt(xml.documentElement.getAttribute("maxcount")));
				var	summary 		= (xml.documentElement.getElementsByTagName("summary"))[0];
	
				// 
				if ( (cnt_ents < 1 && cnt_hotels < 1) || cnt_ents > maxcount) {
					infobar.innerHTML = info+ (suggest ? ' <span class="suggest">'+ suggest+ '</span>' : '');

					// rien a afficher, on l'enlève mais on touche pas au user_toggle
					set_display_state("entitieslist", false);
					// ne pas afficher non plus le toggler
					document.getElementById("toggle_entitieslist").style.display="none";
					// détruit les marqueurs
					for (id in active_markers) {
						// detruit les objet
						delete(active_markers[id]);
					}	
					// détruit tous les overlays (images de markers)
					map.clearOverlays();
					return;
				}
				else {
					// restaurer 
					document.getElementById("toggle_entitieslist").style.display="block";
					// last style
					set_display_state("entitieslist", get_user_toggle("entitieslist"));
				}

				// affiche le nombre de résultats
				var resume = '';
				for(var i=0; i < summary.attributes.length ; i++) {
					var c = parseInt(summary.attributes[i].value);
					if (c > 0) {
						resume  = resume + c 
								+ "&nbsp;fiche" +(cnt_ents> 1 ? "s" : "") + "&nbsp;\"" 
								+ summary.attributes[i].name+ "\"<br />";
					}
				}

				entitiescount.innerHTML = resume;

				// liste des objets
				var entities = merge_list( xml.documentElement.getElementsByTagName("entity")
										  ,xml.documentElement.getElementsByTagName("hotel"));
				
				// buffer de sortie
				var outs= '';

				// décrémente le refcount des markers
				for (id in active_markers) {
					active_markers[id]['refcount'] = Math.max(0, active_markers[id]['refcount']-1);
				}

				for (var i = 0; i < entities.length; i++) {
					// mélange d'hotels et de lieus
					var icone;
					switch(entities[i].tagName) {
					case 'entity':	
						// cas lieu
						var	icone 		= Quid_icon;
						var	id 			= entities[i].getAttribute("id");
						var	fiche_url	= element_to_url(entities[i]);
						var entityname	= entities[i].getAttribute("name");
						// on ajoute a la liste du document
						outs = outs + '<li><a href="'
									+ fiche_url
									+ '" title="aller directement à la fiche de '
									+ entityname+ '">' 
									+ (i+1)+'&nbsp;-&nbsp;'+entityname
									+ '</a></li>';
	
						break;
					case 'hotel':
						// Hotel
						var	icone		= Hotel_icon;
						var	id 		  	= entities[i].getAttribute("id");
						var fiche_url 	= entities[i].getAttribute("url");
						var entityname	= entities[i].getAttribute("name"); 
						break;
					default:
						continue;
					}
					
					var point = new GLatLng(parseFloat(entities[i].getAttribute("latitude")), parseFloat(entities[i].getAttribute("longitude")));

					// marker déjà créé ?
					if (! active_markers[id]) {
						// création complète du marker
						active_markers[id] = {'ref':createMarker( point
																, fiche_url + '&simple=1'
																, "Ouvrir la fiche "+ entityname
																, icone )
											, 'refcount':1};
						// on ajoute seulement qu'en création
						map.addOverlay(active_markers[id]['ref']);
					}
					else {
						// il existe, on incrémente juste sont refcount pour réutilisation
						active_markers[id]['refcount'] = active_markers[id]['refcount'] + 1;
					}			
				}

				// on détruit ceux qui n'ont pas été (ré)utilisés
				for (id in active_markers) {
					if (active_markers[id]['refcount'] == 0) {
						// et on enlève son overlay
						map.removeOverlay(active_markers[id]['ref']);
						// et on le détruit
						delete(active_markers[id]);
					}
				}
				// éventuelle info
				infobar.innerHTML = info+ (suggest ? ' <span class="suggest">'+ suggest+ '</span>' : '');
				// la liste
				list.innerHTML = outs;
				// requets function ends 
			}
		);
	}
	// handler ends

	/**
	 * status par défaut des éléments d'info
	 */
	function default_info_elements() {
		list.innerHTML 			= "<li class='wait'>Récupération de la liste. Un instant svp...</li>";
		entitiescount.innerHTML	= "";
	}

	/**
	 * url de fiche entité ou communes à
	 * partir d'un élément dom entity
	 */
	function element_to_url(elt) {
		switch(elt.getAttribute("area")) {
		default:
		case 'monde':
			return "http://"+ GURI.authority+ "/monde.html"
											+ "?mode=detail"
											+ "&iso="+elt.getAttribute("iso")
											+ "&style=fiche"
											+ "&id="+elt.getAttribute("id");
		case 'communes':
			return "http://"+ GURI.authority+ "/communes.html"
											+ "?mode=detail"
											+ "&style=fiche"
											+ "&id="+elt.getAttribute("id");

		}
	}

	/**
 	 * Icone quid
	 */
	function quid_icon() {
		var Icon = new GIcon();
    	Icon.image 				= "/charte/quidmarker.png";
		Icon.iconSize 			= new GSize(25, 32);
		Icon.iconAnchor 		= new GPoint(13, 31);
		Icon.infoWindowAnchor 	= new GPoint(10, 10);
		Icon.shadow 			= "/charte/quidmarkershade.png";;
		Icon.shadowSize 		= new GSize(48, 32);
		return Icon;
	}

	function hotel_icon() {
		var Icon = new GIcon();
    	Icon.image 				= "/charte/hotelmarker.png";
		Icon.iconSize 			= new GSize(21, 19);
		Icon.iconAnchor 		= new GPoint(13, 19);
		Icon.infoWindowAnchor 	= new GPoint(10, 10);
		Icon.shadow 			= "/charte/hotelmarkershade.png";;
		Icon.shadowSize 		= new GSize(25, 23);
		return Icon;
	}

	/**
	 * Creation de marker avec
	 * listener
	 */
	function createMarker(point, url, title, Icon) {

		var marker = new GMarker(point, {icon:Icon, clickable:true, title:title});		

		GEvent.addListener(marker, "click",
			function() {
				window.open(url ,'','width=780,height=500,status=no,resizable=no,scrollbars=yes');
			}
		);
		return marker; 
	}
}

/*
 * Obtient le user toggle
 */
function get_user_toggle(id) {
	return user_toggles[id];
}
/*
 * positionne user_toggle
 */
function set_user_toggle(id, v) {
	user_toggles[id] = ! get_user_toggle(id);
	set_display_state(id, user_toggles[id]);
}

/*
 * Toggle utilisateur 
 */
function user_toggle(id) {
	set_user_toggle(id,  ! get_user_toggle(id));
}

/**
 * toggle toute les listes ou une seule
 */
function toggle_tables(id) {
	var main;
	var uls = new Array;
	var	all;
	var on;
	var on_all;

	// une seule ou la principale ?
	if (id.match(/^ul-tab/)) {
		// une seule
		all = false;
		uls[0] = document.getElementById(id);
		// il y a le div 'tablemat' entre les 2
		main = uls[0].parentNode.parentNode;
	}
	else {
		// toutes
		all = true;
		main = document.getElementById(id);
		uls = main.getElementsByTagName('ul');
		// l'etat on est le global
		on_all = document.getElementById("toggle_"+main.id).className != "show";			
	}
		
	if (! main) {
		return;
	}
	
	for (var i=0; i< uls.length; i++) {	
		// etat global ou local ?
		on = all ? on_all : uls[i].style.display != "none";

		// on lui colle un id si pas déja
		if (! uls[i].id) {
 			uls[i].id = "ul-tab-"+ i.toString();
		}

		// titre de table
		var h4 = getPrevSibling(uls[i]);
		// lien cacher / montrer
		var link_id = "toggle_" + uls[i].id;
		// que l'on cree si necessaire
		if (! document.getElementById(link_id)) {
			var a = document.createElement('a');
			a.id = link_id;
			a.innerHTML = h4.innerHTML;
			a.setAttribute('href'	, "javascript:toggle_tables('"+uls[i].id+"');");
			a.setAttribute('title'	, "Chapitres de la section "+h4.innerText);
			h4.innerHTML = '';
			h4.appendChild(a);
		}
		// inverse l'état
		set_display_state(uls[i].id, ! on);
	}
	// en all, on inverse aussi le lien global
	if (all) {
		set_display_state(main.id, ! on_all, true);
	}
}

/*
 * Toggle d'affichage
 */
function toggle(id, savedim) {
	var d = document.getElementById(id);
	
    if( false == get_display_state(id)) {
		set_display_state(id, true);
		// dimensions à restaurer ?
		if (savedims[id]) {
			d.style.height= savedims[id]['h'];
			d.style.width = savedims[id]['w'];
		}
    }
    else {
		set_display_state(id, false);
		// sauvgarde les dimensions
		if ( ! encs[id]) {
			encs[id] =  {'w':d.offsetWidth, 'h':d.offsetHeight};
		}

		if (savedim) {
			// sauvegarde des dimensions
			savedims[id] = {'w':d.offsetWidth, 'h':d.offsetHeight};
		}
    }
}

/*
 * Etat d'affichage, optionnellement on
 * agit juste sur le lien et pas sur la cible
 * (pour toggle_tables)
 */
function set_display_state(id, state, just_link) {
	var d = document.getElementById(id);
	var a = document.getElementById("toggle_"+id);
	if (state) {
		// montre
		if (a) {
			a.innerHTML     = a.innerHTML.replace("Voir", "Masquer");
			a.className = "toggle"; 
		}
		if (! just_link) {
        	d.style.display = "block";
		}
	}
	else {
		// cache
		if (a) {
			a.innerHTML     = a.innerHTML.replace("Masquer", "Voir");
			a.className="show"; 
		}
		if (! just_link) {
        	d.style.display = "none";
		}
	}
}

/*
 * Obtient etat d'affichage
 */
function get_display_state(id) {
	var d = document.getElementById(id);
	return (d.style.display != "none");
}

function detach(id) {
	elt = document.getElementById(id);
	if (! elt) {
		return false;
	}

	// si on a les dimensions stockées (au cas ou il serait caché)
	var w = (encs[id] ? encs[id]['w'] : elt.offsetWidth);
	var	h = (encs[id] ? encs[id]['h'] : elt.offsetHeight);

	var win_width 	= Math.min( w , 1000)+50;
	var win_height	= Math.min( h , 1000)+90;
	var uri = GURI; // new Uri(location.href);

	det = window.open('' , id ,'width='+ win_width +',height='+ win_height +',status=no,resizable=yes,scrollbars=yes,menubar=yes');
	resizeWin(det, win_width, win_height);

	if (! det ) {
		return false;
	}

	det.focus();
	
	var tag = elt.tagName.toLowerCase();

	det.document.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">');
	det.document.write('<html>');
	det.document.write('<head>');
	det.document.write('<meta http-equiv="content-type" content="text/html;charset=iso-8859-1" />');
	det.document.write('<base href="http://' + uri.authority + '/" />');
	det.document.write('<script language="JavaScript" src="/quid.js" type="text/javascript"></script>');
	det.document.write('<link rel="stylesheet" href="/quid.css" type="text/css" />');
	det.document.write('</head>');
	det.document.write('<body class="detach">');
	det.document.write('<div class="discardable">');
	det.document.write('<a href="javascript:void(0)" class="printit" title="imprimer" onclick="print()">Imprimer</a>');
	det.document.write('&nbsp;&nbsp;');
	det.document.write('<a href="javascript:void(0)" class="closeit" title="Fermer la fenêtre" onclick="self.close()">Fermer la fenêtre</a>');
	det.document.write('</div>');
	det.document.write('<div id="content"><div class="quid 2006 lastquid">');
	det.document.write("\n\n");
	det.document.write('<' +tag+' ');
	
	var reg1 = new RegExp("etroit|fleft|fright", "g");
	var	reg2 = new RegExp("display: *none;", "g");

	var	atvalue;

	// attributs
	for(i=0; i < elt.attributes.length ; i++) {
		// on ne garde que les attributs standards (merci IE :-< )
		if (elt.attributes[i].name == 'class'
		||  elt.attributes[i].name == 'style'
		||  elt.attributes[i].name == 'id'
		||  elt.attributes[i].name == 'name')
		{
			
			atvalue = elt.attributes[i].value;
			
			// si l'attribut class contient etroit, on le vire
			if (elt.attributes[i].name == 'class') {
				atvalue = atvalue.replace(reg1, "");
			}

			// si l'attribut style contient un display none; on le vire
			if (elt.attributes[i].name == 'style') {
				atvalue = atvalue.replace(reg2, "display:block; ");
			}
			
			det.document.write(elt.attributes[i].name +"=\"" + atvalue + "\" ");
		}
	}
	det.document.write(' >');
	det.document.write(elt.innerHTML);
	det.document.write('</' +tag+ '>');
	
	det.document.write('</div></div>');
	det.document.write('<p style="text-align:center; clear:both;">&copy; Quid.fr - Sté des Encyclopédies Quid</p>');
	det.document.write('</body>');
	det.document.write('</html>');	
	det.document.close();
}

function resizeWin(win, wx, wy) {
	if (win.innerWidth){
		iWidth = win.innerWidth;
		iHeight = win.innerHeight;
	}else{
		iWidth = win.document.body.clientWidth;
		iHeight =win.document.body.clientHeight;
	}
	iWidth = wx - iWidth;
	iHeight = wy - iHeight;
	win.resizeBy(iWidth, iHeight);
}

function getIndexElements() {
	
	h4et = document.getElementById('exploredtheme');
	// si emphase
	get_query_params();
	if ( ! location.url['refnum'] ) {

		if (!h4et) {
			return;
		}

		h4et.style.display="none";
		return ;
	}
	
	// pour IE les ancres marchent pas
	if (isIE) {
		h4et.style.display="none";
	}
	
	// le lien vers l'ancre 
	gt = document.getElementById('gotheme');
	refnum = location.url['refnum'];

	var uri = GURI; //new Uri(location.href);
	// ajoute l'ancre
	uri.fragment = refnum;	
	// l'url de l'ancre
	gt.setAttribute('href', uri.toString());

	spans =  document.getElementsByTagName('span');
	// cherche les refnum
	for(i=0, nf = 0 ; i < spans.length; i++) {
		if (att_refnum = spans[i].getAttribute('refnum')) {
			if (att_refnum.indexOf("("+refnum+")") != -1) {
				eng = englobe(spans[i], 'em', {'class':"iemph"});
				// premier trouvé
				if (nf == 0) {
					explored = document.getElementById('thetheme');
					explored.appendChild(document.createTextNode(spans[i].innerText));				
					// met l'ancre
					anchor = document.createElement("a");
					anchor.setAttribute('name', refnum);
					eng.appendChild(anchor);
				}
				nf++;
			}
		}
	}	
	return;
}

function show_section_links(section_id) {

	var sections 		= get_doc_sections();
	var	section_links	= document.createElement('ul');
	var	maindoc			= document.getElementById('maindoc');

	var h3 = (maindoc.getElementsByTagName('h3'))[0];

	section_links.setAttribute('id','sectionlinks');
	
	for (var i=0; i< sections.length; i++) {
		var title = (sections[i].getElementsByTagName('h4'))[0].innerText;
		var li = document.createElement("li");
		var a = document.createElement("a");
		a.setAttribute('href', "javascript:show_doc_section('" + sections[i].id +"')" );
		a.setAttribute('id'	 , "link"+sections[i].id);
		// pas de saut de ligne dans le texte
		// title = title.replace(/\s+/g,'&nbsp;');
		a.innerHTML = title;
		li.appendChild(a);
		section_links.appendChild(li);
		section_links.appendChild(document.createTextNode(' '));
	}

	// le pose derierre le titre
	maindoc.insertBefore(section_links, h3.nextSibling);

	// ajoute le lien 'tout voir'
	var all = document.createElement("a");
	all.setAttribute('href', "javascript:show_doc_section('all')");
	all.setAttribute('id'  , "seeall");
	all.innerHTML = "Voir toute la fiche";
	maindoc.insertBefore(all, section_links.nextSibling);

	// un separateur à la toute fin du doc
	var sep = document.createElement("hr");
	sep.className = "separateur";	
	maindoc.appendChild(sep);
	// suppression du wait
	var waitdoc;
	if (waitdoc = document.getElementById('waitdoc')) {
		waitdoc.style.display="none";
	}
		
}

/**
 * 
 */
function zoom_photo(filedesc, area) {
	var uri = GURI; //new Uri(location.href);
	var	url;
	switch(area) {
	default:
	case 'monde':
		url = "http://"+ uri.authority  + "/monde.html"
										+ "?mode=detail"
										+ "&iso="+location.url["iso"]
										+ "&style=photo"
										+ "&zoom=2"
										+ "&id=" +location.url["id"]
										+ "&nbphot=" + filedesc
										+ "&simple=1";
	}

	var zwin = window.open(url ,'','width=1100,height=800,status=no,resizable=no,scrollbars=yes');
	zwin.focus();
}

/**
 * Afficher une section, ou les sections
 * jusqu'à until_section_title
 */
function show_doc_section(section_id, until_section_title) {

	// les sections
	var sections = get_doc_sections();
	// until eventuel
	until_section_title = (until_section_title ? until_section_title.toLowerCase() : false);
	// si on doit "montrer jusqu'à"
	var	show  	= until_section_title ? true : false;
	// si l'id est a 'all' on veut tout, et dans ce cas pas de until
	if (section_id == "all") {
		show = true;
		until_section_title = false;
	}
		
	
	for (var i=0; i< sections.length; i++) {
		// le lien de section
		var section_link = document.getElementById("link"+sections[i].id);

		if (show == true 						// simplement inclus dans le 'until'
		||	sections[i].id == section_id)		// ou correspond strictement à l'id à afficher
		{
			sections[i].style.display='block';
			// selectionne egalement son lien
			section_link.className = (section_id != "all" ? "selected" : ''); 
			// pour qui qui ne supporte pas le changement de classe
			section_link.style.backgroundColor=(section_id != "all" ? "#d8ebfa" : "white");
		}
		else {
			sections[i].style.display='none';
			// dé-selectionne egalement son lien
			section_link.className = '';
			// pour ie qui ne supporte pas le changement de classe
			section_link.style.backgroundColor="white";
		}
		// si on est en mode 'until'
		if (until_section_title) {
			// le titre courant
			var title = ((sections[i].getElementsByTagName('h4'))[0].innerText).toLowerCase();
			if (until_section_title == title) { // qui correspond à la ooù on doit s'arreter
				// on s'arretera la
				show = false;
			}
		}
	}
	// le lien voir toute la fiche n'a de sens que si on n'est pas deja en all
	document.getElementById('seeall').style.display = (section_id == "all" ? 'none' : 'block');
}

function get_doc_sections() {
	// deja initialisée
	if (doc_sections) {
		return doc_sections;
	}
	// a faire
	doc_sections = new Array;

	var divs = document.getElementById('maindoc').getElementsByTagName('div');

	for(var i=0, j=0; i<divs.length; i++) {
		if (divs[i].className
		&&	divs[i].className == 'section')
		{ 
			doc_sections[j] = divs[i];
			j++;
		}
	}
	return doc_sections;
}

/**
 * uri object
 */
function Uri( uri_string ) {

	var regexp = "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?$";
	var r = uri_string.match(new RegExp(regexp));

	this.scheme = r[2] || (r[1] ? "" : 'http');
	this.authority = r[4] || (r[3] ? "" : null);
	this.path = r[5]; // can never be undefined
	this.query = r[7] || (r[6] ? "" : null);
	this.fragment  = r[9] || (r[8] ? "" : null);
	/**
 	 * toString method
	 */
	this.toString= function toString() {
		return this.scheme+'://'+this.authority+this.path+'?'+this.query+(this.fragment ? '#'+this.fragment : '');
	}

	/**
	 * baseUri
	 */
	this.base = function base() {
		return this.path+ (this.query ? ('?'+this.query) : '');
	}

}

function add_anchor(url, ancre) {
	var a_url = url.split('#');
	// vire le dernier '#'
	if (a_url.length > 1) {
		a_url.pop();
	}
	return a_url.join('#')+'#'+ancre;
}

function englobe(elt, element_type, attributes) {

	father = elt.parentNode;
	clone  = elt.cloneNode(true);
	new_elt= document.createElement(element_type);

	for (var key in attributes) {
		// pour IE
		for(j = 0; j < new_elt.attributes.length ; j++) {
			if (new_elt.attributes[j].nodeName == key) {
				new_elt.attributes[j].nodeValue = attributes[key];
			}
		}
    	new_elt.setAttribute(key, attributes[key]);						
	}

	new_elt.appendChild(clone);

	// remplace le mot simple par le noeud
	father.replaceChild(new_elt, elt);

	return new_elt;
}

function f1(page) {
	var res = getFile(page);
}

/**
* Envoie des données en GET ou POST
* en utilisant les XmlHttpRequest asynchrone
*/
function sendData(data, page, method)
{
    if(document.all) {
        //Internet Explorer
        var XhrObj = new ActiveXObject("Microsoft.XMLHTTP") ;
    }
    else {
        //Mozilla
        var XhrObj = new XMLHttpRequest();
    }
       
	//try {
		// GET
		if(method == "GET") {
			//var ck = new Date().getTime();
			if(data != '') {
				page = page +"?"+data; //+"&ck="+ck;
			}	
			else {
				//page = page; //+"?ck="+ck;
			}	

			XhrObj.open("GET", page, true);
		}
		// ou POST
		else {
			if(method == "POST") {
				XhrObj.open("POST", page, true);
			}
		}
	//}
	
	/*catch(exc) {
		alert(exc+" sur\n"+page);
	}*/

    // callback
    XhrObj.onreadystatechange = 
		function() { 
        	if (XhrObj.readyState == 4 
			&&  XhrObj.status == 200)
			{
				//	traitement éventuel du retour
			}
    	}    

    if( method == "GET") {
        XhrObj.send(null);
    }
    else if(method == "POST")
    {
        XhrObj.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
        XhrObj.send(data);
    }

}

/**
* Permet de récupérer les données d'un fichier via les XmlHttpRequest:
*/
function getFile(page)
{
    return sendData('null', page, 'GET');
	
}


function emphase() {
	// les params de l'url
	get_query_params();
	// si emphase
	if ( !location.url['emph'] ) {
		return ;
	}
	// prepare la regexp
	words = location.url['emph'].split(",");
	reg = new RegExp("\\b(" + words.join("|") + ")\\b","gi");
	
	// partie à emphaser
	var mainpart = document.getElementById('content');	
	if (mainpart) {
		parse_node(mainpart);
	}

}

function merge_list(e1,e2) {
	var entities = new Array;

	for(var i=0; i<e1.length; i++) {
		entities.push(e1[i]);
	}

	for(var i=0; i<e2.length; i++) {
		entities.push(e2[i]);
	}		
	return entities;
}

function parse_node( node ) {

	var children 	= node.childNodes;
	var	i;
	var	len			= children.length ;
	var	inspected_node;
	var ar;	
	
	if (len == 0) {
		return ;
	}
	

	for (i = 0 ; i < len ; i++) {
		if (children[i].nodeType == 3) {
			if (! children[i].nodeValue.match(spaces_only) ) {
			
				// alteration
				for (inspected_node = children[i]
						; inspected_node != null 
						; )
				{ 
					// il faut ré-initialiser lastIndex car c'est global a
					// l'objet regex, et on veut commencer au _debut_ du texte du 
					// noeud
					reg.lastIndex= 0;	
					
					ar = reg.exec(inspected_node.nodeValue);
					
					if (ar == null) {
						// pas de resulats dans ce noeud
						break;
					}
			
					// position fin et debut chaine
					start	= reg.lastIndex - ar[1].length;					
					end		= reg.lastIndex -1 ;
																				
					// splitte a l'avant
					inspected_node.splitText(start);
					// le noeud au debut du mot
					wordnode 	= inspected_node.nextSibling;
					// le noeud à la fin du mot
					wordnode.splitText(ar[1].length);					
					rearnode	= wordnode.nextSibling;
					// wordnode est maintenant le noeud du mot qui nous intéresse - on en fait une copie					
					clone = wordnode.cloneNode(true);					
					// prépare le prochain noeud a inspecter					
					inspected_node = rearnode;
					// cree l'element em
					em = document.createElement('em');
					// pour IE
					for(j = 0; j < em.attributes.length ; j++) {
						if (em.attributes[j].nodeName == 'class') {
							em.attributes[j].nodeValue = 'emph';
						}
					}
					// pour Moz
					em.setAttribute('class','emph');						
					// rend le noeud mot fils de celui-ci
					em.appendChild(clone);											
					// remplace le mot simple par le noeud
					node.replaceChild(em,wordnode);
				}
				
			}
		}
		else {
			if (children[i].nodeType == 1) {
				parse_node(children[i]);
			}
		}		
	}
}

function get_query_params() {
	// Get the query string
	location.url = /\?.+/.exec(location.href)
    // create the url array
    location.url = location.url ? (location.url[0].substring(1).split('&')) : [] ;
   
	for (var i=0 ,len = location.url.length; i<len ; i++ ) {
		var nameValuePair = location.url[i].split('=');
		location.url[nameValuePair[0]] = unescape(nameValuePair[1]);
	}
}

// valeur destination 
function fill_start(v) {
	document.forms['itineraire'].daddr.value = v;
}

// bouton active_hotel
function redir_hotel(countryCode) {
	var active_url;
	var	dest ;
	var postal;
	// si france	
	if (countryCode == 'FR') {
		active_url=	 'http://www.activehotels.com/servlet/search/resultsPage.do?searchCode=EURO&type=AvailabilitySearch&startIndex=0&trkref=UID'
					+ '&countryCode='+ countryCode;

		// code postal
		if (document.forms['itineraire'].daddr.value) {
			// à l'arrivée ?
			dest = (document.forms['itineraire'].daddr.value).split(',');
		}	
		else {	
			// au départ alors ?
			dest = (document.forms['itineraire'].saddr.value).split(',');
		}
		// 
		if (dest.length) {
			postal = dest[1];
		}
		active_url = active_url	+ '&postcodeOrTown='+ postal;
	}
	else {
		active_url = 'http://www.activehotels.com/servlet/search/searchPage.do?trkref=UID'
					+ '&searchCode='+ countryCode ;
	}

	active_url = active_url + '&language=FR';
	// redir
	location.href = active_url;
}

function change_quid(v) {
	query = document.forms['search'].req.value;
	if (!query) {
		// si query vide, on change de quid
		year = document.forms['search'].year.value;
		location.href="/"+ year+"/";
	}
}

// open window generic
function jump2(url){ 
	w = (document.all ? screen.width : screen.width) * 0.9;
	h = (document.all ? screen.height : screen.height-150) * 0.9;
	op = 'scrollbars=yes,toolbar=yes,location=yes,directories=yes,menubar=yes,resizable=yes,status=yes,width=' + w + ',height=' + h + ',screenX=0,screenY=0,top=0,left=0';
	window.open(url,'',op);
}

function	show_cgv( product_type ) {
	adb=window.open("cgv.html?product_type=" + product_type ,'cgv','width=500,height=420,status=no,resizable=no,scrollbars=yes');
	adb.focus();
}

function	no_cb() {
	f = document.forms['mainform'].nom_client.value;
	n = 0;
	for(i=0; i < f.length ; i++) {
		if (f.charAt(i) >= '0' && f.charAt(i) <=9) {
			n++;
		}
	}
	if (n > 8) {
		debug("Ne saisissez pas votre numéro de carte bancaire maintenant,\nmais uniquement lorsque vous serez sur la page de paiement sécurisé\nVeuillez seulement saisir votre email, ainsi que votre nom ou raison sociale.");
		return false;
	}
	return true;
}

function	show_invoice(order_id) {
	myurl = document.URL;
	if ((p = myurl.indexOf('?')) >= 0) {
		myurl = myurl.substring(0,p);
	}


	myurl = myurl + "?mode=invoice&order_id="+order_id;
	facture=window.open(myurl,'facture','width=500,height=420,status=no,resizable=no,scrollbars=yes,menubar=yes');
	facture.focus();
}

function	open_help(url) {
	window.open(url ,'help','width=770,height=500,status=no,resizable=no,scrollbars=yes');
}

function	show_infos(annonce_id) {
	adb=window.open("more_infos.html?annonce_id=" + annonce_id ,'infos','width=780,height=420,status=no,resizable=no,scrollbars=yes');
	adb.focus();
}

function get_perso() {
	if (perso_cookie = GetCookie('perso'))
	{
		// 0=>logo, 1=>title, 2=>url
		var perso = perso_cookie.split('|');	
		var logo 	= perso[0];
		var	title	= perso[1].replace(/\+/g,' ');
		var	url		= perso[2];
		document.write("<div class='perso'>");

		if (!url) {
			url = "http://www.quid.fr";
		}

		if (logo ) {
			document.write("<a href='"+url+"' target='_blank'>");
			document.write("<img src='/imgpersos/"+ logo + "' alt='"+ title.replace(/'/g, '"') + "' />");
			document.write("</a>");
		}
		else {
			document.write("<h3>");
			if (url) document.write("<a href='"+url+"' target='_blank'>");
			document.write("Acces "+ title);
			if (url) document.write("</a>");
			document.write("</h3>");
		}

		document.write("</div>");	
	}
}

/**
 * Objet Singleton preferences utilisateur
 */
var user_prefs =(
	function() {
		var instance 		= null;
		var defaults 		= {"font_zoom":"100", "onglets":{"bloc-france":"tableregs", "bloc-zoom":"zoomcats"},"version":"1.0"};
		var	FONT_ZOOM_STEP	= 0.1;

		function Single() {
			this.prefs = 	new Object();
			// charge
			this.load();			
		}

		/**
		 * Depuis cookie
		 */
		Single.prototype.load = function () {
			if (user_prefs_cookie = decode64(GetCookie('user_prefs'))) {
				// recupere les preference sous forme d'une string JSON
				this.prefs = user_prefs_cookie.parseJSON();
			}	
			
			// install des defaults si nécessaire
			for(key in defaults) {				
				if (! this.prefs[key]) {	
					// rien du tout : copie bloc
					this.prefs[key] = defaults[key];
				}
				else {
					// si objet "pur", certaines props sont peut être vides
					if ( isObject(this.prefs[key])
					&&	!isArray(this.prefs[key]) )
					{
		
						for (kk in defaults[key]) {
							if (! this.prefs[key][kk]) {
								this.prefs[key][kk] = defaults[key][kk];
							}
						}
					}
				}
			}
		}

		/**
		 * Vers cookie
		 */
		Single.prototype.store = function() {
			// recupere ce qui a été positionné, et le merge
			// on n'écrase pas ce qui n'est pas re-défini (eg. quidzoom en page d'accueil)
			var new_onglets = get_onglets();
			for(var k in new_onglets) {
				if (new_onglets[k]) {
					this.prefs['onglets'][k] = new_onglets[k];
				}
			}
			// stringifie
			var s = encode64(this.prefs.toJSONString());
		
			// sous la forme d'une string JSON
			document.cookie = 'user_prefs=' +  s + ';  path=/';	
		}

		/**
		 * Positionne
		 */
		Single.prototype.activate = function() {	
			set_font_zoom(this.prefs['font_zoom']);	
			set_onglets(this.prefs['onglets']);
		}	

		/**
		 * Agmente, diminue ou remet 
		 * la taille de la police
		 */
		Single.prototype.change_font = function(direction) {
			if (direction == +1
			||	direction == -1)
			{
				this.prefs['font_zoom'] = Math.ceil(this.prefs['font_zoom'] * (1+ FONT_ZOOM_STEP*direction) );	
			}
			else {
				this.prefs['font_zoom'] = defaults['font_zoom'];
			}		
			set_font_zoom(this.prefs['font_zoom']);
		}

		/**
		 * font func wrappers
		 */
		// augmenter la font
		Single.prototype.increase_font = function() {
			this.change_font(+1);
		}
		// diminuer la font
		Single.prototype.decrease_font = function() {
			this.change_font(-1);
		}
		// remettre au defaut
		Single.prototype.normal_font = function() {
			this.change_font(0);
		}

		// retourne l'instance
		return ( 
			function() {
				if(!instance){
					instance = new Single();
				}
				return instance;
			}
		)				
	}
)();

/**
 * recurse copy
 */
function recopy(a) {
	if (isArray(a)) {
		var b = new Array();
		for(var i=0; i< a.length; i++) {
			b[i] = recopy(a[i]);
		}
	}
	else {
		var b = a;
	}
	return b;
}

// onglets actifs
function set_onglets(onglets) {	
	if (! onglets) {
		return;
	}

	for(var i in onglets) {
		select_onglet(document.getElementById(onglets[i]));
	}
}

function set_font_zoom(font_zoom) {
	var ids = new Array('barre', 'content','chdroite','bottom-nav');

	var new_size = font_zoom + '%';

	for (i=0; i< ids.length ; i++) {
		document.getElementById(ids[i]).style.fontSize = new_size;
	}
}

function GetCookie (name) {  
	var arg = name + "=";  
	var alen = arg.length;  
	var clen = document.cookie.length;  
	var i = 0;  
	while (i < clen) {    
		var j = i + alen;    
		if (document.cookie.substring(i, j) == arg)      
			return getCookieVal (j);    
		i = document.cookie.indexOf(" ", i) + 1;    
		if (i == 0) break;   
	}  
	return null;
}

function getCookieVal (offset) { 
	var endstr = document.cookie.indexOf (";", offset);
	if (endstr == -1) 
		endstr = document.cookie.length;
	return unescape(document.cookie.substring(offset, endstr)); 
}

function JsBookPop() {
	return ;
	if (document.cookie.length > 0
	&&  document.cookie.indexOf('popupseen=1') != -1)
	{
		return;
	} 
	now = new Date();
	fpath = '/banners/pop' + pops[(Math.floor(now.getTime() / 1000) % pops.length)] + '.htm' ;
	fene= window.open(fpath ,'popquid','width=351,height=456,status=no,resizable=no,scrollbars=no');
	fene.blur();
	document.cookie='popupseen=1;  path=/';
}

function select_search_item(s) {		
	for (var i=0; i< document.forms['motorform'].elements['secrec'].options.length; i++) {
		if (document.forms['motorform'].elements['secrec'].options[i].value == s) {
			document.forms['motorform'].elements['secrec'].selectedIndex = i;
		}
	}
}

// valeur de l'option d'un select
// @param s object select
function get_select_value(s) {
	return s.options[s.selectedIndex].value;
}

// @param s object select
function hint_search(s) {
	var motorsec= get_select_value(s);
	var	hint	= document.getElementById('hintsearch');
	var	entree	= document.getElementById('entree');

	if ( motorsec == '3'
	||	 motorsec == '8')
	{ 
		hint.innerHTML="";
		entree.style.backgroundImage=(motorsec == '3' ? "url(/charte/miniloupe.gif)" : "url(/charte/minigoogle.png)");
		hint.innerHTML='avec&nbsp;<a href="http://www.google.com/"><img src="http://www.google.com/logos/Logo_25wht.gif" border="0" alt="Google" align="middle" /></a>';
	}
	else {
		hint.innerHTML="(Recherche express)";
		if (motorsec == '5') {
			entree.style.backgroundImage="url(/charte/planisphere_mini.gif)";
		}
		if (motorsec == '4') {
			entree.style.backgroundImage="url(/charte/quidnews_mini.png)";
		}		
		if (motorsec == '1') {
			entree.style.backgroundImage="url(/charte/quidcommunes_mini.gif)";
		}
		if (motorsec == '9') {
			entree.style.backgroundImage="url(/charte/quidshopping_mini.png)";
			hint.innerHTML="(13 000 000 de produits)";
		}
	}
}

// rubrique monde

function select_rubrique() {

	get_query_params();

	var style  	= location.url['style'];
	var rub_id	= "item-"+style+ (style == 'gmap' ? location.url['gmaptype'] : '');	

	var rubriques = document.getElementById('rubriques');

	if (!rubriques) {
		return;
	}

	var items = rubriques.getElementsByTagName('a');

	for(var i =0; i< items.length; i++) {
		if (rub_id == items[i].id) {		
			items[i].className = "selected";			 						
		}
		else {			
			items[i].className = "unselected";	 			
		}
	}

}

// menu principal
function select_menu_item(secnum) {
	if (! secnum) {
		return;
	}

	var items = new Array();
	
	items[1]="item-la-france";
	items[3]="item-quid";
	items[4]="item-zoom";
	items[5]="item-le-monde";
	items[6]="item-selweb";
	items[7]="item-jeux";
	var item = document.getElementById(items[secnum]);
	if (item) {
		item.className="selected";
	}
}

/**
 * Trouve les éléments fils et de classe concernée
 */
// 'class' est un mot reserve chez IE grrr...
function find_by_class(father, tagname ,class_name) {

	var hits = new Array;

	if (!father) {
		return hits;
	}

	var elts = father.getElementsByTagName(tagname);

	if (! elts) {
		return hits;
	}

	for(var i=0, j=0 ;i< elts.length; i++) {
		if (elts[i].className == class_name) {
			hits[j++] = elts[i];
		}
	}
	return hits;
}

/**
 * Gestion dragging de carte 
 */
function install_dragger(carte) {	
	var md = new map_dragger(carte);
}	
	
/**
 * Objet map_dragger
 */
function map_dragger(carte) {

	// le viewer est le pere de la carte
	var	viewer= carte.parentNode;
	// sera determine apres onload
	var	carte_width = carte.offsetWidth;
	var	carte_height= carte.offsetHeight;

	// si la carte tient, pas la peine d'y aller
	if (carte_width < viewer.offsetWidth) {
		// curseurs normaux
		viewer.style.cursor = "auto";
		// et on cherche un lien vers le zoom+
		var a_zoom = (find_by_class(document.getElementById('tools'), 'a', 'tozoomplus'))[0];
	
		if (a_zoom) {
			var a = a_zoom.cloneNode(true);
			a.id = "zoomer";		
			// qui sera aux dimensions de la carte
			a.style.width  	= carte.offsetWidth  +"px";
			a.style.height 	= carte.offsetHeight +"px";
			a.style.left  	= carte.offsetLeft   +"px";
			a.style.top		= carte.offsetTop	 +"px";
			// on gicle le texte
			a.innerText="";
			// qui passe avant l'image et au dessus du viewer
			viewer.appendChild(a);
			
		}		
		else {
			viewer.style.cursor = "auto";
		}	
		return;
	}

	var	new_left= 0;
	var	new_top = 0;

	var lastx 	= false;
	var lasty 	= false;
	var on 		= false;


	/**
 	 * Méthodes 
	 */
	this.mouseup = function mouseup(e) {
		if (!e) {
			e = event;
		}
		on = false;
		return true;
	}

	this.mouseout = function mouseout(e) {
		if (!e) {
			e = event;
		}
		on = false;
		lastx = false;
		lasty = false;
		return false;
	}

	this.mousedown = function mousedown(e) {	
		if (!e) {
			e = event;
		}
		lastx = e.clientX;
		lasty = e.clientY;	
		// redétecte les dimensions du viewer

		on = true;
		return false;
	}

	this.mousemove = function mousemove(e) {		

		if (!e) {
			e = event;
		}
		
		if (false == on) {
			e.returnValue = true;
			e.cancelBubble = false;
			return false;
		}

		if (false == lastx
		&&	false == lasty)
		{
			// pas definies, on se contente de les initialiser
			// et on commencera les calculs au prochain mouvement
			lastx = e.clientX;
			lasty = e.clientY;	
			e.returnValue = true;
			e.cancelBubble = false;
			return false;
		}

		var deltax = e.clientX - lastx;
		var	deltay = e.clientY - lasty;
		lastx = e.clientX;
		lasty = e.clientY;

		// calcul nouvel offset
		new_left = new_left  + deltax; 
		new_top  = new_top   + deltay;

		// si on depasse les bornes, on limite
		if (new_left > 0) {
			new_left = 0;
		}

		if (new_top > 0)
		{
			new_top = 0;
		}
	
		if (Math.abs(new_left) + viewer.offsetWidth > carte_width) {
			new_left = -(carte_width - viewer.offsetWidth);
		}

		if (Math.abs(new_top) + viewer.offsetHeight > carte_height) {
			new_top = -(carte_height - viewer.offsetHeight);
		}
		
		carte.style.left = new_left + "px";
		carte.style.top  = new_top  + "px";
		e.returnValue = false;
		e.cancelBubble = true;
		return false;
	}

	/*
	 * initialisations des handlers 
	 */
	addEvent(carte , 'mousedown' , this.mousedown);
	addEvent(carte , 'mouseup'   , this.mouseup);
	addEvent(carte , 'mouseout'  , this.mouseout);	
	addEvent(carte , 'mousemove' , this.mousemove);

	// creation de l'element capture
	var capture = document.createElement('div');		
	// aux dimensions du viewer
	capture.style.width  = -1 + viewer.offsetWidth  +"px";
	capture.style.height = -1 + viewer.offsetHeight +"px";
	capture.style.left	 =  2 + viewer.offsetLeft   +"px";
	capture.style.top	 =  2 + viewer.offsetTop	+"px";
	capture.id = 'capture';

	// et insertion derriere la carte
	viewer.parentNode.appendChild(capture);
	// on lui ajoute ses handlers
	addEvent(capture , 'mousedown' , this.mousedown);
	addEvent(capture , 'mouseup'   , this.mouseup);
	addEvent(capture , 'mouseout'  , this.mouseout);	
	addEvent(capture , 'mousemove' , this.mousemove);
}

//John Resig : http://ejohn.org/projects/flexible-javascript-events/
function addEvent( obj, type, fn ) {

	if ( obj.attachEvent ) {
		obj['e'+type+fn] = fn;
		obj[type+fn] = function(){obj['e'+type+fn]( window.event );}
		obj.attachEvent( 'on'+type, obj[type+fn] );
	} else {
		obj.addEventListener( type, fn, false );
	}
}
function removeEvent( obj, type, fn ) {
	if ( obj.detachEvent ) {
		obj.detachEvent( 'on'+type, obj[type+fn] );
		obj[type+fn] = null;
	} else
		obj.removeEventListener( type, fn, false);
}

/**
 * Hacks pour firefox qui n'ignore pas
 * les whitespaces
 * Courtesy http://www.agavegroup.com/?p=32
 */
function getNextSibling(startBrother){
  endBrother=startBrother.nextSibling;
  while(endBrother && endBrother.nodeType!=1){
    endBrother = endBrother.nextSibling;
  }
  return endBrother;
}
// et la copine...
function getPrevSibling(startBrother){
  endBrother=startBrother.previousSibling;
  while(endBrother && endBrother.nodeType!=1){
    endBrother = endBrother.previousSibling;
  }
  return endBrother;
}
// This code was written by Tyler Akins and has been placed in the
// public domain.  It would be nice if you left this header intact.
// Base64 code from Tyler Akins -- http://rumkin.com
//... ce que je fais ;-)



function encode64(s) {
   var output = "";
   var chr1, chr2, chr3;
   var enc1, enc2, enc3, enc4;
   var i = 0;
	
	if (!s) {
		return;
	}

   do {
      chr1 = s.charCodeAt(i++);
      chr2 = s.charCodeAt(i++);
      chr3 = s.charCodeAt(i++);

      enc1 = chr1 >> 2;
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
      enc4 = chr3 & 63;

      if (isNaN(chr2)) {
         enc3 = enc4 = 64;
      } else if (isNaN(chr3)) {
         enc4 = 64;
      }

      output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) +
         keyStr.charAt(enc3) + keyStr.charAt(enc4);
   } while (i < s.length);
  
   return output;
}

function decode64(s) {
   var output = "";
   var chr1, chr2, chr3;
   var enc1, enc2, enc3, enc4;
   var i = 0;

	if (!s) {
		return;
	}
   // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
   s = s.replace(/[^A-Za-z0-9\+\/\=]/g, "");

   do {
      enc1 = keyStr.indexOf(s.charAt(i++));
      enc2 = keyStr.indexOf(s.charAt(i++));
      enc3 = keyStr.indexOf(s.charAt(i++));
      enc4 = keyStr.indexOf(s.charAt(i++));

      chr1 = (enc1 << 2) | (enc2 >> 4);
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
      chr3 = ((enc3 & 3) << 6) | enc4;

      output = output + String.fromCharCode(chr1);

      if (enc3 != 64) {
         output = output + String.fromCharCode(chr2);
      }
      if (enc4 != 64) {
         output = output + String.fromCharCode(chr3);
      }
   } while (i < s.length);

   return output;
}
/**
 * Vérifie si une variable est un tableau.
 *
 * @param mixed variable La variable à vérifier.
 * @return boolean true si variable est un tableau, false sinon.
 * @author Julien Fontanet
 **/
function isArray(variable) {
	return variable instanceof Array;
} 
// ou un objet
function isObject(variable) {
	return variable instanceof Object;
}
// + --------------------------------------------------------------------------------------
// + XHRConnection
// + V1.3
// + Thanh Nguyen, http://www.sutekidane.net
// + 20.10.2005
// + http://creativecommons.org/licenses/by-nc-sa/2.0/fr/deed.fr
// + --------------------------------------------------------------------------------------
function XHRConnection() {
	
	// + ----------------------------------------------------------------------------------
	var conn = false;
	var debug = false;
	var datas = new String();
	var areaId = new String();
	// Objet XML
	var xmlObj;
	// Type de comportement au chargement du XML
	var xmlLoad;
	
	// + ----------------------------------------------------------------------------------
	try {
		conn = new XMLHttpRequest();		
	}
	catch (error) {
		if (debug) { alert('Erreur lors de la tentative de création de l\'objet \nnew XMLHttpRequest()\n\n' + error); }
		try {
			conn = new ActiveXObject("Microsoft.XMLHTTP");
		}
		catch (error) {
			if (debug) { alert('Erreur lors de la tentative de création de l\'objet \nnew ActiveXObject("Microsoft.XMLHTTP")\n\n' + error); }
			try {
				conn = new ActiveXObject("Msxml2.XMLHTTP");
			}
			catch (error) {
				if (debug) { alert('Erreur lors de la tentative de création de l\'objet \nnew ActiveXObject("Msxml2.XMLHTTP")\n\n' + error); }
				conn = false;
			}
		}
	}

	// + ----------------------------------------------------------------------------------
	// + setDebugOff
	// + Désactive l'affichage des exceptions
	// + ----------------------------------------------------------------------------------
	this.setDebugOff = function() {
		debug = false;
	};

	// + ----------------------------------------------------------------------------------
	// + setDebugOn
	// + Active l'affichage des exceptions
	// + ----------------------------------------------------------------------------------
	this.setDebugOn = function() {
		debug = true;
	};
	
	// + ----------------------------------------------------------------------------------
	// + resetData
	// + Permet de vider la pile des données
	// + ----------------------------------------------------------------------------------
	this.resetData = function() {
		datas = new String();
		datas = '';
	};
	
	// + ----------------------------------------------------------------------------------
	// + appendData
	// + Permet d'empiler des données afin de les envoyer
	// + ----------------------------------------------------------------------------------
	this.appendData = function(pfield, pvalue) {
		datas += (datas.length == 0) ? pfield+ "=" + escape(pvalue) : "&" + pfield + "=" + escape(pvalue);
	};
	
	// + ----------------------------------------------------------------------------------
	// + setRefreshArea
	// + Indique quel elment identifié par id est valoris lorsque l'objet XHR reoit une réponse
	// + ----------------------------------------------------------------------------------
	this.setRefreshArea = function(id) {
		areaId = id;
	};
	
	// + ----------------------------------------------------------------------------------
	// + createXMLObject
	// + Méthode permettant de créer un objet DOM, retourne la réfrence
	// + Inspiré de: http://www.quirksmode.org/dom/importxml.html
	// + ----------------------------------------------------------------------------------
	this.createXMLObject = function() {
		try {
			 	xmlDoc = document.implementation.createDocument("", "", null);
				xmlLoad = 'onload';
		}
		catch (error) {
			try {
				xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
				xmlLoad = 'onreadystatechange ';
			}
			catch (error) {
				if (debug) { alert('Erreur lors de la tentative de création de l\'objet XML\n\n'); }
				return false;
			}
		}
		return xmlDoc;
	}
	
	// + ----------------------------------------------------------------------------------
	// + Permet de définir l'objet XML qui doit être valorisé lorsque l'objet XHR reoit une réponse
	// + ----------------------------------------------------------------------------------
	this.setXMLObject = function(obj) {
		if (obj == undefined) {
				if (debug) { alert('Paramètre manquant lors de l\'appel de la méthode setXMLObject'); }
				return false;
		}
		try {
			//xmlObj = this.createXMLObject();
			xmlObj = obj;
		}
		catch (error) {
				if (debug) { alert('Erreur lors de l\'affectation de l\'objet XML dans la méthode setXMLObject'); }
		}
	}
	
	// + ----------------------------------------------------------------------------------
	// + loadXML
	// + Charge un fichier XML
	// + Entrées
	// + 	xml			String		Le fichier XML à charger
	// + ----------------------------------------------------------------------------------
	this.loadXML = function(xml, callBack) {
		if (!conn) return false;
		// Chargement pour alimenter un objet DOM
		if (xmlObj && xml) {
			if (typeof callBack == "function") {
				if (xmlLoad == 'onload') {
					xmlObj.onload = function() {
						callBack(xmlObj);
					}
				}
				else {
					xmlObj.onreadystatechange = function() {
						if (xmlObj.readyState == 4) callBack(xmlObj)
					}
				}
			}
			xmlObj.load(xml);
			return;
		}		
	}

	// + ----------------------------------------------------------------------------------
	// + sendAndLoad
	// + Connexion à la page désirée avec envoie des données, puis mise en attente de la réponse
	// + Entrées
	// + 	Url			String		L'url de la page à laquelle l'objet doit se connecter
	// + 	httpMode		String		La méthode de communication HTTP : GET, HEAD ou POST
	// + 	callBack		Objet		Le nom de la fonction de callback
	// + ----------------------------------------------------------------------------------
	this.sendAndLoad = function(Url, httpMode, callBack) {
		httpMode = httpMode.toUpperCase();
		conn.onreadystatechange = function() {
			if (conn.readyState == 4 && conn.status == 200) {
				// Si une fonction de callBack a été définie
				if (typeof callBack == "function") {
					callBack(conn);
					return;
				}
				// Si une zone destinée à récupérer le résultat a été définie
				else if (areaId.length > 0){
					try {
						document.getElementById(areaId).innerHTML = conn.responseText;
					}
					catch(error) {
						if (debug) { alert('Echec, ' + areaId + ' n\'est pas un objet valide'); }
					}
					return;
				}
			}
		};
		switch(httpMode) {
			case "GET":
				try {
					Url = (datas.length > 0) ? Url + "?" + datas : Url;
					conn.open("GET", Url);
					conn.send(null);
				}
				catch(error) {
					if (debug) { alert('Echec lors de la transaction avec ' + Url + ' via la méthode GET'); }
					return false;
				}
			break;
			case "POST":
				try {
					conn.open("POST", Url); 
					conn.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
					conn.send(datas);
				}
				catch(error) {
					if (debug) { alert('Echec lors de la transaction avec ' + Url + ' via la mthode POST'); }
					return false;
				}
			break;
			default :
				return false;
			break;
		}
		return true;
	};
	return this;
}