Index: plugins/agenda_1_9_1/agenda.php
===================================================================
--- plugins/agenda_1_9_1/agenda.php	(revision 6)
+++ plugins/agenda_1_9_1/agenda.php	(revision 6)
@@ -0,0 +1,82 @@
+<?php
+
+function Agenda_ajouter_onglets($flux) {
+  if($flux['args']=='calendrier')
+  {
+		$flux['data']['evenements']= new Bouton(
+																 '../'._DIR_PLUGIN_AGENDA_EVENEMENTS.'/img_pack/agenda-24.png', _T('agenda:evenements'),
+																generer_url_ecrire("calendrier","type=semaine"));
+	
+		$flux['data']['editorial']= new Bouton(
+															 'cal-rv.png', _T('agenda:activite_editoriale'),
+																 generer_url_ecrire("calendrier","mode=editorial&type=semaine"));
+  }
+	return $flux;
+}
+function Agenda_header_prive($flux) {
+	$exec = _request('exec');
+	// les CSS
+	if ($exec == 'calendrier'){
+		$flux .= '<link rel="stylesheet" href="' ._DIR_PLUGIN_AGENDA_EVENEMENTS . '/img_pack/calendrier.css" type="text/css" />'. "\n";
+		$flux .= '<link rel="stylesheet" href="' ._DIR_PLUGIN_AGENDA_EVENEMENTS . '/img_pack/agenda.css" type="text/css" />'. "\n";
+	}
+	if ($exec == 'articles'){
+		$flux .= '<link rel="stylesheet" href="' ._DIR_PLUGIN_AGENDA_EVENEMENTS . '/img_pack/agenda_articles.css" type="text/css" />'. "\n";
+	}
+
+
+	return $flux;
+}
+
+function Agenda_exec_init($flux) {
+	$exec =  $flux['args']['exec'];
+	if (($exec == 'calendrier')||($exec=='articles')){
+		include_spip('inc/calendar');
+		// Reserver les widgets agenda
+		WCalendar_ajoute_lies(_T('agenda:evenement_date_debut'),'_evenement_debut',_T('agenda:evenement_date_fin'),'_evenement_fin');
+		WCalendar_ajoute_statique(_T('agenda:evenement_repetitions'),'_repetitions');
+	}
+	return $flux;
+}
+
+function Agenda_affiche_milieu($flux) {
+	$exec =  $flux['args']['exec'];
+	if ($exec=='articles'){
+		include_spip('inc/calendar');
+		include_spip('inc/agenda_gestion');
+		$id_article = $flux['args']['id_article'];
+		$flux['data'] .= Agenda_formulaire_article($id_article, article_editable($id_article));
+	}
+	return $flux;
+}
+
+function Agenda_rendu_boite($titre,$descriptif,$lieu,$type='ics'){
+	$texte = "<span class='calendrier-verdana10'><span  style='font-weight: bold;'>";
+	$texte .= wordwrap($sum=typo($titre),15)."</span>";
+	$texte .= "<span class='survol'>";
+	$texte .= "<strong>$sum</strong><br />";
+	$texte .= $lieu ? propre($lieu).'<br />':'';
+	$texte .= propre($descriptif);
+	$texte .= "</span>";
+	if ($type=='ics'){	
+		$texte .= (strlen($lieu.$descriptif)?"<hr/>":"").$lieu.(strlen($lieu)?"<br/>":"");
+		$texte .= $descriptif;
+	}
+	$texte .= "</span>";
+
+	return $texte;
+}
+function Agenda_rendu_evenement($flux) {
+	global $couleur_claire;
+	$evenement = $flux['args']['evenement'];
+
+	
+	$url = $evenement['URL']; 
+	$texte = Agenda_rendu_boite($evenement['SUMMARY'],$evenement['DESCRIPTION'],$evenement['LOCATION'],$flux['args']['type']);
+	$texte = http_href(quote_amp($url), $texte, '', '', '', '');
+	
+	$flux['data'] = $texte;
+	return $flux;
+}
+
+?>
Index: plugins/agenda_1_9_1/agenda_jour.html
===================================================================
--- plugins/agenda_1_9_1/agenda_jour.html	(revision 6)
+++ plugins/agenda_1_9_1/agenda_jour.html	(revision 6)
@@ -0,0 +1,52 @@
+<BOUCLE_jour(EVENEMENTS)
+	{agendafull date_debut, date_fin, jour, #ENV{annee}, #ENV{mois}, #ENV{jour}}
+>[(#DATE_DEBUT|Agenda_memo_full{#DATE_FIN,#TITRE,#DESCRIPTIF,#LIEU,#URL_ARTICLE, 
+	calendrier-couleur[(#ENV{theme,0}|modulo{14,1})]})]</BOUCLE_jour>[(#DATE|Agenda_affiche_full{<:aucun_article:>, 'jour', 
+	calendrier-couleur[(#ENV{theme,0}|modulo{14,1})]})][(#TOTAL_BOUCLE|?{' ',''})
+<div style='position: fixed; top:50px; left: 20px'>
+<table style='width: 10px'><tr>
+<td class='calendrier-couleur1'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,0})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur2'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,1})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur3'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,2})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur4'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,3})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur5'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,4})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur6'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,5})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur7'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,6})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur8'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,7})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur9'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,8})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur10'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,9})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur11'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,10})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur12'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,11})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur13'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,12})]'>&nbsp;&nbsp;</a></td></tr>
+<tr><td class='calendrier-couleur14'
+	><a style='text-decoration: none;'
+	href='[(#SELF|parametre_url{theme,13})]'>&nbsp;&nbsp;</a></td></tr>
+</table>
+</div>
+]<//B_jour>
Index: plugins/agenda_1_9_1/agenda_mes_fonctions.php
===================================================================
--- plugins/agenda_1_9_1/agenda_mes_fonctions.php	(revision 6)
+++ plugins/agenda_1_9_1/agenda_mes_fonctions.php	(revision 6)
@@ -0,0 +1,7 @@
+<?php
+
+//include_spip('inc/agenda_filtres'); // declaration directe dans le xml pour eviter un find_in_path
+include_spip('public/criteres_agenda');
+include_spip('inc/agenda_filtres');
+
+?>
Index: plugins/agenda_1_9_1/agenda_mes_options.php
===================================================================
--- plugins/agenda_1_9_1/agenda_mes_options.php	(revision 6)
+++ plugins/agenda_1_9_1/agenda_mes_options.php	(revision 6)
@@ -0,0 +1,80 @@
+<?php
+$p=explode(basename(_DIR_PLUGINS)."/",str_replace('\\','/',realpath(dirname(__FILE__))));
+define('_DIR_PLUGIN_AGENDA_EVENEMENTS',(_DIR_PLUGINS.end($p)));
+include_spip('base/agenda_evenements');
+
+function cron_agenda_nettoyer_base($t){
+	# les evenements lies a un article inexistant
+	$res = spip_query("SELECT evenements.id_evenement,evenements.id_article
+		      FROM spip_evenements AS evenements
+		        LEFT JOIN spip_articles AS articles
+		          ON evenements.id_article=articles.id_article
+		       WHERE articles.id_article IS NULL");
+	while ($row = spip_fetch_array($res,SPIP_ASSOC))
+		spip_query("DELETE FROM spip_evenements
+		WHERE id_evenement=".$row['id_evenement']
+		." AND id_article=".$row['id_article']);
+
+	# les liens de mots affectes a des evenements effaces
+	$res = spip_query("SELECT mots_evenements.id_mot,mots_evenements.id_evenement 
+		        FROM spip_mots_evenements AS mots_evenements
+		        LEFT JOIN spip_evenements AS evenements
+		          ON mots_evenements.id_evenement=evenements.id_evenement
+		       WHERE evenements.id_evenement IS NULL");
+
+	while ($row = spip_fetch_array($res,SPIP_ASSOC))
+		spip_query("DELETE FROM spip_mots_evenements
+		WHERE id_mot=".$row['id_mot']
+		." AND id_evenement=".$row['id_evenement']);
+
+	return 1;
+}
+
+function Agenda_taches_generales_cron($taches_generales){
+	$taches_generales['agenda_nettoyer_base'] = 3600*48;
+	return $taches_generales;
+}
+
+function exec_calendrier()
+{
+	$mode = _request('mode');
+	if ($mode=='editorial'){
+		include_spip('exec/calendrier');
+	  global $type, $css;
+	// icones standards, fonction de la direction de la langue
+	
+	  global $bleu, $vert, $jaune, $spip_lang_rtl;
+	  $bleu = http_img_pack("m_envoi_bleu$spip_lang_rtl.gif", 'B', "class='calendrier-icone'");
+	  $vert = http_img_pack("m_envoi$spip_lang_rtl.gif", 'V', "class='calendrier-icone'");
+	  $jaune= http_img_pack("m_envoi_jaune$spip_lang_rtl.gif", 'J', "class='calendrier-icone'");
+	
+	  $date = date("Y-m-d", time()); 
+		if ($type == 'semaine') {
+		
+			$GLOBALS['afficher_bandeau_calendrier_semaine'] = true;
+			$titre = _T('titre_page_calendrier',
+				array('nom_mois' => nom_mois($date), 'annee' => annee($date)));
+		}
+	  elseif ($type == 'jour') {
+			$titre = nom_jour($date)." ". affdate_jourcourt($date);
+	  }
+		else {
+			$titre = _T('titre_page_calendrier',
+			    array('nom_mois' => nom_mois($date), 'annee' => annee($date)));
+		}
+		
+	  debut_page($titre, "redacteurs", "calendrier","",$css);
+		barre_onglets("calendrier", "editorial");
+		echo "<div>&nbsp;</div>" ;
+	  echo http_calendrier_init('', $type, '','',generer_url_ecrire('calendrier', 'mode=editorial'.($type ? "&type=$type" : '')));
+		
+	  fin_page();
+	}
+	else{
+		$var_f = charger_fonction('agenda_evenements');
+		$var_f();
+	}
+}
+
+
+?>
Index: plugins/agenda_1_9_1/agenda_mois.html
===================================================================
--- plugins/agenda_1_9_1/agenda_mois.html	(revision 6)
+++ plugins/agenda_1_9_1/agenda_mois.html	(revision 6)
@@ -0,0 +1,7 @@
+<BOUCLE_mois(EVENEMENTS)
+	{agendafull date_debut,date_fin, mois, #ENV{annee}, #ENV{mois}}
+>[(#DATE_DEBUT|Agenda_memo_full{#DATE_FIN,#TITRE,#DESCRIPTIF,#LIEU,#URL_ARTICLE,
+		calendrier-couleur[(#ID_SECTEUR|
+			modulo{14,1})]})]</BOUCLE_mois>[(#DATE|
+	Agenda_affiche_full{<:aucun_article:>, 'mois'}
+)]<//B_mois>
Index: plugins/agenda_1_9_1/agenda_periode.html
===================================================================
--- plugins/agenda_1_9_1/agenda_periode.html	(revision 6)
+++ plugins/agenda_1_9_1/agenda_periode.html	(revision 6)
@@ -0,0 +1,8 @@
+<BOUCLE_periode(EVENEMENTS)
+	{agendafull date_debut, date_fin, periode,
+	#ENV{annee}, #ENV{mois}, #ENV{jour},
+	#ENV{annee_fin}, #ENV{mois_fin}, #ENV{jour_fin}}>[
+(#DATE_DEBUT|Agenda_memo_full{#DATE_FIN,#TITRE,#DESCRIPTIF,#LIEU,#URL_ARTICLE, 'calendrier-couleur6'})
+]</BOUCLE_periode>[(#DATE|
+	Agenda_affiche_full{<:aucun_article:>, 'periode', 'calendrier-couleur6'}
+)]<//B_periode>
Index: plugins/agenda_1_9_1/agenda_semaine.html
===================================================================
--- plugins/agenda_1_9_1/agenda_semaine.html	(revision 6)
+++ plugins/agenda_1_9_1/agenda_semaine.html	(revision 6)
@@ -0,0 +1,7 @@
+<BOUCLE_semaine(EVENEMENTS)
+	{agendafull date_debut, date_fin, semaine, #ENV{annee}, #ENV{mois}, #ENV{jour}}
+>[(#DATE_DEBUT|Agenda_memo_full{#DATE_FIN,#TITRE,#DESCRIPTIF,#LIEU,#URL_ARTICLE,
+	[(#COMPTEUR_BOUCLE|
+		alterner{'calendrier-couleur2', 'calendrier-couleur4'})]})]</BOUCLE_semaine>[(#DATE|
+		Agenda_affiche_full{<:aucun_article:>, 'semaine', 'calendrier-couleur2','calendrier-couleur4'}
+)]<//B_semaine>
Index: plugins/agenda_1_9_1/balise/calendrier_mini.php
===================================================================
--- plugins/agenda_1_9_1/balise/calendrier_mini.php	(revision 6)
+++ plugins/agenda_1_9_1/balise/calendrier_mini.php	(revision 6)
@@ -0,0 +1,113 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;	#securite
+
+// Pas besoin de contexte de compilation
+global $balise_CALENDRIER_MINI_collecte;
+$balise_CALENDRIER_MINI_collecte = array('id_rubrique','id_article','id_mot');
+
+function balise_CALENDRIER_MINI ($p) {
+	return calculer_balise_dynamique($p,'CALENDRIER_MINI', array('id_rubrique','id_article', 'id_mot'));
+}
+
+function balise_CALENDRIER_MINI_stat($args, $filtres) {
+	return $args;
+}
+ 
+function balise_CALENDRIER_MINI_dyn($id_rubrique=0, $id_article = 0, $id_mot = 0,$date, $var_date = 'date', $url = '') {
+	if(!$url)
+		$url = self();
+	// nettoyer l'url qui est passee par htmlentities pour raison de securités
+	$url = str_replace("&amp;","&",$url);
+
+	return array('formulaires/calendrier_mini', 0, 
+		array(
+			'date' => $date,
+			'id_rubrique' => $id_rubrique,
+			'id_article' => $id_article,
+			'id_mot' => $id_mot,
+			'var_date' => $var_date,
+			'self' => $url,
+		));
+}
+
+function agenda_mini($i) {
+  $args = func_get_args();
+  $une_date = array_shift($args); // une date comme balise
+  $sinon = array_shift($args);
+  if (!$une_date) return $sinon;
+  $type = 'mini';
+  $agenda = Agenda_memo_full(0);
+  $evt = array();
+  foreach (($args ? $args : array_keys($agenda)) as $k) {  
+      if (is_array($agenda[$k]))
+		foreach($agenda[$k] as $d => $v) { 
+		  $evt[$d] = $evt[$d] ? (array_merge($evt[$d], $v)) : $v;
+		}
+    }
+	$la_date = mktime(0, 0, 0, mois($une_date), 1, annee($une_date));
+    include_spip('inc/agenda');
+    return http_calendrier_init($la_date, $type, '', '', '', array('', $evt));
+}
+
+function http_calendrier_mini($annee, $mois, $jour, $echelle, $partie_cal, $script, $ancre, $evt) {
+	list($sansduree, $evenements, $premier_jour, $dernier_jour) = $evt;
+
+	if ($sansduree)
+		foreach($sansduree as $d => $r) {
+			$evenements[$d] = !$evenements[$d] ? $r : 
+				 array_merge($evenements[$d], $r);
+			 }
+
+	if (!$premier_jour) $premier_jour = '01';
+	if (!$dernier_jour) {
+		$dernier_jour = 31;
+		while (!(checkdate($mois,$dernier_jour,$annee))) $dernier_jour--;
+	}
+
+	// affichage du debut de semaine hors periode
+	$ligne = '';
+	$debut = date("w",mktime(1,1,1,$mois,$premier_jour,$annee));
+	for ($i=$debut ? $debut : 7;$i>1;$i--) {
+		$mois_precedent = mktime(1,1,1,$mois-1,1,$annee);
+		$jour_mois_precedent = date('t', $mois_precedent)+2-$i;
+		$ligne .= "\n\t<td class=\"horsperiode\">$jour_mois_precedent</td>";
+	}
+
+	$total = '';
+	for ($j=$premier_jour; $j<=$dernier_jour; $j++) {
+		$nom = mktime(1,1,1,$mois,$j,$annee);
+		$jour = date("d",$nom);
+		$jour_semaine = date("w",$nom);
+		$mois_en_cours = date("m",$nom);
+		$annee_en_cours = date("Y",$nom);
+		$amj = date("Y",$nom) . $mois_en_cours . $jour;
+
+		if ($jour_semaine==1) { 
+			$total .= "\n<tr>$ligne\n</tr>";
+			$ligne = '';
+		}
+
+		$evts = $evenements[$amj];
+		$class="";
+		if ($evts) {
+			$evts = "<a href='".parametre_url($evts[0]['URL'],'date',"$annee_en_cours-$mois_en_cours-$jour")."' title='".$evts[0]['SUMMARY'].
+			"'>".intval($jour)."</a>";
+			$class='occupe';
+		}
+		else {
+			$evts = intval($jour);
+			$class='libre';
+		}
+		$ligne .= "\n\t<td  class='$class".($amj == date("Ymd")?' today':'')."'>" . $evts . "\n\t</td>";
+	}
+	$jour_mois_suivant=1;
+	// affichage de la fin de semaine hors periode
+	for($j=$jour_semaine ? $jour_semaine : 7; $j<7; $j++) {
+		$ligne .= "\n\t<td class=\"horsperiode\">".$jour_mois_suivant++."</td>";			
+	}
+
+	return $total . ($ligne ? "\n<tr>$ligne\n</tr>" : '');
+}
+
+?>
Index: plugins/agenda_1_9_1/balise/formulaire_edition_evenement.php
===================================================================
--- plugins/agenda_1_9_1/balise/formulaire_edition_evenement.php	(revision 6)
+++ plugins/agenda_1_9_1/balise/formulaire_edition_evenement.php	(revision 6)
@@ -0,0 +1,81 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;	#securite
+
+// Pas besoin de contexte de compilation
+global $balise_FORMULAIRE_EDITION_EVENEMENT_collecte;
+$balise_FORMULAIRE_EDITION_EVENEMENT_collecte = array('id_evenement','id_article');
+
+function balise_FORMULAIRE_EDITION_EVENEMENT ($p) {
+	return calculer_balise_dynamique($p,'FORMULAIRE_EDITION_EVENEMENT', array('id_evenement', 'id_article'));
+}
+
+function balise_FORMULAIRE_EDITION_EVENEMENT_stat($args, $filtres) {
+	return $args;
+}
+ 
+function balise_FORMULAIRE_EDITION_EVENEMENT_dyn($id_evenement = 0, $id_article = 0) {
+	$url = parametre_url(self(),'ajout_evenement','');
+	// nettoyer l'url qui est passee par htmlentities pour raison de securités
+	$url = str_replace("&amp;","&",$url);
+	if ($retour=='') $retour = $url;
+
+	$res = spip_query("SELECT * FROM spip_articles WHERE id_article=".spip_abstract_quote($id_article));
+	if (!spip_num_rows($res)) return;
+
+	$flag_modif = (_request('evenement_modif') && _request('id_evenement') == $id_evenement);
+	$flag_ajout = _request('evenement_insert');
+	if ($flag_ajout || $flag_modif){
+		include_spip("inc/agenda_gestion");
+		Agenda_action_formulaire_article($id_article);
+	}
+
+	
+	$evenement_action='evenement_insert';
+	$valeurs=array('mots'=>array(),'dates'=>array(),'evenement_horaire'=>'oui');
+
+	$formulaire_actif = _request('ajout_evenement')!=NULL;
+	
+	// les champs
+	$res = spip_query("SELECT * FROM spip_evenements WHERE id_evenement=".spip_abstract_quote($id_evenement)." AND id_article=".spip_abstract_quote($id_article));
+	if ($row = spip_fetch_array($res,SPIP_ASSOC)){
+		$evenement_action='evenement_modif';
+		foreach($row as  $k=>$val){
+			$valeurs["evenement_$k"]=$val;
+		}
+		// les mots
+		$res = spip_query("SELECT * FROM spip_mots_evenements WHERE id_evenement=".spip_abstract_quote($id_evenement));
+		while ($row=spip_fetch_array($res)){
+			$valeurs['mots'][]=$row['id_mot'];
+		}
+		
+		$res = spip_query("SELECT date_debut FROM spip_evenements WHERE id_evenement_source=".spip_abstract_quote($id_evenement));
+		while ($row=spip_fetch_array($res)){
+			$valeurs['repetitions'][] = date('m/d/Y',strtotime($row['date_debut']));
+		}
+		$formulaire_actif = true;
+	}
+	$t=time();
+	$valeurs["date_evenement_debut"]=isset($valeurs["evenement_date_debut"])?$valeurs["evenement_date_debut"]:date('Y-m-d H:i:00',$t);
+	$valeurs["date_evenement_fin"]=isset($valeurs["evenement_date_fin"])?$valeurs["evenement_date_fin"]:date('Y-m-d H:i:00',$t+3600);
+
+	if (!$formulaire_actif) return;
+
+	return array('formulaires/formulaire_edition_evenement', 0, 
+		array(
+			#'erreur_message'=>isset($erreur['@'])?$erreur['@']:'',
+			#'erreur'=>serialize($erreur),
+			#'reponse'=>filtrer_entites($reponse),
+			'id_article' => $id_article,
+			'id_evenement' => $id_evenement,
+			'evenement_action' => $evenement_action,
+			'self' => $url,
+			'valeurs' => serialize($valeurs),
+			'url_validation' => str_replace("&amp;","&",$url_validation),
+			#'affiche_sondage' => $affiche_sondage,
+			#'formok' => filtrer_entites($formok),
+			#'formactif' => $formactif,
+		));
+}
+
+?>
Index: plugins/agenda_1_9_1/base/agenda_evenements.php
===================================================================
--- plugins/agenda_1_9_1/base/agenda_evenements.php	(revision 6)
+++ plugins/agenda_1_9_1/base/agenda_evenements.php	(revision 6)
@@ -0,0 +1,107 @@
+<?php
+// -----------------------------------------------------------------------------
+// Declaration des tables evenements
+// creation 11/03/2006 pour SPIP 1.9
+
+include_spip('base/serial'); // pour eviter une reinit posterieure des tables modifiees
+
+global $tables_principales;
+global $tables_auxiliaires;
+
+//-- Table EVENEMENTS ------------------------------------------
+$evenements = array(
+		"id_evenement"	=> "bigint(21) NOT NULL",
+		"id_article"	=> "bigint(21) DEFAULT '0' NOT NULL",
+		"date_debut"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"date_fin"	=> "datetime DEFAULT '0000-00-00 00:00:00' NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"descriptif"	=> "text NOT NULL",
+		"lieu"	=> "text NOT NULL",
+		"horaire" => "ENUM('oui','non') DEFAULT 'oui' NOT NULL",
+		"id_evenement_source"	=> "bigint(21) NOT NULL",
+		"idx"		=> "ENUM('', '1', 'non', 'oui', 'idx') DEFAULT '' NOT NULL",
+		"maj"	=> "TIMESTAMP"
+		);
+
+$evenements_key = array(
+		"PRIMARY KEY"	=> "id_evenement",
+		"KEY date_debut"	=> "date_debut",
+		"KEY date_fin"	=> "date_fin",
+		"KEY id_article"	=> "id_article"
+		);
+
+$tables_principales['spip_evenements'] =
+	array('field' => &$evenements, 'key' => &$evenements_key);
+
+
+//-- Table de relations MOTS_EVENEMENTS----------------------
+$spip_mots_evenements = array(
+		"id_mot"	=> "BIGINT (21) DEFAULT '0' NOT NULL",
+		"id_evenement"	=> "BIGINT (21) DEFAULT '0' NOT NULL");
+
+$spip_mots_evenements_key = array(
+		"PRIMARY KEY"	=> "id_mot, id_evenement",
+		"KEY id_evenement"	=> "id_evenement");
+
+$tables_auxiliaires['spip_mots_evenements'] = array(
+	'field' => &$spip_mots_evenements,
+	'key' => &$spip_mots_evenements_key);
+
+//-- Jointures ----------------------------------------------------
+global $tables_jointures;
+$tables_jointures['spip_evenements'][]= 'mots'; // a placer avant la jointure sur articles
+$tables_jointures['spip_articles'][]= 'evenements';
+$tables_jointures['spip_evenements'][] = 'articles';
+$tables_jointures['spip_mots'][]= 'mots_evenements';
+$tables_jointures['spip_evenements'][] = 'mots_evenements';
+
+global $exceptions_des_tables;
+$exceptions_des_tables['evenements']['id_rubrique']=array('spip_articles', 'id_rubrique');
+
+global $table_primary;
+$table_primary['evenements']="id_evenement";
+
+global $table_date;
+$table_date['evenements'] = 'date_debut';
+// si on declare les tables dans $table_des_tables, il faut mettre le prefixe
+
+// 'spip_' dans l'index de $tables_principales
+global $table_des_tables;
+$table_des_tables['evenements']='evenements';
+$table_des_tables['mots_evenements']='mots_evenements';
+
+
+
+// Extension de la table des groupes de mots cles
+$spip_groupes_mots = array(
+		"id_groupe"	=> "bigint(21) NOT NULL",
+		"titre"	=> "text NOT NULL",
+		"descriptif"	=> "text NOT NULL",
+		"texte"	=> "longblob NOT NULL",
+		"unseul"	=> "varchar(3) NOT NULL",
+		"obligatoire"	=> "varchar(3) NOT NULL",
+		"articles"	=> "varchar(3) NOT NULL",
+		"breves"	=> "varchar(3) NOT NULL",
+		"rubriques"	=> "varchar(3) NOT NULL",
+		"syndic"	=> "varchar(3) NOT NULL");
+if (isset($GLOBALS['meta']['agenda_base_version']))
+	$spip_groupes_mots = array_merge($spip_groupes_mots,array("evenements"	=> "varchar(3) NOT NULL"));
+if (isset($GLOBALS['meta']['pim_agenda_base_version']))
+	$spip_groupes_mots = array_merge($spip_groupes_mots,array("pim_agenda"	=> "varchar(3) NOT NULL"));
+$spip_groupes_mots = array_merge($spip_groupes_mots,array(
+		"minirezo"	=> "varchar(3) NOT NULL",
+		"comite"	=> "varchar(3) NOT NULL",
+		"forum"	=> "varchar(3) NOT NULL",
+		"maj"	=> "TIMESTAMP"));
+
+
+$spip_groupes_mots_key = array(
+		"PRIMARY KEY"	=> "id_groupe");
+
+$tables_principales['spip_groupes_mots'] =
+	array('field' => &$spip_groupes_mots, 'key' => &$spip_groupes_mots_key);
+
+global  $table_des_traitements;
+$table_des_traitements['LIEU'][]= 'propre(%s)';
+
+?>
Index: plugins/agenda_1_9_1/demo_calendrier_mini.html
===================================================================
--- plugins/agenda_1_9_1/demo_calendrier_mini.html	(revision 6)
+++ plugins/agenda_1_9_1/demo_calendrier_mini.html	(revision 6)
@@ -0,0 +1,173 @@
+#CACHE{86400}
+<BOUCLE_article_principal(ARTICLES) {id_article}><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html dir="#LANG_DIR" lang="#LANG">
+<head>
+	<title>[(#TITRE|textebrut)][ - (#NOM_SITE_SPIP|textebrut)]</title>
+	<meta http-equiv="Content-Type" content="text/html; charset=#CHARSET" />
+	[<meta name="description" content="(#INTRODUCTION|couper{150}|attribut_html)" />]
+	<meta name="generator" content="SPIP" />
+	[<link rel="shortcut icon" href="(#CHEMIN{favicon.ico})" />]
+
+	<!-- Lien vers le backend pour navigateurs eclaires -->
+	<link rel="alternate" type="application/rss+xml" title="<:syndiquer_site:>" href="#URL_PAGE{backend}" />
+
+	<!-- Ceci est la feuille de style par defaut pour le code genere par SPIP -->
+	<link rel="stylesheet" href="[(#CHEMIN{spip_style.css}|direction_css)]" type="text/css" media="all" />
+	<!-- Feuille de styles CSS pour l'affichage du site sur ecran -->
+	<link rel="stylesheet" href="[(#CHEMIN{habillage.css}|direction_css)]" type="text/css" media="projection, screen, tv" />
+	<!-- Feuille de styles CSS pour l'impression -->
+	<link rel="stylesheet" href="[(#CHEMIN{impression.css}|direction_css)]" type="text/css" media="print" />
+</head>
+
+<body class="page_article">
+<div id="page">
+
+	[(#REM) Entete de la page + titre du site ]
+	<INCLURE{fond=inc-entete}{lang}>
+
+	[(#REM) Fil d'Ariane ]
+	<div id="hierarchie"><a href="#URL_SITE_SPIP/"><:accueil_site:></a><BOUCLE_ariane(HIERARCHIE){id_article}> &gt; <a href="#URL_RUBRIQUE">[(#TITRE|couper{80})]</a></BOUCLE_ariane>[ &gt; (#TITRE|couper{80})]</div>
+
+
+	<div id="conteneur">
+
+
+		[(#REM) Contenu principal : contenu de l'article ]
+
+		<div id="contenu">
+<style type='text/css'>
+		td.occupe a {font-weight:bold;text-decoration:underline;}
+		td.horsperiode {color:#878787;font-size:.9em;}
+</style>
+[(#REM) mini calendrier : 
+1er arg la date, 
+2eme le nom de la variable date (optionel : 'date' par defaut)
+3eme l'url sur laquelle boucler (optionel : url courante par defaut) ]
+#CALENDRIER_MINI{#ENV{date},'date',#SELF}
+
+		<div class="cartouche">
+				#DEBUT_SURLIGNE
+				[(#LOGO_ARTICLE||image_reduire{200,200})]
+				[<p class="surtitre">(#SURTITRE)</p>]
+				<h1 class="titre">#TITRE</h1>
+				[<p class="soustitre">(#SOUSTITRE)</p>]
+				#FIN_SURLIGNE
+
+				<p><small>[(#DATE|nom_jour) ][(#DATE|affdate)][, <:par_auteur:> (#LESAUTEURS)]</small></p>
+
+				[(#REM) Traductions de l'article ]
+				<B_traductions>
+				<div class="traductions">
+					<p><:trad_article_traduction:></p>
+					<ul>
+						<li[ class="(#EXPOSE)"]>[(#LANG|traduire_nom_langue)]</li>
+						<BOUCLE_traductions(ARTICLES){traduction}{exclus}>
+						<li><a[ href="(#URL_ARTICLE|url_absolue)"] rel="alternate" hreflang="#LANG"[ title="(#TITRE|couper{80}|texte_backend)"]><span lang="#LANG" xml:lang="#LANG" dir="#LANG_DIR">[(#LANG|traduire_nom_langue)]</span></a></li>
+						</BOUCLE_traductions>
+					</ul>
+				</div>
+				</B_traductions>
+			</div>
+
+
+			#DEBUT_SURLIGNE
+			[<div class="chapo">(#CHAPO)</div>]
+			<br class="nettoyeur" />
+			[<p class="lien"><:voir_en_ligne:> : <a href="(#URL_SITE)" class="spip_out">[(#NOM_SITE|sinon{[(#URL_SITE|couper{80})]})]</a></p>]
+			[<div class="texte">(#TEXTE|image_reduire{520,0})</div>]
+			#FIN_SURLIGNE
+
+			[(#REM) Portfolio : album d'images ]
+			<B_documents_portfolio>
+			<div id="documents_portfolio">
+				<h2><:info_portfolio:></h2>
+				<BOUCLE_documents_portfolio(DOCUMENTS) {id_article}
+				{mode=document} {extension IN png,jpg,gif} {par date}
+				{doublons}>
+				[<a href="#URL_DOCUMENT" type="#MIME_TYPE"
+				onclick="this.href='[(#URL_ARTICLE|parametre_url{id_document,#ID_DOCUMENT})]#documents_portfolio';return true;"[title="(#TITRE|couper{80}|texte_backend)"]>(#LOGO_DOCUMENT||image_reduire{0,60}|inserer_attribut{alt,[(#TITRE|couper{80}|texte_backend)]})</a>]
+				</BOUCLE_documents_portfolio>
+			</div>
+			</B_documents_portfolio>
+			<BOUCLE_afficher_document(DOCUMENTS) {id_document}
+			{mode=document}{extension IN png,jpg,gif}>
+			<div class="spip_documents spip_documents_center" id="document_actif">
+				#EMBED_DOCUMENT
+				[<div class="spip_doc_titre">(#TITRE)</div>]
+				[<div class="spip_doc_descriptif">(#DESCRIPTIF)</div>]
+			</div>
+			</BOUCLE_afficher_document>
+
+			[<div class="ps"><h2><:info_ps:></h2>#DEBUT_SURLIGNE(#PS)#FIN_SURLIGNE</div>]
+
+			[(#REM) Autres documents joints a l'article ]
+			<B_documents_joints>
+			<div id="documents_joints">
+				<h2><:titre_documents_joints:></h2>
+				<ul>
+					<BOUCLE_documents_joints(DOCUMENTS) {id_article} {mode=document} {par date} {doublons}>
+					<li>
+					<div class="spip_doc_titre"><a href="#URL_DOCUMENT" title="<:bouton_telecharger:>" type="#MIME_TYPE">[(#TITRE|sinon{<:info_document:>})]</a> <small>(#TYPE_DOCUMENT[ - (#TAILLE|taille_en_octets)])</small></div>
+					[<div class="spip_doc_descriptif">(#DESCRIPTIF)</div>]</li>
+					<br class="nettoyeur" />
+					</BOUCLE_documents_joints>
+				</ul>
+			</div>
+			</B_documents_joints>
+
+			[(#REM) Petition :
+			La petition ayant une PAGINATION il faut absolument lui passer SELF]
+			[ #REM Conserver cet invalideur invisible : (#PETITION|?{'',''}) ]
+			<INCLURE{fond=inc-petition}{id_article}{self=#SELF}>
+
+			[<div class="notes"><h2><:info_notes:></h2>#DEBUT_SURLIGNE(#NOTES)#FIN_SURLIGNE</div>]
+
+			[(#REM) Forum de l'article ]
+			[<h2 class="forum-repondre"><a href="(#PARAMETRES_FORUM|url_reponse_forum)"><:repondre_article:></a></h2>]
+			<INCLURE{fond=inc-forum}{id_article}>
+
+
+		</div><!-- fin contenu -->
+
+
+		[(#REM) Menu de navigation laterale ]
+		<div id="navigation">
+			<h1 class="invisible"><:navigation:></h1>
+
+			[(#REM) Menu de navigation par rubriques ]
+			<INCLURE{fond=inc-rubriques}{lang}{id_rubrique}>
+
+			[(#REM) Articles dans la meme rubrique ]
+			<B_articles_rubrique>
+			<div class="breves">
+				<h2 class="menu-titre"><a href="#URL_RUBRIQUE"><:meme_rubrique:></a></h2>
+				<ul>
+					<BOUCLE_articles_rubrique(ARTICLES) {id_rubrique} {par date}{inverse} {0,10}>
+					<li><a href="#URL_ARTICLE"[ class="(#EXPOSE)"]>#TITRE</a></li>
+					</BOUCLE_articles_rubrique>
+				</ul>
+			</div>
+			</B_articles_rubrique>
+
+			[(#REM) Menu de navigation mots-cles ]
+			<B_mots>
+			<div class="divers">
+				<h2 class="menu-titre"><:mots_clefs:></h2>
+			<ul>
+				<BOUCLE_mots(MOTS) {id_article} {par titre}>
+				<li><a href="#URL_MOT" rel="tag">#TITRE</a></li>
+				</BOUCLE_mots>
+			</ul>
+			</div>
+			</B_mots>
+		</div><!-- fin navigation -->
+
+	</div><!-- fin conteneur -->
+
+	[(#REM) Pied de page ]
+	<INCLURE{fond=inc-pied}{lang}>
+
+</div><!-- fin page -->
+</body>
+</html>
+</BOUCLE_article_principal>
Index: plugins/agenda_1_9_1/exec/agenda_evenements.php
===================================================================
--- plugins/agenda_1_9_1/exec/agenda_evenements.php	(revision 6)
+++ plugins/agenda_1_9_1/exec/agenda_evenements.php	(revision 6)
@@ -0,0 +1,421 @@
+<?php
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/texte');
+include_spip('inc/presentation');
+include_spip('inc/agenda_filtres');
+include_spip('inc/agenda_gestion');
+
+function date_debut_fin($annee,$mois,$jour,$type){
+	if ($type=='jour'){
+		$ts_start=strtotime("$annee-$mois-01 00:00:00");
+		$ts_start+=($jour-1)*24*60*60;
+		$ts_fin=$ts_start+24*60*60;
+	} else
+	if ($type=="semaine"){
+		$ts_start=strtotime("$annee-$mois-01 01:00:00");
+		$ts_start+=($jour-1)*24*60*60;
+		while (date('w',$ts_start)!=1) $ts_start-=24*60*60;
+		$ts_fin=$ts_start+7*24*60*60+60*60;
+		$ts_start-=2*60*60;
+	} else
+	if ($type=='mois'){
+		$ts_start=strtotime("$annee-$mois-01 00:00:00");
+		if ($mois<'12')
+			$ts_fin=strtotime("$annee-".($mois+1)."-01 00:00:00");
+		else
+			$ts_fin=strtotime(($annee+1)."-$mois-01 00:00:00");
+	}
+	return array($ts_start,$ts_fin);	
+}
+function ajoute_creneaux_horaires($urlbase,$ts_start,$ts_fin,$type,$partie_cal,$echelle){
+	if ($echelle<=120)
+		$freq_creneaux=30*60;
+	else
+		$freq_creneaux=60*60;
+
+	$today=date('Y-m-d');
+	// creneaux pour ajout uniquement si ajouter_id_article present
+	if (($type!='mois')&&($partie_cal!='sansheure'))
+	{
+		$heuremin='08';$heuremax='20';
+		if ($partie_cal=='matin'){
+			$heuremin='04';$heuremax='15';
+		}
+		if ($partie_cal=='soir'){
+			$heuremin='12';$heuremax='23';
+		}
+		for ($j=$ts_start;$j<=$ts_fin;$j+=$freq_creneaux){
+			$heure=date('H',$j);
+			if (($heure>=$heuremin)&&($heure<=$heuremax)){
+				$url=parametre_url($urlbase,'ndate',urlencode(date('Y-m-d H:i',$j)));
+				$creneau=date('Y-m-d H:i:s',$j);
+				if (date('Y-m-d',$j)==$today)
+					Agenda_memo_full($creneau,$creneau,preg_replace(",\s+,","&nbsp;",date('H:i',$j)." "._T('agenda:ajouter_un_evenement')), " ", "", $url,'calendrier-creneau-today');
+				else if (date('w',$j)==0)
+					Agenda_memo_full($creneau,$creneau,preg_replace(",\s+,","&nbsp;",date('H:i',$j)." "._T('agenda:ajouter_un_evenement')), " ", "",$url,'calendrier-creneau-sunday');
+				else
+					Agenda_memo_full($creneau,$creneau,preg_replace(",\s+,","&nbsp;",date('H:i',$j)." "._T('agenda:ajouter_un_evenement')), " ", "",$url,'calendrier-creneau');
+			}
+		}
+	}
+	
+}
+
+function affiche_evenements_agenda($flag_editable){
+	global $visu_evenements;
+	$type = _request('type');
+	$partie_cal = _request('partie_cal');
+	if (!$type) $type='semaine';
+	$id_evenement = intval(_request('id_evenement'));
+	$ajouter_id_article = intval(_request('ajouter_id_article'));
+	global $annee,$mois,$jour;
+	$annee = intval(_request('annee'));
+	$mois = intval(_request('mois'));
+	$jour = intval(_request('jour'));
+
+	if ($flag_editable)
+		Agenda_action_formulaire_article($ajouter_id_article);
+
+	$visu_evenements=array();
+
+	if ((!$annee)||(!$mois)||(!$jour)){
+		if (!$id_evenement){ // pas d'id_evenement--> date du jour
+			$stamp=time();
+		}
+		else { // date de l'evenement
+			$res = spip_query("SELECT date_debut FROM spip_evenements WHERE id_evenement=".spip_abstract_quote($id_evenement));
+			if ($row = spip_fetch_array($res))
+				$stamp=strtotime($row['date_debut']);
+			else 
+				$stamp=time();
+		}
+		$annee=date('Y',$stamp);
+		$mois=date('m',$stamp);
+		$jour=date('d',$stamp);
+ 	}
+
+
+ 	$urlbase=self();
+ 	$urlbase=parametre_url($urlbase,'edit','');
+ 	$urlbase=parametre_url($urlbase,'del','');
+ 	$urlbase=parametre_url($urlbase,'ndate','');
+ 	$urlbase=parametre_url($urlbase,'id_evenement','');
+ 	$urlbase=parametre_url($urlbase,'neweven','1');
+ 	
+	//$urlbase=str_replace("&amp;","&",$urlbase);
+
+	// creation des boites creneaux horaires pour ajout rapide
+	list($ts_start,$ts_fin) = date_debut_fin($annee,$mois,$jour,$type);
+	if ($flag_editable)
+		ajoute_creneaux_horaires($urlbase,$ts_start,$ts_fin,$type,$partie_cal,$echelle);
+
+
+	$categorie_concerne=array('plage'=>'calendrier-plage','evenement'=>'calendrier-evenement');
+	$categorie_info=array('plage'=>'calendrier-plage-info','evenement'=>'calendrier-evenement-info');
+
+	$datestart=date('Y-m-d H:i:s',$ts_start-24*60*60);
+	$datefin=date('Y-m-d H:i:s',$ts_fin+24*60*60);
+
+	// tous les evenements
+	$res = spip_query("SELECT * 
+							FROM spip_evenements AS evenements
+						 WHERE ((evenements.date_debut>='$datestart' AND evenements.date_debut<='$datefin') 
+						 		OR (evenements.date_fin>='$datestart' AND evenements.date_fin<='$datefin')
+						 		OR (evenements.date_debut<'$datestart' AND evenements.date_fin>'$datefin'))
+						 ORDER BY evenements.date_debut;");
+ 	$urlbase=parametre_url($urlbase,'neweven','');
+	$urlbase=parametre_url($urlbase,'annee',$annee);
+	$urlbase=parametre_url($urlbase,'mois',$mois);
+	$urlbase=parametre_url($urlbase,'jour',$jour);
+	while ($row = spip_fetch_array($res)){
+		$is_evt=($row['horaire']!='oui')
+						||($row['date_debut']<$datestart && $row['date_fin']>$datefin);
+		$concerne=(!$ajouter_id_article) || ($ajouter_id_article==$row['id_article']);
+
+		$url=parametre_url($urlbase,'id_evenement',$row['id_evenement']);
+		$url=parametre_url($url,'ajouter_id_article',$row['id_article']);
+		
+		$titre = typo($row['titre']);
+		$descriptif = typo($row['descriptif']);
+		$lieu = typo($row['lieu']);
+		$texte=wordwrap(entites_html($row['titre'],ENT_QUOTES),15,"<br />\n");
+		if (($type!='mois')&&(!$is_evt))
+			$texte.="<hr />" . wordwrap(entites_html($row['descriptif'],ENT_QUOTES),15, "<br />\n");
+		if (strlen($texte)==0) $texte=_L("(sans objet)");
+
+		if ($concerne)	$categorie = $categorie_concerne;
+		else						$categorie = $categorie_info;
+		if ($is_evt) 		$categorie = $categorie['evenement'];
+		else 						$categorie = $categorie['plage'];
+		if ($id_evenement==$row['id_evenement'])
+			$categorie.='-selection';
+
+		if (!$is_evt)
+			Agenda_memo_full($row['date_debut'], $row['date_fin'], $titre, $descriptif, $lieu, $url, $categorie);
+		else{
+			//if ($type!='mois')
+			//	Agenda_memo_evt_full($row['date_debut'], $row['date_debut'], Agenda_rendu_boite($titre,$descriptif,$lieu), "", "", $url, $categorie);
+			//else
+				Agenda_memo_evt_full($row['date_debut'], $row['date_fin'], $titre, $descriptif, $lieu, $url, $categorie);
+		}
+		$visu_evenements[$row['id_evenement']]=1;
+	}
+
+	$s = "<span class='agenda-calendrier'>\n";
+	// attention : bug car $type est modifie apres cet appel !
+	$s .= Agenda_affiche_full(1,'', $type, 'calendrier-creneau','calendrier-creneau-today','calendrier-creneau-sunday','calendrier-plage','calendrier-evenement','calendrier-plage-info','calendrier-evenement-info','calendrier-plage-selection','calendrier-evenement-selection');
+	$s .= "</span>";
+
+	return $s;
+}
+
+
+function visu_evenement_agenda($id_evenement,$flag_editable){
+	$out = "";
+	$ndate = _request('ndate');
+	$del = _request('del');
+
+	if ($id_evenement!=NULL){
+		$res = spip_query("SELECT evenements.* FROM spip_evenements AS evenements WHERE evenements.id_evenement=".spip_abstract_quote($id_evenement));
+		if ($row = spip_fetch_array($res)){
+			if (!isset($neweven)){
+				$fid_evenement=$row['id_evenement'];
+				$ftitre=attribut_html(typo($row['titre']));
+				$flieu=attribut_html(typo($row['lieu']));
+
+				$fhoraire=attribut_html($row['horaire']);
+				$fdescriptif=attribut_html(typo($row['descriptif']));
+				$fstdatedeb=strtotime($row['date_debut']);
+				$fstdatefin=strtotime($row['date_fin']);
+				$fid_evenement_source=$row['id_evenement_source'];
+			}
+	 	}
+		$out .= "<div class='agenda-visu-evenement'>";
+		$res2 = spip_query("SELECT articles.* FROM spip_articles AS articles LEFT JOIN spip_evenements AS J ON J.id_article=articles.id_article WHERE J.id_evenement=".spip_abstract_quote($id_evenement));
+		if ($row2 = spip_fetch_array($res2)){
+			$out .= "<div class='article-evenement'>";
+			$out .= "<a href='".generer_url_ecrire('articles',"id_article=".$row2['id_article'])."'>";
+			$out .= http_img_pack("article-24.gif", "", "width='24' height='24' border='0'");
+			$out .= entites_html(typo($row2['titre']))."</a>";
+			$out .= "</div>\n";
+		}
+		
+		$out .= "<div class='agenda-visu-evenement-bouton-fermer'>";
+		$url=self();
+		$url=parametre_url($url,'edit','');
+		$url=parametre_url($url,'neweven','');
+		$url=parametre_url($url,'del','');
+		$url=parametre_url($url,'id_evenement','');
+
+		$out .= "<a href='$url'><img src='"._DIR_PLUGIN_AGENDA_EVENEMENTS."/img_pack/croix.png' width='12' height='12' style='border:none;'></a>";
+		$out .= "</div>\n";
+
+		$fobjet = entites_html($fobjet,ENT_QUOTES);
+		$flieu = entites_html($flieu,ENT_QUOTES);
+		$fdescription = entites_html($fdescription,ENT_QUOTES);
+
+		$out .= "<div class='titre-titre'>Titre</div><div class='titre-visu'>$ftitre &nbsp;</div>\n";
+		$out .= "<div class='lieu-titre'>Lieu</div><div class='lieu-visu'>$flieu &nbsp;</div>\n";
+		$out .= "<div class='horaire-titre'>&nbsp;</div>";
+		$out .= "<div class='date-titre'>Date </div>";
+		$out .= "<div class='date-visu'>";
+		$out .= "Du ".affdate_jourcourt(date("Y-m-d H:i",$fstdatedeb));
+		if ($fhoraire=='oui')
+			$out .= " &agrave; ".date("H:i",$fstdatedeb);
+		$out .= " <br/>\n";
+		$out .= "Au ".affdate_jourcourt(date("Y-m-d H:i",$fstdatefin));
+		if ($fhoraire=='oui')
+			$out .= " &agrave; ".date("H:i",$fstdatefin);
+		$out .= " <br/>\n";
+		$out .= "</div>\n";
+		$out .= "<div class='descriptif-titre'>Description</div><div class='descriptif-visu'>$fdescriptif &nbsp;</div>\n";
+
+		$out .=  "<div class='agenda_mots_cles'>";
+		$res = spip_query("SELECT * FROM spip_groupes_mots WHERE evenements='oui' ORDER BY titre");
+		$sep = "";
+		while ($row = spip_fetch_array($res,SPIP_ASSOC)){
+			$id_groupe = $row['id_groupe'];
+			$row2 = spip_fetch_array(
+						spip_query("SELECT mots.titre FROM spip_mots_evenements AS mots_evenements
+								LEFT JOIN spip_mots AS mots ON mots.id_mot=mots_evenements.id_mot 
+								WHERE mots.id_groupe=".spip_abstract_quote($id_groupe).
+								" AND mots_evenements.id_evenement=".spip_abstract_quote($id_evenement)));
+			if ($row2){
+				$out .= $sep . supprimer_numero($row['titre'])."&nbsp;:&nbsp;".supprimer_numero($row2['titre']);
+				$sep = "\n, ";
+			}
+		}
+		$out .= "</div>\n";
+		
+
+		$url = parametre_url(self(),'annee','');
+		$url = parametre_url($url,'mois','');
+		$url = parametre_url($url,'jour','');
+
+		$out .= "<div class='repetitions-calendrier'>";
+		$id_source = $fid_evenement_source?$fid_evenement_source:$id_evenement;
+		$res2 = spip_query("SELECT * FROM spip_evenements WHERE id_evenement=".spip_abstract_quote($id_source)." OR id_evenement_source=".spip_abstract_quote($id_source)." ORDER BY date_debut");
+		if (spip_num_rows($res2)>1){
+			$out .= _T('agenda:evenement_autres_occurences');
+			while($row2 = spip_fetch_array($res2)){
+				if ($row2['id_evenement']!=$fid_evenement){
+					$url = parametre_url(self(),'id_evenement',$row2['id_evenement']);
+					$out .= " <a href='$url'>" . affdate_jourcourt($row2['date_debut']) ."</a>";
+				}
+			}
+		}
+		$out .= "</div>";
+	
+		if ($fid_evenement_source!=0){
+			$res2 = spip_query("SELECT evenements.* FROM spip_evenements AS evenements WHERE evenements.id_evenement=".spip_abstract_quote($fid_evenement_source));
+			if ($row2 = spip_fetch_array($res2)){
+				$url = parametre_url($url,'id_evenement',$row2['id_evenement']);
+			  $out .= "<div class='edition-bouton'>";
+			  $out .= _T('agenda:repetition_de')." <a href='";
+			  $out .= $url;
+			  $out .= "'>".($row2['titre']?typo($row2['titre']):_T('agenda:sans_titre'))."</a>";
+			  $out .= "</div>";
+			}
+		}
+		else if ($flag_editable){
+			$url=self();
+			$url=parametre_url($url,'edit','');
+			$url=parametre_url($url,'neweven','');
+			$url=parametre_url($url,'del','');
+			$url=parametre_url($url,'id_evenement','');
+			if ($del==1)	{ //---------------Suppression RDV ------------------------------
+			  $out .= "<form name='edition_rdv' action='$url' method='post'>";
+			  //$out .= "<input type='hidden' name='redirect' value='$url' />\n";
+			  $out .= "<input type='hidden' name='id_evenement' value='$fid_evenement' />\n";
+			  $out .= "<input type='hidden' name='suppr' value='1' />\n";
+			  $out .= "<div class='edition-bouton'>";
+			  $out .= "<input type='submit' name='submit' value='Annuler' />";
+			  $out .= "<input type='submit' name='submit' value='Confirmer la suppression' />";
+			  $out .= "</div></form>";
+	  	}
+	  	else {
+				$url=parametre_url($url,'id_evenement',$id_evenement);
+			  $out .= "<form name='edition_rdv' action='$url' method='post'>";
+			  //$out .= "<input type='hidden' name='redirect' value='$url' />\n";
+			  $out .= "<input type='hidden' name='id_evenement' value='$fid_evenement' />\n";
+			  $out .= "<input type='hidden' name='edit' value='1' />\n";
+			  $out .= "<div class='edition-bouton'>";
+				$out .= "<div style='text-align:$spip_lang_right'><input type='submit' name='modifier' value='"._T('bouton_modifier')."' class='fondo'></div>";
+			  $out .= "</div></form>";
+	  	}
+		}
+		$out .= "</div>\n";
+	}
+	return $out;
+}
+
+function exec_agenda_evenements_dist(){
+	// s'assurer que les tables sont crees
+	Agenda_install();
+	include_spip('inc/calendar');
+	// Reserver les widgets agenda
+	WCalendar_ajoute_lies(_T('agenda:evenement_date_debut'),'_evenement_debut',_T('agenda:evenement_date_fin'),'_evenement_fin');
+	WCalendar_ajoute_statique(_T('agenda:evenement_repetitions'),'_repetitions');
+
+	$ajouter_id_article = intval(_request('ajouter_id_article'));
+	$flag_editable = article_editable($ajouter_id_article);
+
+	global $visu_evenements;
+	$type = _request('type');
+	if (!$type) $type='semaine';
+	$id_evenement = intval(_request('id_evenement'));
+	$edit = _request('edit');
+	$neweven = _request('neweven');
+
+	$annee = intval(_request('annee'));
+	$mois = intval(_request('mois'));
+	$jour = intval(_request('jour'));
+	$date = date("Y-m-d", time());
+	if ($annee&&$mois&&$jour)
+		$date = date("Y-m-d", strtotime("$annee-$mois-$jour"));
+
+
+		
+	if ($type == 'semaine') {
+	
+		//$GLOBALS['afficher_bandeau_calendrier_semaine'] = true;
+		$titre = _T('titre_page_calendrier',
+			array('nom_mois' => nom_mois($date), 'annee' => annee($date)));
+	}
+  elseif ($type == 'jour') {
+		$titre = nom_jour($date)." ". affdate_jourcourt($date);
+  }
+	else {
+		$titre = _T('titre_page_calendrier',
+		    array('nom_mois' => nom_mois($date), 'annee' => annee($date)));
+	}
+
+  debut_page($titre, "redacteurs", "calendrier","",$css);
+	barre_onglets("calendrier", "evenements");
+
+	$out = "<div>";
+	if ($ajouter_id_article){
+		$res2 = spip_query("SELECT * FROM spip_articles AS articles WHERE id_article=".spip_abstract_quote($ajouter_id_article));
+		if ($row2 = spip_fetch_array($res2)){
+			$out .= "<div style=' width:750px; font-size: 18px; color: #9DBA00; font-weight: bold;text-align:left;'>";
+			$out .= "<a href='".generer_url_ecrire('articles',"id_article=".$row2['id_article'])."'>";
+			$out .= http_img_pack("article-24.gif", "", "width='24' height='24' border='0'");
+			$out .= entites_html(typo($row2['titre']))."</a></div>";
+		}
+	}
+	echo $out ."&nbsp;</div>" ;
+
+	echo affiche_evenements_agenda($flag_editable);
+
+	if (($edit||$neweven)&&($flag_editable))	{ //---------------Edition RDV ------------------------------
+		$ndate = _request('ndate');
+		echo Agenda_formulaire_edition_evenement($id_evenement,$neweven,$ndate);
+	}
+	else
+		if ((isset($id_evenement))&&(isset($visu_evenements[$id_evenement]))){ //---------------Visualisation RDV ------------------------------
+			echo visu_evenement_agenda($id_evenement,$flag_editable);
+		}
+	fin_page();
+
+}
+
+function http_calendrier_ics_message($annee, $mois, $jour, $large)
+{
+	return "";
+}
+
+function http_calendrier_aide_mess()
+{
+	return "";
+}
+
+function http_calendrier_semainesh($annee, $mois, $jour, $echelle, $partie_cal, $script, $ancre, $evt)
+{
+	global $spip_ecran;
+	if (!isset($spip_ecran)) $spip_ecran = 'large';
+
+	$init = date("w",mktime(1,1,1,$mois,$jour,$annee));
+	$init = $jour+1-($init ? $init : 7);
+	$sd = '';
+
+	if (is_array($evt))
+	  {
+		  list($sansduree, $evenements, $premier_jour, $dernier_jour) = $evt;
+		  if ($sansduree)
+		    foreach($sansduree as $d => $r) 
+		      $evenements[$d] = !$evenements[$d] ? $r : array_merge($evenements[$d], $r);
+	    $finurl = "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre";
+	    $evt =
+	      http_calendrier_semaine_noms($annee, $mois, $init, $script, $finurl) .
+	      http_calendrier_mois_sept($annee, $mois, $init, $init+ 6, $evenements, $script);
+	  } else $evt = "<tr><td>$evt</td></tr>";
+
+	return 
+	  "\n<table class='calendrier-table-$spip_ecran' cellspacing='0' cellpadding='0'>" .
+	  http_calendrier_semaine_navigation($annee, $mois, $init, $echelle, $partie_cal, $script, $ancre) .
+	  $evt .
+	  "</table>" .
+	  (_DIR_RESTREINT ? "" : http_calendrier_aide_mess());
+}
Index: plugins/agenda_1_9_1/exec/mots_tous.php
===================================================================
--- plugins/agenda_1_9_1/exec/mots_tous.php	(revision 6)
+++ plugins/agenda_1_9_1/exec/mots_tous.php	(revision 6)
@@ -0,0 +1,447 @@
+<?php
+
+/***************************************************************************\
+ *  SPIP, Systeme de publication pour l'internet                           *
+ *                                                                         *
+ *  Copyright (c) 2001-2006                                                *
+ *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
+ *                                                                         *
+ *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
+ *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
+\***************************************************************************/
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/presentation');
+include_spip('inc/actions');
+include_spip('base/abstract_sql');
+include_spip('inc/agenda_gestion');
+include_spip('inc/pim_agenda_gestion');
+
+// http://doc.spip.org/@exec_mots_tous_dist
+function exec_mots_tous_dist()
+{
+  global $acces_comite, $acces_forum, $acces_minirezo, $new, $articles, $breves, $change_type, $conf_mot, $connect_statut, $connect_toutes_rubriques, $descriptif, $id_groupe, $modifier_groupe, $obligatoire, $rubriques, $spip_lang, $spip_lang_right, $supp_group, $syndic, $texte, $unseul;
+	global $evenements, $pim_agenda;
+	global $tables_principales;
+	
+  $id_groupe = intval($id_groupe);
+
+  if ($conf_mot = intval($conf_mot)) {
+	$result = spip_query("SELECT * FROM spip_mots WHERE id_mot=$conf_mot");
+	if ($row = spip_fetch_array($result)) {
+		$id_mot = $row['id_mot'];
+		$titre_mot = typo($row['titre']);
+		$type_mot = typo($row['type']);
+
+		if ($connect_statut=="0minirezo") $aff_articles="'prepa','prop','publie','refuse'";
+		else $aff_articles="'prop','publie'";
+
+		$nb_articles = spip_fetch_array(spip_query("SELECT COUNT(*) AS n FROM spip_mots_articles AS lien, spip_articles AS article WHERE lien.id_mot=$conf_mot AND article.id_article=lien.id_article AND (article.statut IN ($aff_articles))>0 AND article.statut!='refuse'"));
+		$nb_articles = $nb_articles['n'];
+
+		$nb_rubriques = spip_fetch_array(spip_query("SELECT COUNT(*) AS n FROM spip_mots_rubriques AS lien, spip_rubriques AS rubrique WHERE lien.id_mot=$conf_mot AND rubrique.id_rubrique=lien.id_rubrique"));
+		$nb_rubriques = $nb_rubriques['n'];
+
+		$nb_breves = spip_fetch_array(spip_query("SELECT COUNT(*) AS n FROM spip_mots_breves AS lien, spip_breves AS breve WHERE lien.id_mot=$conf_mot AND breve.id_breve=lien.id_breve AND (breve.statut IN ($aff_articles))>0 AND breve.statut!='refuse'"));
+		$nb_breves = $nb_breves['n'];
+
+		$nb_sites = spip_fetch_array(spip_query("SELECT COUNT(*) AS n FROM spip_mots_syndic AS lien, spip_syndic AS syndic WHERE lien.id_mot=$conf_mot AND syndic.id_syndic=lien.id_syndic	AND (syndic.statut IN ($aff_articles))>0 AND syndic.statut!='refuse'"));
+		$nb_sites = $nb_sites['n'];
+
+		$nb_forum = spip_fetch_array(spip_query("SELECT COUNT(*) AS n FROM spip_mots_forum AS lien, spip_forum AS forum WHERE lien.id_mot=$conf_mot AND forum.id_forum=lien.id_forum AND forum.statut='publie'"));
+		$nb_forum = $nb_forum['n'];
+
+		$nb_evenements = 0;
+		if (isset($tables_principales['spip_evenements'])){
+			$nb_evenements = spip_fetch_array(spip_query("SELECT COUNT(*) AS n FROM spip_mots_evenements AS lien, spip_evenements AS evenement WHERE lien.id_mot=$conf_mot AND evenement.id_evenement=lien.id_evenement"));
+			$nb_evenements = $nb_evenements['n'];
+		}
+		
+		$nb_agenda = 0;
+		if (isset($tables_principales['spip_pim_agenda'])){
+			$nb_agenda = spip_fetch_array(spip_query("SELECT COUNT(*) AS n FROM spip_mots_pim_agenda AS lien, spip_pim_agenda AS agenda WHERE lien.id_mot=$conf_mot AND agenda.id_agenda=lien.id_agenda"));
+			$nb_agenda = $nb_agenda['n'];
+		}
+		
+		// si le mot n'est pas lie, on demande sa suppression
+		if ($nb_articles + $nb_breves + $nb_sites + $nb_forum + $nb_evenements + $nb_agenda == 0) {
+		  redirige_par_entete(generer_url_ecrire("mots_edit","supp_mot=$id_mot&redirect_ok=oui&redirect=" . rawurlencode(generer_url_ecrire('mots_tous')), true));
+		} // else traite plus loin (confirmation de suppression)
+	}
+}
+
+if ($connect_statut == '0minirezo'  AND $connect_toutes_rubriques) {
+	if (function_exists('Agenda_install'))	Agenda_install();
+	if (function_exists('PIMAgenda_install'))	PIMAgenda_install();
+
+	if ($modifier_groupe == "oui") {
+		$change_type = (corriger_caracteres($change_type));
+		$texte = (corriger_caracteres($texte));
+		$descriptif = (corriger_caracteres($descriptif));
+
+		if (!$new) {	// modif groupe
+			spip_query("UPDATE spip_mots SET type=" . spip_abstract_quote($change_type) . " WHERE id_groupe=$id_groupe");
+
+
+			spip_query("UPDATE spip_groupes_mots SET titre=" . spip_abstract_quote($change_type) . ", texte=" . spip_abstract_quote($texte) . ", descriptif=" . spip_abstract_quote($descriptif) . ", unseul=" . spip_abstract_quote($unseul) . ", obligatoire=" . spip_abstract_quote($obligatoire) . ", articles=" . spip_abstract_quote($articles) . ", breves=" . spip_abstract_quote($breves) . ", rubriques=" . spip_abstract_quote($rubriques) . ", syndic=" . spip_abstract_quote($syndic) . ",	minirezo=" . spip_abstract_quote($acces_minirezo) . ", comite=" . spip_abstract_quote($acces_comite) . ", forum=" . spip_abstract_quote($acces_forum) . " WHERE id_groupe=$id_groupe");
+
+		} else {	// creation groupe
+		  $id_groupe = spip_abstract_insert('spip_groupes_mots', "(titre, texte, descriptif, unseul,  obligatoire, articles, breves, rubriques, syndic, minirezo, comite, forum)", "(" . spip_abstract_quote($change_type) . ", " . spip_abstract_quote($texte) . " , " . spip_abstract_quote($descriptif) . " , " . spip_abstract_quote($unseul) . " , " . spip_abstract_quote($obligatoire) . " , " . spip_abstract_quote($articles) . " ," . spip_abstract_quote($breves) . " , " . spip_abstract_quote($rubriques) . " , " . spip_abstract_quote($syndic) . " , " . spip_abstract_quote($acces_minirezo) . " ,  " . spip_abstract_quote($acces_comite) . " , " . spip_abstract_quote($acces_forum) . " )");
+		}
+		if ($id_groupe && isset($tables_principales['spip_evenements']))
+			spip_query("UPDATE spip_groupes_mots SET evenements=".spip_abstract_quote($evenements)." WHERE id_groupe=$id_groupe");
+		if ($id_groupe && isset($tables_principales['spip_pim_agenda']))
+			spip_query("UPDATE spip_groupes_mots SET pim_agenda=".spip_abstract_quote($pim_agenda)." WHERE id_groupe=$id_groupe");
+	}
+	if ($supp_group){
+		spip_query("DELETE FROM spip_groupes_mots WHERE id_groupe=" . intval($supp_group));
+	}
+ }
+
+
+pipeline('exec_init',array('args'=>array('exec'=>'mots_tous'),'data'=>''));
+debut_page(_T('titre_page_mots_tous'), "naviguer", "mots");
+debut_gauche();
+
+echo pipeline('affiche_gauche',array('args'=>array('exec'=>'mots_tous'),'data'=>''));
+creer_colonne_droite();
+echo pipeline('affiche_droite',array('args'=>array('exec'=>'mots_tous'),'data'=>''));
+debut_droite();
+
+gros_titre(_T('titre_mots_tous'));
+ if (acces_mots()) {
+  echo typo(_T('info_creation_mots_cles')) . aide ("mots") ;
+  }
+echo "<br><br>";
+
+// Preliminaire: confirmation de suppression d'un mot lie à qqch
+// (cf fin de afficher_groupe_mots_boucle executee a l'appel precedent)
+// Faudrait ajaxer ça.
+
+  if ($conf_mot = intval($conf_mot)) {
+	$row = spip_fetch_array(spip_query("SELECT * FROM spip_mots WHERE id_mot=$conf_mot"));
+	$id_mot = $row['id_mot'];
+	$titre_mot = typo($row['titre']);
+	$type_mot = typo($row['type']);
+
+	if (($na = intval($na)) == 1) {
+		$texte_lie = _T('info_un_article')." ";
+	} else if ($na > 1) {
+		$texte_lie = _T('info_nombre_articles', array('nb_articles' => $na)) ." ";
+	}
+	if (($nb = intval($nb)) == 1) {
+		$texte_lie .= _T('info_une_breve')." ";
+	} else if ($nb > 1) {
+		$texte_lie .= _T('info_nombre_breves', array('nb_breves' => $nb))." ";
+	}
+	if (($ns = intval($ns)) == 1) {
+		$texte_lie .= _T('info_un_site')." ";
+	} else if ($ns > 1) {
+		$texte_lie .= _T('info_nombre_sites', array('nb_sites' => $ns))." ";
+	}
+	if (($nr = intval($nr)) == 1) {
+		$texte_lie .= _T('info_une_rubrique')." ";
+	} else if ($nr > 1) {
+		$texte_lie .= _T('info_nombre_rubriques', array('nb_rubriques' => $nr))." ";
+	}
+	if ($nb_evenements == 1) {
+		$texte_lie .= _T('agenda:info_un_evenement')." ";
+	} else if ($nb_evenements > 1) {
+		$texte_lie .= _T('agenda:info_nombre_evenements', array('$nb_evenements' => $nb_evenements))." ";
+	}
+
+	debut_boite_info();
+	echo "<div class='serif'>";
+	echo _T('info_delet_mots_cles', array('titre_mot' => $titre_mot, 'type_mot' => $type_mot, 'texte_lie' => $texte_lie));
+
+	echo "<UL>";
+	echo "<LI><B><A href='", 
+	  redirige_action_auteur('editer_mot', ",$id_mot,,,",'mots_tous'),
+	  "'>",
+	  _T('item_oui'),
+	  "</A>,</B> ",
+	  _T('info_oui_suppression_mot_cle');
+	echo "<LI><B><A href='" . generer_url_ecrire("mots_tous","") . "'>"._T('item_non')."</A>,</B> "._T('info_non_suppression_mot_cle');
+	echo "</UL>";
+	echo "</div>";
+	fin_boite_info();
+	echo "<br />";
+}
+
+//
+// On boucle d'abord sur les groupes de mots
+//
+
+ $result_groupes = spip_query("SELECT *, ".creer_objet_multi ("titre", "$spip_lang")." FROM spip_groupes_mots ORDER BY multi");
+
+
+while ($row_groupes = spip_fetch_array($result_groupes)) {
+	$id_groupe = $row_groupes['id_groupe'];
+	$titre_groupe = typo($row_groupes['titre']);
+	$descriptif = $row_groupes['descriptif'];
+	$texte = $row_groupes['texte'];
+	$unseul = $row_groupes['unseul'];
+	$obligatoire = $row_groupes['obligatoire'];
+	$articles = $row_groupes['articles'];
+	$breves = $row_groupes['breves'];
+	$rubriques = $row_groupes['rubriques'];
+	$syndic = $row_groupes['syndic'];
+	if (isset($tables_principales['spip_evenements']))	$evenements = $row_groupes['evenements'];
+	if (isset($tables_principales['spip_pim_agenda']))	$pim_agenda = $row_groupes['pim_agenda'];
+	$acces_minirezo = $row_groupes['minirezo'];
+	$acces_comite = $row_groupes['comite'];
+	$acces_forum = $row_groupes['forum'];
+
+	// Afficher le titre du groupe
+	debut_cadre_enfonce("groupe-mot-24.gif", false, '', $titre_groupe);
+	// Affichage des options du groupe (types d'elements, permissions...)
+	echo "<font face='Verdana,Arial,Sans,sans-serif' size=1>";
+	if ($articles == "oui") echo "> "._T('info_articles_2')." &nbsp;&nbsp;";
+	if ($breves == "oui") echo "> "._T('info_breves_02')." &nbsp;&nbsp;";
+	if ($rubriques == "oui") echo "> "._T('info_rubriques')." &nbsp;&nbsp;";
+	if ($syndic == "oui") echo "> "._T('icone_sites_references')." &nbsp;&nbsp;";
+	if (isset($tables_principales['spip_evenements']))
+		if ($evenements == "oui") echo "> "._T('agenda:info_evenements')." &nbsp;&nbsp;";
+	if (isset($tables_principales['spip_pim_agenda']))
+		if ($pim_agenda == "oui") echo "> "._T('pimagenda:info_evenements')." &nbsp;&nbsp;";
+
+	if ($unseul == "oui" OR $obligatoire == "oui") echo "<br>";
+	if ($unseul == "oui") echo "> "._T('info_un_mot')." &nbsp;&nbsp;";
+	if ($obligatoire == "oui") echo "> "._T('info_groupe_important')." &nbsp;&nbsp;";
+
+	echo "<br />";
+	if ($acces_minirezo == "oui") echo "> "._T('info_administrateurs')." &nbsp;&nbsp;";
+	if ($acces_comite == "oui") echo "> "._T('info_redacteurs')." &nbsp;&nbsp;";
+	if ($acces_forum == "oui") echo "> "._T('info_visiteurs_02')." &nbsp;&nbsp;";
+
+	echo "</font>";
+	if ($descriptif) {
+		echo "<div style='border: 1px dashed #aaaaaa;'>";
+		echo "<font size='2' face='Verdana,Arial,Sans,sans-serif'>";
+		echo "<b>",_T('info_descriptif'),"</b> ";
+		echo propre($descriptif);
+		echo "&nbsp; ";
+		echo "</font>";
+		echo "</div>";
+	}
+
+	if (strlen($texte)>0){
+		echo "<FONT FACE='Verdana,Arial,Sans,sans-serif'>";
+		echo propre($texte);
+		echo "</FONT>";
+	}
+
+	//
+	// Afficher les mots-cles du groupe
+	//
+	$supprimer_groupe = afficher_groupe_mots($id_groupe);
+
+	echo $supprimer_groupe;
+
+	if (acces_mots() AND !$conf_mot){
+		echo "\n<table cellpadding=0 cellspacing=0 border=0 width=100%>";
+		echo "<tr>";
+		echo "<td>";
+		icone(_T('icone_modif_groupe_mots'), generer_url_ecrire("mots_type","id_groupe=$id_groupe"), "groupe-mot-24.gif", "edit.gif");
+		echo "</td>";
+		if (!$supprimer_groupe) {
+			echo "<td>";
+			icone(_T('icone_supprimer_groupe_mots'), generer_url_ecrire("mots_tous","supp_group=$id_groupe"), "groupe-mot-24.gif", "supprimer.gif");
+			echo "</td>";
+			echo "<td> &nbsp; </td>"; // Histoire de forcer "supprimer" un peu plus vers la gauche
+		}
+		echo "<td>";
+		echo "<div align='$spip_lang_right'>";
+		icone(_T('icone_creation_mots_cles'), generer_url_ecrire("mots_edit","new=oui&id_groupe=$id_groupe&redirect=" . generer_url_retour('mots_tous')), "mot-cle-24.gif", "creer.gif");
+		echo "</div>";
+		echo "</td></tr></table>";
+	}	
+
+	fin_cadre_enfonce();
+}
+
+ if (acces_mots()  AND !$conf_mot){
+	echo "<p>&nbsp;</p><div align='right'>";
+	icone(_T('icone_creation_groupe_mots'), generer_url_ecrire("mots_type","new=oui"), "groupe-mot-24.gif", "creer.gif");
+	echo "</div>";
+}
+
+fin_page();
+}
+
+
+//
+// Calculer les nombres d'elements (articles, etc.) lies a chaque mot
+//
+
+// http://doc.spip.org/@calculer_liens_mots
+function calculer_liens_mots()
+{
+
+if ($GLOBALS['connect_statut'] =="0minirezo") $aff_articles = "'prepa','prop','publie'";
+else $aff_articles = "'prop','publie'";
+
+ $articles = array();
+ $result_articles = spip_query("SELECT COUNT(*) as cnt, lien.id_mot FROM spip_mots_articles AS lien, spip_articles AS article	WHERE article.id_article=lien.id_article AND article.statut IN ($aff_articles) GROUP BY lien.id_mot");
+ while ($row =  spip_fetch_array($result_articles)){
+	$articles[$row['id_mot']] = $row['cnt'];
+}
+
+
+ $rubriques = array();
+ $result_rubriques = spip_query("SELECT COUNT(*) AS cnt, lien.id_mot FROM spip_mots_rubriques AS lien, spip_rubriques AS rubrique WHERE rubrique.id_rubrique=lien.id_rubrique GROUP BY lien.id_mot");
+
+ while ($row = spip_fetch_array($result_rubriques)){
+	$rubriques[$row['id_mot']] = $row['cnt'];
+}
+
+ $breves = array();
+ $result_breves = spip_query("SELECT COUNT(*) AS cnt, lien.id_mot FROM spip_mots_breves AS lien, spip_breves AS breve	WHERE breve.id_breve=lien.id_breve AND breve.statut IN ($aff_articles) GROUP BY lien.id_mot");
+
+ while ($row = spip_fetch_array($result_breves)){
+	$breves[$row['id_mot']] = $row['cnt'];
+}
+
+ $syndic = array(); 
+ $result_syndic = spip_query("SELECT COUNT(*) AS cnt, lien.id_mot FROM spip_mots_syndic AS lien, spip_syndic AS syndic WHERE syndic.id_syndic=lien.id_syndic AND syndic.statut IN ($aff_articles) GROUP BY lien.id_mot");
+ while ($row = spip_fetch_array($result_syndic)){
+	$sites[$row['id_mot']] = $row['cnt'];
+
+ }
+
+ return array('articles' => $articles, 
+	      'breves' => $breves, 
+	      'rubriques' => $rubriques, 
+	      'syndic' => $syndic);
+}
+
+// http://doc.spip.org/@afficher_groupe_mots
+function afficher_groupe_mots($id_groupe) {
+	global $connect_id_auteur, $connect_statut;
+	global $spip_lang_right, $couleur_claire, $spip_lang;
+
+	$jjscript = array("fonction" => "afficher_groupe_mots",
+			  "id_groupe" => $id_groupe);
+	$jjscript = (serialize($jjscript));
+	$hash = "0x".substr(md5($connect_id_auteur.$jjscript), 0, 16);
+	$tmp_var = substr($hash, 2, 6);
+			
+	$javascript = "charger_id_url('" . generer_url_ecrire('memoriser',"&var_ajax=1&id_ajax_fonc=::id_ajax_fonc::::deb::", true) . "','$tmp_var')";
+
+	$select = 'id_mot, titre, ' . creer_objet_multi ("titre", $spip_lang);
+	$from = 'spip_mots';
+	$where = "id_groupe=$id_groupe" ;
+
+	$cpt = spip_fetch_array(spip_query("SELECT COUNT(*) AS n FROM $from WHERE $where"));
+
+	if (! ($cpt = $cpt['n'])) return '' ;
+
+	$occurrences = calculer_liens_mots();
+
+	$res_proch = spip_query("SELECT id_ajax_fonc FROM spip_ajax_fonc WHERE hash=$hash AND id_auteur=$connect_id_auteur ORDER BY id_ajax_fonc DESC LIMIT 1");
+	if ($row = spip_fetch_array($res_proch)) {
+			$id_ajax_fonc = $row["id_ajax_fonc"];
+	} else  {
+			include_spip('base/abstract_sql');
+			$id_ajax_fonc = spip_abstract_insert("spip_ajax_fonc", "(id_auteur, variables, hash, date)", "($connect_id_auteur, " . spip_abstract_quote($jjscript) . ", $hash, NOW())");
+	}
+
+	$nb_aff = 1.5 * _TRANCHES;
+	$deb_aff = intval(_request('t_' .$tmp_var));
+	$limit = ($deb_aff >= 0 ? "$deb_aff, $nb_aff" : "99999");
+
+	if ($cpt > $nb_aff) {
+		$nb_aff = (_TRANCHES); 
+		$tranches = afficher_tranches_requete($cpt, 3, $tmp_var, $javascript, $nb_aff);
+	} else $tranches = '';
+
+
+	$table = array();
+	$result = spip_query("SELECT $select FROM $from WHERE $where ORDER BY multi LIMIT  $limit");
+	while ($row = spip_fetch_array($result)) {
+		$table[] = afficher_groupe_mots_boucle($row, $occurrences);
+	}
+
+	if ($connect_statut=="0minirezo") {
+			$largeurs = array('', 100, 130);
+			$styles = array('arial11', 'arial1', 'arial1');
+		}
+	else {
+			$largeurs = array('', 100);
+			$styles = array('arial11', 'arial1');
+	}
+
+	$res = http_img_pack("searching.gif", "*", "style='visibility: hidden; position: absolute; $spip_lang_right: 0px; top: -20px;' id='img_$tmp_var'") 
+	  . "<div class='liste'>"
+	  . "<table border='0' cellspacing='0' cellpadding='3' width='100%'>"
+	  . str_replace("::id_ajax_fonc::", "$id_ajax_fonc", $tranches)
+	  . afficher_liste($largeurs, $table, $styles)
+	  . "</table>"
+	  . "</div>";
+		
+	if ($deb_aff) return $res;
+
+	return "<div id='$tmp_var' style='position: relative;'>$res</div>";
+}
+
+// http://doc.spip.org/@afficher_groupe_mots_boucle
+function afficher_groupe_mots_boucle($row, $occurrences)
+{
+	global $connect_statut, $connect_toutes_rubriques;
+
+	$id_mot = $row['id_mot'];
+	$titre_mot = typo($row['titre']);
+			
+	if ($connect_statut == "0minirezo" OR $occurrences['articles'][$id_mot] > 0)
+		$titre_mot = "<a href='" .
+		  generer_url_ecrire('mots_edit', "id_mot=$id_mot&redirect=" . generer_url_retour('mots_tous')) .
+		  "' class='liste-mot'>$titre_mot</a>";
+
+	$vals = array($titre_mot);
+
+	$texte_lie = array();
+
+	$na = isset($occurrences['articles'][$id_mot]) ? $occurrences['articles'][$id_mot] : 0;
+	if ($na == 1)
+		$texte_lie[] = _T('info_1_article');
+	else if ($na > 1)
+		$texte_lie[] = $na." "._T('info_articles_02');
+
+	$nb = isset($occurrences['breves'][$id_mot]) ? $occurrences['breves'][$id_mot] : 0;
+	if ($nb == 1)
+		$texte_lie[] = _T('info_1_breve');
+	else if ($nb > 1)
+		$texte_lie[] = $nb." "._T('info_breves_03');
+
+	$ns = isset($occurrences['sites'][$id_mot]) ? $occurrences['sites'][$id_mot] : 0;
+	if ($ns == 1)
+		$texte_lie[] = _T('info_1_site');
+	else if ($ns > 1)
+		$texte_lie[] = $ns." "._T('info_sites');
+
+	$nr = isset($occurrences['rubriques'][$id_mot]) ? $occurrences['rubriques'][$id_mot] : 0;
+	if ($nr == 1)
+		$texte_lie[] = _T('info_une_rubrique_02');
+	else if ($nr > 1)
+		$texte_lie[] = $nr." "._T('info_rubriques_02');
+
+	$texte_lie = join($texte_lie,", ");
+				
+	$vals[] = $texte_lie;
+
+	if (acces_mots()) {
+		$href = ($nr OR $na OR $ns OR $nb)
+		? generer_url_ecrire("mots_tous","conf_mot=$id_mot&na=$na&nb=$nb&nr=$nr&ns=$ns")
+		: redirige_action_auteur('editer_mot', ",$id_mot,,,",'mots_tous');
+
+		$vals[] = "<div style='text-align:right;'><a href='$href'>"
+		. _T('info_supprimer_mot')
+		. "&nbsp;<img src='"
+		. _DIR_IMG_PACK
+		. "croix-rouge.gif' alt='X' width='7' height='7' align='bottom' /></a></div>";
+	} 
+	
+	return $vals;			
+}
+?>
Index: plugins/agenda_1_9_1/exec/mots_type.php
===================================================================
--- plugins/agenda_1_9_1/exec/mots_type.php	(revision 6)
+++ plugins/agenda_1_9_1/exec/mots_type.php	(revision 6)
@@ -0,0 +1,251 @@
+<?php
+
+/***************************************************************************\
+ *  SPIP, Systeme de publication pour l'internet                           *
+ *                                                                         *
+ *  Copyright (c) 2001-2006                                                *
+ *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
+ *                                                                         *
+ *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
+ *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
+\***************************************************************************/
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/presentation');
+include_spip('base/agenda_evenements'); // si le plugin existe
+include_spip('base/pim_agenda'); // si le plugin existe
+
+// http://doc.spip.org/@exec_mots_type_dist
+function exec_mots_type_dist()
+{
+  global $connect_statut, $descriptif, $id_groupe, $new, $options, $texte, $titre;
+  global $tables_principales;
+
+  $id_groupe= intval($id_groupe);
+
+if ($connect_statut == '0minirezo' AND $new == "oui") {
+	$id_groupe = '';
+	$type = filtrer_entites(_T('titre_nouveau_groupe'));
+	$onfocus = " onfocus=\"if(!antifocus){this.value='';antifocus=true;}\"";
+	$ancien_type = '';
+	$unseul = 'non';
+	$obligatoire = 'non';
+	$articles = 'oui';
+	$breves = 'oui';
+	$rubriques = 'non';
+	$syndic = 'oui';
+	$evenements = 'non';
+	$pim_agenda = 'non';
+	$acces_minirezo = 'oui';
+	$acces_comite = 'oui';
+	$acces_forum = 'non';
+} else {
+	$result_groupes = spip_query("SELECT * FROM spip_groupes_mots WHERE id_groupe=$id_groupe");
+
+	while($row = spip_fetch_array($result_groupes)) {
+		$id_groupe = $row['id_groupe'];
+		$type = $row['titre'];
+		$titre = typo($type);
+		$descriptif = $row['descriptif'];
+		$texte = $row['texte'];
+		$unseul = $row['unseul'];
+		$obligatoire = $row['obligatoire'];
+		$articles = $row['articles'];
+		$breves = $row['breves'];
+		$rubriques = $row['rubriques'];
+		$syndic = $row['syndic'];
+		if (isset($row['evenements']))
+			$evenements = $row['evenements'];
+		if (isset($row['pim_agenda']))
+			$pim_agenda = $row['pim_agenda'];
+		$acces_minirezo = $row['minirezo'];
+		$acces_comite = $row['comite'];
+		$acces_forum = $row['forum'];
+		$onfocus ="";
+		$new = '';
+	}
+}
+
+pipeline('exec_init',array('args'=>array('exec'=>'mots_types','id_groupe'=>$id_groupe),'data'=>''));
+debut_page("&laquo; $titre &raquo;", "naviguer", "mots");
+
+debut_gauche();
+
+
+
+echo pipeline('affiche_gauche',array('args'=>array('exec'=>'mots_types','id_groupe'=>$id_groupe),'data'=>''));
+creer_colonne_droite();
+echo pipeline('affiche_droite',array('args'=>array('exec'=>'mots_types','id_groupe'=>$id_groupe),'data'=>''));
+debut_droite();
+
+debut_cadre_relief("groupe-mot-24.gif");
+
+
+
+echo "\n<table cellpadding=0 cellspacing=0 border=0 width='100%'>";
+echo "<tr width='100%'>";
+
+	echo "<td  align='right' valign='top'>";
+	icone(_T('icone_retour'), generer_url_ecrire("mots_tous",""), "mot-cle-24.gif", "rien.gif");
+	echo "</td>";
+	echo "<td>". http_img_pack('rien.gif', " ", "width='5'") . "</td>\n";
+
+echo "<td width='100%' valign='top'>";
+echo "<font face='Verdana,Arial,Sans,sans-serif' size=1><b>"._T('titre_groupe_mots')."</b><br></font>";
+gros_titre($titre);
+echo aide("motsgroupes");
+
+if ($connect_statut =="0minirezo"){
+	$type=entites_html(rawurldecode($type));
+	echo "<p><font face='Verdana,Arial,Sans,sans-serif'>";
+	echo generer_url_post_ecrire("mots_tous", "id_groupe=$id_groupe");
+	echo "<input type='hidden' name='modifier_groupe' value='oui' />\n";
+	echo "<input type='hidden' name='new' value='$new' />\n";
+	debut_cadre_formulaire();
+	echo "<b>"._T('info_changer_nom_groupe')."</b><br />\n";
+	echo "<INPUT TYPE='Text' SIZE=40 CLASS='formo' NAME='change_type' VALUE=\"$type\" $onfocus />\n";
+
+	if ($options == 'avancees' OR $descriptif) {
+		echo "<B>"._T('texte_descriptif_rapide')."</B><BR>";
+		echo "<TEXTAREA NAME='descriptif' CLASS='forml' ROWS='4' COLS='40' wrap=soft>";
+		echo entites_html($descriptif);
+		echo "</TEXTAREA><P>\n";
+	}
+	else
+		echo "<INPUT TYPE='hidden' NAME='descriptif' VALUE=\"$descriptif\">";
+
+	if ($options == 'avancees' OR $texte) {
+		echo "<B>"._T('info_texte_explicatif')."</B><BR>";
+		echo "<TEXTAREA NAME='texte' ROWS='8' CLASS='forml' COLS='40' wrap=soft>";
+		echo entites_html($texte);
+		echo "</TEXTAREA><P>\n";
+	}
+	else
+		echo "<INPUT TYPE='hidden' NAME='texte' VALUE=\"$texte\">";
+
+
+	echo "<p><div align='right'><INPUT TYPE='submit' CLASS='fondo' NAME='Valider' VALUE='"._T('bouton_valider')."'></div>";
+	fin_cadre_formulaire();
+}
+
+
+echo "</td></tr></table>";
+
+
+
+fin_cadre_relief();
+
+if ($connect_statut =="0minirezo"){
+	echo "<p>";
+	debut_cadre_formulaire();
+	echo "<div style='padding: 5px; border: 1px dashed #aaaaaa; background-color: #dddddd;'>";
+		echo "<b>"._T('info_mots_cles_association')."</b>";
+		echo "<ul>";
+		
+		if ($articles == "oui") $checked = "checked";
+		else $checked = "";
+		echo "<input type='checkbox' name='articles' value='oui' $checked id='articles'> <label for='articles'>"._T('item_mots_cles_association_articles')."</label><br>";
+		$activer_breves = $GLOBALS['meta']["activer_breves"];
+		if ($activer_breves != "non"){
+			if ($breves == "oui") $checked = "checked";
+			else $checked = "";
+			echo "<input type='checkbox' name='breves' value='oui' $checked id='breves'> <label for='breves'>"._T('item_mots_cles_association_breves')."</label><br>";
+		} else {
+			echo "<input type='hidden' name='breves' value='non'>";
+		}
+		if ($rubriques == "oui") $checked = "checked";
+		else $checked = "";
+		echo "<input type='checkbox' name='rubriques' value='oui' $checked id='rubriques'> <label for='rubriques'>"._T('item_mots_cles_association_rubriques')."</label><br>";
+		if ($syndic == "oui") $checked = "checked";
+		else $checked = "";
+		echo "<input type='checkbox' name='syndic' value='oui' $checked id='syndic'> <label for='syndic'>"._T('item_mots_cles_association_sites')."</label>";
+		
+		if (isset($tables_principales['spip_evenements'])){
+			echo "<br>";
+			if ($evenements == "oui") $checked = "checked";
+			else $checked = "";
+			echo "<input type='checkbox' name='evenements' value='oui' $checked id='evenements'> <label for='evenements'>"._T('agenda:item_mots_cles_association_evenements')."</label>";
+		}
+		if (isset($tables_principales['spip_pim_agenda'])){
+			echo "<br>";
+			if ($pim_agenda == "oui") $checked = "checked";
+			else $checked = "";
+			echo "<input type='checkbox' name='pim_agenda' value='oui' $checked id='pim_agenda'> <label for='pim_agenda'>"._T('pimagenda:item_mots_cles_association_evenements')."</label>";
+		}
+	
+		echo "</ul>";
+	echo "</div>";
+
+
+	$config_precise_groupes = $GLOBALS['meta']["config_precise_groupes"];
+	if ($config_precise_groupes == "oui" OR $unseul == "oui" OR $obligatoire == "oui"){
+		echo "<p><div style='padding: 5px; border: 1px dashed #aaaaaa; background-color: #dddddd;'>";
+
+		if ($unseul == "oui")
+			$checked = "checked";
+		else
+			$checked = "";
+		echo "<input type='checkbox' name='unseul' value='oui' $checked id='unseul'> <label for='unseul'>"._T('info_selection_un_seul_mot_cle')."</label>";
+		echo "<br>";
+
+		if ($obligatoire == "oui")
+			$checked = "checked";
+		else $checked = "";
+		echo "<input type='checkbox' name='obligatoire' value='oui' $checked id='obligatoire'> <label for='obligatoire'>"._T('avis_conseil_selection_mot_cle')."</label>";
+
+		echo "</div>";
+	} else {
+		echo "<input type='hidden' name='unseul' value='non'>";
+		echo "<input type='hidden' name='obligatoire' value='non'>";
+	}
+
+
+	
+	echo "<p>";
+	echo "<div style='padding: 5px; border: 1px dashed #aaaaaa; background-color: #dddddd;'>";
+		echo "<b>"._T('info_qui_attribue_mot_cle')."</b>";
+		echo "<ul>";
+		
+		if ($acces_minirezo == "oui") $checked = "checked";
+		else $checked = "";
+		echo "<input type='checkbox' name='acces_minirezo' value='oui' $checked id='administrateurs'> <label for='administrateurs'>"._T('bouton_checkbox_qui_attribue_mot_cle_administrateurs')."</label><br>";
+		if ($acces_comite == "oui") $checked = "checked";
+		else $checked = "";
+		echo "<input type='checkbox' name='acces_comite' value='oui' $checked id='comite'> <label for='comite'>"._T('bouton_checkbox_qui_attribue_mot_cle_redacteurs')."</label><br>";
+	
+		$mots_cles_forums = $GLOBALS['meta']["mots_cles_forums"];
+		$forums_publics=$GLOBALS['meta']["forums_publics"];
+		
+		if (($mots_cles_forums == "oui" OR $acces_forum == "oui") AND $forums_publics != "non"){
+			if ($acces_forum == "oui") $checked = "checked";
+			else $checked = "";
+			echo "<input type='checkbox' name='acces_forum' value='oui' $checked id='forum'> <label for='forum'>"._T('bouton_checkbox_qui_attribue_mot_cle_visiteurs')."</label>";
+		} 
+		else {
+			echo "<input type='hidden' name='acces_forum' value='non'>";
+		}
+			
+		echo "</ul>";
+	echo "</div>";
+	
+	
+	
+
+	echo "<p><div align='right'><INPUT TYPE='submit' CLASS='fondo' NAME='Valider' VALUE='"._T('bouton_valider')."'></div>";
+	echo "</FORM><P>";
+	fin_cadre_formulaire();	
+	echo "</font>";
+
+
+}else{
+
+	echo "<H3>"._T('avis_non_acces_page')."</H3>";
+
+}
+
+
+fin_page();
+}
+
+?>
Index: plugins/agenda_1_9_1/formulaires/calendrier_mini.html
===================================================================
--- plugins/agenda_1_9_1/formulaires/calendrier_mini.html	(revision 6)
+++ plugins/agenda_1_9_1/formulaires/calendrier_mini.html	(revision 6)
@@ -0,0 +1,35 @@
+<div id="calendar">
+	<h2><BOUCLE_titre(ARTICLES){id_article}>#TITRE</BOUCLE_titre><:icone_calendrier:><//B_titre></h2>
+	<table summary="<:icone_calendrier:>">
+		<caption>[
+			<a
+				href="(#ENV{self}|parametre_url{#ENV{var_date},[(#ENV{date}|Agenda_dateplus{-27*24*3600,'Y-m'})]})"
+				title="[(#ENV{date}|Agenda_dateplus{-27*24*3600,'Y-m'}|affdate_mois_annee)]">&#171;</a>][
+			(#ENV{date}|affdate_mois_annee)][
+			<a
+				href="(#ENV{self}|parametre_url{#ENV{var_date},[(#ENV{date}|Agenda_dateplus{33*24*3600,'Y-m'})]})"
+				title="[(#ENV{date}|Agenda_dateplus{33*24*3600,'Y-m'}|affdate_mois_annee)]">&#187;</a>]
+		</caption>
+		<thead>
+			<tr>
+				<th scope="col"><abbr title="<:date_jour_2:>"><:date_jour_2|spip_substr{0,1}|strtoupper:></abbr></th>
+				<th scope="col"><abbr title="<:date_jour_3:>"><:date_jour_3|spip_substr{0,1}|strtoupper:></abbr></th>
+				<th scope="col"><abbr title="<:date_jour_4:>"><:date_jour_4|spip_substr{0,1}|strtoupper:></abbr></th>
+				<th scope="col"><abbr title="<:date_jour_5:>"><:date_jour_5|spip_substr{0,1}|strtoupper:></abbr></th>
+				<th scope="col"><abbr title="<:date_jour_6:>"><:date_jour_6|spip_substr{0,1}|strtoupper:></abbr></th>
+				<th scope="col"><abbr title="<:date_jour_7:>"><:date_jour_7|spip_substr{0,1}|strtoupper:></abbr></th>
+				<th scope="col"><abbr title="<:date_jour_1:>"><:date_jour_1|spip_substr{0,1}|strtoupper:></abbr></th>
+			</tr>
+		</thead>
+		<tbody><BOUCLE_calendrier(EVENEMENTS)
+			{id_article}{id_mot?}
+			{agenda date_debut, mois, (#ENV{date}|annee), (#ENV{date}|mois)}>[
+			(#DATE_DEBUT|Agenda_memo_full{#DATE_FIN,[(#TITRE|addslashes)],
+				#DESCRIPTIF,#LIEU,
+				[(#ENV{self}|parametre_url{#ENV{var_date},[(#DATE_DEBUT|affdate{'Y-m-d'})]})]})
+			]</BOUCLE_calendrier>[
+			(#ENV{date}|agenda_mini)
+			]</tbody>
+	</table>
+	<span>&nbsp;</span>
+</div>
Index: plugins/agenda_1_9_1/formulaires/formulaire_edition_evenement.html
===================================================================
--- plugins/agenda_1_9_1/formulaires/formulaire_edition_evenement.html	(revision 6)
+++ plugins/agenda_1_9_1/formulaires/formulaire_edition_evenement.html	(revision 6)
@@ -0,0 +1,116 @@
+<a name='evenement#ID_EVENEMENT'></a>
+<form method='post' action='#ENV{self}#evenement#ID_EVENEMENT'>
+	<div>
+	[(#ENV{self}|form_hidden)]
+	[<input type='hidden' name='id_evenemnt' value='(#ENV{id_evenemnt})' />]
+	<input type='hidden' name='#ENV{evenement_action}' value='1' />
+	
+	</div>
+<fieldset class='agenda-visu-evenement' id='agenda-visu-evenement'>
+<div class='agenda-visu-evenement-bouton-fermer'>
+<a href='[(#ENV{self}|parametre_url{id_evenement,''})]'
+onclick="setvisibility('agenda-visu-evenement', 'hidden');
+setvisibility('afficher_horaire_debut_evenement', 'hidden');
+setvisibility('afficher_horaire_fin_evenement', 'hidden');
+cal_repetitions.hide();
+return false;"><img src='#CHEMIN{img_pack/croix.png}' width='12' height='12' style='border:none;'></a>
+</div>
+<legend>[(#ENV{id_evenement}|?{<:agenda:titre_cadre_modifier_evenement:>,<:agenda:titre_cadre_ajouter_evenement:>})]</legend>
+
+[(#REM) TITRE]
+<span class='titre-titre'>
+	<label for="evenement_titre"><:agenda:evenement_titre:></label>
+	[<span class='spip_form_label_obligatoire[(#ENV**{erreur}|table_valeur{evenement_titre}|?{' ',''})obligatoire_oublie]'>
+		(#ENV**{obligatoire}|table_valeur{evenement_titre}|?{<:agenda:info_obligatoire:>,''})</span>]
+</span>
+<span class='titre-visu'>
+	<input type='text' name='evenement_titre' id='evenement_titre' value="[(#ENV**{valeurs}|table_valeur{evenement_titre,''}|entites_html)]" 
+		class='[(#ENV**{obligatoire}|table_valeur{evenement_titre}|?{forml,formo})][(#ENV**{erreur}|table_valeur{evenement_titre}|?{' ',''}) champ_obli_oubli]' 
+		onfocus="this.className='[(#ENV**{obligatoire}|table_valeur{evenement_titre}|=={oui}|?{forml,formo})]-focus'" 
+		onblur="this.className='[(#ENV**{obligatoire}|table_valeur{evenement_titre}|=={oui}|?{forml,formo})]'" />
+</span>
+[(#REM) LIEU]
+<span class='lieu-titre'>
+	<label for="evenement_lieu"><:agenda:evenement_lieu:></label>
+	[<span class='spip_form_label_obligatoire[(#ENV**{erreur}|table_valeur{evenement_lieu}|?{' ',''})obligatoire_oublie]'>
+		(#ENV**{obligatoire}|table_valeur{evenement_lieu}|?{<:agenda:info_obligatoire:>,''})</span>]
+</span>
+<span class='lieu-visu'>
+	<input type='text' name='evenement_lieu' id='evenement_lieu' value="[(#ENV**{valeurs}|table_valeur{evenement_lieu,''}|entites_html)]" 
+		class='[(#ENV**{obligatoire}|table_valeur{evenement_lieu}|?{forml,formo})][(#ENV**{erreur}|table_valeur{evenement_lieu}|?{' ',''}) champ_obli_oubli]' 
+		onfocus="this.className='[(#ENV**{obligatoire}|table_valeur{evenement_lieu}|=={oui}|?{forml,formo})]-focus'" 
+		onblur="this.className='[(#ENV**{obligatoire}|table_valeur{evenement_lieu}|=={oui}|?{forml,formo})]'" />
+</span>
+
+[(#REM) HORAIRE]
+<span class='horaire-titre'>
+	<label for="evenement_lieu"><:agenda:evenement_horaire:></label>
+	<input type='checkbox' name='evenement_horaire' value='oui' [(#ENV**{valeurs}|table_valeur{evenement_horaire,''}|=={oui}|?{' ',''})checked='checked']
+		onClick="var element =  findObj('evenement_horaire');var choix = element.checked;
+	if (choix==true){	setvisibility('afficher_horaire_debut_evenement', 'visible');setvisibility('afficher_horaire_fin_evenement', 'visible');}
+	else{setvisibility('afficher_horaire_debut_evenement', 'hidden');setvisibility('afficher_horaire_fin_evenement', 'hidden');}" />
+</span>
+
+[(#REM) DATES]
+<span class='date-titre'><:pimagenda:evenement_date:></span>
+<span class='date-visu'>
+<:pimagenda:evenement_date_de:>
+[(#ENV**{valeurs}|table_valeur{date_evenement_debut}|WCalendar_controller{'_evenement_debut'})]
+<span class='agenda_visible_au_chargement' id='afficher_horaire_debut_evenement'>
+<:pimagenda:evenement_date_a:>
+[(#ENV**{valeurs}|table_valeur{date_evenement_debut}|PIMAgenda_heure_selector{'_debut'})]
+</span>
+<br/>
+<:pimagenda:evenement_date_au:>
+[(#ENV**{valeurs}|table_valeur{date_evenement_fin}|WCalendar_controller{'_evenement_fin'})]
+<span class='agenda_visible_au_chargement' id='afficher_horaire_fin_evenement'>
+<:pimagenda:evenement_date_a:>
+[(#ENV**{valeurs}|table_valeur{date_evenement_fin}|PIMAgenda_heure_selector{'_fin'})]
+</span>
+</span>
+
+[(#REM) DESCRIPTIF]
+<span class='descriptif-titre'>
+	<label for="evenement_descriptif"><:agenda:evenement_descriptif:></label>
+	[<span class='spip_form_label_obligatoire[(#ENV**{erreur}|table_valeur{evenement_descriptif}|?{' ',''})obligatoire_oublie]'>
+		(#ENV**{obligatoire}|table_valeur{evenement_descriptif}|?{<:agenda:info_obligatoire:>,''})</span>]
+</span>
+<span class='descriptif-visu'>
+	<textarea name='evenement_descriptif' id='evenement_descriptif'  
+		class='[(#ENV**{obligatoire}|table_valeur{evenement_descriptif}|?{forml,formo})][(#ENV**{erreur}|table_valeur{evenement_descriptif}|?{' ',''}) champ_obli_oubli]' 
+		onfocus="this.className='[(#ENV**{obligatoire}|table_valeur{evenement_descriptif}|=={oui}|?{forml,formo})]-focus'" 
+		onblur="this.className='[(#ENV**{obligatoire}|table_valeur{evenement_descriptif}|=={oui}|?{forml,formo})]'" 
+		rows='3' >[(#ENV**{valeurs}|table_valeur{evenement_descriptif,''}|entites_html)]</textarea>
+</span>
+
+[(#REM) MOTS CLES : chaque groupe de mot cle attribuable a un evenement agenda
+	donne un select ]
+<span class='agenda_mots_cles'>
+<BOUCLE_groupes(GROUPES_MOTS){evenements='oui'}>
+	<select name='evenement_groupe_mot_select_#ID_GROUPE[]' class='fondl verdana1 agenda_mot_cle_select'[
+	(#UNSEUL|=={'oui'}|?{'',' '}) multiple='multiple' size='4']>
+	[<option value='x' style='font-variant: small-caps;' [
+	(#UNSEUL|=={'oui'}|?{'',' '}) disabled='disabled']>(#TITRE|supprimer_numero)</option>]
+	<BOUCLE_mots(MOTS){id_groupe}>
+		<option value='#ID_MOT'
+		[(#ID_MOT|in_any([(#ENV**{valeurs}|table_valeur{mots})selected='selected']>#TITRE</option>
+	</BOUCLE_mots>
+	</select>
+</BOUCLE_groupes>
+</span>
+<script type='text/javascript' src='#CHEMIN{img_pack/multiselect.js}'></script>
+<span class='repetitions-calendrier' id='repetitions-calendrier'>
+[(#ENV**{valeurs}|table_valeur{repetitions}|WCalendar_statique_controller{'_repetitions'})]
+</span>
+
+<div class='edition-bouton' style='text-align:#LANG_RIGHT'>
+[(#ENV{evenement_action}|=={'evenement_modif'}|?{' ',''})
+<div style='float:#LANG_LEFT'>
+<input type='submit' name='supp_evenement' value='<:agenda:bouton_supprimer:>' class="fondl" />
+</div>
+]
+<input type='submit' name='cancel' value='<:agenda:bouton_annuler:>' class="fondl" />
+<input type='submit' name='ajouter' value='[(#ENV{evenement_action}|=={'evenement_modif'}|?{<:bouton_enregistrer:>,<:bouton_ajouter:>})]' class='fondo spip_boutons' onclick='javascript:getSelectedDate_repetitions()'>
+</div>
+</fieldset>
+</form>
Index: plugins/agenda_1_9_1/ical-agenda.html
===================================================================
--- plugins/agenda_1_9_1/ical-agenda.html	(revision 6)
+++ plugins/agenda_1_9_1/ical-agenda.html	(revision 6)
@@ -0,0 +1,20 @@
+#HTTP_HEADER{content-type:text/calendar}
+BEGIN:VCALENDAR
+CALSCALE:GREGORIAN
+X-WR-CALNAME;VALUE=TEXT:<BOUCLE_article (ARTICLES) {id_article}>[(#TITRE|filtrer_ical)] </BOUCLE_article>[[(#NOM_SITE_SPIP|filtrer_ical)]]
+X-WR-RELCALID:#URL_SITE_SPIP
+
+<BOUCLE_evemnt (EVENEMENTS) {id_article ?}>
+BEGIN:VEVENT
+SUMMARY:[(#TITRE|filtrer_ical)]
+UID:evenement#ID_EVENEMENT @ #URL_SITE_SPIP
+DTSTAMP:[(#DATE_DEBUT|date_ical)]
+DTSTART:[(#DATE_DEBUT|date_ical)]
+DTEND:[(#DATE_FIN|date_ical)]
+<B_article2>CATEGORIES:<BOUCLE_article2 (ARTICLES) {id_article=#ID_ARTICLE}>[(#TITRE|filtrer_ical)]</BOUCLE_article2>
+DESCRIPTION:[(#DESCRIPTIF|filtrer_ical)]\n[<:lieu:>(#LIEU|filtrer_ical)]
+STATUS:CONFIRMED
+END:VEVENT
+</BOUCLE_evemnt>
+
+END:VCALENDAR
Index: plugins/agenda_1_9_1/img_pack/agenda.css
===================================================================
--- plugins/agenda_1_9_1/img_pack/agenda.css	(revision 6)
+++ plugins/agenda_1_9_1/img_pack/agenda.css	(revision 6)
@@ -0,0 +1,262 @@
+.agenda_invisible_au_chargement {
+	visibility: hidden;
+}
+.agenda_visible_au_chargement {
+	visibility: visible;
+}
+#container_debut,#container_fin{
+	left:0px;
+	top:0px;
+	z-index:150;
+	filter:alpha(opacity=100);
+	opacity: 1.0;
+	-moz-opacity:1.0;
+}
+
+.agenda-calendrier {
+	width: 100%;
+	height: 60%;
+	font-weight: bold;
+	background-color: none;
+  }
+
+.agenda-visu-evenement {
+	position: absolute;
+	right :0px;
+	top :100px;
+	width: 400px;
+	height: 47em;
+	border-bottom: 1px solid #cccccc;
+	font-weight: bold;
+	z-index:100;
+	-moz-border-radius-topleft: 8px;
+	-moz-border-radius-bottomleft: 8px;
+	border-radius-topleft: 8px;
+	border-radius-bottomleft: 8px;
+	font-family: Verdana, Arial, Sans, sans-serif;
+	font-size:small;
+  background-color: #F0FFC2;
+	filter:alpha(opacity=80);
+	opacity: 0.8;
+	-moz-opacity:0.8;
+	text-align:left;
+ }
+.agenda-visu-evenement-bouton-fermer{
+	position: absolute;
+	right:1em;
+	top:0px;
+	width:12px;
+	height:12px;
+}
+.agenda-visu-evenement-bouton-fermer a:hover{
+	border-color:#cccccc;
+	border-top:1px solid #cccccc;
+	border-left:1px solid #cccccc;
+	border-bottom:2px solid #cccccc;
+	border-right:2px solid #cccccc;
+}
+
+.article-evenement {
+	position: absolute;
+	top :0;
+	left :0px;
+	width : 100%;
+	height : 4em;
+	border-top: 1px solid #cccccc;
+	border-bottom: 1px solid #cccccc;
+	border-left: 1px solid #cccccc;
+	border-right: 1px solid #cccccc;
+	-moz-border-radius-topleft: 8px;
+	-moz-border-radius-topright: 8px;
+	border-radius-topleft: 8px;
+	border-radius-topright: 8px;
+	font-weight: bold;
+	background-color: #ccff66;
+ }
+
+.titre-titre {
+	position: absolute;
+	top :4em;
+	left :0px;
+	width : 20%;
+	height : 1.5em;
+	border-top: 1px solid #cccccc;
+	border-bottom: 1px solid #cccccc;
+	border-left: 1px solid #cccccc;
+	font-weight: bold;
+	background-color: #ccff66;
+ }
+.titre-visu {
+	position: absolute;
+	top :4em;
+	left :20%;
+	width : 80%;
+	height : 1.5em;
+	border-top: 1px solid #cccccc;
+	border-bottom: 1px solid #cccccc;
+	border-right: 1px solid #cccccc;
+	font-weight: bold;
+	background-color: #ccff99;
+ }
+
+.lieu-titre {
+	position: absolute;
+	top :5.5em;
+	left :0px;
+	width : 20%;
+	height : 1.5em;
+	border-top: 1px solid #cccccc;
+	border-bottom: 1px solid #cccccc;
+	border-left: 1px solid #cccccc;
+	-moz-border-radius-bottomleft: 8px;
+	border-radius-bottomleft: 8px;
+	font-weight: bold;
+	background-color: #ccff66;
+ }
+.lieu-visu {
+	position: absolute;
+	top :5.5em;
+	left :20%;
+	width : 80%;
+	height : 1.5em;
+	border-top: 1px solid #cccccc;
+	border-bottom: 1px solid #cccccc;
+	border-right: 1px solid #cccccc;
+	-moz-border-radius-bottomright: 8px;
+	border-radius-bottomright: 8px;
+	font-weight: bold;
+	background-color: #ccff99;
+ }
+.horaire-titre {
+	position: absolute;
+	top :7.1em;
+	left :20%;
+	width : 80%;
+	height : 2em;
+	border-top: 1px solid #cccccc;
+	border-right: 1px solid #cccccc;
+	-moz-border-radius-topright: 8px;
+	border-radius-topright: 8px;
+	font-weight: bold;
+	background-color: #ccff66;
+ }
+.date-titre {
+	position: absolute;
+	top :7.1em;
+	left :0px;
+	width : 20%;
+	height : 2em;
+	border-top: 1px solid #cccccc;
+	border-left: 1px solid #cccccc;
+	-moz-border-radius-topleft: 8px;
+	border-radius-topleft: 8px;
+	font-weight: bold;
+	background-color: #ccff66;
+ }
+.date-visu {
+	position: absolute;
+	top :9em;
+	left :0%;
+	width : 100%;
+	height : 5em;
+	border-top: 1px solid #cccccc;
+	border-bottom: 1px solid #cccccc;
+	border-right: 1px solid #cccccc;
+	-moz-border-radius-bottomright: 8px;
+	border-radius-bottomright: 8px;
+	-moz-border-radius-bottomleft: 8px;
+	border-radius-bottomleft: 8px;
+	font-weight: bold;
+	background-color: #ccff99;
+ }
+.descriptif-titre {
+	visibility: hidden;
+ }
+.descriptif-visu {
+	position: absolute;
+	top :14em;
+	left :0px;
+	width : 100%;
+	height: 6em;
+	border-top: 1px solid #cccccc;
+	border-bottom: 1px solid #cccccc;
+	border-right: 1px solid #cccccc;
+	border-radius-topright: 8px;
+	border-radius-bottomright: 8px;
+	border-radius-topleft: 8px;
+	border-radius-bottomleft: 8px;
+	font-weight: bold;
+	background-color: #ccff99;
+ }
+.agenda_mot_cle_select{
+width:49%;
+}
+.agenda_mots_cles{
+	position: absolute;
+	left:0px;
+	top:20em;
+	height:8em;
+	width:100%;
+	font-weight: bold;
+	background-color: #ccff99;
+}
+.repetitions-calendrier{
+	position: absolute;
+	left:0px;
+	top:28em;
+	height:17em;
+	width:100%;
+}
+.edition-bouton {
+	position: absolute;
+	bottom :0em;
+	left :0%;
+	width : 98%;
+	height:2em;
+	border-top: 1px solid #cccccc;
+	border-bottom: 1px solid #cccccc;
+	border-right: 1px solid #cccccc;
+	text-align : right;
+	vertical-align : bottom;
+	padding-right:2%;
+	-moz-border-radius-topright: 8px;
+	-moz-border-radius-bottomright: 8px;
+	-moz-border-radius-topleft: 8px;
+	-moz-border-radius-bottomleft: 8px;
+	border-radius-topright: 8px;
+	border-radius-bottomright: 8px;
+	border-radius-topleft: 8px;
+	border-radius-bottomleft: 8px;
+	font-weight: bold;
+	background-color: #99cc33;
+ }
+a span.survol {
+	display: none;
+}
+
+a:hover .calendrier-verdana10 > span.survol {
+	display: block;
+	position: fixed;
+	top: auto;
+	left: auto;
+	width: auto;
+	padding: 5px;
+	z-index: 100;
+	text-decoration: none;
+  color: #333;
+	background: #ccff99;
+	border: solid 1px #99cc33;
+	font: 10px Verdana, sans-serif;
+	text-align: left;
+	-moz-border-radius-topright: 8px;
+	-moz-border-radius-bottomright: 8px;
+	-moz-border-radius-topleft: 8px;
+	-moz-border-radius-bottomleft: 8px;
+	border-radius-topright: 8px;
+	border-radius-bottomright: 8px;
+	border-radius-topleft: 8px;
+	border-radius-bottomleft: 8px;
+	filter:alpha(opacity=80);
+	opacity: 0.8;
+	-moz-opacity:0.8;
+}
Index: plugins/agenda_1_9_1/img_pack/agenda_articles.css
===================================================================
--- plugins/agenda_1_9_1/img_pack/agenda_articles.css	(revision 6)
+++ plugins/agenda_1_9_1/img_pack/agenda_articles.css	(revision 6)
@@ -0,0 +1,84 @@
+.agenda_invisible_au_chargement {
+	visibility: hidden;
+}
+.agenda_visible_au_chargement {
+	visibility: visible;
+}
+.agenda-visu-evenement-bouton-fermer{
+display:none;
+}
+#container_debut{
+left:0px;
+top:0px;
+z-index:120;
+}
+#container_fin{
+left:0px;
+top:0px;
+z-index:120;
+}
+.agenda_mot_cle_select{
+float:left;
+width:32%;
+margin-right:0.5em;
+}
+.titre-titre {
+float:left;
+	width : 13%;
+	height : 2em;
+	font-weight: bold;
+ }
+.titre-visu {
+float:left;
+	width : 85%;
+	height : 2em;
+	font-weight: bold;
+ }
+.lieu-titre {
+float:left;
+	width : 13%;
+	height : 2em;
+	font-weight: bold;
+ }
+.lieu-visu {
+float:left;
+	width : 85%;
+	height : 2em;
+	font-weight: bold;
+}
+.horaire-titre {
+float:right;
+	width : 40%;
+	height : 2em;
+	font-weight: bold;
+ }
+.date-titre {
+float:left;
+	width : 58%;
+	height : 2em;
+	font-weight: bold;
+ }
+.date-visu {
+float:left;
+	width : 98%;
+	height : 5em;
+	font-weight: bold;
+}
+.descriptif-titre {
+float:left;
+	left :0px;
+	width : 98%;
+	height : 2em;
+	font-weight: bold;
+ }
+.descriptif-visu {
+float:left;
+	left :0%;
+	width : 98%;
+	height : 6em;
+	font-weight: bold;
+}
+.edition-bouton{
+float:right;
+margin-top:0.5em;
+}
Index: plugins/agenda_1_9_1/img_pack/calendrier.css
===================================================================
--- plugins/agenda_1_9_1/img_pack/calendrier.css	(revision 6)
+++ plugins/agenda_1_9_1/img_pack/calendrier.css	(revision 6)
@@ -0,0 +1,511 @@
+/*
+ * Styles du calendrier
+ */
+
+.calendrier-arial9 {
+	font-family: Arial, Sans, sans-serif; font-size: 9px;
+}
+
+.calendrier-arial10 {
+	font-family: Arial, Sans, sans-serif; font-size: 10px;
+}
+
+.calendrier-arial11 {
+	font-family: Arial, Sans, sans-serif; font-size: 11px;
+}
+
+.calendrier-verdana10 {
+	font-family: Verdana, Arial, Sans, sans-serif; font-size: 10px;
+}
+
+.calendrier-helvetica16 {
+	font-family: arial,helvetica,sans-serif;
+	font-size: 16px;
+	color: black;
+}
+
+div.navigation-calendrier {
+	color: white;
+	background-color: #99cc33;
+	font-family: verdana, arial, sans,sans-serif;
+	font-weight: bold;
+	font-size: 14px;
+}
+
+div.navigation-calendrier img {
+	border: 0px;
+	vertical-align: middle;
+	margin: 1px;
+}
+
+a.calendrier-annee {
+	background-color: #aaaaaa;
+	padding: 3px;
+	margin: 1px;
+	font-family: verdana, arial, sans,sans-serif;
+	font-size: 10px;
+	font-weight: bold;
+	color: white;
+	-moz-border-radius: 5px;
+}
+
+a.calendrier-annee:hover {
+	color: black;
+	background-color: white;
+}
+
+.calendrier-table-large {
+	border: 0px;
+	width: 900px;
+ }
+
+.calendrier-table-etroit {
+	border: 0px;
+	width: 750px;
+ }
+
+.calendrier-td-centre {
+	width: 550px;
+	padding-left: 25px;
+	padding-right: 25px;
+  	vertical-align: top;
+ }
+
+.calendrier-td {
+	width: 14%;
+  	vertical-align: top;
+ }
+
+.calendrier-th {
+	width: 14%;
+	padding: 5px;
+	text-align: center;
+  	vertical-align: center;
+	font-size: 10px;
+	font-weight: bold;
+	font-family: Verdana, Arial, Sans, sans-serif;
+ }
+
+.calendrier-th a {
+  color: black;
+}
+
+.calendrier-table-etroit  .calendrier-td-gauche {
+	width: 0px;
+  	vertical-align: top;
+ }
+
+.calendrier-table-large  .calendrier-td-gauche {
+	width: 150px;
+  	vertical-align: top;
+ }
+
+.calendrier-table-etroit  .calendrier-td-droit {
+	width: 150px;
+  	vertical-align: top;
+ }
+
+.calendrier-table-large  .calendrier-td-droit {
+	width: 150px;
+  	vertical-align: top;
+ }
+
+.calendrier-jour {
+	position: relative;
+	color: #999999;
+	background-color: white;
+	border: 1px solid #aaaaaa;
+}
+
+.calendrier-agenda {
+	margin-left: 1px;
+	margin-top: 1px;
+	padding: 1px;
+	text-align: center;
+	background-color: white;
+	-moz-border-radius: 5px;
+ }
+
+.calendrier-demiagenda {
+	margin-left: 0px;
+	margin-top: 0px;
+	padding: 0px;
+	text-align: center;
+	background-color: white;
+	-moz-border-radius: 5px;
+ }
+
+
+.calendrier-tripleagenda {
+	vertical-align: top;
+	width: 33%;
+ }
+
+.calendrier-cadreagenda {
+	visibility: hidden;
+	width: 100%;
+	position: absolute;
+	padding-top: 5px;
+	padding-bottom: 5px;
+	border: 0px;
+	background-color: #ccff99;
+	-moz-border-radius-bottomleft: 8px;
+	-moz-border-radius-bottomright: 8px;
+ }
+
+.calendrier-titre {
+	padding: 5px;
+	text-align: center;
+	font-weight: bold;
+ }
+
+.calendrier-evenement {
+	padding: 2px;
+	margin-top: 2px;
+ }
+
+.calendrier-heurepile {
+	position: absolute;
+	margin-left: 2px;
+	margin-right: 2px;
+	border-top: 1px solid #cccccc;
+	font-weight: bold;
+	width: 100%;
+ }
+
+.calendrier-heurepile a {
+	color : #777777;
+	font-weight: bold;
+ }
+
+.calendrier-heurepile a:hover {
+	position: absolute;
+	border-bottom: 1px solid #cccccc;
+	font-weight: bold;
+	background-color: #ccff99;
+	width: 100%;
+ }
+
+.calendrier-heureface {
+	position: absolute;
+	margin-left: 2px;
+	margin-right: 2px;
+	border-top: 1px solid #cccccc;
+ }
+
+.calendrier-mozleft {
+	-moz-border-radius-topleft: 10px;
+	-moz-border-radius-bottomleft: 10px;
+ }
+
+.calendrier-mozright {
+	-moz-border-radius-topright: 10px;
+	-moz-border-radius-bottomright: 10px;
+ }
+
+.calendrier-moztop8 {
+	-moz-border-radius-topleft: 8px;
+	-moz-border-radius-topright: 8px;
+}
+
+.calendrier-mozbottom8 {
+	-moz-border-radius-bottomleft: 8px;
+	-moz-border-radius-bottomright: 8px;
+}
+
+.calendrier-moztop6 {
+	-moz-border-radius-topleft: 6px;
+	-moz-border-radius-topright: 6px;
+}
+
+.calendrier-mozbottom6 {
+	-moz-border-radius-bottomleft: 6px;
+	-moz-border-radius-bottomright: 6px;
+}
+
+.calendrier-opacity {
+	-moz-opacity: 0.3;
+	filter: alpha(opacity=30);
+}
+
+
+.calendrier-png {
+	width: 12px;
+	height: 12px;
+	behavior: url(win_png.htc);
+}
+
+.calendrier-icone {
+	width: 14px;
+	height: 7px;
+	border: 0px;
+}
+
+.calendrier-noir  { 		/*  style anar */
+	color: black;
+}
+
+.calendrier-nb  { 		/*  style cinemat(yp)ographe */
+	background-color: white;
+	border: 1px solid black;
+	color: black;
+}
+
+.calendrier-couleur1 { 		/* Fushia */
+		background-color: #FDE5F2;
+		border: 1px solid #CD006F;
+		color: #CD006F;
+}
+.calendrier-couleur1i { 		/* Fushia */
+		background-color: #CD006F;
+		border: 1px solid #FDE5F2;
+		color: #FDE5F2
+}
+.calendrier-couleur2 { 		/* Bleu */
+		background-color: #EDF3FE;
+		border: 1px solid #5da7c5;
+		color: #5da7c5;
+}
+.calendrier-couleur2i { 		/* Bleu */
+		background-color: #5da7c5;
+		border: 1px solid #EDF3FE;
+		color: #EDF3FE
+}
+.calendrier-couleur3 { 		/* Bleu pastel */
+		background-color: #EBE9FF;
+		border: 1px solid #766CF6;
+		color: #766CF6;
+}
+.calendrier-couleur3i { 		/* Bleu pastel */
+		background-color: #766CF6;
+		border: 1px solid #EBE9FF;
+		color: #EBE9FF
+}
+.calendrier-couleur4 { 		/* Orange */
+		background-color: #ffeecc;
+		border: 1px solid #fa9a00;
+		color: #fa9a00;
+}
+.calendrier-couleur4i { 		/* Orange */
+		background-color: #fa9a00;
+		border: 1px solid #ffeecc;
+		color: #ffeecc
+}
+.calendrier-couleur5 { 		/* Rouge (Vermillon) */
+		background-color: #FFEDED;
+		border: 1px solid #FF0000;
+		color: #FF0000;
+}
+.calendrier-couleur5i { 		/* Rouge (Vermillon) */
+		background-color: #FF0000;
+		border: 1px solid #FFEDED;
+		color: #FFEDED
+}
+.calendrier-couleur6 { 		/* Orange */
+		background-color: #FFF2EB;
+		border: 1px solid #E95503;
+		color: #E95503;
+}
+.calendrier-couleur6i { 		/* Orange */
+		background-color: #E95503;
+		border: 1px solid #FFF2EB;
+		color: #FFF2EB
+}
+.calendrier-couleur7 { 		/* Jaune */
+		background-color: #ffffee;
+		border: 1px solid #ccaa00;
+		color: #ccaa00;
+}
+.calendrier-couleur7i { 		/* Jaune */
+		background-color: #ccaa00;
+		border: 1px solid #ffffee;
+		color: #ffffee
+}
+.calendrier-couleur8 { 		/* Vert pastel */
+		background-color: #E2FDEC;
+		border: 1px solid #009F3C;
+		color: #009F3C;
+}
+.calendrier-couleur8i { 		/* Vert pastel */
+		background-color: #009F3C;
+		border: 1px solid #E2FDEC;
+		color: #E2FDEC
+}
+.calendrier-couleur9 { 		/* Vert */
+		background-color: #e5fd63;
+		border: 1px solid #9DBA00;
+		color: #9DBA00;
+}
+.calendrier-couleur9i { 		/* Vert */
+		background-color: #9DBA00;
+		border: 1px solid #e5fd63;
+		color: #e5fd63
+}
+.calendrier-couleur10 { 		/* Rouge (Bordeaux) */
+		background-color: #FFE0E0;
+		border: 1px solid #640707;
+		color: #640707;
+}
+.calendrier-couleur10i { 		/* Rouge (Bordeaux) */
+		background-color: #640707;
+		border: 1px solid #FFE0E0;
+		color: #FFE0E0
+}
+.calendrier-couleur11 { 		/* Gris */
+		background-color: #F2F2F2;
+		border: 1px solid #3F3F3F;
+		color: #3F3F3F;
+}
+.calendrier-couleur11i { 		/* Gris */
+		background-color: #3F3F3F;
+		border: 1px solid #F2F2F2;
+		color: #F2F2F2
+}
+.calendrier-couleur12 {
+		background-color: #aaaaaa;
+		border: 1px solid black;
+		color:black;
+
+}
+.calendrier-couleur12i {
+		background-color: black;
+		border: 1px solid #aaaaaa;
+		color: #aaaaaa}
+.calendrier-couleur13 { /* Caca d'oie */
+		background-color: #FFFFE0;
+		border: 1px solid #666500;
+		color: #666500; 
+}
+.calendrier-couleur13i { 		/* Caca d'oie */
+		background-color: #666500;
+		border: 1px solid #FFFFE0;
+		color: #FFFFE0
+}
+.calendrier-couleur14 { 		/* Marron */
+		background-color: #F5EEE5;
+		border: 1px solid #8C6635;
+		color: #8C6635;
+}
+.calendrier-couleur14i { 		/* Marron */
+		background-color: #8C6635;
+		border: 1px solid #F5EEE5;
+		color: #F5EEE5
+}
+
+.calendrier-creneau,
+.calendrier-creneau-today,
+.calendrier-creneau-sunday {
+	position: absolute;
+	margin-left: 0px;
+	margin-right: 0px;
+	border-top: 0px ;
+	border-right: 0px ;
+	border-bottom: 0px ;
+	border-left: 0px ;
+	font-weight: bold;
+	background-color: #dddddd;
+	color: #dddddd;
+	width: 100%;
+ }
+
+.calendrier-creneau a {
+	color : #dddddd;
+	font-weight: bold;
+}
+.calendrier-creneau a:hover {
+	background-color: #ccff99;
+}
+
+.calendrier-creneau-today {
+	background-color: #eeeeee;
+	color: #eeeeee;
+}
+.calendrier-creneau-today a {
+	color : #eeeeee;
+	font-weight: bold;
+}
+.calendrier-creneau-today a:hover {
+	background-color: #ccff99;
+}
+
+.calendrier-creneau-sunday {
+/*	background-color: #ccff99;
+	color: #ccff99;*/
+}
+
+.calendrier-creneau-sunday a {
+	/*color : #ccff99;*/
+	color : #dddddd;
+	font-weight: bold;
+ }
+
+.calendrier-creneau-sunday a:hover {
+	/*background-color: #dddddd;*/
+	background-color: #ccff99;
+}
+
+.calendrier-plage,.calendrier-plage-selection { 		/* Orange */
+		background-color: #FFF2EB;
+		border: 1px solid #E95503;
+		color: #E95503;
+}
+.calendrier-plage-selection{
+		border: 3px solid #E95503;
+}
+.calendrier-reunions { 		/* Bleu pastel */
+		background-color: #EBE9FF;
+		border: 1px solid #766CF6;
+		color: #766CF6;
+}
+
+.calendrier-evenement,.calendrier-evenement-selection { 		/* Vert pastel */
+		background-color: #eeeeee;
+		border: 0px solid #009F3C;
+}
+.calendrier-evenement-selection{
+}
+
+.calendrier-anniversaire { 		/* Jaune */
+		background-color: #ffffee;
+		border: 1px solid #ccaa00;
+		color: #ccaa00;
+}
+.calendrier-rappel { 		/* Rouge (Vermillon) */
+		background-color: #FFEDED;
+		border: 1px solid #FF0000;
+		color: #FF0000;
+}
+
+.calendrier-plage-info { 		/* Jaune transparent*/
+		background-color: #ffffee;
+		border: 1px solid #ccaa00;
+		color: #ccaa00;
+		filter:alpha(opacity=50);
+		opacity: 0.5;
+		-moz-opacity:0.5;
+}
+.activite-couleur15 { 		/* Fushia */
+		background-color: #FDE5F2;
+		border: 1px solid #CD006F;
+		color: #CD006F;
+}
+.activite-couleur9 { 		/* Bleu pastel */
+		background-color: #EBE9FF;
+		border: 1px solid #766CF6;
+		color: #766CF6;
+}
+.activite-couleur14 { 		/* Bleu pastel */
+		background-color: #EBE9FF;
+		border: 1px solid #766CF6;
+		color: #766CF6;
+}
+.activite-couleur5 { 		/* Vert pastel */
+		background-color: #E2FDEC;
+		border: 1px solid #009F3C;
+		color: #009F3C;
+}
+.activite-couleur12 { 		/* Orange */
+		background-color: #ffeecc;
+		border: 1px solid #fa9a00;
+		color: #fa9a00;
+}
Index: plugins/agenda_1_9_1/img_pack/multiselect.js
===================================================================
--- plugins/agenda_1_9_1/img_pack/multiselect.js	(revision 6)
+++ plugins/agenda_1_9_1/img_pack/multiselect.js	(revision 6)
@@ -0,0 +1,115 @@
+/*
+	coded by Kae - kae@verens.com
+	I'd appreciate any feedback.
+	You have the right to include this in your sites.
+	Please retain this notice.
+*/
+
+/* edit these variables to customise the multiselect */ {
+	var show_toplinks=false;
+}
+
+/* global variables - do not touch */ {
+	var isIE=window.attachEvent?true:false;
+	var selectDefaults=[];
+}
+function addEvent(el,ev,fn){
+	if(isIE)el.attachEvent('on'+ev,fn);
+	else if(el.addEventListener)el.addEventListener(ev,fn,false);
+}
+function buildMultiselects(){
+	do{
+		found=0;
+		a=document.getElementsByTagName('select');
+		for(b=0;b<a.length,!found;b++){
+			var ms=a[b];
+			if(ms==null)break;
+			var name=ms.name.replace(/\[\]$/, '');
+			if(ms.multiple){
+				/* common variables */ {
+					selectDefaults[name]=[];
+					var found=1,disabled=ms.disabled?1:0,width=ms.offsetWidth,height=ms.offsetHeight;
+					if(width<120)width=120;
+					if(height<60)height=60;
+				}
+				/* set up wrapper */ {
+					var wrapper=document.createElement('div');
+					wrapper.style.width=width+"px";
+					wrapper.style.height=height+"px";
+					wrapper.style.position='relative';
+					wrapper.style.border="2px solid #000";
+					wrapper.style.borderColor="#333 #ccc #ccc #333";
+					wrapper.style.font="10px sans-serif";
+					if(disabled)wrapper.style.background='#ddd';
+				}
+				if(show_toplinks){ /* reset, all, none */
+					wrapper.appendChild(newLink("javascript:"+(disabled?"alert('selection disabled')":"multiselect_selectall('"+name+"','checked');"),'all'));
+					wrapper.appendChild(document.createTextNode(', '));
+					wrapper.appendChild(newLink("javascript:"+(disabled?"alert('selection disabled')":"multiselect_selectall('"+name+"','');"),'none'));
+					wrapper.appendChild(document.createTextNode(', '));
+					wrapper.appendChild(newLink("javascript:"+(disabled?"alert('selection disabled')":"multiselect_selectall('"+name+"','reset');"),'reset'));
+				}
+				/* setup multiselect */ {
+					newmultiselect=document.createElement('div');
+					newmultiselect.style.position='absolute';
+					newmultiselect.style.top=show_toplinks?'15px':'0';
+					newmultiselect.style.left='0';
+					newmultiselect.style.overflow='auto';
+					newmultiselect.style.width=(isIE?width-4:width)+"px";
+					newmultiselect.style.height=show_toplinks?height-(isIE?19:15)+"px":height+'px';
+				}
+				c=ms.getElementsByTagName('option');
+				for(d=0;d<c.length;d++){
+					var label=document.createElement('label');
+					label.style.display="block";
+					label.style.border="1px solid #eee";
+					label.style.borderWidth="1px 0";
+					label.style.font="10px arial";
+					label.style.lineHeight="10px";
+					label.style.paddingLeft="20px";
+					checkbox=document.createElement('input');
+					checkbox.type="checkbox";
+					if(c[d].selected){
+						checkbox.checked="checked";
+						checkbox.defaultChecked=true;
+					}
+					if(c[d].disabled){
+						checkbox.disabled='disabled';
+						label.style.color='#666';
+					}
+					selectDefaults[name][d]=c[d].selected?'checked':'';
+					if(disabled)checkbox.disabled="disabled";
+					checkbox.value=c[d].value;
+					checkbox.style.marginLeft="-16px";
+					checkbox.style.marginTop="-2px";
+					checkbox.name=ms.name;
+
+					// escape the label
+					var text=c[d].innerHTML;
+					text=text.replace(/\&nbsp;?/g, ' ');
+					text=text.replace(/\&lt;?/g, '<');
+					text=text.replace(/\&gt;?/g, '>');
+
+					labelText=document.createTextNode(text);
+					label.appendChild(checkbox);
+					label.appendChild(labelText);
+					newmultiselect.appendChild(label);
+				}
+			wrapper.appendChild(newmultiselect);
+			ms.parentNode.insertBefore(wrapper,ms);
+			ms.parentNode.removeChild(ms);
+			}
+		}
+	}while(found);
+}
+function multiselect_selectall(name,val){
+	var els=document.getElementsByTagName('input'),found=0;
+	for(var i=0;i<els.length;++i){
+		if((els[i].name==name+'[]'||els[i].name==name)&&!els[i].disabled)els[i].checked=val=='reset'?selectDefaults[name][found++]:val;
+	}
+}
+function newLink(href,text){
+	var e=document.createElement('a');e.href=href;e.appendChild(document.createTextNode(text));return e;
+}
+
+addEvent(window,'load',buildMultiselects);
Index: plugins/agenda_1_9_1/inc/agenda.php.sav
===================================================================
--- plugins/agenda_1_9_1/inc/agenda.php.sav	(revision 6)
+++ plugins/agenda_1_9_1/inc/agenda.php.sav	(revision 6)
@@ -0,0 +1,1424 @@
+<?php
+
+/***************************************************************************\
+ *  SPIP, Systeme de publication pour l'internet                           *
+ *                                                                         *
+ *  Copyright (c) 2001-2006                                                *
+ *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
+ *                                                                         *
+ *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
+ *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
+\***************************************************************************/
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+include_spip('inc/minipres'); 
+include_spip('inc/layer');
+include_spip('inc/texte'); // inclut inc_filtre
+include_spip('inc/calendar'); // inclut widget calendar
+
+charger_generer_url();
+
+//  Typographie generale des calendriers de 3 type: jour/semaine/mois(ou plus)
+
+// Notes: pour toutes les fonctions ayant parmi leurs parametres
+// annee, mois, jour, echelle, partie_cal, script, ancre
+// ceux-ci apparaissent TOUJOURS dans cet ordre 
+
+define(DEFAUT_D_ECHELLE,120); # 1 pixel = 2 minutes
+
+// 
+// Utilitaires sans html ni sql
+//
+
+// utilitaire de separation script / ancre
+// et de retrait des arguments a remplacer
+// (a mon avis cette fonction ne sert a rien, puisque parametre_url()
+// sait remplacer les arguments au bon endroit -- Fil)
+// Pas si simple: certains param ne sont pas remplaces 
+// et doivent reprendre leur valeur par defaut -- esj.
+function calendrier_retire_args_ancre($script)
+{
+	$script = str_replace('&amp;', '&', $script);
+  $script = str_replace('?bonjour=oui&?','?',$script);
+  if (ereg('^(.*)(#[^=&]*)$',$script, $m)) {
+	  $script = $m[1];
+	  $ancre = $m[2];
+  } else { $ancre = ''; }
+  if ($script[strlen($script)-1] == '?')  $script = substr($script,0,-1);
+  foreach(array('echelle','jour','mois','annee', 'type', 'partie_cal') as $arg) {
+		$script = preg_replace("/([?&])$arg=[^&]*&/",'\1', $script);
+		$script = preg_replace("/([?&])$arg=[^&]*$/",'\1', $script);
+	}
+  if (ereg('[?&]$', $script)) $script =   substr($script,0,-1);
+  return array(quote_amp($script), $ancre);
+}
+
+// tous les liens de navigations sont issus de cette fonction
+// on peut definir generer_url_date et un htacces pour simplifier les URL
+
+function calendrier_args_date($script, $annee, $mois, $jour, $type, $finurl) {
+	if (function_exists('generer_url_date'))
+		return generer_url_date($script, $annee, $mois, $jour, $type, $finurl);
+
+	$script = parametre_url($script, 'annee', sprintf("%04d", $annee));
+	$script = parametre_url($script, 'mois',  sprintf("%02d", $mois));
+	$script = parametre_url($script, 'jour',  sprintf("%02d", $jour));
+	$script = parametre_url($script, 'type',  $type);
+	return $script . $finurl;
+}
+
+# prend une heure de debut et de fin, ainsi qu'une echelle (seconde/pixel)
+# et retourne un tableau compose
+# - taille d'une heure
+# - taille d'une journee
+# - taille de la fonte
+# - taille de la marge
+
+function calendrier_echelle($debut, $fin, $echelle)
+{
+  if ($echelle==0) $echelle = DEFAUT_D_ECHELLE;
+  if ($fin <= $debut) $fin = $debut +1;
+
+  $duree = $fin - $debut;
+  $dimheure = floor((3600 / $echelle));
+  return array($dimheure,
+	       (($duree+2) * $dimheure),
+	       floor (14 / (1+($echelle/240))),
+	       floor(240 / $echelle));
+}
+
+# Calcule le "top" d'une heure
+
+function calendrier_top ($heure, $debut, $fin, $dimheure, $dimjour, $fontsize) {
+	
+	$h_heure = substr($heure, 0, strpos($heure, ":"));
+	$m_heure = substr($heure, strpos($heure,":") + 1, strlen($heure));
+	$heure100 = $h_heure + ($m_heure/60);
+
+	if ($heure100 < $debut) $heure100 = ($heure100 / $debut) + $debut - 1;
+	if ($heure100 > $fin) $heure100 = (($heure100-$fin) / (24 - $fin)) + $fin;
+
+	$top = floor(($heure100 - $debut + 1) * $dimheure);
+
+	return $top;	
+}
+
+# Calcule la hauteur entre deux heures
+function calendrier_height ($heure, $heurefin, $debut, $fin, $dimheure, $dimjour, $fontsize) {
+
+	$height = calendrier_top ($heurefin, $debut, $fin, $dimheure, $dimjour, $fontsize) 
+				- calendrier_top ($heure, $debut, $fin, $dimheure, $dimjour, $fontsize);
+
+	$padding = floor(($dimheure / 3600) * 240);
+	$height = $height - (2* $padding + 2); // pour padding interieur
+	
+	if ($height < ($dimheure/4)) $height = floor($dimheure/4); // eviter paves totalement ecrases
+	
+	return $height;	
+}
+
+//
+// init: calcul generique des evenements a partir des tables SQL
+//
+
+function http_calendrier_init($time='', $ltype='', $lechelle='', $lpartie_cal='', $script='', $evt='')
+{
+	global $mois, $annee, $jour, $type, $echelle, $partie_cal;
+
+	if (!$time) 
+	  {
+	    if (!$mois)
+	      $time = time();
+	    else
+	      $time = mktime(0,0,0,$mois,$jour,$annee);
+	    $type= 'mois';
+	  }
+
+	$jour = date("d",$time);
+	$mois = date("m",$time);
+	$annee = date("Y",$time);
+	if (!$ltype) $ltype = $type ? $type : 'mois';
+	if (!$lechelle) $lechelle = $echelle;
+	if (!$lpartie_cal) $lpartie_cal = $partie_cal;
+	list($script, $ancre) = 
+	  calendrier_retire_args_ancre($script); 
+	if (!$evt) {
+	  $g = 'sql_calendrier_' . $ltype;
+	  $evt = sql_calendrier_interval($g($annee,$mois, $jour));
+	  sql_calendrier_interval_articles("'$annee-$mois-00'", "'$annee-$mois-1'", $evt[0]);
+	  // si on veut les forums, decommenter
+#	  sql_calendrier_interval_forums($g($annee,$mois,$jour), $evt[0]);
+	}
+	$f = 'http_calendrier_' . $ltype;
+	return $f($annee, $mois, $jour, $lechelle, $lpartie_cal, $script, $ancre, $evt);
+
+}
+
+# affichage d'un calendrier de plusieurs semaines
+# si la periode est inferieure a 31 jours, on considere que c'est un mois
+
+function http_calendrier_mois($annee, $mois, $jour, $echelle, $partie_cal, $script, $ancre, $evt)
+{
+	global $spip_ecran;
+	if (!isset($spip_ecran)) $spip_ecran = 'large';
+	$premier_jour = '01';
+	$dernier_jour = '31';
+
+	if (is_array($evt)) {
+	  list($sansduree, $evenements, $premier_jour, $dernier_jour) = $evt;
+	  if (!$premier_jour) $premier_jour = '01';
+	  if (!$dernier_jour)
+	    {
+	      $dernier_jour = 31;
+	      while (!(checkdate($mois,$dernier_jour,$annee))) $dernier_jour--;
+	    }
+	  if ($sansduree)
+	    foreach($sansduree as $d => $r) 
+	      $evenements[$d] = !$evenements[$d] ? $r : array_merge($evenements[$d], $r);
+	  $evt = 
+	    http_calendrier_mois_noms($annee, $mois, $jour, $script, $ancre) .
+	    http_calendrier_mois_sept($annee, $mois, $premier_jour, $dernier_jour,$evenements, $script, "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre") ;
+	} else $evt = "<tr><td>$evt</td></tr>";
+
+	return 
+	  "<table class='calendrier-table-$spip_ecran' cellspacing='0' cellpadding='0'>" .
+	  http_calendrier_mois_navigation($annee, $mois, $premier_jour, $dernier_jour, $echelle, $partie_cal, $script, $ancre) .
+	  $evt .
+	  '</table>' .
+	  http_calendrier_sans_date($annee, $mois, $evenements) .
+	  (_DIR_RESTREINT ? "" : http_calendrier_aide_mess());
+}
+
+// si la periore a plus de 31 jours, c'est du genre trimestre, semestre etc
+// pas de navigation suivant/precedent alors
+
+function http_calendrier_mois_navigation($annee, $mois, $premier_jour, $dernier_jour, $echelle, $partie_cal, $script, $ancre){
+	if ($dernier_jour > 31) {
+	  $prec = $suiv = '';
+	  $periode = affdate_mois_annee(date("Y-m-d", mktime(1,1,1,$mois,$premier_jour,$annee))) . ' - '. affdate_mois_annee(date("Y-m-d", mktime(1,1,1,$mois,$dernier_jour,$annee)));
+	} else {
+
+	$mois_suiv=$mois+1;
+	$annee_suiv=$annee;
+	$mois_prec=$mois-1;
+	$annee_prec=$annee;
+	if ($mois==1){
+	  $mois_prec=12;
+	  $annee_prec=$annee-1;
+	}
+	else if ($mois==12){$mois_suiv=1;	$annee_suiv=$annee+1;}
+	$prec = array($annee_prec, $mois_prec, 1, "mois");
+	$suiv = array($annee_suiv, $mois_suiv, 1, "mois");
+	$periode = affdate_mois_annee("$annee-$mois-1");
+	}
+	return
+	  "\n<tr><td colspan='7'>" .
+	  http_calendrier_navigation($annee,
+				   $mois,
+				   $jour,
+				   $echelle,
+				   $partie_cal,
+				   $periode,
+				   $script,
+				   $prec,
+				   $suiv,
+				   'mois',
+				   $ancre) .
+	  "</td></tr>";
+
+}
+
+function http_calendrier_mois_noms($annee, $mois, $jour, $script, $ancre){
+	global $couleur_claire;
+
+	$bandeau ="";
+	for ($j=1; $j<8;$j++){
+		$bandeau .= 
+		  "\n\t<th class='calendrier-th'>" .
+		  _T('date_jour_' . (($j%7)+1)) .
+		  "</th>";
+	}
+	return "\n<tr" .
+	  (!isset($couleur_claire) ? "" : " style='background-color: $couleur_claire'") . 
+	  ">$bandeau\n</tr>";
+}
+
+# dispose les lignes d'un calendrier de 7 colonnes (les jours)
+# chaque case est garnie avec les evenements du jour figurant dans $evenements
+
+function http_calendrier_mois_sept($annee, $mois, $premier_jour, $dernier_jour,$evenements, $script, $ancre='')
+{
+	global $couleur_claire, $spip_lang_left, $spip_lang_right;
+
+	// affichage du debut de semaine hors periode
+	$init = '';
+	$debut = date("w",mktime(1,1,1,$mois,$premier_jour,$annee));
+	for ($i=$debut ? $debut : 7;$i>1;$i--)
+	  {$init .= "\n\t<td style=\"border-bottom: 1px solid $couleur_claire;\">&nbsp;</td>";}
+
+	$total = '';
+	$ligne = '';
+	$today=date("Ymd");
+	for ($j=$premier_jour; $j<=$dernier_jour; $j++){
+		$nom = mktime(1,1,1,$mois,$j,$annee);
+		$jour = date("d",$nom);
+		$jour_semaine = date("w",$nom);
+		$mois_en_cours = date("m",$nom);
+		$annee_en_cours = date("Y",$nom);
+		$amj = date("Y",$nom) . $mois_en_cours . $jour;
+		$couleur_texte = "black";
+		$couleur_fond = "";
+
+		if ($jour_semaine == 0) $couleur_fond = $couleur_claire;
+		else if ($jour_semaine==1)
+			  { 
+			    if ($ligne||$init)
+			      $total .= "\n<tr>$init$ligne\n</tr>";
+			    $ligne = $init = '';
+			  }
+		
+		if ($amj == $today) {
+			$couleur_texte = "red";
+			$couleur_fond = "white";
+		}
+		$res = '';
+		if ($evts = $evenements[$amj]) {
+		  foreach ($evts as $evenement)
+		    {
+		      $res .= isset($evenement['DTSTART']) ?
+			http_calendrier_avec_heure($evenement, $amj) :
+			http_calendrier_sans_heure($evenement);
+		    }
+		}
+
+		$ligne .= "\n\t\t<td\tclass='calendrier-td'
+			style='height: 100px; border-bottom: 1px solid $couleur_claire; border-$spip_lang_right: 1px solid $couleur_claire;" .
+		  ($couleur_fond ? " background-color: $couleur_fond;" : "") .
+		  ($ligne ? "" :
+		   " border-$spip_lang_left: 1px solid $couleur_claire;") .
+		  "'>" .
+		  (!_DIR_RESTREINT ? 
+		   (http_href(calendrier_args_date($script,$annee_en_cours, $mois_en_cours, $jour, "jour", $ancre), 
+			      $jour,
+			      $jour, "color: $couleur_texte",'calendrier-helvetica16') . 
+		    http_calendrier_ics_message($annee_en_cours, $mois_en_cours, $jour, false)):
+		   http_calendrier_mois_clics($annee_en_cours, $mois_en_cours, $jour, $script, $ancre)) .
+		  $res .
+		  "\n\t</td>";
+	}
+	return  $total . ($ligne ? "\n<tr>$ligne\n</tr>" : '');
+}
+
+// typo pour l'espace public
+
+function http_calendrier_mois_clics($annee, $mois, $jour, $script, $ancre)
+{
+      $d = mktime(0,0,0,$mois, $jour, $annee);
+      $semaine = date("W", $d);
+      return 
+	"<table width='100%'>\n<tr><td style='text-align: left'>". 
+	http_href(calendrier_args_date($script,$annee, $mois, $jour, "jour", $ancre), 
+		  "$jour/$mois",
+		  _T('date_jour_'. (1+date('w',$d))) .
+		  " $jour " .
+		  _T('date_mois_'.(0+$mois)),
+		  '','calendrier-helvetica16') .
+	"</td><td style='text-align: right'>" .
+	http_href(calendrier_args_date($script,$annee, $mois, $jour, "semaine", $ancre),
+		  $semaine,
+		  _T('date_semaines') . ": $semaine",
+		  '',
+		  'calendrier-helvetica16') .
+	"</td></tr>\n</table>";
+}
+
+# dispose les evenements d'une semaine
+
+function http_calendrier_semaine($annee, $mois, $jour, $echelle, $partie_cal, $script, $ancre, $evt)
+{
+	global $spip_ecran;
+	if (!isset($spip_ecran)) $spip_ecran = 'large';
+
+	$init = date("w",mktime(1,1,1,$mois,$jour,$annee));
+	$init = $jour+1-($init ? $init : 7);
+	$sd = '';
+
+	if (is_array($evt))
+	  {
+	  	if($partie_cal!='sansheure'){
+	    $sd = http_calendrier_sans_date($annee, $mois,$evt[0]);
+	    $finurl = "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre";
+	    $evt =
+	      http_calendrier_semaine_noms($annee, $mois, $init, $script, $finurl) .
+	      http_calendrier_semaine_sept($annee, $mois, $init, $echelle, $partie_cal, $evt);
+	  	}
+	  	else {
+			  list($sansduree, $evenements, $premier_jour, $dernier_jour) = $evt;
+			  if ($sansduree)
+			    foreach($sansduree as $d => $r) 
+			      $evenements[$d] = !$evenements[$d] ? $r : array_merge($evenements[$d], $r);
+		    $finurl = "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre";
+		    $evt =
+		      http_calendrier_semaine_noms($annee, $mois, $init, $script, $finurl) .
+		      http_calendrier_mois_sept($annee, $mois, $init, $init+ 6, $evenements, $script);
+	  	}
+	  } else $evt = "<tr><td>$evt</td></tr>";
+
+	return 
+	  "\n<table class='calendrier-table-$spip_ecran' cellspacing='0' cellpadding='0'>" .
+	  http_calendrier_semaine_navigation($annee, $mois, $init, $echelle, $partie_cal, $script, $ancre) .
+	  $evt .
+	  "</table>" .
+	  $sd .
+	  (_DIR_RESTREINT ? "" : http_calendrier_aide_mess());
+}
+
+function http_calendrier_semaine_navigation($annee, $mois, $jour, $echelle, $partie_cal, $script, $ancre){
+
+	$fin = mktime (1,1,1,$mois, $jour+6, $annee);
+	$fjour = date("d",$fin);
+	$fmois = date("m",$fin);
+	$fannee = date("Y",$fin);
+	$fin = date("Y-m-d", $fin);
+	$debut = mktime (1,1,1,$mois, $jour, $annee);
+	$djour = date("d",$debut)+0;
+	$dmois = date("m",$debut);
+	$dannee = date("Y",$debut);
+	$debut = date("Y-m-d", $debut);
+	$periode = (($dannee != $fannee) ?
+		    (affdate($debut)." - ".affdate($fin)) :
+		    (($dmois == $fmois) ?
+		     ($djour ." - ".affdate_jourcourt($fin)) :
+		     (affdate_jourcourt($debut)." - ".affdate_jourcourt($fin))));
+
+  return
+    "\n<tr><td colspan='7'>" .
+    http_calendrier_navigation($annee,
+			       $mois,
+			       $jour,
+			       $echelle,
+			       $partie_cal, 
+			       $periode,
+			       $script,
+			       array($dannee, $dmois, ($djour-7), "semaine"),
+			       array($fannee, $fmois, ($fjour+1), "semaine"),
+			       'semaine',
+			       $ancre) .
+    "</td></tr>\n";
+}
+
+function http_calendrier_semaine_noms($annee, $mois, $jour, $script, $ancre){
+	global $couleur_claire;
+
+	$bandeau = '';
+
+	for ($j=$jour; $j<$jour+7;$j++){
+		$nom = mktime(0,0,0,$mois,$j,$annee);
+		$num = intval(date("d", $nom)) ;
+		$numois = date("m",$nom);
+		$nomjour = _T('date_jour_'. (1+date('w',$nom)));
+		$clic = ($nomjour . " " . $num . (($num == 1) ? 'er' : '') .
+			 ($ancre  ? ('/' . $numois) : ''));
+		$bandeau .= 
+		  "\n\t<th class='calendrier-th'>" .
+		  http_href(calendrier_args_date($script, date("Y",$nom), $numois, $num, 'jour', $ancre), $clic, $clic) .
+		  "</th>";
+	}
+	return "\n<tr" .
+	  (!isset($couleur_claire) ? "" : " style='background-color: $couleur_claire'") . 
+	  ">$bandeau\n</tr>";
+}
+
+function http_calendrier_semaine_sept($annee, $mois, $jour, $echelle, $partie_cal, $evt)
+{
+	global $couleur_claire, $spip_ecran, $spip_lang_left;
+
+	$largeur =  ($spip_ecran == "large") ? 90 : 60;
+
+	$today=date("Ymd");
+	$total = '';
+	$style = "border-$spip_lang_left: 1px solid $couleur_claire; border-bottom: 1px solid $couleur_claire; border-top: 0px; border-right: 0px;";
+	for ($j=$jour; $j<$jour+7;$j++){
+		$v = mktime(0,0,0,$mois, $j, $annee);
+		$total .= "\n<td class='calendrier-td'>" .
+		  http_calendrier_ics($annee,$mois,$j, $echelle, $partie_cal, $largeur, $evt, ($style . ( (date("w",$v)==0 && isset($couleur_claire)) ? 
+			  " background-color: $couleur_claire;" :
+			  ((date("Ymd", $v) == $today) ? 
+			   " background-color: white;" :
+			   " background-color: #eeeeee;")))) .
+		  "\n</td>";
+	}
+	return "\n<tr class='calendrier-verdana10'>$total</tr>";
+}
+
+
+function http_calendrier_jour($annee, $mois, $jour, $echelle, $partie_cal, $script, $ancre, $evt){
+	global $spip_ecran;
+	if (!isset($spip_ecran)) $spip_ecran = 'large';
+
+	return 	
+	  "\n<table class='calendrier-table-$spip_ecran'>" .
+	  "\n<tr><td class='calendrier-td-gauche'></td>" .
+	  "<td colspan='5' class='calendrier-td-centre'>" .
+	  http_calendrier_navigation($annee, $mois, $jour, $echelle, $partie_cal,
+				     (nom_jour("$annee-$mois-$jour") . " " .
+				      affdate_jourcourt("$annee-$mois-$jour")),
+				     $script,
+				     array($annee, $mois, ($jour-1), "jour"),
+				     array($annee, $mois, ($jour+1), "jour"),
+				     'jour',
+				     $ancre) .
+	  "</td>" .
+	  "<td class='calendrier-td-droit calendrier-arial10'></td>" .
+	  "</tr>" .
+	  (!is_array($evt) ? ("<tr><td>$evt</td></tr>") :
+	   (http_calendrier_jour_noms($annee, $mois, $jour, $echelle, $partie_cal, $script, $ancre) .
+	    http_calendrier_jour_sept($annee, $mois, $jour, $echelle,  $partie_cal, $script, $ancre, $evt))) .
+	  "</table>";
+}
+
+function http_calendrier_jour_noms($annee, $mois, $jour, $echelle, $partie_cal, $script, $ancre){
+
+	global $spip_ecran;
+	$finurl = "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre";
+
+	$gauche = (_DIR_RESTREINT  || ($spip_ecran != "large"));
+	return
+	  "\n<tr><td class='calendrier-td-gauche'>" .
+	  ($gauche ? '' :
+	   http_calendrier_ics_titre($annee,$mois,$jour-1,$script, $finurl)) .
+	  "</td><td colspan='5' class='calendrier-td-centre'>" .
+	  (_DIR_RESTREINT ? '' :
+		   ("\n\t<div class='calendrier-titre'>" .
+		    http_calendrier_ics_message($annee, $mois, $jour, true) .
+		    '</div>')) .
+	  "</td><td class='calendrier-td-droit calendrier-arial10'> " .
+	   (_DIR_RESTREINT ? '' : http_calendrier_ics_titre($annee,$mois,$jour+1,$script, $finurl)) .
+	  "</td></tr>";
+}
+
+function http_calendrier_jour_sept($annee, $mois, $jour, $echelle,  $partie_cal, $script, $ancre, $evt){
+	global $spip_ecran;
+
+	$gauche = (_DIR_RESTREINT  || ($spip_ecran != "large"));
+	if ($partie_cal!="sansheure")
+		return
+		  "<tr class='calendrier-verdana10'>" .
+			# afficher en reduction le tableau du jour precedent
+		  "\n<td class='calendrier-td-gauche'>" .
+		  ($gauche  ? '' :
+		   http_calendrier_ics($annee, $mois, $jour-1, $echelle, $partie_cal, 0, $evt)) .
+		  "</td><td colspan='5' class='calendrier-td-centre'>" .
+		   http_calendrier_ics($annee, $mois, $jour, $echelle, $partie_cal, 300, $evt) .
+		  '</td>' .
+			# afficher en reduction le tableau du jour suivant
+		  "\n<td class='calendrier-td-droit'>" .
+	
+		  (_DIR_RESTREINT ? '' :
+		   http_calendrier_ics($annee, $mois, $jour+1, $echelle, $partie_cal, 0, $evt)) .
+		  '</td>' .
+		  "\n</tr>";
+	else {
+	  list($sansduree, $evenements, $premier_jour, $dernier_jour) = $evt;
+	  if ($sansduree)
+	    foreach($sansduree as $d => $r) 
+	      $evenements[$d] = !$evenements[$d] ? $r : array_merge($evenements[$d], $r);
+		return
+		  "<tr class='calendrier-verdana10'>" .
+			# afficher en reduction le tableau du jour precedent
+		  "\n<td class='calendrier-td-gauche'>" .
+		  ($gauche  ? '' :
+		  "<table width='100%'>".
+		   http_calendrier_mois_sept($annee, $mois, $jour-1, $jour-1,$evenements, $script, $ancre)
+		   ."</table>"
+		   ) .
+		  "</td><td colspan='5' class='calendrier-td-centre'>" .
+		  "<table width='100%'>".
+		   http_calendrier_mois_sept($annee, $mois, $jour, $jour,$evenements, $script, $ancre) .
+		   "</table>" .
+		  '</td>' .
+			# afficher en reduction le tableau du jour suivant
+		  "\n<td class='calendrier-td-droit'>" .
+		  (_DIR_RESTREINT ? '' :
+		  "<table width='100%'>".
+		   http_calendrier_mois_sept($annee, $mois, $jour+1, $jour+1,$evenements, $script, $ancre)
+		   ."</table>"
+		   ) .
+		  '</td>' .
+		  "\n</tr>";
+		
+	}
+}
+
+
+// Conversion d'un tableau de champ ics en des balises div positionnees    
+// Le champ categories indique la Classe de CSS a prendre
+// $echelle est le nombre de secondes representees par 1 pixel
+
+function http_calendrier_ics($annee, $mois, $jour,$echelle, $partie_cal,  $largeur, $evt, $style='') {
+	global $spip_lang_left;
+
+	// tableau
+	if ($partie_cal == "soir") {
+		$debut = 12;
+		$fin = 23;
+	} else if ($partie_cal == "matin") {
+		$debut = 4;
+		$fin = 15;
+	} else {
+		$debut = 7;
+		$fin =21;
+	}
+	
+	if ($echelle==0) $echelle = DEFAUT_D_ECHELLE;
+
+	list($dimheure, $dimjour, $fontsize, $padding) =
+	  calendrier_echelle($debut, $fin, $echelle);
+	$modif_decalage = round($largeur/8);
+
+	$date = date("Ymd", mktime(0,0,0,$mois, $jour, $annee));
+	list($sansheure, $avecheure) = $evt;
+	$avecheure = $avecheure[$date];
+	$sansheure = $sansheure[$date];
+
+	$total = '';
+
+	if ($avecheure)
+    {
+		$tous = 1 + count($avecheure);
+		$i = 0;
+		foreach($avecheure as $evenement){
+
+			$d = $evenement['DTSTART'];
+			$e = $evenement['DTEND'];
+			$d_jour = substr($d,0,8);
+			$e_jour = $e ? substr($e,0,8) : $d_jour;
+			$debut_avant = false;
+			$fin_apres = false;
+			
+			/* disparues sauf erreur
+			 $radius_top = " radius-top";
+			$radius_bottom = " radius-bottom";
+			*/
+			if ($d_jour <= $date AND $e_jour >= $date)
+			{
+
+			$i++;
+
+			// Verifier si debut est jour precedent
+			if (substr($d,0,8) < $date)
+			{
+				$heure_debut = 0; $minutes_debut = 0;
+				$debut_avant = true;
+				$radius_top = "";
+			}
+			else
+			{
+				$heure_debut = substr($d,-6,2);
+				$minutes_debut = substr($d,-4,2);
+			}
+
+			if (!$e)
+			{ 
+				$heure_fin = $heure_debut ;
+				$minutes_fin = $minutes_debut ;
+				$bordure = "border-bottom: dashed 2px";
+			}
+			else
+			{
+				$bordure = "";
+				if (substr($e,0,8) > $date) 
+				{
+					$heure_fin = 23; $minutes_fin = 59;
+					$fin_apres = true;
+					$radius_bottom = "";
+				}
+				else
+				{
+					$heure_fin = substr($e,-6,2);
+					$minutes_fin = substr($e,-4,2);
+				}
+			}
+			
+			if ($debut_avant && $fin_apres)  $opacity = "-moz-opacity: 0.6; filter: alpha(opacity=60);";
+			else $opacity = "";
+						
+			$haut = calendrier_top ("$heure_debut:$minutes_debut", $debut, $fin, $dimheure, $dimjour, $fontsize);
+			$bas =  !$e ? $haut :calendrier_top ("$heure_fin:$minutes_fin", $debut, $fin, $dimheure, $dimjour, $fontsize);
+			$hauteur = calendrier_height ("$heure_debut:$minutes_debut", "$heure_fin:$minutes_fin", $debut, $fin, $dimheure, $dimjour, $fontsize);
+
+			if ($bas_prec >= $haut) $decale += $modif_decalage;
+			else $decale = (4 * $fontsize);
+			if ($bas > $bas_prec) $bas_prec = $bas;
+			
+			$url = $evenement['URL']; 
+			$desc = propre($evenement['DESCRIPTION']);
+			$perso = substr($evenement['ATTENDEE'], 0,strpos($evenement['ATTENDEE'],'@'));
+			$lieu = $evenement['LOCATION'];
+			$sum = ereg_replace(' +','&nbsp;', typo($evenement['SUMMARY']));
+			if (!$sum) { $sum = $desc; $desc = '';}
+			if (!$sum) { $sum = $lieu; $lieu = '';}
+			if (!$sum) { $sum = $perso; $perso = '';}
+			if ($sum)
+			  $sum = "<span class='calendrier-verdana10'><span  style='font-weight: bold;'>$sum</span>$lieu $perso</span>";
+			if (($largeur > 90) && $desc)
+			  $sum .=  "\n<br /><span class='calendrier-noir'>$desc</span>";
+			$colors = $evenement['CATEGORIES'];
+		  $sum = ((!$url) ? $sum : http_href(quote_amp($url), $sum, $desc,"border: 0px",$colors));
+			$sum = pipeline('agenda_rendu_evenement',array('args'=>array('evenement'=>$evenement,'type'=>'ics'),'data'=>$sum));
+
+			$total .= "\n<div class='calendrier-arial10 $colors' 
+	style='cursor: auto; position: absolute; overflow: hidden;$opacity z-index: " .
+				$i .
+				"; $spip_lang_left: " .
+				$decale .
+				"px; top: " .
+				$haut .
+				"px; height: " .
+				$hauteur .
+				"px; width: ".
+				($largeur - 2 * ($padding+1)) .
+				"px; font-size: ".
+				floor($fontsize * 1.3) .
+				"px; padding: " .
+				$padding . 
+				"px; $bordure'
+	onmouseover=\"this.style.zIndex=" . $tous . "\"
+	onmouseout=\"this.style.zIndex=" . $i . "\">" .
+			  $sum . 
+				"</div>";
+			}
+		}
+    }
+	return
+	   "\n<div class='calendrier-jour' style='height: ${dimjour}px; font-size: ${fontsize}px;$style'>\n" .
+	  http_calendrier_ics_grille($debut, $fin, $dimheure, $dimjour, $fontsize) .
+	  $total .
+	  "\n</div>" .
+	  (!$sansheure ? "" :
+	   http_calendrier_ics_trois($sansheure, $largeur, $dimjour, $fontsize, '')) ;
+
+}
+
+# Affiche une grille horaire 
+# Selon l'echelle demandee, on affiche heure, 1/2 heure 1/4 heure, 5minutes.
+
+function http_calendrier_ics_grille($debut, $fin, $dimheure, $dimjour, $fontsize)
+{
+	global $spip_lang_left, $spip_lang_right;
+	$slice = floor($dimheure/(2*$fontsize));
+	if ($slice%2) $slice --;
+	if (!$slice) $slice = 1;
+
+	$total = '';
+	for ($i = $debut; $i < $fin; $i++) {
+		for ($j=0; $j < $slice; $j++) 
+		{
+			$total .= "\n<div class='calendrier-heure" .
+				($j  ? "face" : "pile") .
+				"' style='$spip_lang_left: 0px; top: ".
+				calendrier_top ("$i:".sprintf("%02d",floor(($j*60)/$slice)), $debut, $fin, $dimheure, $dimjour, $fontsize) .
+				"px;'>$i:" .
+				sprintf("%02d",floor(($j*60)/$slice)) . 
+				"</div>";
+		}
+	}
+
+	return "\n<div class='calendrier-heurepile' style='border: 0px; $spip_lang_left: 0px; top: 2px;'>0:00</div>" .
+		$total .
+		"\n<div class='calendrier-heurepile' style='$spip_lang_left: 0px; top: ".
+		calendrier_top ("$fin:00", $debut, $fin, $dimheure, $dimjour, $fontsize).
+		"px;'>$fin:00</div>" .
+		"\n<div class='calendrier-heurepile' style='border: 0px; $spip_lang_left: 0px; top: ".
+		($dimjour - $fontsize - 2) .
+		"px;'>23:59</div>";
+}
+
+# si la largeur le permet, les evenements sans duree, 
+# se placent a cote des autres, sinon en dessous
+
+function http_calendrier_ics_trois($evt, $largeur, $dimjour, $fontsize, $border)
+{
+	global $spip_lang_left; 
+
+	$types = array();
+	foreach($evt as $v)
+	  $types[isset($v['DESCRIPTION']) ? 'info_articles' :
+		 (isset($v['DTSTART']) ? 'info_liens_syndiques_3' :
+		  'info_breves_02')][] = $v;
+	$res = '';
+	foreach ($types as $k => $v) {
+	  $res2 = '';
+	  foreach ($v as $evenement) {
+	    $res2 .= http_calendrier_sans_heure($evenement);
+	  }
+	  $res .= "\n<div class='calendrier-verdana10 calendrier-titre'>".
+	    _T($k) .
+	    "</div>" .
+	    $res2;
+	}
+		
+	if ($largeur > 90) {
+		$largeur += (5*$fontsize);
+		$pos = "-$dimjour";
+	} else { $largeur = (3*$fontsize); $pos= 0; }
+	  
+	return "\n<div style='position: relative; z-index: 2; top: ${pos}px; margin-$spip_lang_left: " . $largeur . "px'>$res</div>";
+}
+
+function http_calendrier_ics_titre($annee, $mois, $jour,$script, $finurl='')
+{
+	$date = mktime(0,0,0,$mois, $jour, $annee);
+	$jour = date("d",$date);
+	$mois = date("m",$date);
+	$annee = date("Y",$date);
+	$nom = affdate_jourcourt("$annee-$mois-$jour");
+	return "<div class='calendrier-arial10 calendrier-titre'>" .
+	  http_href(calendrier_args_date($script, $annee, $mois, $jour, 'jour', $finurl), $nom, $nom, '', 'calendrier-noir') .
+	  "</div>";
+}
+
+
+function http_calendrier_sans_date($annee, $mois, $evenements)
+{
+  $r = $evenements[0+($annee . $mois . "00")];
+  if (!$r) return "";
+  $res = "\n<div class='calendrier-arial10 calendrier-titre'>".
+    _T('info_mois_courant').
+    "</div>";
+  foreach ($r as $evenement) $res .= http_calendrier_sans_heure($evenement);
+  return $res;
+}
+
+
+function http_calendrier_sans_heure($ev)
+{
+	$desc = propre($ev['DESCRIPTION']);
+	$sum = $ev['SUMMARY'];
+	if (!$sum) $sum = $desc;
+	$i = isset($ev['DESCRIPTION']) ? 11 : 9; // 11: article; 9:autre
+	if ($ev['URL'])
+	  $sum = http_href(quote_amp($ev['URL']), $sum, $desc);
+	$sum = pipeline('agenda_rendu_evenement',array('args'=>array('evenement'=>$ev,'type'=>'sans_heure'),'data'=>$sum));
+	return "\n<div class='calendrier-arial$i calendrier-evenement'>" .
+	  "<span class='" . $ev['CATEGORIES'] . "'>&nbsp;</span>&nbsp;$sum</div>"; 
+}
+
+function http_calendrier_avec_heure($evenement, $amj)
+{
+	$jour_debut = substr($evenement['DTSTART'], 0,8);
+	$jour_fin = substr($evenement['DTEND'], 0, 8);
+	if ($jour_fin <= 0) $jour_fin = $jour_debut;
+	if (($jour_debut <= 0) OR ($jour_debut > $amj) OR ($jour_fin < $amj))
+	  return "";
+	
+	$desc = propre($evenement['DESCRIPTION']);
+	$sum = $evenement['SUMMARY'];
+	if (!$sum) $sum = $desc;
+	$sum = ereg_replace(' +','&nbsp;', typo($sum));
+	if ($lieu = $evenement['LOCATION'])
+	  $sum .= '<br />' . $lieu;
+	if ($perso = $evenement['ATTENDEE'])
+	  $sum .=  '<br />' . substr($evenement['ATTENDEE'], 0,strpos($evenement['ATTENDEE'],'@'));
+	if ($evenement['URL'])
+	  $sum = http_href(quote_amp($evenement['URL']), $sum, $desc, 'border: 0px');
+
+	$sum = pipeline('agenda_rendu_evenement',array('args'=>array('evenement'=>$evenement,'type'=>'avec_heure'),'data'=>$sum));
+	$opacity = "";
+	$deb_h = substr($evenement['DTSTART'],-6,2);
+	$deb_m = substr($evenement['DTSTART'],-4,2);
+	$fin_h = substr($evenement['DTEND'],-6,2);
+	$fin_m = substr($evenement['DTEND'],-4,2);
+	
+	if ($deb_h >0 OR $deb_m > 0) {
+	  if ((($deb_h > 0) OR ($deb_m > 0)) AND $amj == $jour_debut)
+	    { $deb = "<span  style='font-weight: bold;'>" . $deb_h . ':' . $deb_m . '</span>';}
+	  else { 
+	    $deb = '...'; 
+	  }
+	  
+	  if ((($fin_h > 0) OR ($fin_m > 0)) AND $amj == $jour_fin)
+	    { $fin = "<span  style='font-weight: bold;'>" . $fin_h . ':' . $fin_m . '</span> ';}
+	  else { 
+	    $fin = '...'; 
+	  }
+	  
+	  if ($amj == $jour_debut OR $amj == $jour_fin) {
+	    $sum = "<div>$deb-$fin</div>$sum";
+	  } else {
+	    $opacity =' calendrier-opacity';
+	  }
+	}
+	return "\n<div class='calendrier-arial10 calendrier-evenement " . $evenement['CATEGORIES'] ."$opacity'>$sum\n</div>\n"; 
+}
+
+# Bandeau superieur d'un calendrier selon son $type (jour/mois/annee):
+# 2 icones vers les 2 autres types, a la meme date $jour $mois $annee
+# 2 icones de loupes pour zoom sur la meme date et le meme type
+# 2 fleches appelant le $script sur les periodes $pred/$suiv avec une $ancre
+# et le $nom du calendrier
+
+function http_calendrier_navigation($annee, $mois, $jour, $echelle, $partie_cal, $nom, $script, $args_pred, $args_suiv, $type, $ancre)
+{
+	global $spip_lang_right, $spip_lang_left, $couleur_foncee;
+
+	if (!$echelle) $echelle = DEFAUT_D_ECHELLE;
+
+	if ($args_pred) {
+	  list($a, $m, $j, $t) = $args_pred;
+	  $args_pred = http_href(calendrier_args_date($script, $a, $m, $j, $t, "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre"),
+				 http_img_pack("fleche-$spip_lang_left.png", '&lt;&lt;&lt;', "class='calendrier-png'"),
+				 _T('precedent'));
+	}
+
+	if ($args_suiv) {
+	  list($a, $m, $j, $t) = $args_suiv;
+	  $args_suiv = http_href(calendrier_args_date($script, $a, $m, $j, $t, "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre"),
+				 http_img_pack("fleche-$spip_lang_right.png",  '&gt;&gt;&gt;', "class='calendrier-png'"),
+				 _T('suivant'));
+	}
+
+	$today=getdate(time());
+	$jour_today = $today["mday"];
+	$mois_today = $today["mon"];
+	$annee_today = $today["year"];
+
+	$id = 'nav-agenda' .ereg_replace('[^A-Za-z0-9]', '', $ancre);
+
+	return 
+	  "<div class='navigation-calendrier calendrier-moztop8'" 
+	  . (!isset($couleur_foncee) ? "" : "\nstyle='background-color: $couleur_foncee;'")
+	  . "><div style='float: $spip_lang_right; padding-left: 5px; padding-right: 5px;'>"
+	  . (($type == "mois") ? '' :
+	     (
+		  http_href_img(calendrier_args_date($script, $annee, $mois, $jour, $type, "&amp;echelle=$echelle&amp;partie_cal=sansheure$ancre"),
+				 "sans-heure.gif",
+				 "class='calendrier-png" .
+				 (($partie_cal == "sansheure") ? " calendrier-opacity'" : "'"),
+				 _T('sans_heure'))
+		  .http_href_img(calendrier_args_date($script, $annee, $mois, $jour, $type, "&amp;echelle=$echelle&amp;partie_cal=tout$ancre"),
+				 "heures-tout.png",
+				 "class='calendrier-png" .
+				 (($partie_cal == "tout") ? " calendrier-opacity'" : "'"),
+				 _T('cal_jour_entier'))
+		  .http_href_img(calendrier_args_date($script, $annee, $mois, $jour, $type, "&amp;echelle=$echelle&amp;partie_cal=matin$ancre"),
+				 "heures-am.png",
+				 "class='calendrier-png" .
+				 (($partie_cal == "matin") ? " calendrier-opacity'" : "'"),
+				 _T('cal_matin'))
+
+		  .http_href_img(calendrier_args_date($script, $annee, $mois, $jour, $type, "&amp;echelle=$echelle&amp;partie_cal=soir$ancre"),
+				 "heures-pm.png", 
+				 "class='calendrier-png" .
+				 (($partie_cal == "soir") ? " calendrier-opacity'" : "'"),
+				 _T('cal_apresmidi'))
+		  . "&nbsp;"
+		  . http_href_img(calendrier_args_date($script, $annee, $mois, $jour, $type, "&amp;partie_cal=$partie_cal&amp;echelle=" .
+					  floor($echelle * 1.5)) . $ancre,
+					 "loupe-moins.gif",
+					 '',
+					 _T('info_zoom'). '-')
+		  . http_href_img(calendrier_args_date($script, $annee, $mois, $jour, $type, "&amp;partie_cal=$partie_cal&amp;echelle=" .
+					  floor($echelle / 1.5)) . $ancre, 
+					 "loupe-plus.gif",
+					 '', 
+					 _T('info_zoom'). '+')
+		  ))
+	  . http_href_img(calendrier_args_date($script,$annee, $mois, $jour, "jour", "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre"),"cal-jour.gif",
+			  (($type == 'jour') ? " class='calendrier-opacity'" : ''),
+			  _T('cal_par_jour'))
+
+	  . http_href_img(calendrier_args_date($script,$annee, $mois, $jour, "semaine", "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre"), "cal-semaine.gif", 
+			  (($type == 'semaine') ?  " class='calendrier-opacity'" : "" ),
+			  _T('cal_par_semaine'))
+
+	  . http_href_img(calendrier_args_date($script,$annee, $mois, $jour, "mois", "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre"),"cal-mois.gif",
+			  (($type == 'mois') ? " class='calendrier-opacity'" : "" ),
+			  _T('cal_par_mois'))
+	  . "</div>"
+	  . "&nbsp;&nbsp;"
+	  . http_href_img(calendrier_args_date($script,$annee_today, $mois_today, $jour_today, $type, "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre"),
+			  "cal-today.gif",
+			  (" onmouseover=\"montrer('$id');\"" .
+			   (($annee == $annee_today && $mois == $mois_today && (($type == 'mois')  || ($jour == $jour_today)))
+			    ? " class='calendrier-opacity'" : "")),
+			  _T("ecrire:info_aujourdhui"))
+	  . "&nbsp;"
+	  . $args_pred 
+	  . $args_suiv
+	  . "&nbsp;&nbsp;"
+	  . $nom
+	  . (_DIR_RESTREINT ? '' :  aide("messcalen"))
+	  . "</div>"
+	  . http_calendrier_invisible($annee, $mois, $jour, $script, "&amp;echelle=$echelle&amp;partie_cal=$partie_cal$ancre", $id);
+}
+
+
+// fabrique un petit agenda accessible par survol
+
+function http_calendrier_invisible($annee, $mois, $jour, $script, $ancre, $id)
+{
+	global $spip_lang_right, $spip_lang_left, $couleur_claire;
+	$gadget = "<div style='position: relative;z-index: 1000;'
+			onmouseover=\"montrer('$id');\"
+			onmouseout=\"cacher('$id');\">"
+	  . "<table id='$id' class='calendrier-cadreagenda'"
+	  . (!isset($couleur_claire) ? "" : " style='background-color: $couleur_claire'")
+	  . ">\n<tr><td colspan='3' style='text-align:$spip_lang_left;'>";
+
+	$annee_avant = $annee - 1;
+	$annee_apres = $annee + 1;
+
+	for ($i=$mois; $i < 13; $i++) {
+	  $nom = nom_mois("$annee_avant-$i-1");
+	  $gadget .= http_href(calendrier_args_date($script,$annee_avant, $i, 1, "mois", $ancre),
+				     $nom,$nom . ' ' . $annee_avant,'', 'calendrier-annee') ;
+			}
+	for ($i=1; $i < $mois - 1; $i++) {
+	  $nom = nom_mois("$annee-$i-1");
+	  $gadget .= http_href(calendrier_args_date($script,$annee, $i, 1, "mois", $ancre),
+					$nom,$nom . ' ' . $annee,'', 'calendrier-annee');
+			}
+	$gadget .= "</td></tr>"
+		. "\n<tr><td class='calendrier-tripleagenda'>"
+		. http_calendrier_agenda($annee, $mois-1, $jour, $mois, $annee, $GLOBALS['afficher_bandeau_calendrier_semaine'], $script,$ancre) 
+		. "</td>\n<td class='calendrier-tripleagenda'>"
+	  . http_calendrier_agenda($annee, $mois, $jour, $mois, $annee, $GLOBALS['afficher_bandeau_calendrier_semaine'], $script,$ancre) 
+		. "</td>\n<td class='calendrier-tripleagenda'>"
+	  . http_calendrier_agenda($annee, $mois+1, $jour, $mois, $annee, $GLOBALS['afficher_bandeau_calendrier_semaine'], $script,$ancre) 
+		. "</td>"
+		. "</tr>"
+		. "\n<tr><td colspan='3' style='text-align:$spip_lang_right;'>";
+	for ($i=$mois+2; $i <= 12; $i++) {
+	  $nom = nom_mois("$annee-$i-1");
+	  $gadget .= http_href(calendrier_args_date($script,$annee, $i, 1, "mois", $ancre),
+					$nom,$nom . ' ' . $annee,'', 'calendrier-annee');
+			}
+	for ($i=1; $i < $mois+1; $i++) {
+	  $nom = nom_mois("$annee_apres-$i-1");
+	  $gadget .= http_href(calendrier_args_date($script, $annee_apres, $i, 1, "mois", $ancre),
+					$nom,$nom . ' ' . $annee_apres,'', 'calendrier-annee');
+			}
+	return $gadget . "</td></tr></table></div>";
+}
+
+// agenda mensuel 
+
+function http_calendrier_agenda ($annee, $mois, $jour_ved, $mois_ved, $annee_ved, $semaine = false,  $script='', $ancre='', $evt='') {
+
+  if (!$script) $script =  $GLOBALS['PHP_SELF'] ;
+
+  if (!$mois) {$mois = 12; $annee--;}
+  elseif ($mois==13) {$mois = 1; $annee++;}
+  if (!$evt) $evt = sql_calendrier_agenda($annee, $mois);
+  $nom = affdate_mois_annee("$annee-$mois-1");
+  return 
+    "<div class='calendrier-titre calendrier-arial10'>" .
+    http_href(calendrier_args_date($script, $annee, $mois, 1, 'mois', $ancre),
+	      $nom, $nom,
+	      'color: black;') .
+    "<table width='100%' cellspacing='0' cellpadding='0'>" .
+    http_calendrier_agenda_rv ($annee, $mois, $evt,				
+			        'http_calendrier_clic', array($script, $ancre),
+			        $jour_ved, $mois_ved, $annee_ved, 
+				$semaine) . 
+    "</table>" .
+    "</div>";
+}
+
+function http_calendrier_clic($annee, $mois, $jour, $type, $couleur, $perso)
+{
+
+  list($script, $ancre) = $perso;
+
+  return http_href(calendrier_args_date($script, $annee, $mois, $jour,$type, $ancre), 
+		   $jour,
+		   "$jour-$mois-$annee",
+		   "color: $couleur; font-weight: bold");
+}
+
+// typographie un mois sous forme d'un tableau de 7 colonnes
+
+function http_calendrier_agenda_rv ($annee, $mois, $les_rv, $fclic, $perso='',
+				    $jour_ved='', $mois_ved='', $annee_ved='',
+				    $semaine='') {
+	global $couleur_foncee, $spip_lang_left, $spip_lang_right;
+
+	// Former une date correcte (par exemple: $mois=13; $annee=2003)
+	$date_test = date("Y-m-d", mktime(0,0,0,$mois, 1, $annee));
+	$mois = mois($date_test);
+	$annee = annee($date_test);
+	if ($semaine) 
+	{
+		$jour_semaine_valide = date("w",mktime(1,1,1,$mois_ved,$jour_ved,$annee_ved));
+		if ($jour_semaine_valide==0) $jour_semaine_valide=7;
+		$debut = mktime(1,1,1,$mois_ved,$jour_ved-$jour_semaine_valide+1,$annee_ved);
+		$fin = mktime(1,1,1,$mois_ved,$jour_ved-$jour_semaine_valide+7,$annee_ved);
+	} else { $debut = $fin = '';}
+	
+	$today=getdate(time());
+	$jour_today = $today["mday"];
+	$cemois = ($mois == $today["mon"] AND $annee ==  $today["year"]);
+
+	$total = '';
+	$ligne = '';
+	$jour_semaine = date("w", mktime(1,1,1,$mois,1,$annee));
+	if ($jour_semaine==0) $jour_semaine=7;
+	for ($i=1;$i<$jour_semaine;$i++) $ligne .= "\n\t<td></td>";
+	$style0 = (!isset($couleur_foncee)) ? "" : " style='border: 1px solid $couleur_foncee;'";
+	for ($j=1; (checkdate($mois,$j,$annee)); $j++) {
+		$style = "";
+		$nom = mktime(1,1,1,$mois,$j,$annee);
+		$jour_semaine = date("w",$nom);
+		if ($jour_semaine==0) $jour_semaine=7;
+
+		if ($j == $jour_ved AND $mois == $mois_ved AND $annee == $annee_ved) {
+		  $class= 'calendrier-arial11 calendrier-demiagenda';
+		  $type = 'jour';
+		  $couleur = "black";
+		  } else if ($semaine AND $nom >= $debut AND $nom <= $fin) {
+		  $class= 'calendrier-arial11 calendrier-demiagenda' . 
+ 		      (($jour_semaine==1) ? " calendrier-$spip_lang_left"  :
+		       (($jour_semaine==7) ? " calendrier-$spip_lang_right" :
+			''));
+		  $type = ($semaine ? 'semaine' : 'jour') ;
+		  $couleur = "black";
+		} else {
+		  if ($j == $jour_today AND $cemois) {
+			$style = $couleur_foncee;
+			if(!$style) $style = '#333333';
+			$couleur = "white";
+		    } else {
+			if ($jour_semaine == 7) {
+				$style = "#aaaaaa";
+				$couleur = 'white';
+			} else {
+				$style = "#ffffff";
+				$couleur = "#aaaaaa";
+			}
+			if ($les_rv[$j] > 0) {
+			  $style = "#ffffff";
+			  $couleur = "black";
+			}
+		  }
+		  $class= 'calendrier-arial11 calendrier-agenda';
+		  $type = ($semaine ? 'semaine' : 'jour') ;
+		}
+		if ($style)
+		  $style = " style='background-color: $style'";
+		else $style = $style0;
+		$ligne .= "\n\t<td><div class='$class'$style>" .
+		  $fclic($annee,$mois, $j, $type, $couleur, $perso) .
+		  "</div></td>";
+		if ($jour_semaine==7) 
+		    {
+		      if ($ligne) $total .= "\n<tr>$ligne\n</tr>";
+		      $ligne = '';
+		    }
+	}
+	return $total . (!$ligne ? '' : "\n<tr>$ligne\n</tr>");
+}
+
+
+function calendrier_categories($table, $num, $objet)
+{
+  if (function_exists('generer_calendrier_class'))
+    return generer_calendrier_class($table, $num, $objet);
+  else {
+    // cf calendrier.css
+    $result= spip_fetch_array(spip_query("SELECT " . (($objet != 'id_breve') ? 'id_secteur' : 'id_rubrique') . "
+FROM	$table
+WHERE	$objet=$num
+"));
+    if ($result) $num = $result[0];
+    return 'calendrier-couleur' . (($num%14)+1);
+  }
+}
+
+//------- fonctions d'appel MySQL. 
+// au dela cette limite, pas de production HTML
+
+function sql_calendrier_mois($annee,$mois,$jour) {
+	$avant = "'" . date("Y-m-d", mktime(0,0,0,$mois,1,$annee)) . "'";
+	$apres = "'" . date("Y-m-d", mktime(0,0,0,$mois+1,1,$annee)) .
+	" 00:00:00'";
+	return array($avant, $apres);
+}
+
+function sql_calendrier_semaine($annee,$mois,$jour) {
+	$w_day = date("w", mktime(0,0,0,$mois, $jour, $annee));
+	if ($w_day == 0) $w_day = 7; // Gaffe: le dimanche est zero
+	$debut = $jour-$w_day;
+	$avant = "'" . date("Y-m-d", mktime(0,0,0,$mois,$debut,$annee)) . "'";
+	$apres = "'" . date("Y-m-d", mktime(1,1,1,$mois,$debut+7,$annee)) .
+	" 23:59:59'";
+	return array($avant, $apres);
+}
+
+// ici on prend en fait le jour, la veille et le lendemain
+
+function sql_calendrier_jour($annee,$mois,$jour) {
+	$avant = "'" . date("Y-m-d", mktime(0,0,0,$mois,$jour-1,$annee)) . "'";
+	$apres = "'" . date("Y-m-d", mktime(1,1,1,$mois,$jour+1,$annee)) .
+	" 23:59:59'";
+	return array($avant, $apres);
+}
+
+// retourne un tableau de 2 tableaux indexes par des dates
+// - le premier indique les evenements du jour, sans indication de duree
+// - le deuxime indique les evenements commencant ce jour, avec indication de duree
+
+function sql_calendrier_interval($limites) {
+	list($avant, $apres) = $limites;
+	$evt = array();
+	sql_calendrier_interval_articles($avant, $apres, $evt);
+	sql_calendrier_interval_breves($avant, $apres, $evt);
+	sql_calendrier_interval_rubriques($avant, $apres, $evt);
+	return array($evt, sql_calendrier_interval_rv($avant, $apres));
+}
+
+function  sql_calendrier_interval_forums($limites, &$evenements) {
+	list($avant, $apres) = $limites;
+	$result=spip_query("
+SELECT	DISTINCT titre, date_heure, id_forum
+FROM	spip_forum
+WHERE	date_heure >= $avant
+ AND	date_heure < $apres
+ORDER BY date_heure
+");
+	while($row=spip_fetch_array($result)){
+		$amj = date_anneemoisjour($row['date_heure']);
+		$id = $row['id_forum'];
+		$evenements[$amj][]=
+		array(
+			'URL' => generer_url_forum($id),
+			'CATEGORIES' => 'calendrier-couleur7',
+			'SUMMARY' => $row['titre'],
+			'DTSTART' => date_ical($row['date_heure']));
+	}
+}
+
+# 3 fonctions retournant les evenements d'une periode
+# le tableau retourne est indexe par les balises du format ics
+# afin qu'il soit facile de produire de tels documents.
+
+function sql_calendrier_interval_articles($avant, $apres, &$evenements) {
+	
+	$result=spip_query("
+SELECT	id_article, titre, date, descriptif, chapo
+FROM	spip_articles
+WHERE	statut='publie'
+ AND	date >= $avant
+ AND	date < $apres
+ORDER BY date
+");
+	while($row=spip_fetch_array($result)){
+		$amj = date_anneemoisjour($row['date']);
+		$id = $row['id_article'];
+		$evenements[$amj][]=
+		    array(
+			  'CATEGORIES' => calendrier_categories('spip_articles', $id, 'id_article'),
+			'DESCRIPTION' => $row['descriptif'],
+			'SUMMARY' => $row['titre'],
+			'URL' => generer_url_article($id, 'prop'));
+	}
+}
+
+function sql_calendrier_interval_rubriques($avant, $apres, &$evenements) {
+	
+	$result=spip_query("
+SELECT	DISTINCT R.id_rubrique, titre, descriptif, date
+FROM	spip_rubriques AS R, spip_documents_rubriques AS L
+WHERE	statut='publie'
+ AND	date >= $avant
+ AND	date < $apres
+ AND	R.id_rubrique = L.id_rubrique
+ORDER BY date
+");
+	while($row=spip_fetch_array($result)){
+		$amj = date_anneemoisjour($row['date']);
+		$id = $row['id_rubrique'];
+		$evenements[$amj][]=
+		    array(
+			  'CATEGORIES' => calendrier_categories('spip_rubriques', $id, 'id_rubrique'),
+			'DESCRIPTION' => $row['descriptif'],
+			'SUMMARY' => $row['titre'],
+			'URL' => generer_url_rubrique($id, 'prop'));
+	}
+}
+
+function sql_calendrier_interval_breves($avant, $apres, &$evenements) {
+	$result=spip_query("
+SELECT	id_breve, titre, date_heure, id_rubrique
+FROM	spip_breves
+WHERE	statut='publie'
+ AND	date_heure >= $avant
+ AND	date_heure < $apres
+ORDER BY date_heure
+");
+	while($row=spip_fetch_array($result)){
+		$amj = date_anneemoisjour($row['date_heure']);
+		$id = $row['id_breve'];
+		$ir = $row['id_rubrique'];
+		$evenements[$amj][]=
+		array(
+		      'URL' => generer_url_breve($id, 'prop'),
+		      'CATEGORIES' => calendrier_categories('spip_breves', $ir, 'id_breve'),
+		      'SUMMARY' => $row['titre']);
+	}
+}
+
+function sql_calendrier_interval_rv($avant, $apres) {
+	global $connect_id_auteur;
+	$evenements= array();
+	if (!$connect_id_auteur) return $evenements;
+	$result=spip_query("
+SELECT	messages.id_message, messages.titre, messages.texte,
+	messages.date_heure, messages.date_fin, messages.type
+FROM	spip_messages AS messages, 
+	spip_auteurs_messages AS lien
+WHERE	((lien.id_auteur='$connect_id_auteur'
+ AND	lien.id_message=messages.id_message) OR messages.type='affich')
+ AND	messages.rv='oui' 
+ AND	((messages.date_fin >= $avant OR messages.date_heure >= $avant) AND messages.date_heure <= $apres)
+ AND	messages.statut='publie'
+GROUP BY messages.id_message
+ORDER BY messages.date_heure
+");
+	while($row=spip_fetch_array($result)){
+		$date_heure=$row["date_heure"];
+		$date_fin=$row["date_fin"];
+		$type=$row["type"];
+		$id_message=$row['id_message'];
+
+		if ($type=="pb")
+		  $cat = 'calendrier-couleur2';
+		else {
+		  if ($type=="affich")
+		  $cat = 'calendrier-couleur4';
+		  else {
+		    if ($type!="normal")
+		      $cat = 'calendrier-couleur12';
+		    else {
+		      $cat = 'calendrier-couleur9';
+		      $auteurs = array();
+		      $result_aut=spip_query("
+SELECT	auteurs.nom 
+FROM	spip_auteurs AS auteurs,
+	spip_auteurs_messages AS lien 
+WHERE	(lien.id_message='$id_message' 
+  AND	(auteurs.id_auteur!='$connect_id_auteur'
+  AND	lien.id_auteur=auteurs.id_auteur))");
+			while($row_auteur=spip_fetch_array($result_aut)){
+				$auteurs[] = $row_auteur['nom'];
+			}
+		    }
+		  }
+		}
+
+		$jour_avant = substr($avant, 9,2);
+		$mois_avant = substr($avant, 6,2);
+		$annee_avant = substr($avant, 1,4);
+		$jour_apres = substr($apres, 9,2);
+		$mois_apres = substr($apres, 6,2);
+		$annee_apres = substr($apres, 1,4);
+		$ical_apres = date_anneemoisjour("$annee_apres-$mois_apres-".sprintf("%02d",$jour_apres));
+
+		// Calcul pour les semaines a cheval sur deux mois 
+ 		$j = 0;
+		$amj = date_anneemoisjour("$annee_avant-$mois_avant-".sprintf("%02d", $j+($jour_avant)));
+
+		while ($amj <= $ical_apres) {
+		if (!($amj == date_anneemoisjour($date_fin) AND ereg("00:00:00", $date_fin)))  // Ne pas prendre la fin a minuit sur jour precedent
+			$evenements[$amj][$id_message]=
+			  array(
+				'URL' => generer_url_ecrire("message","id_message=$id_message"),
+				'DTSTART' => date_ical($date_heure),
+				'DTEND' => date_ical($date_fin),
+				'DESCRIPTION' => $row['texte'],
+				'SUMMARY' => $row['titre'],
+				'CATEGORIES' => $cat,
+				'ATTENDEE' => (count($auteurs) == 0) ? '' : join($auteurs,", "));
+			
+			$j ++; 
+			$ladate = date("Y-m-d",mktime (1,1,1,$mois_avant, ($j + $jour_avant), $annee_avant));
+			
+			$amj = date_anneemoisjour($ladate);
+
+		}
+
+	}
+  return $evenements;
+}
+
+// fonction SQL, pour la messagerie
+
+function sql_calendrier_taches_annonces () {
+	global $connect_id_auteur;
+	$r = array();
+	if (!$connect_id_auteur) return $r;
+	$result = spip_query("
+SELECT * FROM spip_messages 
+WHERE type = 'affich' AND rv != 'oui' AND statut = 'publie' ORDER BY date_heure DESC");
+	if (spip_num_rows($result) > 0)
+		while ($x = spip_fetch_array($result)) $r[] = $x;
+	return $r;
+}
+
+function sql_calendrier_taches_pb () {
+	global $connect_id_auteur;
+	$r = array();
+	if (!$connect_id_auteur) return $r;
+	$result = spip_query("
+SELECT * FROM spip_messages AS messages 
+WHERE id_auteur=$connect_id_auteur AND statut='publie' AND type='pb' AND rv!='oui'");
+	if (spip_num_rows($result) > 0){
+	  $r = array();
+	  while ($x = spip_fetch_array($result)) $r[] = $x;
+	}
+	return $r;
+}
+
+function sql_calendrier_taches_rv () {
+	global $connect_id_auteur;
+	$r = array();
+	if (!$connect_id_auteur) return $r;
+	$result = spip_query("
+SELECT messages.* 
+FROM spip_messages AS messages, spip_auteurs_messages AS lien 
+WHERE ((lien.id_auteur='$connect_id_auteur' 
+	AND lien.id_message=messages.id_message) 
+	OR messages.type='affich') 
+AND messages.rv='oui'
+AND ( (messages.date_heure > DATE_SUB(NOW(), INTERVAL 1 DAY) 
+	AND messages.date_heure < DATE_ADD(NOW(), INTERVAL 1 MONTH))
+	OR (messages.date_heure < NOW() AND messages.date_fin > NOW() ))
+AND messages.statut='publie' 
+GROUP BY messages.id_message 
+ORDER BY messages.date_heure");
+	if (spip_num_rows($result) > 0){
+	  $r = array();
+	  while ($x = spip_fetch_array($result)) $r[] = $x;
+	}
+	return  $r;
+}
+
+function sql_calendrier_agenda ($annee, $mois) {
+	global $connect_id_auteur;
+
+	$rv = array();
+	if (!$connect_id_auteur) return $rv;
+	$date = date("Y-m-d", mktime(0,0,0,$mois, 1, $annee));
+	$mois = mois($date);
+	$annee = annee($date);
+
+	// rendez-vous personnels dans le mois
+	$result_messages=spip_query("SELECT messages.date_heure FROM spip_messages AS messages, spip_auteurs_messages AS lien WHERE ((lien.id_auteur='$connect_id_auteur' AND lien.id_message=messages.id_message) OR messages.type='affich') AND messages.rv='oui' AND messages.date_heure >='$annee-$mois-1' AND date_heure < DATE_ADD('$annee-$mois-1', INTERVAL 1 MONTH) AND messages.statut='publie'");
+	while($row=spip_fetch_array($result_messages)){
+		$rv[journum($row['date_heure'])] = 1;
+	}
+	return $rv;
+}
+
+?>
Index: plugins/agenda_1_9_1/inc/agenda_filtres.php
===================================================================
--- plugins/agenda_1_9_1/inc/agenda_filtres.php	(revision 6)
+++ plugins/agenda_1_9_1/inc/agenda_filtres.php	(revision 6)
@@ -0,0 +1,180 @@
+<?php
+/**
+ * Fichier de filtres communs au plugin Agenda et PIM_agenda
+ *
+ */
+
+function Agenda_memo_full($date_deb=0, $date_fin=0 , $titre='', $descriptif='', $lieu='', $url='', $cal='')
+{
+	static $agenda = array();
+	if (!$date_deb) {
+		$res = $agenda;
+		$agenda=array();
+		return $res;
+	}
+	$url=str_replace("&amp;","&",$url);
+	
+	$idatedeb = date_ical($date_deb);
+	$idatefin = date_ical($date_fin);
+	$cal = trim($cal); // func_get_args (filtre alterner) rajoute \n !!!!
+	$startday1=explode(' ',$date_deb);
+	$startday1=$startday1['0'].' 00:00:00';
+	$ts_startday1=strtotime($startday1);
+	$ts_date_fin=strtotime($date_fin);
+	$maxdays=365;
+	while (($ts_startday1<$ts_date_fin)&&($maxdays-->0))
+	{
+		$day=date('Y-m-d H:i:s',$ts_startday1);
+		$agenda[$cal][(date_anneemoisjour($day))][] =  array(
+			'CATEGORIES' => $cal,
+			'DTSTART' => $idatedeb,
+			'DTEND' => $idatefin,
+			'DESCRIPTION' => $descriptif,
+			'SUMMARY' => $titre,
+			'LOCATION' => $lieu,
+			'URL' => $url);
+		$ts_startday1 += 24*3600; // le jour suivant
+	}
+
+	// toujours retourner vide pour qu'il ne se passe rien
+	return "";
+}
+
+function Agenda_memo_evt_full($date_deb=0, $date_fin=0 , $titre='', $descriptif='', $lieu='', $url='', $cal='')
+{
+	static $evenements = array();
+	if (!$date_deb) return $evenements;
+	$url=str_replace("&amp;","&",$url);
+	
+	$idatedeb = date_ical(reset(explode(" ",$date_deb))." 00:00:00");
+	$idatefin = date_ical(reset(explode(" ",$date_fin))." 00:00:00");
+	$cal = trim($cal); // func_get_args (filtre alterner) rajoute \n !!!!
+	$startday1=explode(' ',$date_deb);
+	$startday1=$startday1['0'].' 00:00:00';
+	$ts_startday1=strtotime($startday1);
+	$ts_date_fin=strtotime($date_fin);
+	$maxdays=365;
+	while (($ts_startday1<$ts_date_fin)&&($maxdays-->0))
+	{
+		$day=date('Y-m-d H:i:s',$ts_startday1);
+		$evenements[$cal][(date_anneemoisjour($day))][] =  array(
+			'CATEGORIES' => $cal,
+			'DTSTART' => $idatedeb,
+			'DTEND' => $idatefin,
+			'DESCRIPTION' => $descriptif,
+			'SUMMARY' => $titre,
+			'LOCATION' => $lieu,
+			'URL' => $url);
+		$ts_startday1 += 24*3600; // le jour suivant
+	}
+
+	// toujours retourner vide pour qu'il ne se passe rien
+	return "";
+}
+
+function Agenda_affiche_full($i)
+{
+	$args = func_get_args();
+	$nb = array_shift($args); // nombre d'evenements (on pourrait l'afficher)
+	$sinon = array_shift($args);
+	if (!$nb) return $sinon;
+	$type = array_shift($args);
+	$agenda = Agenda_memo_full(0);
+	$evt_avec = array();
+	foreach (($args ? $args : array_keys($agenda)) as $k) {
+		if (isset($agenda[$k])&&is_array($agenda[$k]))
+			foreach($agenda[$k] as $d => $v) {
+				$evt_avec[$d] = isset($evt_avec[$d]) ? (array_merge($evt_avec[$d], $v)) : $v;
+			}
+	}
+
+	$evenements = Agenda_memo_evt_full(0);
+	$evt_sans = array();
+	foreach (($args ? $args : array_keys($evenements)) as $k) {
+		if (isset($evenements[$k])&&is_array($evenements[$k]))
+			foreach($evenements[$k] as $d => $v) {
+				$evt_sans[$d] = isset($evt_sans[$d]) ? (array_merge($evt_sans[$d], $v)) : $v;
+			}
+	}
+
+
+	if ($type != 'periode')
+		$evt = array($evt_sans, $evt_avec);
+	else
+	{
+		$d = array_keys($evt_avec);
+		$mindate = min($d);
+		$min = substr($mindate,6,2);
+		$max = $min + ((strtotime(max($d)) - strtotime($mindate)) / (3600 * 24));
+		if ($max < 31) $max = 0;
+			$evt = array($evt_sans, $evt_avec, $min, $max);
+		$type = 'mois';
+	}
+
+	include_spip('inc/agenda');
+	$texte=http_calendrier_init('', $type, '', '', self(), $evt);
+
+	return $texte;
+}
+
+function Agenda_affdate_debut_fin($date_debut, $date_fin, $horaire = 'oui'){
+	static $trans_tbl=NULL;
+	if ($trans_tbl==NULL){
+		$trans_tbl = get_html_translation_table (HTML_ENTITIES);
+		$trans_tbl = array_flip ($trans_tbl);
+	}
+	
+	$date_debut = strtotime($date_debut);
+	$date_fin = strtotime($date_fin);
+	$s = "";
+	if (($d=date("Y-m-d",$date_debut))==date("Y-m-d",$date_fin))
+	{ // meme jour
+		$s = ucfirst(nom_jour($d))." ".affdate_jourcourt($d);
+		if ($horaire=='oui'){
+			$s .= " ".($hd=date("H:i",$date_debut));
+			if ($hd!=($hf=date("H:i",$date_fin)))
+				$s .= "-$hf";
+		}
+	}
+	else if ((date("Y-m",$date_debut))==date("Y-m",$date_fin))
+	{ // meme annee et mois, jours differents
+		$d=date("Y-m-d",$date_debut);
+		if ($horaire=='oui'){
+			$s = _T('agenda:evenement_date_du') . " " . affdate_jourcourt($d);
+			$s .= " ".($hd=date("H:i",$date_debut));
+			$s .= " " . _T('agenda:evenement_date_au').date("d  H:i ",$date_fin);
+		}
+		else {
+			$s = _T('agenda:evenement_date_du') . " " . jour($d);
+			$s .= " " . _T('agenda:evenement_date_au').affdate_jourcourt(date("Y-m-d",$date_fin));
+		}
+	}
+	else if ((date("Y",$date_debut))==date("Y",$date_fin))
+	{ // meme annee, mois et jours differents
+		$d=date("Y-m-d",$date_debut);
+		$s = _T('agenda:evenement_date_du') . " " . affdate_jourcourt($d);
+		if ($horaire=='oui')
+			$s .= " ".date("H:i",$date_debut);
+		$d = date("Y-m-d",$date_fin);
+		$s .= " "._T('agenda:evenement_date_au').affdate_jourcourt($d);
+		if ($horaire=='oui')
+			$s .= " ".date("H:i",$date_fin);
+	}
+	else
+	{ // tout different
+		$s = _T('agenda:evenement_date_du') . " " . affdate($d);
+		if ($horaire=='oui')
+			$s .= " ".date("(H:i)",$date_debut);
+		$d = date("Y-m-d",$date_fin);
+		$s .= " "._T('agenda:evenement_date_au').affdate($d);
+		if ($horaire=='oui')
+			$s .= " ".date("(H:i)",$date_fin);
+	}
+	return unicode2charset(charset2unicode(strtr($s,$trans_tbl),''));	
+}
+
+function Agenda_dateplus($date,$secondes,$format){
+	$date = strtotime($date)+eval("return $secondes;"); // permet de passer une expression
+	return date($format,$date);
+}
+?>
Index: plugins/agenda_1_9_1/inc/agenda_gestion.php
===================================================================
--- plugins/agenda_1_9_1/inc/agenda_gestion.php	(revision 6)
+++ plugins/agenda_1_9_1/inc/agenda_gestion.php	(revision 6)
@@ -0,0 +1,753 @@
+<?php
+
+include_spip('inc/texte');
+include_spip('inc/date');
+
+function Agenda_install(){
+	Agenda_verifier_base();
+}
+
+function Agenda_uninstall(){
+	include_spip('base/agenda_evenements');
+	include_spip('base/abstract_sql');
+
+	// suppression du champ evenements a la table spip_groupe_mots
+	spip_query("ALTER TABLE `spip_groupes_mots` DROP `evenements`");
+	
+}
+
+function Agenda_verifier_base(){
+	$version_base = 0.12;
+	$current_version = 0.0;
+	if (   (!isset($GLOBALS['meta']['agenda_base_version']) )
+			|| (($current_version = $GLOBALS['meta']['agenda_base_version'])!=$version_base)){
+		include_spip('base/agenda_evenements');
+		if ($current_version==0.0){
+			include_spip('base/create');
+			include_spip('base/abstract_sql');
+			creer_base();
+			// ajout du champ evenements a la table spip_groupe_mots
+			// si pas deja existant
+			$desc = spip_abstract_showtable("spip_groupes_mots", '', true);
+			if (!isset($desc['field']['evenements'])){
+				spip_query("ALTER TABLE spip_groupes_mots ADD `evenements` VARCHAR(3) NOT NULL AFTER `syndic`");
+			}
+			ecrire_meta('agenda_base_version',$current_version=$version_base);
+		}
+		if ($current_version<0.11){
+			spip_query("ALTER TABLE spip_evenements ADD `horaire` ENUM('oui','non') DEFAULT 'oui' NOT NULL AFTER `lieu`");
+			ecrire_meta('agenda_base_version',$current_version=0.11);
+		}
+		if ($current_version<0.12){
+			spip_query("ALTER TABLE spip_evenements ADD `id_article` bigint(21) DEFAULT '0' NOT NULL AFTER `id_evenement`");
+			spip_query("ALTER TABLE spip_evenements ADD INDEX ( `id_article` )");
+			$res = spip_query ("SELECT * FROM spip_evenements_articles");
+			while ($row = spip_fetch_array($res)){
+				$id_article = $row['id_article'];
+				$id_evenement = $row['id_evenement'];
+				spip_query("UPDATE spip_evenements SET id_article=$id_article WHERE id_evenement=$id_evenement");
+			}
+			spip_query("DROP TABLE spip_evenements_articles");
+			ecrire_meta('agenda_base_version',$current_version=0.12);
+		}
+		
+		ecrire_metas();
+	}
+	
+	if (isset($GLOBALS['meta']['INDEX_elements_objet'])){
+		$INDEX_elements_objet = unserialize($GLOBALS['meta']['INDEX_elements_objet']);
+		if (!isset($INDEX_elements_objet['spip_evenements'])){
+			$INDEX_elements_objet['spip_evenements'] = array('titre'=>8,'descriptif'=>4,'lieu'=>3);
+			ecrire_meta('INDEX_elements_objet',serialize($INDEX_elements_objet));
+			ecrire_metas();
+		}
+	}
+	if (isset($GLOBALS['meta']['INDEX_objet_associes'])){
+		$INDEX_objet_associes = unserialize($GLOBALS['meta']['INDEX_objet_associes']);
+		if (!isset($INDEX_objet_associes['spip_articles']['spip_evenements'])){
+			$INDEX_objet_associes['spip_articles']['spip_evenements'] = 1;
+			ecrire_meta('INDEX_objet_associes',serialize($INDEX_objet_associes));
+			ecrire_metas();
+		}
+	}
+	if (isset($GLOBALS['meta']['INDEX_elements_associes'])){
+		$INDEX_elements_associes = unserialize($GLOBALS['meta']['INDEX_elements_associes']);
+		if (!isset($INDEX_elements_associes['spip_evenements'])){
+			$INDEX_elements_associes['spip_evenements'] = array('titre'=>2,'descriptif'=>1);
+			ecrire_meta('INDEX_elements_associes',serialize($INDEX_elements_associes));
+			ecrire_metas();
+		}
+	}
+}
+
+function article_editable($id_article){
+	$flag_editable = false;
+	global $connect_id_auteur, $id_secteur; 
+
+ 	$id_parent = intval($id_parent);
+ 	if (!($id_article=intval($id_article)))
+ 		return false;
+
+	if ($row = spip_fetch_array(spip_query("SELECT statut, titre, id_rubrique FROM spip_articles WHERE id_article=".spip_abstract_quote($id_article)))) {
+		$statut_article = $row['statut'];
+		$titre_article = $row['titre'];
+		$id_rubrique = $row['id_rubrique'];
+		$statut_rubrique = acces_rubrique($id_rubrique);
+		if ($titre_article=='') $titre_article = _T('info_sans_titre');
+	}
+	else {
+		$statut_article = '';
+		$statut_rubrique = false;
+		$id_rubrique = '0';
+		if ($titre=='') $titre = _T('info_sans_titre');
+	}
+
+	$flag_auteur = spip_num_rows(spip_query("SELECT id_auteur FROM spip_auteurs_articles WHERE id_article=".spip_abstract_quote($id_article)." AND id_auteur=".spip_abstract_quote($connect_id_auteur)." LIMIT 1"));
+
+	$ok_nouveau_statut = false;
+	$flag_editable = ($statut_rubrique
+		OR ($flag_auteur
+			AND ($statut_article == 'prepa'
+				OR $statut_article == 'prop' 
+				OR $statut_article == 'poubelle')));
+	return $flag_editable;
+}
+
+function Agenda_afficher_date_evenement($date_debut, $date_fin, $horaire){
+	$s = "";
+	if (($d=date("Y-m-d",$date_debut))==date("Y-m-d",$date_fin))
+	{ // meme jour
+		$s = affdate_jourcourt($d);
+		if ($horaire=='oui'){
+			$s .= " ".($hd=date("H:i",$date_debut));
+			if ($hd!=($hf=date("H:i",$date_fin)))
+				$s .= "-$hf";
+		}
+	}
+	else if ((date("Y-m",$date_debut))==date("Y-m",$date_fin))
+	{ // meme annee et mois, jours differents
+		$d=date("Y-m-d",$date_debut);
+		$s = affdate_jourcourt($d);
+		if ($horaire=='oui')
+			$s .= " ".($hd=date("H:i",$date_debut));
+		$s .= "<br/>"._T('agenda:evenement_date_au').date(($horaire=='oui')?"d  H:i ":"d ",$date_fin);
+	}
+	else if ((date("Y",$date_debut))==date("Y",$date_fin))
+	{ // meme annee, mois et jours differents
+		$d=date("Y-m-d",$date_debut);
+		$s = affdate_jourcourt($d);
+		if ($horaire=='oui')
+			$s .= " ".date("H:i",$date_debut);
+		$d = date("Y-m-d",$date_fin);
+		$s .= "<br/>"._T('agenda:evenement_date_au').affdate_jourcourt($d);
+		if ($horaire=='oui')
+			$s .= " ".date("H:i",$date_fin);
+	}
+	else
+	{ // tout different
+		$s = affdate($d);
+		if ($horaire=='oui')
+			$s .= " ".date("(H:i)",$date_debut);
+		$d = date("Y-m-d",$date_fin);
+		$s .= "<br/>"._T('agenda:evenement_date_au').affdate($d);
+		if ($horaire=='oui')
+			$s .= " ".date("(H:i)",$date_fin);
+	}
+	return $s;	
+}
+
+function Agenda_formulaire_article_afficher_evenements($id_article, $flag_editable)
+{
+	global $connect_statut, $options,$connect_id_auteur;
+	$out = "";
+
+	$les_evenements = array();
+
+	$result = spip_query( "SELECT * FROM spip_evenements AS evenements "
+	. "WHERE evenements.id_article=".spip_abstract_quote($id_article)
+	. " AND evenements.id_evenement_source=0"
+	. " GROUP BY evenements.id_evenement ORDER BY evenements.date_debut");
+
+	if (spip_num_rows($result)) {
+		$out .= "<div class='liste liste-evenements'>";
+		$out .= "<table width='100%' cellpadding='3' cellspacing='0' border='0' background=''>";
+		$table = array();
+		while ($row = spip_fetch_array($result,SPIP_ASSOC)) {
+			$vals = array();
+			$id_evenement = $row['id_evenement'];
+			$titre = typo($row['titre']);
+			$descriptif = typo($row['descriptif']);
+			$horaire = $row['horaire'];
+			$date_debut = strtotime($row['date_debut']);
+			$date_fin = strtotime($row['date_fin']);
+			$id_evenement_source = $row['id_evenement_source'];
+			$repetition = ($id_evenement_source!=0);
+			
+			$les_evenements[] = $id_evenement;
+
+			$s = "<a href='".generer_url_ecrire('calendrier',"id_evenement=$id_evenement&ajouter_id_article=$id_article")."'>";
+			$s .= http_img_pack("../"._DIR_PLUGIN_AGENDA_EVENEMENTS."/img_pack/agenda-12.png",'', "border='0'", _T('agenda:titre_sur_l_agenda'));
+			$s .= "</a>";
+			$vals[] = $s;
+
+			$s = Agenda_afficher_date_evenement($date_debut,$date_fin, $horaire);
+			$s_rep = "";
+			$count_rep = 0;
+			$res2 = spip_query("SELECT * FROM spip_evenements WHERE id_evenement_source=".spip_abstract_quote($id_evenement)." ORDER BY date_debut");
+			while ($row2 = spip_fetch_array($res2)){
+				$s_rep .= Agenda_afficher_date_evenement(strtotime($row2['date_debut']),strtotime($row2['date_fin']),$row2['horaire'])."<br/>";
+				$count_rep++;
+			}
+			if (strlen($s_rep)){
+				$s .= "<br/>".bouton_block_invisible("repetitions_evenement_$id_evenement");
+				$s .= "$count_rep ". _T('agenda:evenement_repetitions');
+				$s .= debut_block_invisible("repetitions_evenement_$id_evenement");
+				$s .= $s_rep;
+				$s .= fin_block();
+			}
+
+			$vals[] = $s;
+
+			
+			if ($flag_editable) {
+				$url = self();
+				$url = parametre_url($url,'id_article',$id_article);
+				$url = parametre_url($url,'id_evenement',$id_evenement);
+				$url = parametre_url($url,'edit',1);
+				$s = "<a href='$url'>".($titre ? $titre : '<em>('._T('info_sans_titre').')</em>')."</a>";
+				$vals[] = $s;
+			}
+			else{
+				$vals[] = $titre;
+			}
+			$vals[] = propre($descriptif);
+		
+			if ($flag_editable) {
+				$vals[] =  "<a href='" . generer_url_ecrire("articles","id_article=$id_article&supp_evenement=$id_evenement#agenda") . "'>"._T('agenda:lien_retirer_evenement')."&nbsp;". http_img_pack('croix-rouge.gif', "X", "width='7' height='7' border='0' align='middle'") . "</a>";
+			} else {
+				$vals[] = "";
+			}
+			
+			$table[] = $vals;
+		}
+	
+		$largeurs = array('', '', '', '', '');
+		$styles = array('arial11', 'arial11', 'arial2', 'arial11', 'arial11');
+		$out .= afficher_liste($largeurs, $table, $styles, false);
+	
+		$out .= "</table></div>\n";
+	
+		$les_evenements = join(',', $les_evenements);
+	}
+	return array($out,$les_evenements) ;
+}
+
+
+//
+// Liste des evenements agenda de l'article
+//
+
+function Agenda_formulaire_article_ajouter_evenement($id_article, $les_evenements, $flag_editable){
+  global $spip_lang_left, $spip_lang_right, $options;
+	global $connect_statut, $options,$connect_id_auteur, $couleur_claire ;
+	$id_evenement = intval(_request('id_evenement'));
+	$edit = _request('edit');
+
+	$out = "";
+	$out .= "<div style='clear: both;'></div>";
+	if ($flag_editable){
+		if ((in_array($id_evenement,explode(",",$les_evenements)) && $edit==1)||_request('neweven'))
+			$out .=  debut_block_visible("evenementsarticle");
+		else
+			$out .=  debut_block_invisible("evenementsarticle");
+		
+		$out .=  "<div style='width:100%;'>";
+		$out .=  "<table width='100%'>";
+		$out .=  "<tr>";
+		$out .=  "<td>";
+	
+		$out .=  generer_url_post_ecrire("articles", "id_article=$id_article");
+		if (in_array($id_evenement,explode(",",$les_evenements)) && $edit==1){
+			$out .=  "<span class='verdana1'><strong>"._T('agenda:titre_cadre_modifier_evenement')."&nbsp; </strong></span>\n";
+		} else {
+			$out .=  "<span class='verdana1'><strong>"._T('agenda:titre_cadre_ajouter_evenement')."&nbsp; </strong></span>\n";
+		}
+		$out .=  "<div><input type='hidden' name='id_article' value=\"$id_article\">";
+
+		if (in_array($id_evenement,explode(",",$les_evenements)) && $edit==1){
+			$out .= Agenda_formulaire_edition_evenement($id_evenement, false);
+			$out .= "</div>";
+			$out .=  "</td></tr></table>";
+			$out .= "<div style='clear: both;'></div>";
+			$url = parametre_url(self(),'edit','');
+			$url = parametre_url($url,'neweven','1');
+			$url = parametre_url($url,'id_evenement','');
+			$out .= icone_horizontale(_T("agenda:icone_creer_evenement"),$url , "../"._DIR_PLUGIN_AGENDA_EVENEMENTS."/img_pack/agenda-24.png", "creer.gif",false);
+		}
+		else{
+			// recuperer le titre de l'article pour le mettre par defaut sur l'evenement
+			$titre_defaut = "";
+			$res = spip_query("SELECT titre FROM spip_articles where id_article=".spip_abstract_quote($id_article));
+			if ($row = spip_fetch_array($res))
+				$titre_defaut = $row['titre'];
+			
+			$out .= Agenda_formulaire_edition_evenement(NULL, true, '', $titre_defaut);
+			$out .= "</div>";
+			$out .=  "</td></tr></table>";
+		}
+
+		$out .= "</div>";
+		$out .=  fin_block();
+	}
+	return $out;
+}
+
+function Agenda_formulaire_article($id_article, $flag_editable){
+
+  global $spip_lang_left, $spip_lang_right, $options;
+	global $connect_statut, $options,$connect_id_auteur, $couleur_claire ;
+	
+	$out = "";
+	$out .= "<a name='agenda'></a>";
+	if ($flag_editable) {
+		$out .= Agenda_action_formulaire_article($id_article);
+		if (_request('edit')||_request('neweven'))
+			$bouton = bouton_block_visible("evenementsarticle");
+		else
+			$bouton = bouton_block_invisible("evenementsarticle");
+	}
+
+	$out .= debut_cadre_enfonce("../"._DIR_PLUGIN_AGENDA_EVENEMENTS."/img_pack/agenda-24.png", true, "", $bouton._T('agenda:texte_agenda')
+	." <a href='".generer_url_ecrire('calendrier',"ajouter_id_article=$id_article")."'>"._T('icone_calendrier')."</a>");
+
+	//
+	// Afficher les evenements
+	//
+
+	list($s,$les_evenements) = Agenda_formulaire_article_afficher_evenements($id_article, $flag_editable);
+	$out .= $s;
+	//
+	// Ajouter un evenements
+	//
+
+	if ($flag_editable)
+		$out .= Agenda_formulaire_article_ajouter_evenement($id_article, $les_evenements, $flag_editable);
+
+
+	$out .= fin_cadre_enfonce(true);
+	return $out;
+}
+
+
+function Agenda_action_update_repetitions($id_evenement,$repetitions,$liste_mots){
+	// evenement source
+	$res = spip_query("SELECT * FROM spip_evenements WHERE id_evenement=".spip_abstract_quote($id_evenement));
+	if ($row = spip_fetch_array(($res))){
+		$titre = $row['titre'];
+		$descriptif = $row['descriptif'];
+		$horaire = $row['horaire'];
+		$lieu = $row['lieu'];
+		$date_debut = strtotime($row['date_debut']);
+		$date_fin = strtotime($row['date_fin']);
+		$duree = $date_fin - $date_debut;
+		$id_evenement_source = $row['id_evenement_source'];
+		$id_article = $row['id_article'];
+		if ($id_evenement_source!=0)
+			return; // pas un evenement source donc rien a faire ici
+
+		$repetitions_updated = array();
+		// mettre a jour toutes les repetitions deja existantes ou les supprimer si plus lieu
+		$res = spip_query("SELECT id_evenement FROM spip_evenements WHERE id_evenement_source=".spip_abstract_quote($id_evenement));
+		while ($row = spip_fetch_array($res)){
+			$date = strtotime(date('Y-m-d',$row['date_debut']));
+			if (in_array($date,$repetitions)){
+				// il est maintenu, on l'update
+				$repetitions_updated[] = $date;
+				$update_date_debut = date('Y-m-d',$date)." ".date('H:i:s',$date_debut);
+				$update_date_fin = date('Y-m-d H:i:s',strtotime($update_date_debut)+$duree);
+				
+				// TODO : prendre en charge la mise a jour uniquement si conforme a l'original
+				$update_titre = $titre;
+				$update_descriptif = $descriptif;
+				$update_lieu = $lieu;
+				
+				// mettre a jour l'evenement
+				$res=spip_query("UPDATE spip_evenements SET `titre`=".spip_abstract_quote($update_titre)
+				. ",`descriptif`=".spip_abstract_quote($update_descriptif)
+				. ",`lieu`=".spip_abstract_quote($update_lieu)
+				. ",`horaire`=".spip_abstract_quote($horaire)
+				. ",`date_debut`=".spip_abstract_quote($update_date_debut)
+				. ",`date_fin`=".spip_abstract_quote($update_date_fin)
+				. ",`id_article`=".spip_abstract_quote($id_article)
+				. " WHERE `id_evenement` =".spip_abstract_quote($row['id_evenement']));
+				Agenda_action_update_liste_mots($row['id_evenement'],$liste_mots);
+			}
+			else {
+				// il est supprime
+				spip_query("DELETE FROM spip_mots_evenements WHERE id_evenement=".$row['id_evenement']);
+				spip_query("DELETE FROM spip_evenements WHERE id_evenement=".$row['id_evenement']);
+			}
+			
+		}
+		// regarder les repetitions a ajouter
+		foreach($repetitions as $date){
+			if (!in_array($date,$repetitions_updated)){
+				$update_date_debut = date('Y-m-d',$date)." ".date('H:i:s',$date_debut);
+				$update_date_fin = date('Y-m-d H:i:s',strtotime($update_date_debut)+$duree);
+				$update_titre = $titre;
+				$update_descriptif = $descriptif;
+				$update_lieu = $lieu;
+
+				$id_evenement_new = spip_abstract_insert("spip_evenements",
+					"(id_evenement_source,maj)",
+					"(".spip_abstract_quote($id_evenement).",NOW())");
+				if ($id_evenement_new==0)
+					spip_log("agenda action formulaire article : impossible d'ajouter un evenement repete");
+				else {
+					// mettre a jour l'evenement
+					$res=spip_query("UPDATE spip_evenements SET `titre`=".spip_abstract_quote($update_titre)
+					. ",`descriptif`=".spip_abstract_quote($update_descriptif)
+					. ",`lieu`=".spip_abstract_quote($update_lieu)
+					. ",`horaire`=".spip_abstract_quote($horaire)
+					. ",`date_debut`=".spip_abstract_quote($update_date_debut)
+					. ",`date_fin`=".spip_abstract_quote($update_date_fin)
+					. ",`id_article`=".spip_abstract_quote($id_article)
+					. " WHERE `id_evenement` =".spip_abstract_quote($id_evenement_new));
+					
+					Agenda_action_update_liste_mots($id_evenement_new,$liste_mots);
+				}
+			}
+		}
+	}
+}
+function Agenda_action_supprime_repetitions($supp_evenement){
+	$res = spip_query("SELECT * FROM spip_evenements WHERE id_evenement_source=".spip_abstract_quote($supp_evenement));
+	while ($row = spip_fetch_array($res)){
+		$id_evenement = $row['id_evenement'];
+		spip_query("DELETE FROM spip_mots_evenements WHERE id_evenement=".spip_abstract_quote($id_evenement));
+		spip_query("DELETE FROM spip_evenements WHERE id_evenement=".spip_abstract_quote($id_evenement));
+	}
+}
+
+function Agenda_action_update_liste_mots($id_evenement,$liste_mots){
+	// suppression des mots obsoletes
+	$cond_in = "";
+	if (count($liste_mots))
+		$cond_in = "AND " . calcul_mysql_in('id_mot', implode(",",$liste_mots), 'NOT');
+	spip_query("DELETE FROM spip_mots_evenements WHERE id_evenement=".spip_abstract_quote($id_evenement)." ".$cond_in);
+	// ajout/maj des nouveaux mots
+	foreach($liste_mots as $id_mot){
+		if (!spip_fetch_array(spip_query("SELECT * FROM spip_mots_evenements WHERE id_evenement=".spip_abstract_quote($id_evenement)." AND id_mot=".spip_abstract_quote($id_mot))))
+			spip_query("INSERT INTO spip_mots_evenements (id_mot,id_evenement) VALUES (".spip_abstract_quote($id_mot).",".spip_abstract_quote($id_evenement).")");
+	}
+}
+
+
+function Agenda_action_formulaire_article($id_article){
+	include_spip('base/abstract_sql');
+	// s'assurer que les tables sont crees
+	Agenda_install();
+	// gestion des requetes de mises à jour dans la base
+	$id_evenement = intval(_request('id_evenement'));
+	$insert = _request('evenement_insert');
+	$modif = _request('evenement_modif');
+	$supp_evenement = intval(_request('supp_evenement'));
+	if ($insert || $modif){
+	
+		if ( ($insert) && (!$id_evenement) ){
+			$id_evenement = spip_abstract_insert("spip_evenements",
+				"(id_evenement_source,maj)",
+				"('0',NOW())");
+			if ($id_evenement==0){
+				spip_log("agenda action formulaire article : impossible d'ajouter un evenement");
+				return;
+			}
+	 	}
+	 	if ($id_article){
+			// mettre a jour le lien evenement-article
+			spip_query("UPDATE spip_evenements SET id_article=".spip_abstract_quote($id_article)." WHERE id_evenement=".spip_abstract_quote($id_evenement));
+	 	}
+		$titre = _request('evenement_titre');
+		$descriptif = _request('evenement_descriptif');
+		$lieu = _request('evenement_lieu');
+		$horaire = _request('evenement_horaire');
+		if ($horaire!='oui') $horaire='non';
+	
+		// pour les cas ou l'utilisateur a saisi 29-30-31 un mois ou ca n'existait pas
+		$maxiter=4;
+		$st_date_deb=FALSE;
+		$jour_debut=_request('jour_evenement_debut');
+		// test <= car retour strtotime retourne -1 ou FALSE en cas d'echec suivant les versions
+		while(($st_date_deb<=FALSE)&&($maxiter-->0)) {
+			$date_deb=_request('annee_evenement_debut')."-"._request('mois_evenement_debut')."-".($jour_debut--)." "._request('heure_evenement_debut').":"._request('minute_evenement_debut');
+			$st_date_deb=strtotime($date_deb);
+		}
+		$date_deb=format_mysql_date(date("Y",$st_date_deb),date("m",$st_date_deb),date("d",$st_date_deb),date("H",$st_date_deb),date("i",$st_date_deb), $s=0);
+	
+		// pour les cas ou l'utilisateur a saisi 29-30-31 un mois ou ca n'existait pas
+		$maxiter=4;
+		$st_date_fin=FALSE;
+		$jour_fin=_request('jour_evenement_fin');
+		// test <= car retour strtotime retourne -1 ou FALSE en cas d'echec suivant les versions
+		while(($st_date_fin<=FALSE)&&($maxiter-->0)) {
+			$st_date_fin=_request('annee_evenement_fin')."-"._request('mois_evenement_fin')."-".($jour_fin--)." "._request('heure_evenement_fin').":"._request('minute_evenement_fin');
+			$st_date_fin=strtotime($st_date_fin);
+		}
+		$st_date_fin = max($st_date_deb,$st_date_fin);
+		$date_fin=format_mysql_date(date("Y",$st_date_fin),date("m",$st_date_fin),date("d",$st_date_fin),date("H",$st_date_fin),date("i",$st_date_fin), $s=0);
+	
+		// mettre a jour l'evenement
+		$res=spip_query("UPDATE spip_evenements SET `titre`=".spip_abstract_quote($titre)
+		. ",`descriptif`=".spip_abstract_quote($descriptif)
+		. ",`lieu`=".spip_abstract_quote($lieu)
+		. ",`horaire`=".spip_abstract_quote($horaire)
+		. ",`date_debut`=".spip_abstract_quote($date_deb)
+		. ",`date_fin`=".spip_abstract_quote($date_fin)
+		. " WHERE `id_evenement` =".spip_abstract_quote($id_evenement));
+
+		// les mots cles : par groupes
+		$res = spip_query("SELECT * FROM spip_groupes_mots WHERE evenements='oui' ORDER BY titre");
+		$liste_mots = array();
+		while ($row = spip_fetch_array($res,SPIP_ASSOC)){
+			$id_groupe = $row['id_groupe'];
+			$id_mot_a = _request("evenement_groupe_mot_select_$id_groupe"); // un array
+			if (is_array($id_mot_a) && count($id_mot_a)){
+				if ($row['unseul']=='oui')
+					$liste_mots[] = intval(reset($id_mot_a));
+				else 
+					foreach($id_mot_a as $id_mot)
+						$liste_mots[] = intval($id_mot);
+			}				
+		}
+
+		Agenda_action_update_liste_mots($id_evenement,$liste_mots);
+				
+		// gestion des repetitions
+		if (($repetitions = _request('selected_date_repetitions'))!=NULL){
+			$repetitions = explode(',',$repetitions);
+			$rep = array();
+			foreach($repetitions as $key=>$date){
+				if (preg_match(",[0-9][0-9]?/[0-9][0-9]?/[0-9][0-9][0-9][0-9],",$date)){
+					$date = explode('/',$date);
+					$date = $date[2]."/".$date[0]."/".$date[1];
+					$date = strtotime($date);
+				}
+				else {
+					$date = preg_replace(",[0-2][0-9]:[0-6][0-9]:[0-6][0-9]\s*(UTC|GMT)(\+|\-)[0-9]{4},","",$date);
+					$date = explode(' ',$date);
+					$date = strtotime($date[2]." ".$date[1]." ".$date[3]);
+				}
+				if (!in_array($date,$repetitions))
+					$rep[] = $date;
+			}
+			$repetitions = $rep;
+		}
+		else 
+			$repetitions = array();
+		Agenda_action_update_repetitions($id_evenement, $repetitions, $liste_mots);
+	}
+	else if ($supp_evenement){
+		$id_article = intval(_request('id_article'));
+		if (!$id_article)
+			$id_article = intval(_request('ajouter_id_article'));
+		$res = spip_query("SELECT * FROM spip_evenements WHERE id_article=".spip_abstract_quote($id_article)." AND id_evenement=".spip_abstract_quote($supp_evenement));
+		if ($row = spip_fetch_array($res)){
+			spip_query("DELETE FROM spip_mots_evenements WHERE id_evenement=".spip_abstract_quote($supp_evenement));
+			spip_query("DELETE FROM spip_evenements WHERE id_evenement=".spip_abstract_quote($supp_evenement));
+		}
+		Agenda_action_supprime_repetitions($supp_evenement);
+	}
+	return "";
+}
+
+
+function Agenda_formulaire_edition_evenement($id_evenement, $neweven, $ndate="", $titre_defaut=""){
+	global $spip_lang_right;
+	$out = "";
+
+	// inits
+	$ftitre=$titre_defaut;
+	$flieu='';
+	$fdescriptif='';
+	$fstdatedeb=time();
+	$fhoraire = 'oui';
+	if (($neweven)&&($ndate)){
+		$newdate=urldecode($ndate);
+		$test=strtotime($newdate);
+		if ($test>0)
+			$fstdatedeb=$test;
+	}
+	$fstdatefin=$fstdatedeb+60*60;
+
+	if ($id_evenement!=NULL){
+		$res = spip_query("SELECT evenements.* FROM spip_evenements AS evenements WHERE evenements.id_evenement=".spip_abstract_quote($id_evenement));
+		if ($row = spip_fetch_array($res)){
+			if (!$neweven){
+				$fid_evenement=$row['id_evenement'];
+				$ftitre=attribut_html($row['titre']);
+				$flieu=attribut_html($row['lieu']);
+				$fhoraire=attribut_html($row['horaire']);
+				$fdescriptif=attribut_html($row['descriptif']);
+				$fstdatedeb=strtotime($row['date_debut']);
+				$fstdatefin=strtotime($row['date_fin']);
+			}
+	 	}
+	}
+
+	$url=self();
+	$url=parametre_url($url,'edit','');
+	$url=parametre_url($url,'neweven','');
+	$url=parametre_url($url,'ndate','');
+	$url=parametre_url($url,'id_evenement','');
+
+	$out .= "<div class='agenda-visu-evenement'>";
+
+	$ajouter_id_article = _request('ajouter_id_article');
+	if ($ajouter_id_article && !_request('id_article')){
+		$res2 = spip_query("SELECT * FROM spip_articles AS articles WHERE id_article=".spip_abstract_quote($ajouter_id_article));
+		if ($row2 = spip_fetch_array($res2)){
+			$out .= "<div class='article-evenement'>";
+			$out .= "<a href='".generer_url_ecrire('articles',"id_article=".$row2['id_article'])."'>";
+			$out .= http_img_pack("article-24.gif", "", "width='24' height='24' border='0'");
+			$out .= entites_html($row2['titre'])."</a>";
+			$out .= "</div>\n";
+		}
+	}
+	
+	$out .= "<div class='agenda-visu-evenement-bouton-fermer'>";
+  $out .=	"<a href='$url'><img src='"._DIR_PLUGIN_AGENDA_EVENEMENTS."/img_pack/croix.png' width='12' height='12' style='border:none;'></a>";
+  $out .= "</div>\n";
+  $out .=  "<form name='edition_evenement' action='$url' method='post'>";
+  #$out .=  "<input type='hidden' name='redirect' value='$url' />\n";
+	if (!$neweven){
+	  $out .=  "<input type='hidden' name='id_evenement' value='$fid_evenement' />\n";
+	  $out .=  "<input type='hidden' name='evenement_modif' value='1' />\n";
+	}
+	else {
+	  $out .=  "<input type='hidden' name='evenement_insert' value='1' />\n";
+	}
+	
+	// TITRE
+	$out .=  "<div class='titre-titre'>"._T('agenda:evenement_titre')."</div>\n";
+	$out .=  "<div class='titre-visu'>";
+	$out .=  "<input type='text' name='evenement_titre' value=\"$ftitre\" style='width:100%;' />";
+	$out .=  "</div>\n";
+
+	// LIEU
+	$out .=  "<div class='lieu-titre'>"._T('agenda:evenement_lieu')."</div>";
+	$out .=  "<div class='lieu-visu'>";
+	$out .=  "<input type='text' name='evenement_lieu' value=\"$flieu\" style='width:100%;' />";
+	$out .=  "</div>\n";
+
+	// Horaire
+	$out .=  "<div class='horaire-titre'>";
+	$out .=  "<input type='checkbox' name='evenement_horaire' value='oui' ";
+	$out .= ($fhoraire=='oui'?"checked='checked' ":"");
+	$out .= " onClick=\"var element =  findObj('evenement_horaire');var choix = element.checked;
+	if (choix==true){	setvisibility('afficher_horaire_debut_evenement', 'visible');setvisibility('afficher_horaire_fin_evenement', 'visible');}
+	else{setvisibility('afficher_horaire_debut_evenement', 'hidden');setvisibility('afficher_horaire_fin_evenement', 'hidden');}\"";
+	$out .= "/>";
+	$out .= _T('agenda:evenement_horaire')."</div>";
+
+	// DATES
+	$out .=  "<div class='date-titre'>"._T('agenda:evenement_date')."</div>";
+	$out .=  "<div class='date-visu'>";
+	$out .=  _T('agenda:evenement_date_de');
+	$out .= WCalendar_controller(date('Y-m-d H:i:s',$fstdatedeb),"_evenement_debut");
+	$out .= "<span class='agenda_".($fhoraire=='oui'?"":"in")."visible_au_chargement' id='afficher_horaire_debut_evenement'>";
+	$out .=  _T('agenda:evenement_date_a');
+	$out .= Agenda_heure_selector(date('H',$fstdatedeb),date('i',$fstdatedeb),"_debut");
+	$out .=	"</span>";
+	$out .=  "<br/>";
+	$out .=  _T('agenda:evenement_date_au');
+	$out .= WCalendar_controller(date('Y-m-d H:i:s',$fstdatefin),"_evenement_fin");
+	$out .= "<span class='agenda_".($fhoraire=='oui'?"":"in")."visible_au_chargement' id='afficher_horaire_fin_evenement'>";
+	$out .=  _T('agenda:evenement_date_a');
+	$out .= Agenda_heure_selector(date('H',$fstdatefin),date('i',$fstdatefin),"_fin");
+	$out .=	"</span>";
+	$out .=  "</div>\n";
+	
+	// DESCRIPTIF
+	$out .=  "<div class='descriptif-titre'>"._T('agenda:evenement_descriptif')."</div>";
+	$out .=  "<div class='descriptif-visu'>";
+	$out .=  "<textarea name='evenement_descriptif' style='width:100%;' rows='3'>";
+	$out .=  $fdescriptif;
+	$out .=  "</textarea>\n";
+	$out .=  "</div>\n";
+
+	// MOTS CLES : chaque groupe de mot cle attribuable a un evenement agenda
+	// donne un select
+	$out .=  "<div class='agenda_mots_cles'>";
+	$res = spip_query("SELECT * FROM spip_groupes_mots WHERE evenements='oui' ORDER BY titre");
+	while ($row = spip_fetch_array($res,SPIP_ASSOC)){
+		$id_groupe = $row['id_groupe'];
+		$multiple = ($row['unseul']=='oui')?"size='4'":"multiple='multiple' size='4'";
+		
+		$id_mot_select = array();
+		if ($id_evenement){
+			$res2 = spip_query("SELECT mots_evenements.id_mot FROM spip_mots_evenements AS mots_evenements
+								LEFT JOIN spip_mots AS mots ON mots.id_mot=mots_evenements.id_mot 
+								WHERE mots.id_groupe=".spip_abstract_quote($id_groupe)." AND mots_evenements.id_evenement=".spip_abstract_quote($id_evenement));
+			while ($row2 = spip_fetch_array($res2))
+				$id_mot_select[] = $row2['id_mot'];
+		}
+
+		$nb_mots = 0;
+		$select = "";	
+		$select .= "<select name='evenement_groupe_mot_select_{$id_groupe}[]' class='fondl verdana1 agenda_mot_cle_select' $multiple>\n";
+		$select .= "\n<option value='x' style='font-variant: small-caps;' >".supprimer_numero($row['titre'])."</option>";
+
+		$res2= spip_query("SELECT * FROM spip_mots WHERE id_groupe=".spip_abstract_quote($id_groupe)." ORDER BY titre");
+		while ($row2 = spip_fetch_array($res2,SPIP_ASSOC)){
+			$id_mot = $row2['id_mot'];
+			$titre = $row2['titre'];
+			$select .= my_sel($id_mot, "&nbsp;&nbsp;&nbsp;$titre", in_array($id_mot,$id_mot_select)?$id_mot:0);
+			$nb_mots++;
+		}
+		$select .= "</select>\n";
+		if ($nb_mots)
+			$out .= $select;
+	}
+	$out .=  "</div>";
+	
+	$dates = "";
+	if ($id_evenement!=NULL){
+		$dates = array();
+		$res = spip_query("SELECT date_debut FROM spip_evenements WHERE id_evenement_source=".spip_abstract_quote($id_evenement));
+		while ($row=spip_fetch_array($res)){
+			$dates[] = date('m/d/Y',strtotime($row['date_debut']));
+		}
+		$dates = implode(",",$dates);
+	}
+	$out .= "<div class='repetitions-calendrier'>";
+	$out .= WCalendar_statique_point_entree('_repetitions',$dates);
+	$out .= "</div>";
+	
+  $out .=  "<div class='edition-bouton'>";
+  #echo "<input type='submit' name='submit' value='Annuler' />";
+	if ($neweven==1){
+		$out .=	"<div style='text-align:$spip_lang_right'><input type='submit' name='ajouter' value='"._T('bouton_ajouter')."' class='fondo' onclick='javascript:getSelectedDate_repetitions()'></div>";
+	}
+	else{
+		$out .=	"<div style='text-align:$spip_lang_right'><input type='submit' name='ajouter' value='"._T('bouton_enregistrer')."' class='fondo' onclick='javascript:getSelectedDate_repetitions()'></div>";
+	}
+	$out .=  "</div>\n";
+
+	// feature desactivee pour le moment
+	// $out .= "<script type='text/javascript' src='"._DIR_PLUGIN_AGENDA_EVENEMENTS."/img_pack/multiselect.js'></script>";
+
+  $out .=  "</div>";
+
+	$out .=  "</form>";
+	$out .=  "</div>\n";
+	return $out;
+}
+
+// Pre traitements -----------------------------------------------------------------------
+
+function Agenda_heure_selector($heure,$minute,$suffixe){
+	return
+		afficher_heure($heure, "name='heure_evenement$suffixe' size='1' class='fondl'") .
+  	afficher_minute($minute, "name='minute_evenement$suffixe' size='1' class='fondl'");
+}
+?>
Index: plugins/agenda_1_9_1/lang/agenda_es.php
===================================================================
--- plugins/agenda_1_9_1/lang/agenda_es.php	(revision 6)
+++ plugins/agenda_1_9_1/lang/agenda_es.php	(revision 6)
@@ -0,0 +1,39 @@
+<?php
+
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+'bouton_annuler' => 'Anular',
+'activite_editoriale' => 'Actividad editorial',
+'ajouter_un_evenement' => 'Añadir un evento a éste artículo',
+'texte_agenda' => 'AGENDA',
+'titre_cadre_ajouter_evenement' => 'Añadir un evento',
+'titre_cadre_modifier_evenement' => 'Modificar un evento',
+'item_mots_cles_association_evenements' => 'a los eventos',
+'info_un_evenement' => 'un evento,',
+'info_nombre_evenements' => '@nb_evenements@ eventos,',
+'info_evenements' => 'Eventos',
+'evenements' => 'Eventos',
+'evenement_titre' => 'Titulo',
+'evenement_descriptif' => 'Descripción',
+'evenement_lieu' => 'Lugar',
+'evenement_date' => 'Fecha',
+'evenement_date_de' => 'De ',
+'evenement_date_du' => 'Del ',
+'evenement_date_a' => 'a las ',
+'evenement_date_au' => 'Hasta ',
+'evenement_date_debut' => 'Fecha de comienzo',
+'evenement_date_fin' => 'Fecha de fin',
+'lien_retirer_evenement' => 'Suprimir',
+'evenement_horaire' => 'Horario',
+'titre_sur_l_agenda' => "Sobre la agenda",
+'icone_creer_evenement' => 'Creación de un nuevo evento',
+'evenement_repetitions' => 'Repeticiones',
+'repetition_de' => "Repetición de",
+'sans_titre' => "(con título)",
+'evenement_autres_occurences' => "Otras ocurrencias :",
+'bouton_supprimer' => "Suprimir",
+);
+
+
+?>
Index: plugins/agenda_1_9_1/lang/agenda_fr.php
===================================================================
--- plugins/agenda_1_9_1/lang/agenda_fr.php	(revision 6)
+++ plugins/agenda_1_9_1/lang/agenda_fr.php	(revision 6)
@@ -0,0 +1,39 @@
+<?php
+
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+'bouton_annuler' => 'Annuler',
+'activite_editoriale' => 'Activit&eacute; &Eacute;ditoriale',
+'ajouter_un_evenement' => 'ajouter un &eacute;v&eacute;nement &agrave; cet article',
+'texte_agenda' => 'AGENDA',
+'titre_cadre_ajouter_evenement' => 'Ajouter un &eacute;v&eacute;nement',
+'titre_cadre_modifier_evenement' => 'Modifier un &eacute;v&eacute;nement',
+'item_mots_cles_association_evenements' => 'aux &eacute;v&eacute;nements',
+'info_un_evenement' => 'un &eacute;v&eacute;nement,',
+'info_nombre_evenements' => '@nb_evenements@ &eacute;v&eacute;nements,',
+'info_evenements' => '&Eacute;v&eacute;nements',
+'evenements' => '&Eacute;v&eacute;nements',
+'evenement_titre' => 'Titre',
+'evenement_descriptif' => 'Descriptif',
+'evenement_lieu' => 'Lieu',
+'evenement_date' => 'Date',
+'evenement_date_de' => 'De ',
+'evenement_date_du' => 'Du ',
+'evenement_date_a' => '&agrave; ',
+'evenement_date_au' => 'Au ',
+'evenement_date_debut' => 'Date de d&eacute;but',
+'evenement_date_fin' => 'Date de fin',
+'lien_retirer_evenement' => 'Supprimer',
+'evenement_horaire' => 'Horaire',
+'titre_sur_l_agenda' => "Sur l'agenda",
+'icone_creer_evenement' => 'Cr&eacute;er un nouvel &eacute;v&eacute;nement',
+'evenement_repetitions' => 'R&eacute;p&eacute;titions',
+'repetition_de' => "R&eacute;p&eacute;tition de",
+'sans_titre' => "(sans titre)",
+'evenement_autres_occurences' => "Autres occurences :",
+'bouton_supprimer' => "Supprimer",
+);
+
+
+?>
Index: plugins/agenda_1_9_1/lang/agenda_nl.php
===================================================================
--- plugins/agenda_1_9_1/lang/agenda_nl.php	(revision 6)
+++ plugins/agenda_1_9_1/lang/agenda_nl.php	(revision 6)
@@ -0,0 +1,39 @@
+<?php
+
+// This is a SPIP language file  --  Ceci est un fichier langue de SPIP
+
+$GLOBALS[$GLOBALS['idx_lang']] = array(
+'bouton_annuler' => 'Annuleren',
+'activite_editoriale' => 'Hoofdactiviteit',
+'ajouter_un_evenement' => 'een gebeurtenis toevoegen aan dit artikel',
+'texte_agenda' => 'AGENDA',
+'titre_cadre_ajouter_evenement' => 'een gebeurtenis toevoegen',
+'titre_cadre_modifier_evenement' => 'een gebeurtenis wijzigen',
+'item_mots_cles_association_evenements' => 'aan de gebeurtenissen',
+'info_un_evenement' => 'een gebeurtenis,',
+'info_nombre_evenements' => '@nb_gebeurtenis@ gebeurtenissen,',
+'info_evenements' => 'gebeurtenissen',
+'evenements' => 'gebeurtenissen',
+'evenement_titre' => 'titel',
+'evenement_descriptif' => 'beschrijvend',
+'evenement_lieu' => 'Plaats',
+'evenement_date' => 'Date',
+'evenement_date_de' => 'van ',
+'evenement_date_du' => 'van ',
+'evenement_date_a' => 'tot ',
+'evenement_date_au' => 'tot ',
+'evenement_date_debut' => 'aanvangsdatum',
+'evenement_date_fin' => 'Einddatum',
+'lien_retirer_evenement' => 'Afschaffen',
+'evenement_horaire' => 'Dienstregeling',
+'titre_sur_l_agenda' => "Op de agenda",
+'icone_creer_evenement' => 'Een nieuwe gebeurtenis creëren',
+'evenement_repetitions' => 'Herhalingen',
+'repetition_de' => "Herhaling van",
+'sans_titre' => "(zonder titel)",
+'evenement_autres_occurences' => "Andere omstandigheden :",
+'bouton_supprimer' => "Afschaffen",
+);
+
+
+?>
Index: plugins/agenda_1_9_1/plugin.xml
===================================================================
--- plugins/agenda_1_9_1/plugin.xml	(revision 6)
+++ plugins/agenda_1_9_1/plugin.xml	(revision 6)
@@ -0,0 +1,61 @@
+<plugin>
+	<nom> <!-- Nom du plugin -->
+	Agenda
+	</nom>
+	<auteur>	<!-- Auteur du plugin -->
+	Cedric MORIN
+ 	[notre-ville.net->http://www.notre-ville.net]
+_ &copy; 2006 - Licence GPL
+	</auteur>
+	<version>
+	0.11
+	</version>
+	<etat>
+	stable
+	</etat>
+	<description>
+	Agenda Evenementiel
+_	{{Ce plugin necessite le plugin Widget Calendar}}
+	</description>
+	<options> <!-- fichier charge a chaque hit -->
+	agenda_mes_options.php
+	</options>
+	<fonctions> <!-- fichier charge a chaque recalcul -->
+	agenda_mes_fonctions.php
+	</fonctions>
+	<!-- classe d'implementation : espace de nommage qui prefixera les appels de fonction
+	sur le mode Rien::
+	ainsi les fonctions hors espace de nommage ne peuvent etre appelees
+	ce parametre est obligatoire et doit etre non vide
+	-->
+	<prefix> 
+	Agenda
+	</prefix>
+	<!-- Definitions des fonctions qui s'inserent dans les pipelines -->
+	<pipeline>
+		<nom>ajouter_onglets</nom>
+		<inclure>agenda.php</inclure>
+	</pipeline>
+	<pipeline>
+		<nom>exec_init</nom>
+		<inclure>agenda.php</inclure>
+	</pipeline>
+	<pipeline>
+		<nom>header_prive</nom>
+		<inclure>agenda.php</inclure>
+	</pipeline>
+	<pipeline>
+		<nom>affiche_milieu</nom>
+		<inclure>agenda.php</inclure>
+	</pipeline>
+	<pipeline>
+		<nom>agenda_rendu_evenement</nom>
+		<action>rendu_evenement</action>
+		<inclure>agenda.php</inclure>
+	</pipeline>
+	<pipeline>
+		<nom>taches_generales_cron</nom>
+	</pipeline>
+
+	<!-- Le parametre action est facultatif : en son absence la methode de la classe portant le nom du pipeline est appelee. Le parametre inclure est facultatif.	-->
+</plugin>
Index: plugins/agenda_1_9_1/public/criteres_agenda.php
===================================================================
--- plugins/agenda_1_9_1/public/criteres_agenda.php	(revision 6)
+++ plugins/agenda_1_9_1/public/criteres_agenda.php	(revision 6)
@@ -0,0 +1,117 @@
+<?php
+
+// {branche ?}
+// http://www.spip.net/@branche
+function critere_branche($idb, &$boucles, $crit) {
+	$not = $crit->not;
+	$boucle = &$boucles[$idb];
+  $type = $boucle->type_requete;
+  $nom = $table_des_tables[$type];
+  if ($boucle->id_table!='evenements' && $boucle->id_table!='pim_agenda')
+  	critere_branche_dist($idb, &$boucles, $crit);
+  else{
+		$arg = calculer_argument_precedent($idb, 'id_rubrique', $boucles);
+		$champ = 'id_rubrique';
+
+    $type = $boucle->type_requete;
+    $nom = $table_des_tables[$type];
+    list($nom, $desc) = trouver_def_table($nom ? $nom : $type, $boucle);
+
+    $cle = trouver_champ_exterieur($champ, $boucle->jointures, $boucle);
+    if ($cle) 
+      $cle = calculer_jointure($boucle, array($boucle->id_table, $desc), $cle, false);
+    if ($cle) $t = "L$cle";
+		// faire la jointure sur id_rubrique
+		
+		$c = "calcul_mysql_in('" .
+		  $t .
+		  ".id_rubrique', calcul_branche($arg), '')";
+		if ($crit->cond) $c = "($arg ? $c : 1)";
+				
+		if ($not)
+			$boucle->where[]= array("'NOT'", $c);
+		else
+			$boucle->where[]= $c;
+  }
+}
+
+function critere_agendafull_dist($idb, &$boucles, $crit)
+{
+	$params = $crit->param;
+
+	if (count($params) < 1)
+	      erreur_squelette(_T('zbug_info_erreur_squelette'),
+			       "{agenda ?} BOUCLE$idb");
+
+	$parent = $boucles[$idb]->id_parent;
+
+	// les valeurs $date et $type doivent etre connus a la compilation
+	// autrement dit ne pas etre des champs
+
+	$date_deb = array_shift($params);
+	$date_deb = $date_deb[0]->texte;
+
+	$date_fin = array_shift($params);
+	$date_fin = $date_fin[0]->texte;
+
+	$type = array_shift($params);
+	$type = $type[0]->texte;
+
+	$annee = $params ? array_shift($params) : "";
+	$annee = "\n" . 'sprintf("%04d", ($x = ' .
+		calculer_liste($annee, array(), $boucles, $parent) .
+		') ? $x : date("Y"))';
+
+	$mois =  $params ? array_shift($params) : "";
+	$mois = "\n" . 'sprintf("%02d", ($x = ' .
+		calculer_liste($mois, array(), $boucles, $parent) .
+		') ? $x : date("m"))';
+
+	$jour =  $params ? array_shift($params) : "";
+	$jour = "\n" . 'sprintf("%02d", ($x = ' .
+		calculer_liste($jour, array(), $boucles, $parent) .
+		') ? $x : date("d"))';
+
+	$annee2 = $params ? array_shift($params) : "";
+	$annee2 = "\n" . 'sprintf("%04d", ($x = ' .
+		calculer_liste($annee2, array(), $boucles, $parent) .
+		') ? $x : date("Y"))';
+
+	$mois2 =  $params ? array_shift($params) : "";
+	$mois2 = "\n" . 'sprintf("%02d", ($x = ' .
+		calculer_liste($mois2, array(), $boucles, $parent) .
+		') ? $x : date("m"))';
+
+	$jour2 =  $params ? array_shift($params) : "";
+	$jour2 = "\n" .  'sprintf("%02d", ($x = ' .
+		calculer_liste($jour2, array(), $boucles, $parent) .
+		') ? $x : date("d"))';
+
+	$boucle = &$boucles[$idb];
+	$date = $boucle->id_table . ".$date";
+
+	if ($type == 'jour')
+		$boucle->where[]= array("'AND'", 
+					array("'<='", "'DATE_FORMAT($date_deb, \'%Y%m%d\')'",("$annee . $mois . $jour")),
+					array("'>='", "'DATE_FORMAT($date_fin, \'%Y%m%d\')'",("$annee . $mois . $jour")));
+	elseif ($type == 'mois')
+		$boucle->where[]= array("'AND'", 
+					array("'<='", "'DATE_FORMAT($date_deb, \'%Y%m\')'",("$annee . $mois")),
+					array("'>='", "'DATE_FORMAT($date_fin, \'%Y%m\')'",("$annee . $mois")));
+	elseif ($type == 'semaine')
+		$boucle->where[]= array("'AND'", 
+					array("'>='",
+					     "'DATE_FORMAT($date_fin, \'%Y%m%d\')'", 
+					      ("date_debut_semaine($annee, $mois, $jour)")),
+					array("'<='",
+					      "'DATE_FORMAT($date_deb, \'%Y%m%d\')'",
+					      ("date_fin_semaine($annee, $mois, $jour)")));
+	elseif (count($crit->param) > 3)
+		$boucle->where[]= array("'AND'",
+					array("'>='",
+					      "'DATE_FORMAT($date_fin, \'%Y%m%d\')'",
+					      ("$annee . $mois . $jour")),
+					array("'<='", "'DATE_FORMAT($date_deb, \'%Y%m%d\')'", ("$annee2 . $mois2 . $jour2")));
+	// sinon on prend tout
+}
+?>
Index: plugins/agenda_1_9_1/svn.revision
===================================================================
--- plugins/agenda_1_9_1/svn.revision	(revision 6)
+++ plugins/agenda_1_9_1/svn.revision	(revision 6)
@@ -0,0 +1,3 @@
+Ce paquet a Ã©tÃ© produit Ã  partir de svn://zone.spip.org/spip-zone/_plugins_branche_stable_/_spip_1_9_1_/agenda Ã  Sun Sep  3 16:02:08 CEST 2006
+Revision: 4991
+Date: Thu Aug 31 09:02:04 CEST 2006
Index: plugins/widget_calendar_1_9/exec/demo_articles.php
===================================================================
--- plugins/widget_calendar_1_9/exec/demo_articles.php	(revision 6)
+++ plugins/widget_calendar_1_9/exec/demo_articles.php	(revision 6)
@@ -0,0 +1,1568 @@
+<?php
+
+/***************************************************************************\
+ *  SPIP, Systeme de publication pour l'internet                           *
+ *                                                                         *
+ *  Copyright (c) 2001-2006                                                *
+ *  Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James  *
+ *                                                                         *
+ *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
+ *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
+\***************************************************************************/
+
+if (!defined("_ECRIRE_INC_VERSION")) return;
+
+
+include_spip('inc/presentation');
+include_spip('inc/texte');
+include_spip('inc/rubriques');
+include_spip('inc/logos');
+include_spip('inc/mots');
+include_spip('inc/date');
+include_spip('inc/documents');
+include_spip('inc/forum');
+include_spip('base/abstract_sql');
+include_spip('inc/calendar');
+
+  // 28 paremetres, qui dit mieux ?
+  // moi ! elle en avait 61 en premiere approche
+
+function exec_affiche_articles_dist($id_article, $ajout_auteur, $change_accepter_forum, $change_petition, $changer_virtuel, $cherche_auteur, $cherche_mot, $debut, $email_unique, $flag_auteur, $flag_editable, $langue_article, $message, $nom_select, $nouv_auteur, $nouv_mot, $rubrique_article, $site_obli, $site_unique, $supp_auteur, $supp_mot, $texte_petition, $titre_article, $lier_trad)
+{
+  global $options, $spip_display, $spip_lang_left, $spip_lang_right, $dir_lang;
+
+$result = spip_query("SELECT * FROM spip_articles WHERE id_article='$id_article'");
+
+if ($row = spip_fetch_array($result)) {
+	$id_article = $row["id_article"];
+	$surtitre = $row["surtitre"];
+	$titre = $row["titre"];
+	$soustitre = $row["soustitre"];
+	$id_rubrique = $row["id_rubrique"];
+	$descriptif = $row["descriptif"];
+	$nom_site = $row["nom_site"];
+	$url_site = $row["url_site"];
+	$chapo = $row["chapo"];
+	$texte = $row["texte"];
+	$ps = $row["ps"];
+	$date = $row["date"];
+	$statut_article = $row["statut"];
+	$maj = $row["maj"];
+	$date_redac = $row["date_redac"];
+	$visites = $row["visites"];
+	$referers = $row["referers"];
+	$extra = $row["extra"];
+	$id_trad = $row["id_trad"];
+	$id_version = $row["id_version"];
+
+	if (ereg("([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2})", $date_redac, $regs)) {
+		$annee_redac = $regs[1];
+		$mois_redac = $regs[2];
+		$jour_redac = $regs[3];
+		$heure_redac = $regs[4];
+		$minute_redac = $regs[5];
+		if ($annee_redac > 4000) $annee_redac -= 9000;
+	}
+
+	if (ereg("([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2})", $date, $regs)) {
+		$annee = $regs[1];
+		$mois = $regs[2];
+		$jour = $regs[3];
+		$heure = $regs[4];
+		$minute = $regs[5];
+	}
+ }
+// reserver les Widget Calendar avant de commencer l'affichage
+WCalendar_ajoute(_T('texte_date_publication_article'),'');
+WCalendar_ajoute(_T('texte_date_publication_anterieure'),'_redac');
+
+debut_page("&laquo; $titre_article &raquo;", "documents", "articles", "", "", $id_rubrique);
+
+debut_grand_cadre();
+
+afficher_hierarchie($id_rubrique);
+
+fin_grand_cadre();
+
+if (!$row) {echo _T('public:aucun_article'); exit;}
+
+//
+// Affichage de la colonne de gauche
+//
+
+debut_gauche();
+
+boite_info_articles($id_article, $statut_article, $visites, $id_version);
+
+//
+// Logos de l'article et Boites de configuration avancee
+//
+
+
+// pour l'affichage du virtuel
+unset($virtuel);
+if (substr($chapo, 0, 1) == '=') {
+	$virtuel = substr($chapo, 1);
+}
+
+boites_de_config_articles($id_article, $id_rubrique, $flag_editable,
+			  $change_accepter_forum, $change_petition,
+			  $email_unique, $site_obli, $site_unique,
+			  $message, $texte_petition,
+			  $changer_virtuel, $virtuel);
+ 
+//
+// Affichage de la colonne de droite
+//
+
+debut_droite();
+
+changer_typo('','article'.$id_article);
+
+debut_cadre_relief();
+
+//
+// Titre, surtitre, sous-titre
+//
+
+ $modif = titres_articles($titre, $statut_article,$surtitre, $soustitre, $descriptif, $url_site, $nom_site, $flag_editable, $id_article, $id_rubrique);
+
+
+echo "<div class='serif' align='$spip_lang_left'>";
+
+ dates_articles($id_article, $id_rubrique, $flag_editable, $statut_article, $date,$annee, $mois, $jour, $heure, $minute, $date_redac, $annee_redac, $mois_redac, $jour_redac, $heure_redac, $minute_redac);
+
+//
+// Liste des auteurs de l'article
+//
+
+echo "<a name='auteurs'></a>";
+
+if ($flag_editable AND $options == 'avancees') {
+	$bouton = bouton_block_invisible("auteursarticle");
+}
+
+debut_cadre_enfonce("auteur-24.gif", false, "", $bouton._T('texte_auteurs').aide ("artauteurs"));
+
+//
+// Recherche d'auteur
+//
+
+ $supprimer_bouton_creer_auteur = rechercher_auteurs_articles($cherche_auteur, $id_article, $id_rubrique, $ajout_auteur, $flag_editable, $nouv_auteur, $supp_auteur);
+
+//
+// Afficher les auteurs
+//
+
+$les_auteurs = afficher_auteurs_articles($id_article, $flag_editable);
+
+//
+// Ajouter un auteur
+//
+
+if ($flag_editable AND $options == 'avancees') 
+	ajouter_auteurs_articles($id_article, $id_rubrique, $les_auteurs, $flag_editable, $rubrique_article, $supprimer_bouton_creer_auteur);
+
+fin_cadre_enfonce(false);
+
+//
+// Liste des mots-cles de l'article
+//
+
+if ($options == 'avancees' AND $GLOBALS['meta']["articles_mots"] != 'non') {
+  formulaire_mots('articles', $id_article, $nouv_mot, $supp_mot, $cherche_mot, $flag_editable, generer_url_ecrire("articles","id_article=$id_article"));
+}
+
+ langues_articles($id_article, $langue_article, $flag_editable, $id_rubrique, $id_trad, $dir_lang, $nom_select, $lier_trad);
+
+
+afficher_statut_articles($id_article, $rubrique_article, $statut_article);
+
+
+ afficher_corps_articles($virtuel, $chapo, $texte, $ps, $extra);
+
+if ($flag_editable) {
+	echo "\n\n<div align='$spip_lang_right'><br />";
+	bouton_modifier_articles($id_article, $id_rubrique, $modif,_T('texte_travail_article', $modif), "warning-24.gif", "");
+	echo "</div>";
+}
+
+//
+// Documents associes a l'article
+//
+
+ if ($spip_display != 4)
+ afficher_documents_non_inclus($id_article, "article", $flag_editable);
+
+//
+// "Demander la publication"
+//
+
+
+if ($flag_auteur AND $statut_article == 'prepa') {
+	echo "<P>";
+	debut_cadre_relief();
+	echo	"<center>",
+		"<B>"._T('texte_proposer_publication')."</B>",
+		aide ("artprop"),
+		"\n<form method='post' action='",
+		generer_action_auteur("instituer", "article $id_article prop", generer_url_ecrire('articles', "id_article=$id_article", true)),
+      "'>",
+		"<input type='submit' class='fondo' value=\"", 
+		_T('bouton_demande_publication'),
+		"\" />\n",
+		"</form>",
+		"</center>";
+	fin_cadre_relief();
+}
+
+echo "</div>";
+
+echo "</div>";
+fin_cadre_relief();
+
+ affiche_forums_article($id_article, $id_rubrique, $titre, $debut);
+
+fin_page();
+
+}
+
+function boite_info_articles($id_article, $statut_article, $visites, $id_version)
+{
+  global $connect_statut, $options, $flag_revisions;
+
+	debut_boite_info();
+ 
+	echo "<div align='center'>\n";
+
+	echo "<font face='Verdana,Arial,Sans,sans-serif' size='1'><b>"._T('info_numero_article')."</b></font>\n";
+	echo "<br><font face='Verdana,Arial,Sans,sans-serif' size='6'><b>$id_article</b></font>\n";
+
+	voir_en_ligne ('article', $id_article, $statut_article);
+
+
+	$activer_statistiques = $GLOBALS['meta']["activer_statistiques"];
+
+	if ($connect_statut == "0minirezo" AND $statut_article == 'publie' AND $visites > 0 AND $activer_statistiques != "non" AND $options == "avancees"){
+	icone_horizontale(_T('icone_evolution_visites', array('visites' => $visites)), generer_url_ecrire("statistiques_visites","id_article=$id_article"), "statistiques-24.gif","rien.gif");
+}
+
+	if ((($GLOBALS['meta']["articles_versions"]=='oui') && $flag_revisions)
+		AND $id_version>1 AND $options == "avancees") {
+	icone_horizontale(_T('info_historique_lien'), generer_url_ecrire("articles_versions","id_article=$id_article"), "historique-24.gif", "rien.gif");
+}
+
+	// Correction orthographique
+	if ($GLOBALS['meta']['articles_ortho'] == 'oui') {
+		$js_ortho = "onclick=\"window.open(this.href, 'spip_ortho', 'scrollbars=yes, resizable=yes, width=740, height=580'); return false;\"";
+		icone_horizontale(_T('ortho_verifier'), generer_url_ecrire("articles_ortho", "id_article=$id_article"), "ortho-24.gif", "rien.gif", 'echo', $js_ortho);
+	}
+
+	echo "</div>\n";
+	
+	fin_boite_info();
+}
+
+function boites_de_config_articles($id_article, $id_rubrique, $flag_editable,
+				   $change_accepter_forum, $change_petition,
+				   $email_unique, $site_obli, $site_unique,
+				   $message, $texte_petition,
+				   $changer_virtuel, $virtuel)
+{
+  global $connect_statut, $options, $spip_lang_right;
+
+// Logos de l'article
+
+	if ($id_article AND $flag_editable)
+	  afficher_boite_logo('art', 'id_article', $id_article,
+			      _T('logo_article').aide ("logoart"), _T('logo_survol'), 'articles');
+
+
+//
+// Boites de configuration avancee
+//
+
+	if ($options == "avancees" && $connect_statut=='0minirezo' && $flag_editable) {
+	  echo "<p>";
+	  debut_cadre_relief("forum-interne-24.gif");
+
+
+	list($nb_forums) = spip_fetch_array(spip_query("SELECT count(*) AS count FROM spip_forum WHERE id_article=$id_article 	AND statut IN ('publie', 'off', 'prop')"));
+
+	list($nb_signatures) = spip_fetch_array(spip_query("SELECT COUNT(*) AS count FROM spip_signatures WHERE id_article=$id_article AND statut IN ('publie', 'poubelle')"));
+
+	$visible = $change_accepter_forum || $change_petition
+		|| $nb_forums || $nb_signatures;
+
+	echo "<div class='verdana1' style='text-align: center;'><b>";
+	if ($visible)
+		echo bouton_block_visible("forumpetition");
+	else
+		echo bouton_block_invisible("forumpetition");
+	echo _T('bouton_forum_petition') .aide('confforums');
+	echo "</b></div>";
+	if ($visible)
+		echo debut_block_visible("forumpetition");
+	else
+		echo debut_block_invisible("forumpetition");
+
+
+	echo "<font face='Verdana,Arial,Sans,sans-serif' size='1'>\n";
+
+
+	// Forums
+
+	if ($nb_forums) {
+		echo "<br />\n";
+		icone_horizontale(_T('icone_suivi_forum', array('nb_forums' => $nb_forums)), generer_url_ecrire("articles_forum","id_article=$id_article"), "suivi-forum-24.gif", "");
+	}
+
+	// Reglage existant
+	$forums_publics = get_forums_publics($id_article);
+
+	// Modification du reglage ?
+	if (isset($change_accepter_forum)
+	AND $change_accepter_forum <> $forums_publics) {
+		$forums_publics = $change_accepter_forum;
+		modifier_forums_publics($id_article, $forums_publics);
+	}
+
+	// Afficher le formulaire de modification du reglage
+	echo formulaire_modification_forums_publics($id_article, $forums_publics, generer_url_ecrire("articles","id_article=$id_article"));
+
+
+	// Petitions
+
+	if ($change_petition) {
+		if ($change_petition == "on") {
+			if (!$email_unique) $email_unique = "non";
+			if (!$site_obli) $site_obli = "non";
+			if (!$site_unique) $site_unique = "non";
+			if (!$message) $message = "non";
+
+			$texte_petition = addslashes($texte_petition);
+
+			$result_pet = spip_query("REPLACE spip_petitions (id_article, email_unique, site_obli, site_unique, message, texte) VALUES ($id_article, '$email_unique', '$site_obli', '$site_unique', '$message', '$texte_petition')");
+		}
+		else if ($change_petition == "off") {
+			$result_pet = spip_query("DELETE FROM spip_petitions WHERE id_article=$id_article");
+		}
+	}
+
+	$petition = spip_fetch_array(spip_query("SELECT * FROM spip_petitions WHERE id_article=$id_article"));
+
+	$email_unique=$petition["email_unique"];
+	$site_obli=$petition["site_obli"];
+	$site_unique=$petition["site_unique"];
+	$message=$petition["message"];
+	$texte_petition=$petition["texte"];
+
+	echo generer_url_post_ecrire("articles","id_article=$id_article");
+
+	echo "<select name='change_petition'
+		class='fondl' style='font-size:10px;'
+		onChange=\"setvisibility('valider_petition', 'visible');\"
+		>\n";
+
+	if ($petition) {
+		$menu = array(
+			'on' => _T('bouton_radio_petition_activee'),
+			'off'=> _T('bouton_radio_supprimer_petition')
+		);
+		$val_menu = 'on';
+	} else {
+		$menu = array(
+			'off'=> _T('bouton_radio_pas_petition'),
+			'on' => _T('bouton_radio_activer_petition')
+		);
+		$val_menu = 'off';
+	}
+
+
+	foreach ($menu as $val => $desc) {
+		echo "<option";
+		if ($val_menu == $val)
+			echo " selected";
+		echo " value='$val'>".$desc."</option>\n";
+	}
+	echo "</select>\n";
+
+	if ($petition) {
+		if ($nb_signatures) {
+			echo "<br />\n";
+			icone_horizontale($nb_signatures.'&nbsp;'. _T('info_signatures'), generer_url_ecrire("controle_petition","id_article=$id_article"), "suivi-petition-24.gif", "");
+		}
+
+		echo "<br />\n";
+
+		if ($email_unique=="oui")
+			echo "<input type='checkbox' name='email_unique' value='oui' id='emailunique' checked>";
+		else
+			echo "<input type='checkbox' name='email_unique' value='oui' id='emailunique'>";
+		echo " <label for='emailunique'>"._T('bouton_checkbox_signature_unique_email')."</label><BR>";
+		if ($site_obli=="oui")
+			echo "<input type='checkbox' name='site_obli' value='oui' id='siteobli' checked>";
+		else
+			echo "<input type='checkbox' name='site_obli' value='oui' id='siteobli'>";
+		echo " <label for='siteobli'>"._T('bouton_checkbox_indiquer_site')."</label><BR>";
+		if ($site_unique=="oui")
+			echo "<input type='checkbox' name='site_unique' value='oui' id='siteunique' checked>";
+		else
+			echo "<input type='checkbox' name='site_unique' value='oui' id='siteunique'>";
+		echo " <label for='siteunique'>"._T('bouton_checkbox_signature_unique_site')."</label><BR>";
+		if ($message=="oui")
+			echo "<input type='checkbox' name='message' value='oui' id='message' checked>";
+		else
+			echo "<input type='checkbox' name='message' value='oui' id='message'>";
+		echo " <label for='message'>"._T('bouton_checkbox_envoi_message')."</label>";
+
+		echo "<P>"._T('texte_descriptif_petition')."&nbsp;:<BR>";
+		echo "<TEXTAREA NAME='texte_petition' CLASS='forml' ROWS='4' COLS='10' wrap=soft>";
+		echo entites_html($texte_petition);
+		echo "</TEXTAREA><P>\n";
+
+		echo "<P align='$spip_lang_right'>";
+	}
+
+	if (!$petition) echo "<span class='visible_au_chargement' id='valider_petition'>";
+	echo "<INPUT TYPE='submit' NAME='Changer' CLASS='fondo' VALUE='"._T('bouton_changer')."' STYLE='font-size:10px'>";
+	if (!$petition)  echo "</span>";
+	echo "</FORM>";
+
+	echo "</font>";
+	echo fin_block();
+
+	fin_cadre_relief();
+
+	// Redirection (article virtuel)
+	debut_cadre_relief("site-24.gif");
+	$visible = ($changer_virtuel || $virtuel);
+
+	echo "<div class='verdana1' style='text-align: center;'><b>";
+	if ($visible)
+		echo bouton_block_visible("redirection");
+	else
+		echo bouton_block_invisible("redirection");
+	echo _T('bouton_redirection');
+	echo aide ("artvirt");
+	echo "</b></div>";
+	if ($visible)
+		echo debut_block_visible("redirection");
+	else
+		echo debut_block_invisible("redirection");
+
+	echo generer_url_post_ecrire("articles", "id_article=$id_article");
+	echo "\n<INPUT TYPE='hidden' NAME='changer_virtuel' VALUE='oui'>";
+	$virtuelhttp = ($virtuel ? "" : "http://");
+
+	echo "<INPUT TYPE='text' NAME='virtuel' CLASS='formo' style='font-size:9px;' VALUE=\"$virtuelhttp$virtuel\" SIZE='40'><br>";
+	echo "<font face='Verdana,Arial,Sans,sans-serif' size=2>";
+	echo "(<b>"._T('texte_article_virtuel')."&nbsp;:</b> "._T('texte_reference_mais_redirige').")";
+	echo "</font>";
+	echo "<div align='$spip_lang_right'><INPUT TYPE='submit' NAME='Changer' CLASS='fondo' VALUE='"._T('bouton_changer')."' STYLE='font-size:10px'></div>";
+	echo "</form>";
+	echo fin_block();
+
+	fin_cadre_relief();
+ }
+
+//
+// Articles dans la meme rubrique
+//
+
+meme_rubrique_articles($id_rubrique, $id_article, $options);
+
+}
+
+function meme_rubrique_articles($id_rubrique, $id_article, $options, $order='articles.date', $limit=30)
+{
+	global $spip_lang_right, $spip_lang_left;
+
+	$vos_articles = spip_query("SELECT articles.id_article, articles.titre, articles.statut FROM spip_articles AS articles WHERE articles.id_rubrique='$id_rubrique' AND (articles.statut = 'publie' OR articles.statut = 'prop') AND articles.id_article != '$id_article' ORDER BY $order DESC LIMIT $limit");
+	if (spip_num_rows($vos_articles) > 0) {
+			echo "<div>&nbsp;</div>";
+			echo "<div class='bandeau_rubriques' style='z-index: 1;'>";
+			bandeau_titre_boite2(_T('info_meme_rubrique'), "article-24.gif");
+			echo "<div class='plan-articles'>";
+			while($row = spip_fetch_array($vos_articles)) {
+				$ze_article = $row['id_article'];
+				$ze_titre = typo($row['titre']);
+				$ze_statut = $row['statut'];
+				
+				if ($options == "avancees") {
+					$numero = "<div class='arial1' style='float: $spip_lang_right; color: black; padding-$spip_lang_left: 4px;'><b>"._T('info_numero_abbreviation')."$ze_article</b></div>";
+				}
+				echo "<a class='$ze_statut' style='font-size: 10px;' href='" . generer_url_ecrire("articles","id_article=$ze_article") . "'>$numero$ze_titre</a>";
+			}
+			echo "</div>";
+			echo "</div>";
+		}
+}
+
+function bouton_modifier_articles($id_article, $id_rubrique, $flag_modif, $mode, $ip, $im)
+{
+	if ($flag_modif) {
+	  icone(_T('icone_modifier_article'), generer_url_ecrire("articles_edit","id_article=$id_article"), $ip, $im);
+		echo "<font face='arial,helvetica,sans-serif' size='2'>$mode</font>";
+		echo aide("artmodif");
+	}
+	else {
+		icone(_T('icone_modifier_article'), generer_url_ecrire("articles_edit","id_article=$id_article"), "article-24.gif", "edit.gif");
+	}
+
+}
+
+function titres_articles($titre, $statut_article,$surtitre, $soustitre, $descriptif, $url_site, $nom_site, $flag_editable, $id_article, $id_rubrique)
+{
+	global  $dir_lang, $spip_lang_left, $connect_id_auteur;
+
+	$logo_statut = "puce-".puce_statut($statut_article).".gif";
+	
+	echo "\n<table cellpadding=0 cellspacing=0 border=0 width='100%'>";
+	echo "<tr width='100%'><td width='100%' valign='top'>";
+	
+	if ($surtitre) {
+		echo "<span $dir_lang><font face='arial,helvetica' size=3><b>";
+		echo typo($surtitre);
+		echo "</b></font></span>\n";
+	 }
+	 
+	gros_titre($titre, $logo_statut);
+	
+	if ($soustitre) {
+		echo "<span $dir_lang><font face='arial,helvetica' size=3><b>";
+		echo typo($soustitre);
+		echo "</b></font></span>\n";
+	}
+	
+	
+	if ($descriptif OR $url_site OR $nom_site) {
+		echo "<p><div align='$spip_lang_left' style='padding: 5px; border: 1px dashed #aaaaaa; background-color: #e4e4e4;' $dir_lang>";
+		echo "<font size=2 face='Verdana,Arial,Sans,sans-serif'>";
+		$texte_case = ($descriptif) ? "{{"._T('info_descriptif')."}} $descriptif\n\n" : '';
+		$texte_case .= ($nom_site.$url_site) ? "{{"._T('info_urlref')."}} [".$nom_site."->".$url_site."]" : '';
+		echo propre($texte_case);
+		echo "</font>";
+		echo "</div>";
+	}
+	
+	
+	if ($statut_article == 'prop') {
+		echo "<P><FONT FACE='Verdana,Arial,Sans,sans-serif' SIZE=2 COLOR='red'><B>"._T('text_article_propose_publication')."</B></FONT></P>";
+	}
+	
+	echo "</td>";
+	
+	$flag_modif = false;
+	
+	if ($flag_editable) {
+		echo "<td>". http_img_pack('rien.gif', " ", "width='5'") . "</td>\n";
+		echo "<td align='center'>";
+	
+		// Recuperer les donnees de l'article
+		if ($GLOBALS['meta']['articles_modif'] != 'non') {
+			$result = spip_query("SELECT auteur_modif, UNIX_TIMESTAMP(date_modif) AS modification, UNIX_TIMESTAMP(NOW()) AS maintenant FROM spip_articles WHERE id_article='$id_article'");
+
+	
+			if ($row = spip_fetch_array($result)) {
+				$auteur_modif = $row["auteur_modif"];
+				$modification = $row["modification"];
+				$maintenant = $row["maintenant"];
+	
+				$date_diff = floor(($maintenant - $modification)/60);
+	
+				if ($date_diff >= 0 AND $date_diff < 60 AND $auteur_modif > 0 AND $auteur_modif != $connect_id_auteur) {
+					$result_auteur = spip_query("SELECT nom FROM spip_auteurs WHERE id_auteur='$auteur_modif'");
+
+					if ($row_auteur = spip_fetch_array($result_auteur)) {
+						$nom_auteur_modif = typo($row_auteur["nom"]);
+					}
+					$modif = array('nom_auteur_modif' => $nom_auteur_modif, 'date_diff' => $date_diff);
+				}
+			}
+		}
+		bouton_modifier_articles($id_article, $id_rubrique, $modif, _T('avis_article_modifie', $modif), "article-24.gif", "edit.gif");
+	
+		echo "</td>";
+	 }
+	echo "</tr></table>\n";
+	echo "<div>&nbsp;</div>";
+	return $modif;
+}
+
+
+function dates_articles($id_article, $id_rubrique, $flag_editable, $statut_article, $date, $annee, $mois, $jour, $heure, $minute, $date_redac, $annee_redac, $mois_redac, $jour_redac, $heure_redac, $minute_redac)
+{
+
+  global $spip_lang_left, $spip_lang_right, $options;
+
+  if ($flag_editable AND $options == 'avancees') {
+	debut_cadre_couleur();
+
+	echo generer_url_post_ecrire("articles", "id_article=$id_article");
+
+	if ($statut_article == 'publie') {
+
+		echo "<div><b>";
+		echo bouton_block_invisible("datepub");
+		echo "<span class='verdana1'>"._T('texte_date_publication_article').'</span> ';
+		echo majuscules(affdate($date)),
+			"</b>".aide('artdate')."</div>";
+
+		echo debut_block_invisible("datepub"),
+		  "<div style='margin: 5px; margin-$spip_lang_left: 20px;'>",
+			WCalendar_controller($date,''),
+		  /*afficher_jour($jour, "name='jour' size='1' class='fondl' onChange=\"setvisibility('valider_date', 'visible')\"", true),
+		  afficher_mois($mois, "name='mois' size='1' class='fondl' onChange=\"setvisibility('valider_date', 'visible')\"", true),
+		  afficher_annee($annee, "name='annee' size='1' class='fondl' onChange=\"setvisibility('valider_date', 'visible')\""),*/
+		  ' - ',
+		  afficher_heure($heure, "name='heure' size='1' class='fondl' onChange=\"setvisibility('valider_date', 'visible')\""),
+		  afficher_minute($minute, "name='minute' size='1' class='fondl' onChange=\"setvisibility('valider_date', 'visible')\""),
+		  "<span class='visible_au_chargement' id='valider_date'>",
+		  " &nbsp; <INPUT TYPE='submit' NAME='Changer' CLASS='fondo' VALUE='"._T('bouton_changer')."'>",
+		  "</span>",
+		  "</div>",
+		  fin_block();
+	}
+	else {
+		echo "<div><b> <span class='verdana1'>"._T('texte_date_creation_article').'</span> ';
+		echo majuscules(affdate($date))."</b>".aide('artdate')."</div>";
+	}
+
+	$possedeDateRedac=($annee_redac.'-'.$mois_redac.'-'.$jour_redac != '0000-00-00');
+	if (($options == 'avancees' AND $GLOBALS['meta']["articles_redac"] != 'non')
+	OR $possedeDateRedac) {
+		if ($possedeDateRedac)
+			$date_affichee = majuscules(affdate($date_redac))
+#			." " ._T('date_fmt_heures_minutes', array('h' =>$heure_redac, 'm'=>$minute_redac))
+			;
+		else
+			$date_affichee = majuscules(_T('jour_non_connu_nc'));
+
+		echo "<div><b>";
+		echo bouton_block_invisible('dateredac');
+		echo "<span class='verdana1'>"
+			. majuscules(_T('texte_date_publication_anterieure'))
+			.'</span> '. $date_affichee ." ".aide('artdate_redac')."</b></div>";
+
+		echo debut_block_invisible('dateredac');
+		echo "<div style='margin: 5px; margin-$spip_lang_left: 20px;'>";
+		echo '<table cellpadding="0" cellspacing="0" border="0" width="100%">';
+		echo '<tr><td align="$spip_lang_left">';
+		echo '<input type="radio" name="avec_redac" value="non" id="avec_redac_on"';
+		if (!$possedeDateRedac) echo ' checked="checked"';
+		echo " onClick=\"setvisibility('valider_date_prec', 'visible')\"";
+		echo ' /> <label for="avec_redac_on">'._T('texte_date_publication_anterieure_nonaffichee').'</label>';
+		echo '<br /><input type="radio" name="avec_redac" value="oui" id="avec_redac_off"';
+		if ($possedeDateRedac) echo ' checked="checked"';
+		echo " onClick=\"setvisibility('valider_date_prec', 'visible')\"";
+		echo ' /> <label for="avec_redac_off">'._T('bouton_radio_afficher').' :</label> ',
+		WCalendar_controller($date_redac,'_redac');
+		/*afficher_jour($jour_redac, "name='jour_redac' class='fondl' onChange=\"setvisibility('valider_date_prec', 'visible')\"", true),
+		afficher_mois($mois_redac, "name='mois_redac' class='fondl' onChange=\"setvisibility('valider_date_prec', 'visible')\"", true);
+		echo "<input type='text' name='annee_redac' class='fondl' value='".$annee_redac."' size='5' maxlength='4' onClick=\"setvisibility('valider_date_prec', 'visible')\"/>";*/
+
+		echo '<div align="center">',
+		afficher_heure($heure_redac, "name='heure_redac' class='fondl' onChange=\"setvisibility('valider_date_prec', 'visible')\"", true),
+		afficher_minute($minute_redac, "name='minute_redac' class='fondl' onChange=\"setvisibility('valider_date_prec', 'visible')\"", true),
+		"</div>\n";
+
+		echo '</td><td align="$spip_lang_right">';
+		echo "<span class='visible_au_chargement' id='valider_date_prec'>";
+		echo '<input type="submit" name="Changer" class="fondo" value="'._T('bouton_changer').'" />';
+		echo "</span>";
+		echo '</td></tr>';
+		echo '</table>';
+		echo "</div>";
+		echo fin_block();
+	}
+
+	echo "</FORM>";
+	fin_cadre_couleur();
+ }
+else {
+	if ($statut_article == 'publie') $texte_date = _T('texte_date_publication_article');
+	else $texte_date = _T('texte_date_creation_article');
+
+	debut_cadre_couleur();
+		echo "<div style='text-align:center;'><b> <span class='verdana1'>$texte_date</span> ";
+		echo majuscules(affdate($date))."</b>".aide('artdate')."</div>";
+
+
+		if ($annee_redac.'-'.$mois_redac.'-'.$jour_redac != '0000-00-00') {
+			$date_affichee = ' : '.majuscules(affdate($date_redac));		
+			echo "<div style='text-align:center;'><b> <span class='verdana1'>"._T(texte_date_publication_anterieure)."</span> ";
+			echo $date_affichee."</b>".aide('artdate_redac')."</div>";
+		}
+
+	fin_cadre_couleur();
+ }
+}
+
+
+function langues_articles($id_article, $langue_article, $flag_editable, $id_rubrique, $id_trad, $dir_lang, $nom_select, $lier_trad)
+{
+
+  global $connect_statut, $couleur_claire, $options, $connect_toutes_rubriques;
+
+  if (($GLOBALS['meta']['multi_articles'] == 'oui')
+	OR (($GLOBALS['meta']['multi_rubriques'] == 'oui') AND ($GLOBALS['meta']['gerer_trad'] == 'oui'))) {
+
+	list($langue_article) = spip_fetch_array(spip_query("SELECT lang FROM spip_articles WHERE id_article=$id_article"));
+
+	if ($GLOBALS['meta']['gerer_trad'] == 'oui')
+		$titre_barre = _T('titre_langue_trad_article');
+	else
+		$titre_barre = _T('titre_langue_article');
+
+	$titre_barre .= "&nbsp; (".traduire_nom_langue($langue_article).")";
+
+	debut_cadre_enfonce('langues-24.gif', false, "", bouton_block_invisible('languesarticle,ne_plus_lier,lier_traductions').$titre_barre);
+
+
+	// Choix langue article
+	if ($GLOBALS['meta']['multi_articles'] == 'oui' AND $flag_editable) {
+		echo debut_block_invisible('languesarticle');
+
+		$row = spip_fetch_array(spip_query("SELECT lang FROM spip_rubriques WHERE id_rubrique=$id_rubrique"));
+		$langue_parent = $row['lang'];
+
+		debut_cadre_couleur();
+		echo "<div style='text-align: center;'>";
+		echo menu_langues('changer_lang', $langue_article, _T('info_multi_cet_article').' ', $langue_parent);
+		echo "</div>\n";
+		fin_cadre_couleur();
+
+		echo fin_block();
+	}
+
+
+	// Gerer les groupes de traductions
+	if ($GLOBALS['meta']['gerer_trad'] == 'oui') {
+		if ($flag_editable AND _request('supp_trad') == 'oui') { // Ne plus lier a un groupe de trad
+			spip_query("UPDATE spip_articles SET id_trad=0, date_modif=NOW() WHERE id_article = $id_article");
+
+			// Verifier si l'ancien groupe ne comporte plus qu'un seul article. Alors mettre a zero.
+			$result_autres_trad= spip_query("SELECT COUNT(id_article) AS total FROM spip_articles WHERE id_trad = $id_trad");
+			if ($row = spip_fetch_array($result_autres_trad))
+				$nombre_autres_trad = $row["total"];
+			if ($nombre_autres_trad == 1)
+				spip_query("UPDATE spip_articles SET id_trad = 0, date_modif=NOW() WHERE id_trad = $id_trad");
+
+			$id_trad = 0;
+		}
+
+		// Changer article de reference de la trad
+		if ($id_trad_new = intval($id_trad_new)
+		AND $id_trad_old = intval($id_trad_old)
+		AND $connect_statut=='0minirezo'
+		AND $connect_toutes_rubriques) { 
+			spip_query("UPDATE spip_articles SET id_trad = $id_trad_new, date_modif=NOW() WHERE id_trad = $id_trad_old");
+			$id_trad = $id_trad_new;
+		}
+
+		if ($flag_editable AND $lier_trad > 0) { // Lier a un groupe de trad
+			$result_lier = spip_query("SELECT id_trad FROM spip_articles WHERE id_article=$lier_trad");
+
+			if ($row = spip_fetch_array($result_lier)) {
+				$id_lier = $row['id_trad'];
+
+				if ($id_lier == 0) { // Si l'article vise n'a pas deja de traduction, creer nouveau id_trad
+					$nouveau_trad = $lier_trad;
+				}
+				else {
+					if ($id_lier == $id_trad) $err = "<div>"._T('trad_deja_traduit')."</div>";
+					$nouveau_trad = $id_lier;
+				}
+
+				spip_query("UPDATE spip_articles SET id_trad = $nouveau_trad, date_modif=NOW() WHERE id_article = $lier_trad");
+				if ($id_lier > 0) spip_query("UPDATE spip_articles SET id_trad = $nouveau_trad, date_modif=NOW() WHERE id_trad = $id_lier");
+				spip_query("UPDATE spip_articles SET id_trad = $nouveau_trad, date_modif=NOW() WHERE id_article = $id_article");
+				if ($id_trad > 0) spip_query("UPDATE spip_articles SET id_trad = $nouveau_trad, date_modif=NOW() WHERE id_trad = $id_trad");
+
+				$id_trad = $nouveau_trad;
+			}
+			else
+				$err .= "<div>"._T('trad_article_inexistant')."</div>";
+
+			if ($err) echo "<font color='red' size=2' face='verdana,arial,helvetica,sans-serif'>$err</font>";
+		}
+
+
+		// Afficher la liste des traductions
+		if ($id_trad != 0) {
+			$result_trad = spip_query("SELECT id_article, id_rubrique, titre, lang, statut FROM spip_articles WHERE id_trad = $id_trad");
+			
+			$table='';
+			while ($row = spip_fetch_array($result_trad)) {
+				$vals = '';
+				$id_article_trad = $row["id_article"];
+				$id_rubrique_trad = $row["id_rubrique"];
+				$titre_trad = $row["titre"];
+				$lang_trad = $row["lang"];
+				$statut_trad = $row["statut"];
+
+				changer_typo($lang_trad);
+				$titre_trad = "<span $dir_lang>$titre_trad</span>";
+
+				if ($ifond == 1) {
+					$ifond = 0;
+					$bgcolor = "white";
+				} else {
+					$ifond = 1;
+					$bgcolor = $couleur_claire;
+				}
+
+
+				$vals[] = http_img_pack("puce-".puce_statut($statut_trad).'.gif', "", "width='7' height='7' border='0' NAME='statut'");
+				
+				if ($id_article_trad == $id_trad) {
+				  $vals[] = http_img_pack('langues-12.gif', "", "width='12' height='12' border='0'");
+					$titre_trad = "<b>$titre_trad</b>";
+				} else {
+				  if ($connect_statut=='0minirezo'
+				  AND $connect_toutes_rubriques)
+				  	$vals[] = "<a href='" . generer_url_ecrire("articles","id_article=$id_article&id_trad_old=$id_trad&id_trad_new=$id_article_trad&id_rubrique=$id_rubrique_trad") . "'>". 
+				    http_img_pack('langues-off-12.gif', _T('trad_reference'), "width='12' height='12' border='0'", _T('trad_reference')) . "</a>";
+				  else $vals[] = http_img_pack('langues-off-12.gif', "", "width='12' height='12' border='0'");
+				}
+
+				$ret .= "</td>";
+
+				$s = typo($titre_trad);
+				if ($id_article_trad != $id_article) 
+					$s = "<a href='" . generer_url_ecrire("articles","id_article=$id_article_trad&id_rubrique=$id_rubrique_trad") . "'>$s</a>";
+				if ($id_article_trad == $id_trad)
+					$s .= " "._T('trad_reference');
+
+				$vals[] = $s;
+				$vals[] = traduire_nom_langue($lang_trad);
+				$table[] = $vals;
+			}
+
+			// changer_typo($spip_lang); (probleme d'affichage rtl?)
+
+			// bloc traductions
+			if (count($vals) > 0) {
+
+				echo "<div class='liste'>";
+				bandeau_titre_boite2(_T('trad_article_traduction'),'');
+				echo "<table width='100%' cellspacing='0' border='0' cellpadding='2'>";
+				//echo "<tr bgcolor='#eeeecc'><td colspan='4' class='serif2'><b>"._T('trad_article_traduction')."</b></td></tr>";
+
+				$largeurs = array(7, 12, '', 100);
+				$styles = array('', '', 'arial2', 'arial2');
+				echo afficher_liste($largeurs, $table, $styles);
+
+				echo "</table>";
+				echo "</div>";
+
+			}
+
+			changer_typo($langue_article);
+		}
+
+		echo debut_block_invisible('lier_traductions');
+
+		echo "<table width='100%'><tr>";
+		if ($flag_editable AND $options == "avancees" AND !$ret) {
+			// Formulaire pour lier a un article
+			echo "<td class='arial2' width='60%'>";
+
+			echo "<form action='" . generer_url_ecrire("articles","id_article=$id_article") . "' method='post' style='margin:0px; padding:0px;'>";
+			echo _T('trad_lier');
+			echo "<div align='$spip_lang_right'><input type='text' class='fondl' name='lier_trad' size='5'> <INPUT TYPE='submit' NAME='Valider' VALUE='"._T('bouton_valider')."' CLASS='fondl'></div>";
+			echo "</form>";
+			echo "</td>\n";
+			echo "<td background='' width='10'> &nbsp; </td>";
+			echo "<td background='" . _DIR_IMG_PACK . "tirets-separation.gif' width='2'>". http_img_pack('rien.gif', " ", "width='2' height='2'") . "</td>";
+			echo "<td background='' width='10'> &nbsp; </td>";
+		}
+		echo "<td>";
+		icone_horizontale(_T('trad_new'), generer_url_ecrire("articles_edit","new=oui&lier_trad=$id_article&id_rubrique=$id_rubrique"), "traductions-24.gif", "creer.gif");
+		echo "</td>";
+		if ($flag_editable AND $options == "avancees" AND $ret) {
+			echo "<td background='' width='10'> &nbsp; </td>";
+			echo "<td background='" . _DIR_IMG_PACK . "tirets-separation.gif' width='2'>". http_img_pack('rien.gif', " ", "width='2' height='2'") . "</td>";
+			echo "<td background='' width='10'> &nbsp; </td>";
+			echo "<td>";
+			icone_horizontale(_T('trad_delier'), generer_url_ecrire("articles","id_article=$id_article&supp_trad=oui"), "traductions-24.gif", "supprimer.gif");
+			echo "</td>\n";
+		}
+
+		echo "</tr></table>";
+
+		echo fin_block();
+	}
+
+	fin_cadre_enfonce();
+  }
+}
+
+function add_auteur_article($id_article, $nouv_auteur)
+{
+	$res = spip_query("SELECT id_article FROM spip_auteurs_articles WHERE id_auteur='$nouv_auteur' AND id_article='$id_article'");
+	if (!spip_num_rows($res))
+		spip_abstract_insert('spip_auteurs_articles', "(id_auteur,id_article)", "('$nouv_auteur','$id_article')");
+}
+
+function rechercher_auteurs_articles($cherche_auteur, $id_article, $id_rubrique, $ajout_auteur, $flag_editable, $nouv_auteur, $supp_auteur)
+{
+  global $spip_lang_left;
+
+  $supprimer_bouton_creer_auteur = false;
+
+  if ($cherche_auteur) {
+	echo "<P ALIGN='$spip_lang_left'>";
+	$result = spip_query("SELECT id_auteur, nom FROM spip_auteurs");
+	$table_auteurs = array();
+	$table_ids = array();
+	while ($row = spip_fetch_array($result)) {
+		$table_auteurs[] = $row["nom"];
+		$table_ids[] = $row["id_auteur"];
+	}
+	$resultat = mots_ressemblants($cherche_auteur, $table_auteurs, $table_ids);
+	debut_boite_info();
+	if (!$resultat) {
+		echo "<B>"._T('texte_aucun_resultat_auteur', array('cherche_auteur' => $cherche_auteur)).".</B><BR>";
+	}
+	else if (count($resultat) == 1) {
+		$ajout_auteur = 'oui';
+		list(, $nouv_auteur) = each($resultat);
+		echo "<B>"._T('texte_ajout_auteur')."</B><BR>";
+		$result = spip_query("SELECT * FROM spip_auteurs WHERE id_auteur=$nouv_auteur");
+		echo "<UL>";
+		while ($row = spip_fetch_array($result)) {
+			$id_auteur = $row['id_auteur'];
+			$nom_auteur = $row['nom'];
+			$email_auteur = $row['email'];
+			$bio_auteur = $row['bio'];
+
+			echo "<LI><FONT FACE='Verdana,Arial,Sans,sans-serif' SIZE=2><B><FONT SIZE=3>".typo($nom_auteur)."</FONT></B>";
+			echo "</FONT>\n";
+		}
+		echo "</UL>";
+	}
+	else if (count($resultat) < 16) {
+		reset($resultat);
+		$les_auteurs = array();
+		while (list(, $id_auteur) = each($resultat)) $les_auteurs[] = $id_auteur;
+		if ($les_auteurs) {
+			$les_auteurs = join(',', $les_auteurs);
+			echo "<B>"._T('texte_plusieurs_articles', array('cherche_auteur' => $cherche_auteur))."</B><BR>";
+			$result = spip_query("SELECT * FROM spip_auteurs WHERE id_auteur IN ($les_auteurs) ORDER BY nom");
+
+			echo "<UL class='verdana1'>";
+			while ($row = spip_fetch_array($result)) {
+				$id_auteur = $row['id_auteur'];
+				$nom_auteur = $row['nom'];
+				$email_auteur = $row['email'];
+				$bio_auteur = $row['bio'];
+
+				echo "<li><b>".typo($nom_auteur)."</b>";
+
+				if ($email_auteur) echo " ($email_auteur)";
+				echo " | <A href='", generer_url_ecrire('articles', "id_article=$id_article&ajout_auteur=oui&nouv_auteur=$id_auteur#auteurs"),
+				  "'>",_T('lien_ajouter_auteur'),"</A>";
+
+				if (trim($bio_auteur)) {
+					echo "<br />".couper(propre($bio_auteur), 100)."\n";
+				}
+				echo "</li>\n";
+			}
+			echo "</UL>";
+		}
+	}
+	else {
+		echo "<B>"._T('texte_trop_resultats_auteurs', array('cherche_auteur' => $cherche_auteur))."</B><BR>";
+	}
+
+	if ($GLOBALS['connect_statut'] == '0minirezo' 
+	AND $GLOBALS['connect_toutes_rubriques']) {
+
+		echo "<div style='width: 200px;'>";
+		$retour = rawurlencode(generer_url_ecrire("articles","id_article=$id_article"));
+		$titre = rawurlencode($cherche_auteur);
+		icone_horizontale(_T('icone_creer_auteur'), generer_url_ecrire("auteur_infos","ajouter_id_article=$id_article&nom=$titre&redirect=$retour"), "redacteurs-24.gif", "creer.gif");
+		echo "</div> ";
+
+		// message pour ne pas afficher le second bouton "creer un auteur"
+		$supprimer_bouton_creer_auteur = true;
+	}
+
+	fin_boite_info();
+	echo "<P>";
+
+  }
+
+//
+// Appliquer les modifications sur les auteurs
+//
+
+  if ($ajout_auteur && $flag_editable) {
+	if ($nouv_auteur > 0) {
+		add_auteur_article($id_article, $nouv_auteur);
+	}
+
+	if ($GLOBALS['meta']['activer_moteur'] == 'oui') {
+		include_spip("inc/indexation");
+		marquer_indexer('article', $id_article);
+	}
+  }
+
+
+  if ($supp_auteur && $flag_editable) {
+	spip_query("DELETE FROM spip_auteurs_articles WHERE id_auteur='$supp_auteur' AND id_article='$id_article'");
+
+	if ($GLOBALS['meta']['activer_moteur'] == 'oui') {
+		include_spip("inc/indexation");
+		marquer_indexer('article', $id_article);
+	}
+  }
+
+  return $supprimer_bouton_creer_auteur;
+}
+
+function afficher_auteurs_articles($id_article, $flag_editable)
+{
+	global $connect_statut, $options,$connect_id_auteur;
+
+	$les_auteurs = array();
+
+	$result = spip_query("SELECT * FROM spip_auteurs AS auteurs, spip_auteurs_articles AS lien WHERE auteurs.id_auteur=lien.id_auteur AND lien.id_article=$id_article GROUP BY auteurs.id_auteur ORDER BY auteurs.nom");
+
+	if (spip_num_rows($result)) {
+		echo "<div class='liste'>";
+		echo "<table width='100%' cellpadding='3' cellspacing='0' border='0' background=''>";
+		$table = array();
+		while ($row = spip_fetch_array($result)) {
+			$vals = array();
+			$id_auteur = $row["id_auteur"];
+			$nom_auteur = $row["nom"];
+			$email_auteur = $row["email"];
+			if ($bio_auteur = attribut_html(propre(couper($row["bio"], 100))))
+			  $bio_auteur = " TITLE=\"$bio_auteur\"";
+			$url_site_auteur = $row["url_site"];
+			$statut_auteur = $row["statut"];
+			if ($row['messagerie'] == 'non' OR $row['login'] == '') $messagerie = 'non';
+			
+			$les_auteurs[] = $id_auteur;
+
+			if ($connect_statut == "0minirezo") $aff_articles = "('prepa', 'prop', 'publie', 'refuse')";
+			else $aff_articles = "('prop', 'publie')";
+
+			$result2 = spip_query("SELECT COUNT(articles.id_article) AS compteur FROM spip_auteurs_articles AS lien, spip_articles AS articles WHERE lien.id_auteur=$id_auteur AND articles.id_article=lien.id_article AND articles.statut IN $aff_articles GROUP BY lien.id_auteur");
+
+			if ($result2) list($nombre_articles) = spip_fetch_array($result2);
+			else $nombre_articles = 0;
+
+			$vals[] = bonhomme_statut($row);
+
+			$vals[] = "<A href='" . generer_url_ecrire('auteurs_edit', "id_auteur=$id_auteur") . "' $bio_auteur>".typo($nom_auteur)."</A>";
+
+			$vals[] = bouton_imessage($id_auteur);
+
+		
+		
+		if ($email_auteur) $vals[] =  "<A href='mailto:$email_auteur'>"._T('email')."</A>";
+		else $vals[] =  "&nbsp;";
+
+		if ($url_site_auteur) $vals[] =  "<A href='$url_site_auteur'>"._T('info_site_min')."</A>";
+		else $vals[] =  "&nbsp;";
+
+		if ($nombre_articles > 1) $vals[] =  $nombre_articles.' '._T('info_article_2');
+		else if ($nombre_articles == 1) $vals[] =  _T('info_1_article');
+		else $vals[] =  "&nbsp;";
+
+		if ($flag_editable AND ($connect_id_auteur != $id_auteur OR $connect_statut == '0minirezo') AND $options == 'avancees') {
+		  $vals[] =  "<A href='" . generer_url_ecrire("articles","id_article=$id_article&supp_auteur=$id_auteur#auteurs") . "'>"._T('lien_retirer_auteur')."&nbsp;". http_img_pack('croix-rouge.gif', "X", "width='7' height='7' border='0' align='middle'") . "</A>";
+		} else {
+			$vals[] = "";
+		}
+		
+		$table[] = $vals;
+		}
+	
+	
+	$largeurs = array('14', '', '', '', '', '', '');
+	$styles = array('arial11', 'arial2', 'arial11', 'arial11', 'arial11', 'arial11', 'arial1');
+	echo afficher_liste($largeurs, $table, $styles);
+
+	
+	echo "</table></div>\n";
+
+	$les_auteurs = join(',', $les_auteurs);
+	}
+	return $les_auteurs ;
+}
+
+
+function ajouter_auteurs_articles($id_article, $id_rubrique, $les_auteurs, $flag_editable, $rubrique_article, $supprimer_bouton_creer_auteur)
+{
+	global $connect_toutes_rubriques, $connect_statut, $couleur_claire ;
+
+	echo debut_block_invisible("auteursarticle");
+	echo "<table width='100%'><tr>";
+
+	if ($connect_statut == '0minirezo'
+	    AND $connect_toutes_rubriques
+	    AND !$supprimer_bouton_creer_auteur) {
+	echo "<td width='200'>";
+	$retour = rawurlencode(generer_url_ecrire("articles","id_article=$id_article"));
+	icone_horizontale(_T('icone_creer_auteur'), generer_url_ecrire("auteur_infos","ajouter_id_article=$id_article&redirect=$retour"), "redacteurs-24.gif", "creer.gif");
+	echo "</td>";
+	echo "<td width='20'>&nbsp;</td>";
+	}
+
+	echo "<td>";
+
+	$result = spip_query("SELECT * FROM spip_auteurs WHERE " .
+			(!$les_auteurs ? '' : "id_auteur NOT IN ($les_auteurs) AND ") .
+			"statut!='5poubelle' AND statut!='6forum' AND statut!='nouveau' ORDER BY statut, nom");
+
+	$num = spip_num_rows($result);
+	if ($num) {
+		echo generer_url_post_ecrire("articles", "id_article=$id_article");;
+		echo "<span class='verdana1'><B>"._T('titre_cadre_ajouter_auteur')."&nbsp; </B></span>\n";
+		echo "<DIV><INPUT TYPE='Hidden' NAME='id_article' VALUE=\"$id_article\">";
+
+		if ($num > 200) {
+			echo "<INPUT TYPE='text' NAME='cherche_auteur' onClick=\"setvisibility('valider_ajouter_auteur','visible');\" CLASS='fondl' VALUE='' SIZE='20'>";
+			echo "<span  class='visible_au_chargement' id='valider_ajouter_auteur'>";
+			echo " <INPUT TYPE='submit' NAME='Chercher' VALUE='"._T('bouton_chercher')."' CLASS='fondo'>";
+			echo "</span>";
+		} else {
+			echo "<INPUT TYPE='Hidden' NAME='ajout_auteur' VALUE='oui'>";
+			echo "<SELECT NAME='nouv_auteur' SIZE='1' STYLE='width:150px;' CLASS='fondl' onChange=\"setvisibility('valider_ajouter_auteur','visible');\">";
+			while ($row = spip_fetch_array($result)) {
+				$id_auteur = $row["id_auteur"];
+				$nom = $row["nom"];
+				$email = $row["email"];
+				$statut = $row["statut"];
+
+				$statut=str_replace("0minirezo", _T('info_administrateurs'), $statut);
+				$statut=str_replace("1comite", _T('info_redacteurs'), $statut);
+				$statut=str_replace("6visiteur", _T('info_visiteurs'), $statut);
+				
+				$premiere = strtoupper(substr(trim($nom), 0, 1));
+
+				if ($connect_statut != '0minirezo')
+					if ($p = strpos($email, '@'))
+					  $email = substr($email, 0, $p).'@...';
+				if ($email)
+					$email = " ($email)";
+
+				if ($statut != $statut_old) {
+					echo "\n<OPTION VALUE=\"x\">";
+					echo "\n<OPTION VALUE=\"x\" style='background-color: $couleur_claire;'> $statut";
+				}
+
+				if ($premiere != $premiere_old AND ($statut != _T('info_administrateurs') OR !$premiere_old)) {
+				  echo "\n<OPTION VALUE=\"x\">";
+				}
+
+				
+				echo "\n<OPTION VALUE=\"$id_auteur\">&nbsp;&nbsp;&nbsp;&nbsp;", supprimer_tags(couper(typo("$nom$email"), 40));
+				$statut_old = $statut;
+				$premiere_old = $premiere;
+			}
+			
+			echo "</SELECT>",
+				"<span  class='visible_au_chargement' id='valider_ajouter_auteur'>",
+				" <input type='submit' value="._T('bouton_ajouter')." CLASS='fondo'>",
+				"</span>";
+		}
+		echo "</div></FORM>";
+	}
+	
+	echo "</td></tr></table>";
+
+	echo fin_block();
+}
+
+function afficher_corps_articles($virtuel, $chapo, $texte, $ps,  $extra)
+{
+  global $revision_nbsp, $activer_revision_nbsp, $champs_extra, $les_notes, $dir_lang;
+
+	echo "\n\n<div align='justify' style='padding: 10px;'>";
+
+	if ($virtuel) {
+		debut_boite_info();
+		echo _T('info_renvoi_article')." ".propre("<center>[->$virtuel]</center>");
+		fin_boite_info();
+	} else {
+		$revision_nbsp = $activer_revision_nbsp;
+
+		if (strlen($chapo) > 0) {
+			echo "<div $dir_lang><b>";
+			echo propre($chapo);
+			echo "</b></div>\n\n";
+		}
+
+		echo "<div $dir_lang>";
+#	echo reduire_image(propre($texte), 500,10000);
+		echo propre($texte);
+		echo "<br clear='both' />";
+		echo "</div>";
+
+		if ($ps) {
+			echo debut_cadre_enfonce();
+			echo "<div $dir_lang><font style='font-family:Verdana,Arial,Sans,sans-serif; font-size: small;'>";
+			echo justifier("<b>"._T('info_ps')."</b> ".propre($ps));
+			echo "</font></div>";
+			echo fin_cadre_enfonce();
+		}
+		$revision_nbsp = false;
+
+		if ($les_notes) {
+			echo debut_cadre_relief();
+			echo "<div $dir_lang class='arial11'>";
+			echo justifier("<b>"._T('info_notes')."&nbsp;:</b> ".$les_notes);
+			echo "</div>";
+			echo fin_cadre_relief();
+		}
+		
+		if ($champs_extra AND $extra) {
+			include_spip('inc/extra');
+			extra_affichage($extra, "articles");
+		}
+	}
+}
+
+function affiche_forums_article($id_article, $id_rubrique, $titre, $debut, $mute=false)
+{
+  global $spip_lang_left;
+
+  echo "<BR><BR>";
+
+  $forum_retour = generer_url_ecrire("articles","id_article=$id_article", true);
+  
+  if (!$mute) {
+    $tm = rawurlencode($titre);
+    echo "\n<div align='center'>";
+    icone(_T('icone_poster_message'), generer_url_ecrire("forum_envoi","statut=prive&adresse_retour=" . rawurlencode($forum_retour) . "&id_article=$id_article&titre_message=$tm"), "forum-interne-24.gif", "creer.gif");
+    echo "</div>";
+  }
+
+  echo "<P align='$spip_lang_left'>";
+
+  $result_forum = spip_query("SELECT COUNT(*) AS cnt FROM spip_forum WHERE statut='prive' AND id_article='$id_article' AND id_parent=0");
+
+  $total = 0;
+  if ($row = spip_fetch_array($result_forum)) $total = $row["cnt"];
+
+  if (!$debut) $debut = 0;
+  $total_afficher = 8;
+  if ($total > $total_afficher) {
+	echo "<div class='serif2' align='center'>";
+	for ($i = 0; $i < $total; $i = $i + $total_afficher){
+		$y = $i + $total_afficher - 1;
+		if ($i == $debut)
+			echo "<FONT SIZE=3><B>[$i-$y]</B></FONT> ";
+		else
+			echo "[<A href='" . generer_url_ecrire("articles","id_article=$id_article&debut=$i") . "'>$i-$y</A>] ";
+	}
+	echo "</div>";
+}
+
+	$result_forum = spip_query("SELECT * FROM spip_forum WHERE statut='prive' AND id_article='$id_article' AND id_parent=0 ORDER BY date_heure DESC" .
+#				   " LIMIT $total_afficher OFFSET $debut" # PG
+				   " LIMIT $debut,$total_afficher"
+				   ); 
+
+	afficher_forum($result_forum, $forum_retour, $mute);
+
+	if (!$debut) $debut = 0;
+	$total_afficher = 8;
+	if ($total > $total_afficher) {
+	  echo "<div class='serif2' align='center'>";
+	  for ($i = 0; $i < $total; $i = $i + $total_afficher){
+		$y = $i + $total_afficher - 1;
+		if ($i == $debut)
+			echo "<FONT SIZE=3><B>[$i-$y]</B></FONT> ";
+		else
+			echo "[<A href='" . generer_url_ecrire("articles","id_article=$id_article&debut=$i") . "'>$i-$y</A>] ";
+	  }
+	  echo "</div>";
+	}
+
+	echo "</div>\n";
+}
+
+function afficher_statut_articles($id_article, $rubrique_article, $statut_article)
+{
+  global $connect_statut;
+
+  if ($connect_statut == '0minirezo' AND acces_rubrique($rubrique_article)) {
+  	
+    echo "\n<form method='post' action='",
+      generer_action_auteur("instituer", "article $id_article", generer_url_ecrire('articles', "id_article=$id_article", true)),
+      "'>",
+	  debut_cadre_relief("", true),
+      "\n<center>", "<B>",_T('texte_article_statut'),"</B>",
+	  "\n<SELECT NAME='statut_nouv' SIZE='1' CLASS='fondl'\n",
+	  "onChange=\"document.statut.src='",
+	  _DIR_IMG_PACK,
+	  "' + puce_statut(options[selectedIndex].value);",
+	  " setvisibility('valider_statut', 'visible');\">\n",
+	 "<OPTION" , mySel("prepa", $statut_article) ," style='background-color: white'>",_T('texte_statut_en_cours_redaction'),"</OPTION>\n",
+	 "<OPTION" , mySel("prop", $statut_article) , " style='background-color: #FFF1C6'>",_T('texte_statut_propose_evaluation'),"</OPTION>\n",
+	 "<OPTION" , mySel("publie", $statut_article) , " style='background-color: #B4E8C5'>",_T('texte_statut_publie'),"</OPTION>\n",
+	 "<OPTION" , mySel("poubelle", $statut_article),
+	   http_style_background('rayures-sup.gif') , '>' ,_T('texte_statut_poubelle'),"</OPTION>\n",
+	 "<OPTION" , mySel("refuse", $statut_article) , " style='background-color: #FFA4A4'>",_T('texte_statut_refuse'),"</OPTION>\n",
+	  "</SELECT>",
+	  " &nbsp; ",
+	  http_img_pack("puce-".puce_statut($statut_article).'.gif', "", "border='0' NAME='statut'"),
+	  "  &nbsp;\n";
+
+	echo "<span class='visible_au_chargement' id='valider_statut'>";
+	echo "<INPUT TYPE='submit' VALUE='"._T('bouton_valider')."' CLASS='fondo'>";
+	echo "</span>";
+	echo aide("artstatut");
+	echo "</center>";
+	fin_cadre_relief();
+	echo "\n</form>";
+ }
+}
+
+//
+// Reunit les textes decoupes parce que trop longs
+//
+
+function trop_longs_articles($texte_plus)
+{
+	$nb_texte = 0;
+	while ($nb_texte ++ < count($texte_plus)+1){
+		$texte_ajout .= ereg_replace("<!--SPIP-->[\n\r]*","",
+					     $texte_plus[$nb_texte]);
+	}
+	return $texte_ajout;
+}
+
+
+function modif_langue_articles($id_article, $id_rubrique, $changer_lang)
+{
+
+// Appliquer la modification de langue
+ if ($GLOBALS['meta']['multi_articles'] == 'oui') {
+	list($langue_parent) = spip_fetch_array(spip_query("SELECT lang FROM spip_rubriques WHERE id_rubrique=" . $id_rubrique));
+
+	if ($changer_lang) {
+		if ($changer_lang != "herit")
+			spip_query("UPDATE spip_articles SET lang='".addslashes($changer_lang)."', langue_choisie='oui', date_modif=NOW() WHERE id_article=$id_article");
+		else
+			spip_query("UPDATE spip_articles SET lang='".addslashes($langue_parent)."', langue_choisie='non', date_modif=NOW() WHERE id_article=$id_article");
+	}
+ }
+}
+
+// Passer les images/docs en "inclus=non"
+
+function inclus_non_articles($id_article)
+{
+  $result = spip_query("SELECT docs.id_document FROM spip_documents AS docs, spip_documents_articles AS lien WHERE lien.id_article=$id_article AND lien.id_document=docs.id_document");
+
+while($row=spip_fetch_array($result)){
+	$ze_doc[]=$row['id_document'];
+}
+
+if (count($ze_doc)>0){
+	$ze_docs = join($ze_doc,",");
+	spip_query("UPDATE spip_documents SET inclus='non' WHERE id_document IN ($ze_docs)");
+}
+
+}
+
+function revisions_articles ($id_article, $id_secteur, $id_rubrique, $id_rubrique_old, $change_rubrique, $new, $champs) {
+{
+  global $connect_id_auteur, $flag_revisions, $champs_extra;
+
+	// Stockage des versions : creer une premier version si non-existante
+	if (($GLOBALS['meta']["articles_versions"]=='oui') && $flag_revisions) {
+		include_spip('inc/revisions');
+		if  ($new != 'oui') {
+			$query = spip_query("SELECT id_article FROM spip_versions WHERE id_article=$id_article LIMIT 1");
+			if (!spip_num_rows($query)) {
+				$select = join(", ", array_keys($champs));
+				$query = spip_query("SELECT $select FROM spip_articles WHERE id_article=$id_article");
+				$champs_originaux = spip_fetch_array($query);
+				$id_version = ajouter_version($id_article, $champs_originaux, _T('version_initiale'), 0);
+
+				// Remettre une date un peu ancienne pour la version initiale 
+				if ($id_version == 1) // test inutile ?
+				spip_query("UPDATE spip_versions SET date=DATE_SUB(NOW(), INTERVAL 2 HOUR) WHERE id_article=$id_article AND id_version=1");
+			}
+		}
+	}
+
+	if ($champs_extra) {
+		include_spip('inc/extra');
+		$champs_extra = ", extra = '".addslashes(extra_recup_saisie("articles", $id_secteur))."'";
+	}
+
+	spip_query("UPDATE spip_articles SET surtitre='" .
+		   addslashes($champs['surtitre']) .
+		   "', titre='" .
+		   addslashes($champs['titre']) .
+		   "', soustitre='" .
+		   addslashes($champs['soustitre']) .
+		   "', id_rubrique=" .
+		   intval($id_rubrique) .
+		   ", descriptif='" .
+		   addslashes($champs['descriptif']) .
+		   "', chapo='" .
+		   addslashes($champs['chapo']) .
+		   "', texte='" .
+		   addslashes($champs['texte']) .
+		   "', ps='" .
+		   addslashes($champs['ps']) .
+		   "', url_site='" .
+		   addslashes($champs['url_site']) .
+		   "', nom_site='" .
+		   addslashes($champs['nom_site']) .
+		   "', date_modif=NOW() $champs_extra WHERE id_article=$id_article");
+
+	// Stockage des versions
+	if (($GLOBALS['meta']["articles_versions"]=='oui') && $flag_revisions) {
+		ajouter_version($id_article, $champs, '', $connect_id_auteur);
+	}
+
+	// Changer la langue heritee
+	if ($id_rubrique != $id_rubrique_old) {
+		propager_les_secteurs();
+		$row = spip_fetch_array(spip_query("SELECT lang, langue_choisie FROM spip_articles WHERE id_article=$id_article"));
+		$langue_old = $row['lang'];
+		$langue_choisie_old = $row['langue_choisie'];
+
+		if ($langue_choisie_old != "oui") {
+			$row = spip_fetch_array(spip_query("SELECT lang FROM spip_rubriques WHERE id_rubrique=$id_rubrique"));
+			$langue_new = $row['lang'];
+			if ($langue_new != $langue_old) spip_query("UPDATE spip_articles SET lang = '$langue_new', date_modif=NOW() WHERE id_article = $id_article");
+		}
+	}
+
+	// marquer l'article (important pour les articles nouvellement crees)
+	spip_query("UPDATE spip_articles SET date_modif=NOW(), auteur_modif=$connect_id_auteur WHERE id_article=$id_article");
+	calculer_rubriques();
+ }
+}
+
+function insert_article($id_parent, $new)
+{
+	if ($new!='oui')  redirige_par_entete("./");
+	// Avec l'Ajax parfois id_rubrique vaut 0... ne pas l'accepter
+	if (!$id_rubrique = intval($id_parent)) {
+		list($id_rubrique) = spip_fetch_array(spip_query("SELECT id_rubrique FROM spip_rubriques WHERE id_parent=0 ORDER by 0+titre,titre LIMIT 1"));
+	}
+
+	$row = spip_fetch_array(spip_query("SELECT lang FROM spip_rubriques WHERE id_rubrique=$id_rubrique"));
+
+	$id_article = spip_abstract_insert("spip_articles",
+			"(id_rubrique, statut, date, accepter_forum, lang, langue_choisie)", 
+			"($id_rubrique, 'prepa', NOW(), '" .
+				substr($GLOBALS['meta']['forums_publics'],0,3)
+				. "', '"
+				. ($row["lang"] ? $row["lang"] : $GLOBALS['meta']['langue_site'])
+				. "', 'non')");
+	return $id_article;
+}
+// Y a-t-il vraiment 56 variables determinant l'edition d'un article ?
+
+function exec_articles_dist()
+{
+global $ajout_auteur, $annee, $annee_redac, $avec_redac, $champs_extra, $change_accepter_forum, $change_petition, $changer_lang, $changer_virtuel, $chapo, $cherche_auteur, $cherche_mot, $connect_id_auteur, $date, $date_redac, $debut, $descriptif, $email_unique, $heure, $heure_redac, $id_article, $id_article_bloque, $id_parent, $id_rubrique_old, $id_secteur, $jour, $jour_redac, $langue_article, $lier_trad, $message, $minute, $minute_redac, $mois, $mois_redac, $new, $nom_select, $nom_site, $nouv_auteur, $nouv_mot, $ps, $row, $site_obli, $site_unique, $soustitre, $supp_auteur, $supp_mot, $surtitre, $texte, $texte_petition, $texte_plus, $titre, $titre_article, $url_site, $virtuel; 
+
+ $id_parent = intval($id_parent);
+ $nouv_auteur = intval($nouv_auteur);
+ if (!($id_article=intval($id_article))) {
+   $id_article = insert_article($id_parent, $new);
+   add_auteur_article($id_article, $connect_id_auteur);
+ }
+
+// aucun doc implicitement inclus au départ.
+
+inclus_non_articles($id_article);
+
+
+if ($row = spip_fetch_array(spip_query("SELECT statut, titre, id_rubrique FROM spip_articles WHERE id_article=$id_article"))) {
+	$statut_article = $row['statut'];
+	$titre_article = $row['titre'];
+	$id_rubrique = $row['id_rubrique'];
+	$statut_rubrique = acces_rubrique($id_rubrique);
+	if ($titre_article=='') $titre_article = _T('info_sans_titre');
+}
+else {
+	$statut_article = '';
+	$statut_rubrique = false;
+	$id_rubrique = '0';
+	if ($titre=='') $titre = _T('info_sans_titre');
+}
+
+$flag_auteur = spip_num_rows(spip_query("SELECT id_auteur FROM spip_auteurs_articles WHERE id_article=$id_article AND id_auteur=$connect_id_auteur LIMIT 1"));
+
+ $flag_editable = ($statut_rubrique OR ($flag_auteur AND $flag_editable));
+
+if ($flag_editable) {
+
+if ($jour) {
+	$date = format_mysql_date($annee, $mois, $jour, $heure, $minute);
+	spip_query("UPDATE spip_articles SET date='$date', date_modif=NOW()
+		WHERE id_article=$id_article");
+	calculer_rubriques();
+}
+
+if ($jour_redac) {
+	if ($annee_redac<>'' AND $annee_redac < 1001) $annee_redac += 9000;
+
+	if ($avec_redac == 'non')
+		$date_redac = format_mysql_date();
+	else
+		$date_redac = format_mysql_date(
+			$annee_redac, $mois_redac, $jour_redac,
+			$heure_redac, $minute_redac);
+
+	spip_query("UPDATE spip_articles SET date_redac='$date_redac',  date_modif=NOW() WHERE id_article=$id_article");
+}
+
+
+modif_langue_articles($id_article, $id_rubrique, $changer_lang);
+
+maj_documents($id_article, 'article');
+
+if ($changer_virtuel) {
+	$virtuel = eregi_replace("^http://$", "", trim($virtuel));
+	if ($virtuel) $chapo = addslashes(corriger_caracteres("=$virtuel"));
+	else $chapo = "";
+	spip_query("UPDATE spip_articles SET chapo='$chapo', date_modif=NOW() WHERE id_article=$id_article");
+}
+
+if ($titre) {
+
+  // prendre en compte le changement eventuel, et seulement si autorise
+	if ($id_parent AND ($flag_auteur OR acces_rubrique($id_parent))) {
+		$id_rubrique = $id_parent;
+	}
+	$champs = array(
+			'surtitre' => corriger_caracteres($surtitre),
+			'titre' => ($titre_article=corriger_caracteres($titre)),
+			'soustitre' => corriger_caracteres($soustitre),
+			'descriptif' => corriger_caracteres($descriptif),
+			'nom_site' => corriger_caracteres($nom_site),
+			'url_site' => corriger_caracteres($url_site),
+			'chapo' => corriger_caracteres($chapo),
+			'texte' => corriger_caracteres(trop_longs_articles($texte_plus) . $texte),
+			'ps' => corriger_caracteres($ps))  ;
+
+	revisions_articles ($id_article, $id_secteur, $id_rubrique, $id_rubrique_old,
+			    ($flag_auteur||$statut_rubrique),
+			    $new, $champs);
+	$id_article_bloque = $id_article;   // message pour inc/presentation
+
+ }
+ }
+
+exec_affiche_articles_dist($id_article, $ajout_auteur, $change_accepter_forum, $change_petition, $changer_virtuel, $cherche_auteur, $cherche_mot, $debut, $email_unique, $flag_auteur, $flag_editable, $langue_article, $message, $nom_select, $nouv_auteur, $nouv_mot, $id_rubrique, $site_obli, $site_unique, $supp_auteur, $supp_mot, $texte_petition, $titre_article, $lier_trad);
+
+}
+?>
Index: plugins/widget_calendar_1_9/img_pack/SPIP.js
===================================================================
--- plugins/widget_calendar_1_9/img_pack/SPIP.js	(revision 6)
+++ plugins/widget_calendar_1_9/img_pack/SPIP.js	(revision 6)
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2006 Yahoo! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class The Spip global namespace
+ */
+var SPIP = function() {
+
+    return {
+
+        /**
+         * Spip presentation platform utils namespace
+         */
+        util: {},
+
+        /**
+         * Spip presentation platform widgets namespace
+         */
+        widget: {},
+
+        /**
+         * Spip presentation platform examples namespace
+         */
+        example: {},
+
+        /**
+         * Returns the namespace specified and creates it if it doesn't exist
+         *
+         * SPIP.namespace("property.package");
+         * SPIP.namespace("SPIP.property.package");
+         *
+         * Either of the above would create SPIP.property, then
+         * SPIP.property.package
+         *
+         * @param  {String} sNameSpace String representation of the desired
+         *                             namespace
+         * @return {Object}            A reference to the namespace object
+         */
+        namespace: function( sNameSpace ) {
+
+            if (!sNameSpace || !sNameSpace.length) {
+                return null;
+            }
+
+            var levels = sNameSpace.split(".");
+
+            var currentNS = SPIP;
+
+            // SPIP is implied, so it is ignored if it is included
+            for (var i=(levels[0] == "SPIP") ? 1 : 0; i<levels.length; ++i) {
+                currentNS[levels[i]] = currentNS[levels[i]] || {};
+                currentNS = currentNS[levels[i]];
+            }
+
+            return currentNS;
+
+        }
+    };
+
+} ();
+
+// Spip presentation platform packages.  Hard-coding them into the object
+// uses fewer chars than the namespace function does
+// SPIP.namespace("util");
+// SPIP.namespace("widget");
+// SPIP.namespace("example");
Index: plugins/widget_calendar_1_9/img_pack/calendar.css
===================================================================
--- plugins/widget_calendar_1_9/img_pack/calendar.css	(revision 6)
+++ plugins/widget_calendar_1_9/img_pack/calendar.css	(revision 6)
@@ -0,0 +1,181 @@
+/* Copyright (c) 2006 Yahoo! Inc. All rights reserved. */
+/* Container Styles */
+
+.calcontainer {*height:1%;} /* IE */
+.calcontainer:after {content:'.';clear:both;display:block;visibility:hidden;height:0;} /* others */
+
+.calbordered {
+	font-family: Verdana, Arial, Sans, sans-serif;
+	font-size:small;
+	float:left;
+	padding:5px;
+	background-color:#F7F9FB;
+	border:1px solid #7B9EBD;
+min-width:28em;
+-height:14em;
+}
+
+.califrame{
+margin:1px;
+	padding:5px;
+	font-family: Verdana, Arial, Sans, sans-serif;
+	font-size:small;
+width:28em;
+height:14em;
+}
+.calbordered .title{
+	font:small Arial,Helvetica,sans-serif;
+	color:#000;
+	font-weight:bold;
+	margin-bottom:5px;
+	height:auto;
+-width:28em;
+	position:relative;
+}
+
+.close-icon-right, .close-icon-left {
+	position:absolute;
+	top:0;
+	border:none;
+}
+.close-icon-right {
+right:0;
+}
+.close-icon-left {
+left:0;
+}
+.cal2up {
+	/*float:left;*/
+	-position:absolute;
+left:0.5em;
+}
+.calbordered > .cal2up{
+	float:left;
+}
+
+.cal2up2 {
+	/*float:left;*/
+	-position:absolute;
+-left:14em;
+}
+.calbordered > .cal2up2{
+	float:left;
+}
+
+.calnavleft {
+	position:absolute;
+	top:0;
+	bottom:0;
+	height:12px;   
+	left:2px;
+}
+
+.calnavright {
+	position:absolute;
+	top:0;
+	bottom:0;
+	height:12px;  
+	right:2px;
+}
+
+/* Calendar element styles */
+
+.calendar {
+	font:small Arial,Helvetica,sans-serif;
+	text-align:center;
+	border-spacing:0;
+}
+
+.calcell{
+	width:1.5em;
+	height:1em;
+	border:1px solid #E0E0E0;
+	background-color:#FFF;
+text-align:center;
+}
+
+.calcell a {
+	color:#003DB8;
+	text-decoration:none;
+}
+
+.calcell.today {
+	border:1px solid #000;
+}
+
+.calcell.oom, .calcell.oom:hover {
+	cursor:default;
+	color:#999;
+	background-color:#EEE;
+	border:1px solid #E0E0E0;
+}
+
+.selected, .calcell.selected {
+	color:#003DB8;
+	background-color:#FFF19F;
+	border:1px solid #FF9900;
+font-weight:bold;
+}
+
+.calcell:hover, .calcell.calcellhover, .calcell a:hover{
+	cursor:pointer;
+	color:#FFF;
+	background-color:#FF9900;
+	border:1px solid #FF9900;
+}
+
+.calcell.calcellhover a, .calcell:hover a {
+	color:#FFF;
+	background-color:#FF9900;
+	border:1px solid #FF9900;
+}
+
+.calcell.restricted {
+	text-decoration:line-through;
+}
+
+.calcell.previous {
+	color:#CCC;
+}
+
+.calcell.highlight1 { background-color:#CCFF99; }
+.calcell.highlight2 { background-color:#99CCFF; }
+.calcell.highlight3 { background-color:#FFCCCC; }
+.calcell.highlight4 { background-color:#CCFF99; }
+
+
+.calhead {
+	border:1px solid #E0E0E0;
+	vertical-align:middle;
+	background-color:#FFF;
+}
+
+.calheader {
+	position:relative;
+	width:100%;
+}
+
+.calheader img {
+	border:none;
+}
+
+.calweekdaycell {
+	color:#666;
+	font-weight:normal;
+}
+
+.calfoot {
+	background-color:#EEE;
+}
+
+.calrowhead, .calrowfoot {
+	color:#666;
+	font-size:9px;
+	font-style:italic;
+	font-weight:normal;
+	width:15px;
+}
+
+.calrowhead {
+	border-right-width:2px;
+}
Index: plugins/widget_calendar_1_9/img_pack/calendar.js
===================================================================
--- plugins/widget_calendar_1_9/img_pack/calendar.js	(revision 6)
+++ plugins/widget_calendar_1_9/img_pack/calendar.js	(revision 6)
@@ -0,0 +1,2841 @@
+/*
+Copyright (c) 2006 Spip! Inc. All rights reserved.
+version 0.9.0
+*/
+
+SPIP.namespace("SPIP.widget");
+
+/**
+* @class
+* <p>SPIP.widget.DateMath is used for simple date manipulation. The class is a static utility
+* used for adding, subtracting, and comparing dates.</p>
+*/
+SPIP.widget.DateMath = new function() {
+
+	/**
+	* Constant field representing Day
+	* @type String
+	*/
+	this.DAY = "D";
+
+	/**
+	* Constant field representing Week
+	* @type String
+	*/
+	this.WEEK = "W";
+
+	/**
+	* Constant field representing Year
+	* @type String
+	*/
+	this.YEAR = "Y";
+
+	/**
+	* Constant field representing Month
+	* @type String
+	*/
+	this.MONTH = "M";
+
+	/**
+	* Constant field representing one day, in milliseconds
+	* @type Integer
+	*/
+	this.ONE_DAY_MS = 1000*60*60*24;
+
+	/**
+	* Adds the specified amount of time to the this instance.
+	* @param {Date} date	The JavaScript Date object to perform addition on
+	* @param {string} field	The this field constant to be used for performing addition.
+	* @param {Integer} amount	The number of units (measured in the field constant) to add to the date.
+	*/
+	this.add = function(date, field, amount) {
+		var d = new Date(date.getTime());
+		switch (field)
+		{
+			case this.MONTH:
+				var newMonth = date.getMonth() + amount;
+				var years = 0;
+
+
+				if (newMonth < 0) {
+					while (newMonth < 0)
+					{
+						newMonth += 12;
+						years -= 1;
+					}
+				} else if (newMonth > 11) {
+					while (newMonth > 11)
+					{
+						newMonth -= 12;
+						years += 1;
+					}
+				}
+
+				d.setMonth(newMonth);
+				d.setFullYear(date.getFullYear() + years);
+				break;
+			case this.DAY:
+				d.setDate(date.getDate() + amount);
+				break;
+			case this.YEAR:
+				d.setFullYear(date.getFullYear() + amount);
+				break;
+			case this.WEEK:
+				d.setDate(date.getDate() + 7);
+				break;
+		}
+		return d;
+	};
+
+	/**
+	* Subtracts the specified amount of time from the this instance.
+	* @param {Date} date	The JavaScript Date object to perform subtraction on
+	* @param {Integer} field	The this field constant to be used for performing subtraction.
+	* @param {Integer} amount	The number of units (measured in the field constant) to subtract from the date.
+	*/
+	this.subtract = function(date, field, amount) {
+		return this.add(date, field, (amount*-1));
+	};
+
+	/**
+	* Determines whether a given date is before another date on the calendar.
+	* @param {Date} date		The Date object to compare with the compare argument
+	* @param {Date} compareTo	The Date object to use for the comparison
+	* @return {Boolean} true if the date occurs before the compared date; false if not.
+	*/
+	this.before = function(date, compareTo) {
+		var ms = compareTo.getTime();
+		if (date.getTime() < ms) {
+			return true;
+		} else {
+			return false;
+		}
+	};
+
+	/**
+	* Determines whether a given date is after another date on the calendar.
+	* @param {Date} date		The Date object to compare with the compare argument
+	* @param {Date} compareTo	The Date object to use for the comparison
+	* @return {Boolean} true if the date occurs after the compared date; false if not.
+	*/
+	this.after = function(date, compareTo) {
+		var ms = compareTo.getTime();
+		if (date.getTime() > ms) {
+			return true;
+		} else {
+			return false;
+		}
+	};
+
+	/**
+	* Retrieves a JavaScript Date object representing January 1 of any given year.
+	* @param {Integer} calendarYear		The calendar year for which to retrieve January 1
+	* @return {Date}	January 1 of the calendar year specified.
+	*/
+	this.getJan1 = function(calendarYear) {
+		return new Date(calendarYear,0,1);
+	};
+
+	/**
+	* Calculates the number of days the specified date is from January 1 of the specified calendar year.
+	* Passing January 1 to this function would return an offset value of zero.
+	* @param {Date}	date	The JavaScript date for which to find the offset
+	* @param {Integer} calendarYear	The calendar year to use for determining the offset
+	* @return {Integer}	The number of days since January 1 of the given year
+	*/
+	this.getDayOffset = function(date, calendarYear) {
+		var beginYear = this.getJan1(calendarYear); // Find the start of the year. This will be in week 1.
+
+		// Find the number of days the passed in date is away from the calendar year start
+		var dayOffset = Math.ceil((date.getTime()-beginYear.getTime()) / this.ONE_DAY_MS);
+		return dayOffset;
+	};
+
+	/**
+	* Calculates the week number for the given date. This function assumes that week 1 is the
+	* week in which January 1 appears, regardless of whether the week consists of a full 7 days.
+	* The calendar year can be specified to help find what a the week number would be for a given
+	* date if the date overlaps years. For instance, a week may be considered week 1 of 2005, or
+	* week 53 of 2004. Specifying the optional calendarYear allows one to make this distinction
+	* easily.
+	* @param {Date}	date	The JavaScript date for which to find the week number
+	* @param {Integer} calendarYear	OPTIONAL - The calendar year to use for determining the week number. Default is
+	*											the calendar year of parameter "date".
+	* @param {Integer} weekStartsOn	OPTIONAL - The integer (0-6) representing which day a week begins on. Default is 0 (for Sunday).
+	* @return {Integer}	The week number of the given date.
+	*/
+	this.getWeekNumber = function(date, calendarYear, weekStartsOn) {
+		if (! weekStartsOn) {
+			weekStartsOn = 0;
+		}
+		if (! calendarYear) {
+			calendarYear = date.getFullYear();
+		}
+		var weekNum = -1;
+
+		var jan1 = this.getJan1(calendarYear);
+		var jan1DayOfWeek = jan1.getDay();
+
+		var month = date.getMonth();
+		var day = date.getDate();
+		var year = date.getFullYear();
+
+		var dayOffset = this.getDayOffset(date, calendarYear); // Days since Jan 1, Calendar Year
+
+		if (dayOffset < 0 && dayOffset >= (-1 * jan1DayOfWeek)) {
+			weekNum = 1;
+		} else {
+			weekNum = 1;
+			var testDate = this.getJan1(calendarYear);
+
+			while (testDate.getTime() < date.getTime() && testDate.getFullYear() == calendarYear) {
+				weekNum += 1;
+				testDate = this.add(testDate, this.WEEK, 1);
+			}
+		}
+
+		return weekNum;
+	};
+
+	/**
+	* Determines if a given week overlaps two different years.
+	* @param {Date}	weekBeginDate	The JavaScript Date representing the first day of the week.
+	* @return {Boolean}	true if the date overlaps two different years.
+	*/
+	this.isYearOverlapWeek = function(weekBeginDate) {
+		var overlaps = false;
+		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
+		if (nextWeek.getFullYear() != weekBeginDate.getFullYear()) {
+			overlaps = true;
+		}
+		return overlaps;
+	};
+
+	/**
+	* Determines if a given week overlaps two different months.
+	* @param {Date}	weekBeginDate	The JavaScript Date representing the first day of the week.
+	* @return {Boolean}	true if the date overlaps two different months.
+	*/
+	this.isMonthOverlapWeek = function(weekBeginDate) {
+		var overlaps = false;
+		var nextWeek = this.add(weekBeginDate, this.DAY, 6);
+		if (nextWeek.getMonth() != weekBeginDate.getMonth()) {
+			overlaps = true;
+		}
+		return overlaps;
+	};
+
+	/**
+	* Gets the first day of a month containing a given date.
+	* @param {Date}	date	The JavaScript Date used to calculate the month start
+	* @return {Date}		The JavaScript Date representing the first day of the month
+	*/
+	this.findMonthStart = function(date) {
+		var start = new Date(date.getFullYear(), date.getMonth(), 1);
+		return start;
+	};
+
+	/**
+	* Gets the last day of a month containing a given date.
+	* @param {Date}	date	The JavaScript Date used to calculate the month end
+	* @return {Date}		The JavaScript Date representing the last day of the month
+	*/
+	this.findMonthEnd = function(date) {
+		var start = this.findMonthStart(date);
+		var nextMonth = this.add(start, this.MONTH, 1);
+		var end = this.subtract(nextMonth, this.DAY, 1);
+		return end;
+	};
+
+	/**
+	* Clears the time fields from a given date, effectively setting the time to midnight.
+	* @param {Date}	date	The JavaScript Date for which the time fields will be cleared
+	* @return {Date}		The JavaScript Date cleared of all time fields
+	*/
+	this.clearTime = function(date) {
+		date.setHours(0,0,0,0);
+		return date;
+	};
+}
+
+SPIP.namespace("SPIP.widget");
+
+/**
+* @class
+* <p>Calendar_Core is the base class for the Calendar widget. In its most basic
+* implementation, it has the ability to render a calendar widget on the page
+* that can be manipulated to select a single date, move back and forth between
+* months and years.</p>
+* <p>To construct the placeholder for the calendar widget, the code is as
+* follows:
+*	<xmp>
+*		<div id="cal1Container"></div>
+*	</xmp>
+* Note that the table can be replaced with any kind of element.
+* </p>
+* @constructor
+* @param {String}	id			The id of the table element that will represent the calendar widget
+* @param {String}	containerId	The id of the container element that will contain the calendar table
+* @param {String}	monthyear	The month/year string used to set the current calendar page
+* @param {String}	selected	A string of date values formatted using the date parser. The built-in
+								default date format is MM/DD/YYYY. Ranges are defined using
+								MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+								Any combination of these can be combined by delimiting the string with
+								commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+*/
+SPIP.widget.Calendar_Core = function(id, containerId, monthyear, selected) {
+	if (arguments.length > 0)
+	{
+		this.init(id, containerId, monthyear, selected);
+	}
+}
+
+/**
+* Type constant used for renderers to represent an individual date (M/D/Y)
+* @final
+* @type String
+*/
+SPIP.widget.Calendar_Core.DATE = "D";
+
+/**
+* Type constant used for renderers to represent an individual date across any year (M/D)
+* @final
+* @type String
+*/
+SPIP.widget.Calendar_Core.MONTH_DAY = "MD";
+
+/**
+* Type constant used for renderers to represent a weekday
+* @final
+* @type String
+*/
+SPIP.widget.Calendar_Core.WEEKDAY = "WD";
+
+/**
+* Type constant used for renderers to represent a range of individual dates (M/D/Y-M/D/Y)
+* @final
+* @type String
+*/
+SPIP.widget.Calendar_Core.RANGE = "R";
+
+/**
+* Type constant used for renderers to represent a month across any year
+* @final
+* @type String
+*/
+SPIP.widget.Calendar_Core.MONTH = "M";
+
+/**
+* Constant that represents the total number of date cells that are displayed in a given month
+* including
+* @final
+* @type Integer
+*/
+SPIP.widget.Calendar_Core.DISPLAY_DAYS = 42;
+
+/**
+* Constant used for halting the execution of the remainder of the render stack
+* @final
+* @type String
+*/
+SPIP.widget.Calendar_Core.STOP_RENDER = "S";
+
+SPIP.widget.Calendar_Core.prototype = {
+
+	/**
+	* The configuration object used to set up the calendars various locale and style options.
+	* @type Object
+	*/
+	Config : null,
+
+	/**
+	* The parent CalendarGroup, only to be set explicitly by the parent group
+	* @type CalendarGroup
+	*/
+	parent : null,
+
+	/**
+	* The index of this item in the parent group
+	* @type Integer
+	*/
+	index : -1,
+
+	/**
+	* The collection of calendar table cells
+	* @type HTMLTableCellElement[]
+	*/
+	cells : null,
+
+	/**
+	* The collection of calendar week header cells
+	* @type HTMLTableCellElement[]
+	*/
+	weekHeaderCells : null,
+
+	/**
+	* The collection of calendar week footer cells
+	* @type HTMLTableCellElement[]
+	*/
+	weekFooterCells : null,
+
+	/**
+	* The collection of calendar cell dates that is parallel to the cells collection. The array contains dates field arrays in the format of [YYYY, M, D].
+	* @type Array[](Integer[])
+	*/
+	cellDates : null,
+
+	/**
+	* The id that uniquely identifies this calendar. This id should match the id of the placeholder element on the page.
+	* @type String
+	*/
+	id : null,
+
+	/**
+	* The DOM element reference that points to this calendar's container element. The calendar will be inserted into this element when the shell is rendered.
+	* @type HTMLElement
+	*/
+	oDomContainer : null,
+
+	/**
+	* A Date object representing today's date.
+	* @type Date
+	*/
+	today : null,
+
+	/**
+	* The list of render functions, along with required parameters, used to render cells.
+	* @type Array[]
+	*/
+	renderStack : null,
+
+	/**
+	* A copy of the initial render functions created before rendering.
+	* @type Array
+	* @private
+	*/
+	_renderStack : null,
+
+	/**
+	* A Date object representing the month/year that the calendar is currently set to
+	* @type Date
+	*/
+	pageDate : null,
+
+	/**
+	* A Date object representing the month/year that the calendar is initially set to
+	* @type Date
+	* @private
+	*/
+	_pageDate : null,
+
+	/**
+	* A Date object representing the minimum selectable date
+	* @type Date
+	*/
+	minDate : null,
+
+	/**
+	* A Date object representing the maximum selectable date
+	* @type Date
+	*/
+	maxDate : null,
+
+	/**
+	* The list of currently selected dates. The data format for this local collection is
+	* an array of date field arrays, e.g:
+	* [
+	*	[2004,5,25],
+	*	[2004,5,26]
+	* ]
+	* @type Array[](Integer[])
+	*/
+	selectedDates : null,
+
+	/**
+	* The private list of initially selected dates.
+	* @type Array
+	* @private
+	*/
+	_selectedDates : null,
+
+	/**
+	* A boolean indicating whether the shell of the calendar has already been rendered to the page
+	* @type Boolean
+	*/
+	shellRendered : false,
+
+	/**
+	* The HTML table element that represents this calendar
+	* @type HTMLTableElement
+	*/
+	table : null,
+
+	/**
+	* The HTML cell element that represents the main header cell TH used in the calendar table
+	* @type HTMLTableCellElement
+	*/
+	headerCell : null
+
+
+};
+
+
+
+/**
+* Initializes the calendar widget. This method must be called by all subclass constructors.
+* @param {String}	id			The id of the table element that will represent the calendar widget
+* @param {String}	containerId	The id of the container element that will contain the calendar table
+* @param {String}	monthyear	The month/year string used to set the current calendar page
+* @param {String}	selected	A string of date values formatted using the date parser. The built-in
+								default date format is MM/DD/YYYY. Ranges are defined using
+								MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+								Any combination of these can be combined by delimiting the string with
+								commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+*/
+SPIP.widget.Calendar_Core.prototype.init = function(id, containerId, monthyear, selected) {
+	this.setupConfig();
+
+	this.id = id;
+
+	this.cellDates = new Array();
+
+	this.cells = new Array();
+
+	this.renderStack = new Array();
+	this._renderStack = new Array();
+
+	this.oDomContainer = document.getElementById(containerId);
+
+	this.today = new Date();
+	SPIP.widget.DateMath.clearTime(this.today);
+
+	var month;
+	var year;
+
+	if (monthyear)
+	{
+		var aMonthYear = monthyear.split(this.Locale.DATE_FIELD_DELIMITER);
+		month = parseInt(aMonthYear[this.Locale.MY_MONTH_POSITION-1]);
+		year = parseInt(aMonthYear[this.Locale.MY_YEAR_POSITION-1]);
+	} else {
+		month = this.today.getMonth()+1;
+		year = this.today.getFullYear();
+	}
+
+	this.pageDate = new Date(year, month-1, 1);
+	this._pageDate = new Date(this.pageDate.getTime());
+
+	if (selected)
+	{
+		this.selectedDates = this._parseDates(selected);
+		this._selectedDates = this.selectedDates.concat();
+	} else {
+		this.selectedDates = new Array();
+		this._selectedDates = new Array();
+	}
+
+	this.wireDefaultEvents();
+	this.wireCustomEvents();
+};
+
+
+/**
+* Wires the local DOM events for the Calendar, including cell selection, hover, and
+* default navigation that is used for moving back and forth between calendar pages.
+*/
+SPIP.widget.Calendar_Core.prototype.wireDefaultEvents = function() {
+
+	/**
+	* The default event function that is attached to a date link within a calendar cell
+	* when the calendar is rendered.
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	*/
+	this.doSelectCell = function(e, cal) {
+		var cell = this;
+		var index = cell.index;
+
+		if (cal.Options.MULTI_SELECT) {
+			var link = cell.getElementsByTagName("A")[0];
+			link.blur();
+
+			var cellDate = cal.cellDates[index];
+			var cellDateIndex = cal._indexOfSelectedFieldArray(cellDate);
+
+			if (cellDateIndex > -1)
+			{
+				cal.deselectCell(index);
+			} else {
+				cal.selectCell(index);
+			}
+
+		} else {
+			var link = cell.getElementsByTagName("A")[0];
+			link.blur()
+
+			cal.selectCell(index);
+		}
+	}
+
+	/**
+	* The event that is executed when the user hovers over a cell
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	* @private
+	*/
+	this.doCellMouseOver = function(e, cal) {
+		SPIP.widget.Calendar_Core.prependCssClass(this, cal.Style.CSS_CELL_HOVER);
+	}
+
+	/**
+	* The event that is executed when the user moves the mouse out of a cell
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	* @private
+	*/
+	this.doCellMouseOut = function(e, cal) {
+		SPIP.widget.Calendar_Core.removeCssClass(this, cal.Style.CSS_CELL_HOVER);
+	}
+
+	/**
+	* A wrapper event that executes the nextMonth method through a DOM event
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	* @private
+	*/
+	this.doNextMonth = function(e, cal) {
+		cal.nextMonth();
+	}
+
+	/**
+	* A wrapper event that executes the previousMonth method through a DOM event
+	* @param	e		The event
+	* @param	cal		A reference to the calendar passed by the Event utility
+	* @private
+	*/
+	this.doPreviousMonth = function(e, cal) {
+		cal.previousMonth();
+	}
+}
+
+/**
+* This function can be extended by subclasses to attach additional DOM events to
+* the calendar. By default, this method is unimplemented.
+*/
+SPIP.widget.Calendar_Core.prototype.wireCustomEvents = function() { }
+
+/**
+This method is called to initialize the widget configuration variables, including
+style, localization, and other display and behavioral options.
+<p>Config: Container for the CSS style configuration variables.</p>
+<p><strong>Config.Style</strong> - Defines the CSS classes used for different calendar elements</p>
+<blockquote>
+	<div><em>CSS_CALENDAR</em> : Container table</div>
+	<div><em>CSS_HEADER</em> : </div>
+	<div><em>CSS_HEADER_TEXT</em> : Calendar header</div>
+	<div><em>CSS_FOOTER</em> : Calendar footer</div>
+	<div><em>CSS_CELL</em> : Calendar day cell</div>
+	<div><em>CSS_CELL_OOM</em> : Calendar OOM (out of month) cell</div>
+	<div><em>CSS_CELL_SELECTED</em> : Calendar selected cell</div>
+	<div><em>CSS_CELL_RESTRICTED</em> : Calendar restricted cell</div>
+	<div><em>CSS_CELL_TODAY</em> : Calendar cell for today's date</div>
+	<div><em>CSS_ROW_HEADER</em> : The cell preceding a row (used for week number by default)</div>
+	<div><em>CSS_ROW_FOOTER</em> : The cell following a row (not implemented by default)</div>
+	<div><em>CSS_WEEKDAY_CELL</em> : The cells used for labeling weekdays</div>
+	<div><em>CSS_WEEKDAY_ROW</em> : The row containing the weekday label cells</div>
+	<div><em>CSS_BORDER</em> : The border style used for the default UED rendering</div>
+	<div><em>CSS_CONTAINER</em> : Special container class used to properly adjust the sizing and float</div>
+	<div><em>CSS_NAV_LEFT</em> : Left navigation arrow</div>
+	<div><em>CSS_NAV_RIGHT</em> : Right navigation arrow</div>
+	<div><em>CSS_CELL_TOP</em> : Outlying cell along the top row</div>
+	<div><em>CSS_CELL_LEFT</em> : Outlying cell along the left row</div>
+	<div><em>CSS_CELL_RIGHT</em> : Outlying cell along the right row</div>
+	<div><em>CSS_CELL_BOTTOM</em> : Outlying cell along the bottom row</div>
+	<div><em>CSS_CELL_HOVER</em> : Cell hover style</div>
+	<div><em>CSS_CELL_HIGHLIGHT1</em> : Highlight color 1 for styling cells</div>
+	<div><em>CSS_CELL_HIGHLIGHT2</em> : Highlight color 2 for styling cells</div>
+	<div><em>CSS_CELL_HIGHLIGHT3</em> : Highlight color 3 for styling cells</div>
+	<div><em>CSS_CELL_HIGHLIGHT4</em> : Highlight color 4 for styling cells</div>
+
+</blockquote>
+<p><strong>Config.Locale</strong> - Defines the locale string arrays used for localization</p>
+<blockquote>
+	<div><em>MONTHS_SHORT</em> : Array of 12 months in short format ("Jan", "Feb", etc.)</div>
+	<div><em>MONTHS_LONG</em> : Array of 12 months in short format ("Jan", "Feb", etc.)</div>
+	<div><em>WEEKDAYS_1CHAR</em> : Array of 7 days in 1-character format ("S", "M", etc.)</div>
+	<div><em>WEEKDAYS_SHORT</em> : Array of 7 days in short format ("Su", "Mo", etc.)</div>
+	<div><em>WEEKDAYS_MEDIUM</em> : Array of 7 days in medium format ("Sun", "Mon", etc.)</div>
+	<div><em>WEEKDAYS_LONG</em> : Array of 7 days in long format ("Sunday", "Monday", etc.)</div>
+	<div><em>DATE_DELIMITER</em> : The value used to delimit series of multiple dates (Default: ",")</div>
+	<div><em>DATE_FIELD_DELIMITER</em> : The value used to delimit date fields (Default: "/")</div>
+	<div><em>DATE_RANGE_DELIMITER</em> : The value used to delimit date fields (Default: "-")</div>
+	<div><em>MY_MONTH_POSITION</em> : The value used to determine the position of the month in a month/year combo (e.g. 12/2005) (Default: 1)</div>
+	<div><em>MY_YEAR_POSITION</em> : The value used to determine the position of the year in a month/year combo (e.g. 12/2005) (Default: 2)</div>
+	<div><em>MD_MONTH_POSITION</em> : The value used to determine the position of the month in a month/day combo (e.g. 12/25) (Default: 1)</div>
+	<div><em>MD_DAY_POSITION</em> : The value used to determine the position of the day in a month/day combo (e.g. 12/25) (Default: 2)</div>
+	<div><em>MDY_MONTH_POSITION</em> : The value used to determine the position of the month in a month/day/year combo (e.g. 12/25/2005) (Default: 1)</div>
+	<div><em>MDY_DAY_POSITION</em> : The value used to determine the position of the day in a month/day/year combo (e.g. 12/25/2005) (Default: 2)</div>
+	<div><em>MDY_YEAR_POSITION</em> : The value used to determine the position of the year in a month/day/year combo (e.g. 12/25/2005) (Default: 3)</div>
+</blockquote>
+<p><strong>Config.Options</strong> - Defines other configurable calendar widget options</p>
+<blockquote>
+	<div><em>SHOW_WEEKDAYS</em> : Boolean, determines whether to display the weekday headers (defaults to true)</div>
+	<div><em>LOCALE_MONTHS</em> : Array, points to the desired Config.Locale array (defaults to Config.Locale.MONTHS_LONG)</div>
+	<div><em>LOCALE_WEEKDAYS</em> : Array, points to the desired Config.Locale array (defaults to Config.Locale.WEEKDAYS_SHORT)</div>
+	<div><em>START_WEEKDAY</em> : Integer, 0-6, representing the day that a week begins on</div>
+	<div><em>SHOW_WEEK_HEADER</em> : Boolean, determines whether to display row headers</div>
+	<div><em>SHOW_WEEK_FOOTER</em> : Boolean, determines whether to display row footers</div>
+	<div><em>HIDE_BLANK_WEEKS</em> : Boolean, determines whether to hide extra weeks that are completely OOM</div>
+	<div><em>NAV_ARROW_LEFT</em> : String, the image path used for the left navigation arrow</div>
+	<div><em>NAV_ARROW_RIGHT</em> : String, the image path used for the right navigation arrow</div>
+</blockquote>
+*/
+SPIP.widget.Calendar_Core.prototype.setupConfig = function() {
+	/**
+	* Container for the CSS style configuration variables.
+	*/
+	this.Config = new Object();
+
+	this.Config.Style = {
+		// Style variables
+		CSS_ROW_HEADER: "calrowhead",
+		CSS_ROW_FOOTER: "calrowfoot",
+		CSS_CELL : "calcell",
+		CSS_CELL_SELECTED : "selected",
+		CSS_CELL_RESTRICTED : "restricted",
+		CSS_CELL_TODAY : "today",
+		CSS_CELL_OOM : "oom",
+		CSS_HEADER : "calheader",
+		CSS_HEADER_TEXT : "calhead",
+		CSS_WEEKDAY_CELL : "calweekdaycell",
+		CSS_WEEKDAY_ROW : "calweekdayrow",
+		CSS_FOOTER : "calfoot",
+		CSS_CALENDAR : "calendar",
+		CSS_BORDER : "calbordered",
+		CSS_CONTAINER : "calcontainer",
+		CSS_NAV_LEFT : "calnavleft",
+		CSS_NAV_RIGHT : "calnavright",
+		CSS_CELL_TOP : "calcelltop",
+		CSS_CELL_LEFT : "calcellleft",
+		CSS_CELL_RIGHT : "calcellright",
+		CSS_CELL_BOTTOM : "calcellbottom",
+		CSS_CELL_HOVER : "calcellhover",
+		CSS_CELL_HIGHLIGHT1 : "highlight1",
+		CSS_CELL_HIGHLIGHT2 : "highlight2",
+		CSS_CELL_HIGHLIGHT3 : "highlight3",
+		CSS_CELL_HIGHLIGHT4 : "highlight4"
+	};
+
+	this.Style = this.Config.Style;
+
+	this.Config.Locale = {
+		// Locale definition
+		MONTHS_SHORT : ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
+		MONTHS_LONG : ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
+		WEEKDAYS_1CHAR : ["S", "M", "T", "W", "T", "F", "S"],
+		WEEKDAYS_SHORT : ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
+		WEEKDAYS_MEDIUM : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
+		WEEKDAYS_LONG : ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
+		DATE_DELIMITER : ",",
+		DATE_FIELD_DELIMITER : "/",
+		DATE_RANGE_DELIMITER : "-",
+		MY_MONTH_POSITION : 1,
+		MY_YEAR_POSITION : 2,
+		MD_MONTH_POSITION : 1,
+		MD_DAY_POSITION : 2,
+		MDY_MONTH_POSITION : 1,
+		MDY_DAY_POSITION : 2,
+		MDY_YEAR_POSITION : 3
+	};
+
+	this.Locale = this.Config.Locale;
+
+	this.Config.Options = {
+		// Configuration variables
+		MULTI_SELECT : false,
+		SHOW_WEEKDAYS : true,
+		START_WEEKDAY : 0,
+		SHOW_WEEK_HEADER : false,
+		SHOW_WEEK_FOOTER : false,
+		HIDE_BLANK_WEEKS : false,
+		NAV_ARROW_LEFT : "img/callt.gif",
+		NAV_ARROW_RIGHT : "img/calrt.gif",
+		IMG_CLOSE : "img/calx.gif",
+		IMG_CLOSE_CLASS : "close-icon"
+	};
+
+	this.Options = this.Config.Options;
+
+	this.customConfig();
+
+	if (! this.Options.LOCALE_MONTHS) {
+		this.Options.LOCALE_MONTHS=this.Locale.MONTHS_LONG;
+	}
+	if (! this.Options.LOCALE_WEEKDAYS) {
+		this.Options.LOCALE_WEEKDAYS=this.Locale.WEEKDAYS_SHORT;
+	}
+
+	// If true, reconfigure weekday arrays to place Mondays first
+	if (this.Options.START_WEEKDAY > 0)
+	{
+		for (var w=0;w<this.Options.START_WEEKDAY;++w) {
+			this.Locale.WEEKDAYS_SHORT.push(this.Locale.WEEKDAYS_SHORT.shift());
+			this.Locale.WEEKDAYS_MEDIUM.push(this.Locale.WEEKDAYS_MEDIUM.shift());
+			this.Locale.WEEKDAYS_LONG.push(this.Locale.WEEKDAYS_LONG.shift());
+		}
+	}
+};
+
+/**
+* This method is called when subclasses need to override configuration variables
+* or create new ones. Values can be explicitly set as follows:
+* <blockquote><code>
+*	this.Config.Style.CSS_CELL = "newcalcell";
+*	this.Config.Locale.MONTHS_SHORT = ["Jan", "Fév", "Mars", "Avr", "Mai", "Juin", "Juil", "Août", "Sept", "Oct", "Nov", "Déc"];
+* </code></blockquote>
+*/
+SPIP.widget.Calendar_Core.prototype.customConfig = function() { };
+
+/**
+* Builds the date label that will be displayed in the calendar header or
+* footer, depending on configuration.
+* @return	The formatted calendar month label
+* @type String
+*/
+SPIP.widget.Calendar_Core.prototype.buildMonthLabel = function() {
+	var text = this.Options.LOCALE_MONTHS[this.pageDate.getMonth()] + " " + this.pageDate.getFullYear();
+	return text;
+};
+
+/**
+* Builds the date digit that will be displayed in calendar cells
+* @return	The formatted day label
+* @type	String
+*/
+SPIP.widget.Calendar_Core.prototype.buildDayLabel = function(workingDate) {
+	var day = workingDate.getDate();
+	return day;
+};
+
+
+
+/**
+* Builds the calendar table shell that will be filled in with dates and formatting.
+* This method calls buildShellHeader, buildShellBody, and buildShellFooter (in that order)
+* to construct the pieces of the calendar table. The construction of the shell should
+* only happen one time when the calendar is initialized.
+*/
+SPIP.widget.Calendar_Core.prototype.buildShell = function() {
+
+	this.table = document.createElement("TABLE");
+	this.table.cellSpacing = 0;
+	SPIP.widget.Calendar_Core.setCssClasses(this.table, [this.Style.CSS_CALENDAR]);
+
+	this.table.id = this.id;
+
+	this.buildShellHeader();
+	this.buildShellBody();
+	this.buildShellFooter();
+
+	SPIP.util.Event.addListener(window, "unload", this._unload, this);
+};
+
+/**
+* Builds the calendar shell header by inserting a THEAD into the local calendar table.
+*/
+SPIP.widget.Calendar_Core.prototype.buildShellHeader = function() {
+	var head = document.createElement("THEAD");
+	var headRow = document.createElement("TR");
+
+	var headerCell = document.createElement("TH");
+
+	var colSpan = 7;
+	if (this.Config.Options.SHOW_WEEK_HEADER) {
+		this.weekHeaderCells = new Array();
+		colSpan += 1;
+	}
+	if (this.Config.Options.SHOW_WEEK_FOOTER) {
+		this.weekFooterCells = new Array();
+		colSpan += 1;
+	}
+
+	headerCell.colSpan = colSpan;
+
+	SPIP.widget.Calendar_Core.setCssClasses(headerCell,[this.Style.CSS_HEADER_TEXT]);
+
+	this.headerCell = headerCell;
+
+	headRow.appendChild(headerCell);
+	head.appendChild(headRow);
+
+	// Append day labels, if needed
+	if (this.Options.SHOW_WEEKDAYS)
+	{
+		var row = document.createElement("TR");
+		var fillerCell;
+
+		SPIP.widget.Calendar_Core.setCssClasses(row,[this.Style.CSS_WEEKDAY_ROW]);
+
+		if (this.Config.Options.SHOW_WEEK_HEADER) {
+			fillerCell = document.createElement("TH");
+			SPIP.widget.Calendar_Core.setCssClasses(fillerCell,[this.Style.CSS_WEEKDAY_CELL]);
+			row.appendChild(fillerCell);
+		}
+
+		for(var i=0;i<this.Options.LOCALE_WEEKDAYS.length;++i)
+		{
+			var cell = document.createElement("TH");
+			SPIP.widget.Calendar_Core.setCssClasses(cell,[this.Style.CSS_WEEKDAY_CELL]);
+			cell.innerHTML=this.Options.LOCALE_WEEKDAYS[i];
+			row.appendChild(cell);
+		}
+
+		if (this.Config.Options.SHOW_WEEK_FOOTER) {
+			fillerCell = document.createElement("TH");
+			SPIP.widget.Calendar_Core.setCssClasses(fillerCell,[this.Style.CSS_WEEKDAY_CELL]);
+			row.appendChild(fillerCell);
+		}
+
+		head.appendChild(row);
+	}
+
+	this.table.appendChild(head);
+};
+
+/**
+* Builds the calendar shell body (6 weeks by 7 days)
+*/
+SPIP.widget.Calendar_Core.prototype.buildShellBody = function() {
+	// This should only get executed once
+	this.tbody = document.createElement("TBODY");
+
+	for (var r=0;r<6;++r)
+	{
+		var row = document.createElement("TR");
+
+		for (var c=0;c<this.headerCell.colSpan;++c)
+		{
+			var cell;
+			if (this.Config.Options.SHOW_WEEK_HEADER && c===0) { // Row header
+				cell = document.createElement("TH");
+				this.weekHeaderCells[this.weekHeaderCells.length] = cell;
+			} else if (this.Config.Options.SHOW_WEEK_FOOTER && c==(this.headerCell.colSpan-1)){ // Row footer
+				cell = document.createElement("TH");
+				this.weekFooterCells[this.weekFooterCells.length] = cell;
+			} else {
+				cell = document.createElement("TD");
+				this.cells[this.cells.length] = cell;
+				SPIP.widget.Calendar_Core.setCssClasses(cell, [this.Style.CSS_CELL]);
+			}
+
+			row.appendChild(cell);
+		}
+		this.tbody.appendChild(row);
+	}
+
+	this.table.appendChild(this.tbody);
+};
+
+/**
+* Builds the calendar shell footer. In the default implementation, there is
+* no footer.
+*/
+SPIP.widget.Calendar_Core.prototype.buildShellFooter = function() { };
+
+/**
+* Outputs the calendar shell to the DOM, inserting it into the placeholder element.
+*/
+SPIP.widget.Calendar_Core.prototype.renderShell = function() {
+	this.oDomContainer.appendChild(this.table);
+	this.shellRendered = true;
+};
+
+/**
+* Renders the calendar after it has been configured. The render() method has a specific call chain that will execute
+* when the method is called: renderHeader, renderBody, renderFooter.
+* Refer to the documentation for those methods for information on
+* individual render tasks.
+*/
+SPIP.widget.Calendar_Core.prototype.render = function() {
+	if (! this.shellRendered)
+	{
+		this.buildShell();
+		this.renderShell();
+	}
+
+	this.resetRenderers();
+
+	this.cellDates.length = 0;
+
+	// Find starting day of the current month
+	var workingDate = SPIP.widget.DateMath.findMonthStart(this.pageDate);
+
+	this.renderHeader();
+	this.renderBody(workingDate);
+	this.renderFooter();
+
+	this.onRender();
+};
+
+
+
+/**
+* Appends the header contents into the widget header.
+*/
+SPIP.widget.Calendar_Core.prototype.renderHeader = function() {
+	this.headerCell.innerHTML = "";
+
+	var headerContainer = document.createElement("DIV");
+	headerContainer.className = this.Style.CSS_HEADER;
+
+	var labelMonth = document.createElement("span");
+	labelMonth.innerHTML = this.buildMonthLabel();
+	/*headerContainer.appendChild(document.createTextNode(this.buildMonthLabel()));*/
+	headerContainer.appendChild(labelMonth);
+	this.headerCell.appendChild(headerContainer);
+};
+
+/**
+* Appends the calendar body. The default implementation calculates the number of
+* OOM (out of month) cells that need to be rendered at the start of the month, renders those,
+* and renders all the day cells using the built-in cell rendering methods.
+*
+* While iterating through all of the cells, the calendar checks for renderers in the
+* local render stack that match the date of the current cell, and then applies styles
+* as necessary.
+*
+* @param {Date}	workingDate	The current working Date object being used to generate the calendar
+*/
+SPIP.widget.Calendar_Core.prototype.renderBody = function(workingDate) {
+
+	this.preMonthDays = workingDate.getDay();
+	if (this.Options.START_WEEKDAY > 0) {
+		this.preMonthDays -= this.Options.START_WEEKDAY;
+	}
+	if (this.preMonthDays < 0) {
+		this.preMonthDays += 7;
+	}
+
+	this.monthDays = SPIP.widget.DateMath.findMonthEnd(workingDate).getDate();
+	this.postMonthDays = SPIP.widget.Calendar_Core.DISPLAY_DAYS-this.preMonthDays-this.monthDays;
+
+	workingDate = SPIP.widget.DateMath.subtract(workingDate, SPIP.widget.DateMath.DAY, this.preMonthDays);
+
+	this.table.style.visibility = "hidden"; // Hide while we render
+
+	var weekRowIndex = 0;
+
+	for (var c=0;c<this.cells.length;++c)
+	{
+		var cellRenderers = new Array();
+
+		var cell = this.cells[c];
+
+		this.clearElement(cell);
+
+		SPIP.util.Event.removeListener(cell, "click", this.doSelectCell);
+		if (SPIP.widget.Calendar_Core._getBrowser() == "ie") {
+			SPIP.util.Event.removeListener(cell, "mouseover", this.doCellMouseOver);
+			SPIP.util.Event.removeListener(cell, "mouseout", this.doCellMouseOut);
+		}
+
+		cell.index = c;
+		cell.id = this.id + "_cell" + c;
+
+		this.cellDates[this.cellDates.length]=[workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()]; // Add this date to cellDates
+
+		if (workingDate.getDay() == this.Options.START_WEEKDAY) {
+			var rowHeaderCell = null;
+			var rowFooterCell = null;
+
+			if (this.Options.SHOW_WEEK_HEADER) {
+				rowHeaderCell = this.weekHeaderCells[weekRowIndex];
+				this.clearElement(rowHeaderCell);
+			}
+
+			if (this.Options.SHOW_WEEK_FOOTER) {
+				rowFooterCell = this.weekFooterCells[weekRowIndex];
+				this.clearElement(rowFooterCell);
+			}
+
+			if (this.Options.HIDE_BLANK_WEEKS && this.isDateOOM(workingDate) && ! SPIP.widget.DateMath.isMonthOverlapWeek(workingDate)) {
+				// The first day of the week is not in this month, and it's not an overlap week
+				continue;
+			} else {
+				if (rowHeaderCell) {
+					this.renderRowHeader(workingDate, rowHeaderCell);
+				}
+				if (rowFooterCell) {
+					this.renderRowFooter(workingDate, rowFooterCell);
+				}
+			}
+		}
+
+
+
+		var renderer = null;
+
+		if (workingDate.getFullYear()	== this.today.getFullYear() &&
+			workingDate.getMonth()		== this.today.getMonth() &&
+			workingDate.getDate()		== this.today.getDate())
+		{
+			cellRenderers[cellRenderers.length]=this.renderCellStyleToday;
+		}
+
+		if (this.isDateOOM(workingDate))
+		{
+			cellRenderers[cellRenderers.length]=this.renderCellNotThisMonth;
+		} else {
+			for (var r=0;r<this.renderStack.length;++r)
+			{
+				var rArray = this.renderStack[r];
+				var type = rArray[0];
+
+				var month;
+				var day;
+				var year;
+
+				switch (type) {
+					case SPIP.widget.Calendar_Core.DATE:
+						month = rArray[1][1];
+						day = rArray[1][2];
+						year = rArray[1][0];
+
+						if (workingDate.getMonth()+1 == month && workingDate.getDate() == day && workingDate.getFullYear() == year)
+						{
+							renderer = rArray[2];
+							this.renderStack.splice(r,1);
+						}
+						break;
+					case SPIP.widget.Calendar_Core.MONTH_DAY:
+						month = rArray[1][0];
+						day = rArray[1][1];
+
+						if (workingDate.getMonth()+1 == month && workingDate.getDate() == day)
+						{
+							renderer = rArray[2];
+							this.renderStack.splice(r,1);
+						}
+						break;
+					case SPIP.widget.Calendar_Core.RANGE:
+						var date1 = rArray[1][0];
+						var date2 = rArray[1][1];
+
+						var d1month = date1[1];
+						var d1day = date1[2];
+						var d1year = date1[0];
+
+						var d1 = new Date(d1year, d1month-1, d1day);
+
+						var d2month = date2[1];
+						var d2day = date2[2];
+						var d2year = date2[0];
+
+						var d2 = new Date(d2year, d2month-1, d2day);
+
+						if (workingDate.getTime() >= d1.getTime() && workingDate.getTime() <= d2.getTime())
+						{
+							renderer = rArray[2];
+
+							if (workingDate.getTime()==d2.getTime()) {
+								this.renderStack.splice(r,1);
+							}
+						}
+						break;
+					case SPIP.widget.Calendar_Core.WEEKDAY:
+
+						var weekday = rArray[1][0];
+						if (workingDate.getDay()+1 == weekday)
+						{
+							renderer = rArray[2];
+						}
+						break;
+					case SPIP.widget.Calendar_Core.MONTH:
+
+						month = rArray[1][0];
+						if (workingDate.getMonth()+1 == month)
+						{
+							renderer = rArray[2];
+						}
+						break;
+				}
+
+				if (renderer) {
+					cellRenderers[cellRenderers.length]=renderer;
+				}
+			}
+
+		}
+
+		if (this._indexOfSelectedFieldArray([workingDate.getFullYear(),workingDate.getMonth()+1,workingDate.getDate()]) > -1)
+		{
+			cellRenderers[cellRenderers.length]=this.renderCellStyleSelected;
+		}
+
+		if (this.minDate)
+		{
+			this.minDate = SPIP.widget.DateMath.clearTime(this.minDate);
+		}
+		if (this.maxDate)
+		{
+			this.maxDate = SPIP.widget.DateMath.clearTime(this.maxDate);
+		}
+
+		if (
+			(this.minDate && (workingDate.getTime() < this.minDate.getTime())) ||
+			(this.maxDate && (workingDate.getTime() > this.maxDate.getTime()))
+		) {
+			cellRenderers[cellRenderers.length]=this.renderOutOfBoundsDate;
+		} else {
+			cellRenderers[cellRenderers.length]=this.renderCellDefault;
+		}
+
+		for (var x=0;x<cellRenderers.length;++x)
+		{
+			var ren = cellRenderers[x];
+			if (ren.call(this,workingDate,cell) == SPIP.widget.Calendar_Core.STOP_RENDER) {
+				break;
+			}
+		}
+
+		workingDate = SPIP.widget.DateMath.add(workingDate, SPIP.widget.DateMath.DAY, 1); // Go to the next day
+		if (workingDate.getDay() == this.Options.START_WEEKDAY) {
+			weekRowIndex += 1;
+		}
+
+		SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL);
+		if (c >= 0 && c <= 6) {
+			SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_TOP);
+		}
+		if ((c % 7) == 0) {
+			SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_LEFT);
+		}
+		if (((c+1) % 7) == 0) {
+			SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_RIGHT);
+		}
+
+		var postDays = this.postMonthDays;
+		if (postDays >= 7 && this.Options.HIDE_BLANK_WEEKS) {
+			var blankWeeks = Math.floor(postDays/7);
+			for (var p=0;p<blankWeeks;++p) {
+				postDays -= 7;
+			}
+		}
+
+		if (c >= ((this.preMonthDays+postDays+this.monthDays)-7)) {
+			SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_BOTTOM);
+		}
+	}
+
+	this.table.style.visibility = "visible"; // Show table, now that it's rendered
+
+};
+
+/**
+* Appends the contents of the calendar widget footer into the shell. By default,
+* the calendar does not contain a footer, and this method must be implemented by
+* subclassing the widget.
+*/
+SPIP.widget.Calendar_Core.prototype.renderFooter = function() { };
+
+/**
+* @private
+*/
+SPIP.widget.Calendar_Core.prototype._unload = function(e, cal) {
+	for (var c in cal.cells) {
+		c = null;
+	}
+
+	cal.cells = null;
+
+	cal.tbody = null;
+	cal.oDomContainer = null;
+	cal.table = null;
+	cal.headerCell = null;
+
+	cal = null;
+};
+
+
+/****************** BEGIN BUILT-IN TABLE CELL RENDERERS ************************************/
+
+SPIP.widget.Calendar_Core.prototype.renderOutOfBoundsDate = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, "previous");
+	cell.innerHTML = workingDate.getDate();
+	return SPIP.widget.Calendar_Core.STOP_RENDER;
+}
+
+/**
+* Renders the row header for a week. The date passed in should be
+* the first date of the given week.
+* @param {Date}					workingDate		The current working Date object (beginning of the week) being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+*/
+SPIP.widget.Calendar_Core.prototype.renderRowHeader = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_ROW_HEADER);
+
+	var useYear = this.pageDate.getFullYear();
+
+	if (! SPIP.widget.DateMath.isYearOverlapWeek(workingDate)) {
+		useYear = workingDate.getFullYear();
+	}
+
+	var weekNum = SPIP.widget.DateMath.getWeekNumber(workingDate, useYear, this.Options.START_WEEKDAY);
+	cell.innerHTML = weekNum;
+
+	if (this.isDateOOM(workingDate) && ! SPIP.widget.DateMath.isMonthOverlapWeek(workingDate)) {
+		SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_OOM);
+	}
+};
+
+/**
+* Renders the row footer for a week. The date passed in should be
+* the first date of the given week.
+* @param {Date}					workingDate		The current working Date object (beginning of the week) being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+*/
+SPIP.widget.Calendar_Core.prototype.renderRowFooter = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_ROW_FOOTER);
+
+	if (this.isDateOOM(workingDate) && ! SPIP.widget.DateMath.isMonthOverlapWeek(workingDate)) {
+		SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_OOM);
+	}
+};
+
+/**
+* Renders a single standard calendar cell in the calendar widget table.
+* All logic for determining how a standard default cell will be rendered is
+* encapsulated in this method, and must be accounted for when extending the
+* widget class.
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return SPIP.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+SPIP.widget.Calendar_Core.prototype.renderCellDefault = function(workingDate, cell) {
+	cell.innerHTML = "";
+	var link = document.createElement("a");
+
+	link.href="javascript:void(null);";
+	link.name=this.id+"__"+workingDate.getFullYear()+"_"+(workingDate.getMonth()+1)+"_"+workingDate.getDate();
+
+	//link.onclick = this._selectEventLink;
+	//cell.onclick = this.doSelectCell;
+
+	SPIP.util.Event.addListener(cell, "click", this.doSelectCell, this);
+	if (SPIP.widget.Calendar_Core._getBrowser() == "ie") {
+		SPIP.util.Event.addListener(cell, "mouseover", this.doCellMouseOver, this);
+		SPIP.util.Event.addListener(cell, "mouseout", this.doCellMouseOut, this);
+	}
+	link.appendChild(document.createTextNode(this.buildDayLabel(workingDate)));
+	cell.appendChild(link);
+
+	//cell.onmouseover = this.doCellMouseOver;
+	//cell.onmouseout = this.doCellMouseOut;
+};
+
+SPIP.widget.Calendar_Core.prototype.renderCellStyleHighlight1 = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_HIGHLIGHT1);
+};
+SPIP.widget.Calendar_Core.prototype.renderCellStyleHighlight2 = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_HIGHLIGHT2);
+};
+SPIP.widget.Calendar_Core.prototype.renderCellStyleHighlight3 = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_HIGHLIGHT3);
+};
+SPIP.widget.Calendar_Core.prototype.renderCellStyleHighlight4 = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_HIGHLIGHT4);
+};
+
+/**
+* Applies the default style used for rendering today's date to the current calendar cell
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return	SPIP.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+SPIP.widget.Calendar_Core.prototype.renderCellStyleToday = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_TODAY);
+};
+
+/**
+* Applies the default style used for rendering selected dates to the current calendar cell
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return	SPIP.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+SPIP.widget.Calendar_Core.prototype.renderCellStyleSelected = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_SELECTED);
+};
+
+/**
+* Applies the default style used for rendering dates that are not a part of the current
+* month (preceding or trailing the cells for the current month)
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return	SPIP.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+SPIP.widget.Calendar_Core.prototype.renderCellNotThisMonth = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.addCssClass(cell, this.Style.CSS_CELL_OOM);
+	cell.innerHTML=workingDate.getDate();
+	return SPIP.widget.Calendar_Core.STOP_RENDER;
+};
+
+/**
+* Renders the current calendar cell as a non-selectable "black-out" date using the default
+* restricted style.
+* @param {Date}					workingDate		The current working Date object being used to generate the calendar
+* @param {HTMLTableCellElement}	cell			The current working cell in the calendar
+* @return	SPIP.widget.Calendar_Core.STOP_RENDER if rendering should stop with this style, null or nothing if rendering
+*			should not be terminated
+* @type String
+*/
+SPIP.widget.Calendar_Core.prototype.renderBodyCellRestricted = function(workingDate, cell) {
+	SPIP.widget.Calendar_Core.setCssClasses(cell, [this.Style.CSS_CELL,this.Style.CSS_CELL_RESTRICTED]);
+	cell.innerHTML=workingDate.getDate();
+	return SPIP.widget.Calendar_Core.STOP_RENDER;
+};
+/******************** END BUILT-IN TABLE CELL RENDERERS ************************************/
+
+/******************** BEGIN MONTH NAVIGATION METHODS ************************************/
+/**
+* Adds the designated number of months to the current calendar month, and sets the current
+* calendar page date to the new month.
+* @param {Integer}	count	The number of months to add to the current calendar
+*/
+SPIP.widget.Calendar_Core.prototype.addMonths = function(count) {
+	this.pageDate = SPIP.widget.DateMath.add(this.pageDate, SPIP.widget.DateMath.MONTH, count);
+	this.resetRenderers();
+	this.onChangePage();
+};
+
+/**
+* Subtracts the designated number of months from the current calendar month, and sets the current
+* calendar page date to the new month.
+* @param {Integer}	count	The number of months to subtract from the current calendar
+*/
+SPIP.widget.Calendar_Core.prototype.subtractMonths = function(count) {
+	this.pageDate = SPIP.widget.DateMath.subtract(this.pageDate, SPIP.widget.DateMath.MONTH, count);
+	this.resetRenderers();
+	this.onChangePage();
+};
+
+/**
+* Adds the designated number of years to the current calendar, and sets the current
+* calendar page date to the new month.
+* @param {Integer}	count	The number of years to add to the current calendar
+*/
+SPIP.widget.Calendar_Core.prototype.addYears = function(count) {
+	this.pageDate = SPIP.widget.DateMath.add(this.pageDate, SPIP.widget.DateMath.YEAR, count);
+	this.resetRenderers();
+	this.onChangePage();
+};
+
+/**
+* Subtcats the designated number of years from the current calendar, and sets the current
+* calendar page date to the new month.
+* @param {Integer}	count	The number of years to subtract from the current calendar
+*/
+SPIP.widget.Calendar_Core.prototype.subtractYears = function(count) {
+	this.pageDate = SPIP.widget.DateMath.subtract(this.pageDate, SPIP.widget.DateMath.YEAR, count);
+	this.resetRenderers();
+	this.onChangePage();
+};
+
+/**
+* Navigates to the next month page in the calendar widget.
+*/
+SPIP.widget.Calendar_Core.prototype.nextMonth = function() {
+	this.addMonths(1);
+};
+
+/**
+* Navigates to the previous month page in the calendar widget.
+*/
+SPIP.widget.Calendar_Core.prototype.previousMonth = function() {
+	this.subtractMonths(1);
+};
+
+/**
+* Navigates to the next year in the currently selected month in the calendar widget.
+*/
+SPIP.widget.Calendar_Core.prototype.nextYear = function() {
+	this.addYears(1);
+};
+
+/**
+* Navigates to the previous year in the currently selected month in the calendar widget.
+*/
+SPIP.widget.Calendar_Core.prototype.previousYear = function() {
+	this.subtractYears(1);
+};
+
+/****************** END MONTH NAVIGATION METHODS ************************************/
+
+/************* BEGIN SELECTION METHODS *************************************************************/
+
+/**
+* Resets the calendar widget to the originally selected month and year, and
+* sets the calendar to the initial selection(s).
+*/
+SPIP.widget.Calendar_Core.prototype.reset = function() {
+	this.selectedDates.length = 0;
+	this.selectedDates = this._selectedDates.concat();
+	this.deselectAll();
+	/*this.pageDate = new Date(this._pageDate.getTime());*/
+	this.onReset();
+};
+
+/**
+* Clears the selected dates in the current calendar widget and sets the calendar
+* to the current month and year.
+*/
+SPIP.widget.Calendar_Core.prototype.clear = function() {
+	this.selectedDates.length = 0;
+	/*this.pageDate = new Date(this.today.getTime());*/
+	this.onClear();
+};
+
+/**
+* Selects a date or a collection of dates on the current calendar. This method, by default,
+* does not call the render method explicitly. Once selection has completed, render must be
+* called for the changes to be reflected visually.
+* @param	{String/Date/Date[]}	date	The date string of dates to select in the current calendar. Valid formats are
+*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
+*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
+*								This method can also take a JavaScript Date object or an array of Date objects.
+* @return						Array of JavaScript Date objects representing all individual dates that are currently selected.
+* @type Date[]
+*/
+SPIP.widget.Calendar_Core.prototype.select = function(date) {
+	this.onBeforeSelect();
+
+	var aToBeSelected = this._toFieldArray(date);
+
+	for (var a=0;a<aToBeSelected.length;++a)
+	{
+		var toSelect = aToBeSelected[a]; // For each date item in the list of dates we're trying to select
+		if (this._indexOfSelectedFieldArray(toSelect) == -1) // not already selected?
+		{
+			this.selectedDates[this.selectedDates.length]=toSelect;
+		}
+	}
+
+	if (this.parent) {
+		this.parent.sync(this);
+	}
+
+	this.onSelect();
+
+	return this.getSelectedDates();
+};
+
+/**
+* Selects a date on the current calendar by referencing the index of the cell that should be selected.
+* This method is used to easily select a single cell (usually with a mouse click) without having to do
+* a full render. The selected style is applied to the cell directly.
+* @param	{Integer}	cellIndex	The index of the cell to select in the current calendar.
+* @return							Array of JavaScript Date objects representing all individual dates that are currently selected.
+* @type Date[]
+*/
+SPIP.widget.Calendar_Core.prototype.selectCell = function(cellIndex) {
+	this.onBeforeSelect();
+
+	this.cells = this.tbody.getElementsByTagName("TD");
+
+	var cell = this.cells[cellIndex];
+	var cellDate = this.cellDates[cellIndex];
+
+	var dCellDate = this._toDate(cellDate);
+
+	var selectDate = cellDate.concat();
+
+	this.selectedDates.push(selectDate);
+
+	if (this.parent) {
+		this.parent.sync(this);
+	}
+
+	this.renderCellStyleSelected(dCellDate,cell);
+
+	this.onSelect();
+	this.doCellMouseOut.call(cell, null, this);
+
+	return this.getSelectedDates();
+};
+
+/**
+* Deselects a date or a collection of dates on the current calendar. This method, by default,
+* does not call the render method explicitly. Once deselection has completed, render must be
+* called for the changes to be reflected visually.
+* @param	{String/Date/Date[]}	date	The date string of dates to deselect in the current calendar. Valid formats are
+*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
+*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
+*								This method can also take a JavaScript Date object or an array of Date objects.
+* @return						Array of JavaScript Date objects representing all individual dates that are currently selected.
+* @type Date[]
+*/
+SPIP.widget.Calendar_Core.prototype.deselect = function(date) {
+	this.onBeforeDeselect();
+
+	var aToBeSelected = this._toFieldArray(date);
+
+	for (var a=0;a<aToBeSelected.length;++a)
+	{
+		var toSelect = aToBeSelected[a]; // For each date item in the list of dates we're trying to select
+		var index = this._indexOfSelectedFieldArray(toSelect);
+
+		if (index != -1)
+		{
+			this.selectedDates.splice(index,1);
+		}
+	}
+
+	if (this.parent) {
+		this.parent.sync(this);
+	}
+
+	this.onDeselect();
+	return this.getSelectedDates();
+};
+
+/**
+* Deselects a date on the current calendar by referencing the index of the cell that should be deselected.
+* This method is used to easily deselect a single cell (usually with a mouse click) without having to do
+* a full render. The selected style is removed from the cell directly.
+* @param	{Integer}	cellIndex	The index of the cell to deselect in the current calendar.
+* @return							Array of JavaScript Date objects representing all individual dates that are currently selected.
+* @type Date[]
+*/
+SPIP.widget.Calendar_Core.prototype.deselectCell = function(i) {
+	this.onBeforeDeselect();
+	this.cells = this.tbody.getElementsByTagName("TD");
+
+	var cell = this.cells[i];
+	var cellDate = this.cellDates[i];
+	var cellDateIndex = this._indexOfSelectedFieldArray(cellDate);
+
+	var dCellDate = this._toDate(cellDate);
+
+	var selectDate = cellDate.concat();
+
+	if (cellDateIndex > -1)
+	{
+		if (this.pageDate.getMonth() == dCellDate.getMonth() &&
+			this.pageDate.getFullYear() == dCellDate.getFullYear())
+		{
+			SPIP.widget.Calendar_Core.removeCssClass(cell, this.Style.CSS_CELL_SELECTED);
+		}
+
+		this.selectedDates.splice(cellDateIndex, 1);
+	}
+
+
+	if (this.parent) {
+		this.parent.sync(this);
+	}
+
+	this.onDeselect();
+	return this.getSelectedDates();
+};
+
+/**
+* Deselects all dates on the current calendar.
+* @return				Array of JavaScript Date objects representing all individual dates that are currently selected.
+*						Assuming that this function executes properly, the return value should be an empty array.
+*						However, the empty array is returned for the sake of being able to check the selection status
+*						of the calendar.
+* @type Date[]
+*/
+SPIP.widget.Calendar_Core.prototype.deselectAll = function() {
+	this.onBeforeDeselect();
+	var count = this.selectedDates.length;
+	this.selectedDates.length = 0;
+
+	if (this.parent) {
+		this.parent.sync(this);
+	}
+
+	if (count > 0) {
+		this.onDeselect();
+	}
+
+	return this.getSelectedDates();
+};
+/************* END SELECTION METHODS *************************************************************/
+
+
+/************* BEGIN TYPE CONVERSION METHODS ****************************************************/
+
+/**
+* Converts a date (either a JavaScript Date object, or a date string) to the internal data structure
+* used to represent dates: [[yyyy,mm,dd],[yyyy,mm,dd]].
+* @private
+* @param	{String/Date/Date[]}	date	The date string of dates to deselect in the current calendar. Valid formats are
+*								individual date(s) (12/24/2005,12/26/2005) or date range(s) (12/24/2005-1/1/2006).
+*								Multiple comma-delimited dates can also be passed to this method (12/24/2005,12/11/2005-12/13/2005).
+*								This method can also take a JavaScript Date object or an array of Date objects.
+* @return						Array of date field arrays
+* @type Array[](Integer[])
+*/
+SPIP.widget.Calendar_Core.prototype._toFieldArray = function(date) {
+	var returnDate = new Array();
+
+	if (date instanceof Date)
+	{
+		returnDate = [[date.getFullYear(), date.getMonth()+1, date.getDate()]];
+	}
+	else if (typeof date == 'string')
+	{
+		returnDate = this._parseDates(date);
+	}
+	else if (date instanceof Array)
+	{
+		for (var i=0;i<date.length;++i)
+		{
+			var d = date[i];
+			returnDate[returnDate.length] = [d.getFullYear(),d.getMonth()+1,d.getDate()];
+		}
+	}
+
+	return returnDate;
+};
+
+/**
+* Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
+* @private
+* @param	{Integer[]}		dateFieldArray	The date field array to convert to a JavaScript Date.
+* @return					JavaScript Date object representing the date field array
+* @type Date
+*/
+SPIP.widget.Calendar_Core.prototype._toDate = function(dateFieldArray) {
+	if (dateFieldArray instanceof Date)
+	{
+		return dateFieldArray;
+	} else
+	{
+		return new Date(dateFieldArray[0],dateFieldArray[1]-1,dateFieldArray[2]);
+	}
+};
+/************* END TYPE CONVERSION METHODS ******************************************************/
+
+
+/************* BEGIN UTILITY METHODS ****************************************************/
+/**
+* Converts a date field array [yyyy,mm,dd] to a JavaScript Date object.
+* @private
+* @param	{Integer[]}	array1	The first date field array to compare
+* @param	{Integer[]}	array2	The first date field array to compare
+* @return						The boolean that represents the equality of the two arrays
+* @type Boolean
+*/
+SPIP.widget.Calendar_Core.prototype._fieldArraysAreEqual = function(array1, array2) {
+	var match = false;
+
+	if (array1[0]==array2[0]&&array1[1]==array2[1]&&array1[2]==array2[2])
+	{
+		match=true;
+	}
+
+	return match;
+};
+
+/**
+* Gets the index of a date field array [yyyy,mm,dd] in the current list of selected dates.
+* @private
+* @param	{Integer[]}		find	The date field array to search for
+* @return					The index of the date field array within the collection of selected dates.
+*								-1 will be returned if the date is not found.
+* @type Integer
+*/
+SPIP.widget.Calendar_Core.prototype._indexOfSelectedFieldArray = function(find) {
+	var selected = -1;
+
+	for (var s=0;s<this.selectedDates.length;++s)
+	{
+		var sArray = this.selectedDates[s];
+		if (find[0]==sArray[0]&&find[1]==sArray[1]&&find[2]==sArray[2])
+		{
+			selected = s;
+			break;
+		}
+	}
+
+	return selected;
+};
+
+/**
+* Determines whether a given date is OOM (out of month).
+* @param	{Date}	date	The JavaScript Date object for which to check the OOM status
+* @return	{Boolean}	true if the date is OOM
+*/
+SPIP.widget.Calendar_Core.prototype.isDateOOM = function(date) {
+	var isOOM = false;
+	if (date.getMonth() != this.pageDate.getMonth()) {
+		isOOM = true;
+	}
+	return isOOM;
+};
+
+/************* END UTILITY METHODS *******************************************************/
+
+/************* BEGIN EVENT HANDLERS ******************************************************/
+
+/**
+* Event executed before a date is selected in the calendar widget.
+*/
+SPIP.widget.Calendar_Core.prototype.onBeforeSelect = function() {
+	if (! this.Options.MULTI_SELECT) {
+		this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);
+		this.deselectAll();
+	}
+};
+
+/**
+* Event executed when a date is selected in the calendar widget.
+*/
+SPIP.widget.Calendar_Core.prototype.onSelect = function() { };
+
+/**
+* Event executed before a date is deselected in the calendar widget.
+*/
+SPIP.widget.Calendar_Core.prototype.onBeforeDeselect = function() { };
+
+/**
+* Event executed when a date is deselected in the calendar widget.
+*/
+SPIP.widget.Calendar_Core.prototype.onDeselect = function() { };
+
+/**
+* Event executed when the user navigates to a different calendar page.
+*/
+SPIP.widget.Calendar_Core.prototype.onChangePage = function() { this.render(); };
+
+/**
+* Event executed when the calendar widget is rendered.
+*/
+SPIP.widget.Calendar_Core.prototype.onRender = function() { };
+
+/**
+* Event executed when the calendar widget is reset to its original state.
+*/
+SPIP.widget.Calendar_Core.prototype.onReset = function() { this.render(); };
+
+/**
+* Event executed when the calendar widget is completely cleared to the current month with no selections.
+*/
+SPIP.widget.Calendar_Core.prototype.onClear = function() { this.render(); };
+
+/**
+* Validates the calendar widget. This method has no default implementation
+* and must be extended by subclassing the widget.
+* @return	Should return true if the widget validates, and false if
+* it doesn't.
+* @type Boolean
+*/
+SPIP.widget.Calendar_Core.prototype.validate = function() { return true; };
+
+/************* END EVENT HANDLERS *********************************************************/
+
+
+/************* BEGIN DATE PARSE METHODS ***************************************************/
+
+
+/**
+* Converts a date string to a date field array
+* @private
+* @param	{String}	sDate			Date string. Valid formats are mm/dd and mm/dd/yyyy.
+* @return				A date field array representing the string passed to the method
+* @type Array[](Integer[])
+*/
+SPIP.widget.Calendar_Core.prototype._parseDate = function(sDate) {
+	var aDate = sDate.split(this.Locale.DATE_FIELD_DELIMITER);
+	var rArray;
+
+	if (aDate.length == 2)
+	{
+		rArray = [aDate[this.Locale.MD_MONTH_POSITION-1],aDate[this.Locale.MD_DAY_POSITION-1]];
+		rArray.type = SPIP.widget.Calendar_Core.MONTH_DAY;
+	} else {
+		rArray = [aDate[this.Locale.MDY_YEAR_POSITION-1],aDate[this.Locale.MDY_MONTH_POSITION-1],aDate[this.Locale.MDY_DAY_POSITION-1]];
+		rArray.type = SPIP.widget.Calendar_Core.DATE;
+	}
+	return rArray;
+};
+
+/**
+* Converts a multi or single-date string to an array of date field arrays
+* @private
+* @param	{String}	sDates		Date string with one or more comma-delimited dates. Valid formats are mm/dd, mm/dd/yyyy, mm/dd/yyyy-mm/dd/yyyy
+* @return							An array of date field arrays
+* @type Array[](Integer[])
+*/
+SPIP.widget.Calendar_Core.prototype._parseDates = function(sDates) {
+	var aReturn = new Array();
+
+	var aDates = sDates.split(this.Locale.DATE_DELIMITER);
+
+	for (var d=0;d<aDates.length;++d)
+	{
+		var sDate = aDates[d];
+
+		if (sDate.indexOf(this.Locale.DATE_RANGE_DELIMITER) != -1) {
+			// This is a range
+			var aRange = sDate.split(this.Locale.DATE_RANGE_DELIMITER);
+
+			var dateStart = this._parseDate(aRange[0]);
+			var dateEnd = this._parseDate(aRange[1]);
+
+			var fullRange = this._parseRange(dateStart, dateEnd);
+			aReturn = aReturn.concat(fullRange);
+		} else {
+			// This is not a range
+			var aDate = this._parseDate(sDate);
+			aReturn.push(aDate);
+		}
+	}
+	return aReturn;
+};
+
+/**
+* Converts a date range to the full list of included dates
+* @private
+* @param	{Integer[]}	startDate	Date field array representing the first date in the range
+* @param	{Integer[]}	endDate		Date field array representing the last date in the range
+* @return							An array of date field arrays
+* @type Array[](Integer[])
+*/
+SPIP.widget.Calendar_Core.prototype._parseRange = function(startDate, endDate) {
+	var dStart   = new Date(startDate[0],startDate[1]-1,startDate[2]);
+	var dCurrent = SPIP.widget.DateMath.add(new Date(startDate[0],startDate[1]-1,startDate[2]),SPIP.widget.DateMath.DAY,1);
+	var dEnd     = new Date(endDate[0],  endDate[1]-1,  endDate[2]);
+
+	var results = new Array();
+	results.push(startDate);
+	while (dCurrent.getTime() <= dEnd.getTime())
+	{
+		results.push([dCurrent.getFullYear(),dCurrent.getMonth()+1,dCurrent.getDate()]);
+		dCurrent = SPIP.widget.DateMath.add(dCurrent,SPIP.widget.DateMath.DAY,1);
+	}
+	return results;
+};
+
+/************* END DATE PARSE METHODS *****************************************************/
+
+/************* BEGIN RENDERER METHODS *****************************************************/
+
+/**
+* Resets the render stack of the current calendar to its original pre-render value.
+*/
+SPIP.widget.Calendar_Core.prototype.resetRenderers = function() {
+	this.renderStack = this._renderStack.concat();
+};
+
+/**
+* Clears the inner HTML, CSS class and style information from the specified cell.
+* @param	{HTMLTableCellElement}	The cell to clear
+*/
+SPIP.widget.Calendar_Core.prototype.clearElement = function(cell) {
+	cell.innerHTML = "&nbsp;";
+	cell.className="";
+};
+
+/**
+* Adds a renderer to the render stack. The function reference passed to this method will be executed
+* when a date cell matches the conditions specified in the date string for this renderer.
+* @param	{String}	sDates		A date string to associate with the specified renderer. Valid formats
+*									include date (12/24/2005), month/day (12/24), and range (12/1/2004-1/1/2005)
+* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
+*/
+SPIP.widget.Calendar_Core.prototype.addRenderer = function(sDates, fnRender) {
+	var aDates = this._parseDates(sDates);
+	for (var i=0;i<aDates.length;++i)
+	{
+		var aDate = aDates[i];
+
+		if (aDate.length == 2) // this is either a range or a month/day combo
+		{
+			if (aDate[0] instanceof Array) // this is a range
+			{
+				this._addRenderer(SPIP.widget.Calendar_Core.RANGE,aDate,fnRender);
+			} else { // this is a month/day combo
+				this._addRenderer(SPIP.widget.Calendar_Core.MONTH_DAY,aDate,fnRender);
+			}
+		} else if (aDate.length == 3)
+		{
+			this._addRenderer(SPIP.widget.Calendar_Core.DATE,aDate,fnRender);
+		}
+	}
+};
+
+/**
+* The private method used for adding cell renderers to the local render stack.
+* This method is called by other methods that set the renderer type prior to the method call.
+* @private
+* @param	{String}	type		The type string that indicates the type of date renderer being added.
+*									Values are SPIP.widget.Calendar_Core.DATE, SPIP.widget.Calendar_Core.MONTH_DAY, SPIP.widget.Calendar_Core.WEEKDAY,
+*									SPIP.widget.Calendar_Core.RANGE, SPIP.widget.Calendar_Core.MONTH
+* @param	{Array}		aDates		An array of dates used to construct the renderer. The format varies based
+*									on the renderer type
+* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
+*/
+SPIP.widget.Calendar_Core.prototype._addRenderer = function(type, aDates, fnRender) {
+	var add = [type,aDates,fnRender];
+	this.renderStack.unshift(add);
+
+	this._renderStack = this.renderStack.concat();
+};
+
+/**
+* Adds a month to the render stack. The function reference passed to this method will be executed
+* when a date cell matches the month passed to this method.
+* @param	{Integer}	month		The month (1-12) to associate with this renderer
+* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
+*/
+SPIP.widget.Calendar_Core.prototype.addMonthRenderer = function(month, fnRender) {
+	this._addRenderer(SPIP.widget.Calendar_Core.MONTH,[month],fnRender);
+};
+
+/**
+* Adds a weekday to the render stack. The function reference passed to this method will be executed
+* when a date cell matches the weekday passed to this method.
+* @param	{Integer}	weekay		The weekday (1-7) to associate with this renderer
+* @param	{Function}	fnRender	The function executed to render cells that match the render rules for this renderer.
+*/
+SPIP.widget.Calendar_Core.prototype.addWeekdayRenderer = function(weekday, fnRender) {
+	this._addRenderer(SPIP.widget.Calendar_Core.WEEKDAY,[weekday],fnRender);
+};
+/************* END RENDERER METHODS *******************************************************/
+
+/***************** BEGIN CSS METHODS *******************************************/
+/**
+* Adds the specified CSS class to the element passed to this method.
+* @param	{HTMLElement}	element		The element to which the CSS class should be applied
+* @param	{String}	style		The CSS class name to add to the referenced element
+*/
+SPIP.widget.Calendar_Core.addCssClass = function(element, style) {
+	if (element.className.length === 0)
+	{
+		element.className += style;
+	} else {
+		element.className += " " + style;
+	}
+};
+
+SPIP.widget.Calendar_Core.prependCssClass = function(element, style) {
+	element.className = style + " " + element.className;
+}
+
+/**
+* Removed the specified CSS class from the element passed to this method.
+* @param	{HTMLElement}	element		The element from which the CSS class should be removed
+* @param	{String}	style		The CSS class name to remove from the referenced element
+*/
+SPIP.widget.Calendar_Core.removeCssClass = function(element, style) {
+	var aStyles = element.className.split(" ");
+	for (var s=0;s<aStyles.length;++s)
+	{
+		if (aStyles[s] == style)
+		{
+			aStyles.splice(s,1);
+			break;
+		}
+	}
+	SPIP.widget.Calendar_Core.setCssClasses(element, aStyles);
+};
+
+/**
+* Sets the specified array of CSS classes into the referenced element
+* @param	{HTMLElement}	element		The element to set the CSS classes into
+* @param	{String[]}		aStyles		An array of CSS class names
+*/
+SPIP.widget.Calendar_Core.setCssClasses = function(element, aStyles) {
+	element.className = "";
+	var className = aStyles.join(" ");
+	element.className = className;
+};
+
+/**
+* Removes all styles from all body cells in the current calendar table.
+* @param	{style}		The CSS class name to remove from all calendar body cells
+*/
+SPIP.widget.Calendar_Core.prototype.clearAllBodyCellStyles = function(style) {
+	for (var c=0;c<this.cells.length;++c)
+	{
+		SPIP.widget.Calendar_Core.removeCssClass(this.cells[c],style);
+	}
+};
+
+/***************** END CSS METHODS *********************************************/
+
+/***************** BEGIN GETTER/SETTER METHODS *********************************/
+/**
+* Sets the calendar's month explicitly.
+* @param {Integer}	month		The numeric month, from 1 (January) to 12 (December)
+*/
+SPIP.widget.Calendar_Core.prototype.setMonth = function(month) {
+	this.pageDate.setMonth(month);
+};
+
+/**
+* Sets the calendar's year explicitly.
+* @param {Integer}	year		The numeric 4-digit year
+*/
+SPIP.widget.Calendar_Core.prototype.setYear = function(year) {
+	this.pageDate.setFullYear(year);
+};
+
+/**
+* Gets the list of currently selected dates from the calendar.
+* @return	An array of currently selected JavaScript Date objects.
+* @type Date[]
+*/
+SPIP.widget.Calendar_Core.prototype.getSelectedDates = function() {
+	var returnDates = new Array();
+
+	for (var d=0;d<this.selectedDates.length;++d)
+	{
+		var dateArray = this.selectedDates[d];
+
+		var date = new Date(dateArray[0],dateArray[1]-1,dateArray[2]);
+		returnDates.push(date);
+	}
+
+	returnDates.sort();
+	return returnDates;
+};
+
+/***************** END GETTER/SETTER METHODS *********************************/
+
+SPIP.widget.Calendar_Core._getBrowser = function()
+{
+  /**
+   * UserAgent
+   * @private
+   * @type String
+   */
+  var ua = navigator.userAgent.toLowerCase();
+
+  if (ua.indexOf('opera')!=-1) // Opera (check first in case of spoof)
+	 return 'opera';
+  else if (ua.indexOf('msie')!=-1) // IE
+	 return 'ie';
+  else if (ua.indexOf('safari')!=-1) // Safari (check before Gecko because it includes "like Gecko")
+	 return 'safari';
+  else if (ua.indexOf('gecko') != -1) // Gecko
+	 return 'gecko';
+ else
+  return false;
+}
+
+
+SPIP.widget.Cal_Core = SPIP.widget.Calendar_Core;
+
+SPIP.namespace("SPIP.widget");
+
+/**
+* @class
+* <p>SPIP.widget.CalendarGroup is a special container class for SPIP.widget.Calendar_Core. This class facilitates
+* the ability to have multi-page calendar views that share a single dataset and are
+* dependent on each other.</p>
+*
+* <p>The calendar group instance will refer to each of its elements using a 0-based index.
+* For example, to construct the placeholder for a calendar group widget with id "cal1" and
+* containerId of "cal1Container", the markup would be as follows:
+*	<xmp>
+*		<div id="cal1Container_0"></div>
+*		<div id="cal1Container_1"></div>
+*	</xmp>
+* The tables for the calendars ("cal1_0" and "cal1_1") will be inserted into those containers.
+* </p>
+* @constructor
+* @param {Integer}		pageCount	The number of pages that this calendar should display.
+* @param {String}		id			The id of the element that will be inserted into the DOM.
+* @param {String}	containerId	The id of the container element that the calendar will be inserted into.
+* @param {String}		monthyear	The month/year string used to set the current calendar page
+* @param {String}		selected	A string of date values formatted using the date parser. The built-in
+									default date format is MM/DD/YYYY. Ranges are defined using
+									MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+									Any combination of these can be combined by delimiting the string with
+									commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+*/
+SPIP.widget.CalendarGroup = function(pageCount, id, containerId, monthyear, selected) {
+	if (arguments.length > 0)
+	{
+		this.init(pageCount, id, containerId, monthyear, selected);
+	}
+}
+
+/**
+* Initializes the calendar group. All subclasses must call this method in order for the
+* group to be initialized properly.
+* @param {Integer}		pageCount	The number of pages that this calendar should display.
+* @param {String}		id			The id of the element that will be inserted into the DOM.
+* @param {String}		containerId	The id of the container element that the calendar will be inserted into.
+* @param {String}		monthyear	The month/year string used to set the current calendar page
+* @param {String}		selected	A string of date values formatted using the date parser. The built-in
+									default date format is MM/DD/YYYY. Ranges are defined using
+									MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+									Any combination of these can be combined by delimiting the string with
+									commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+*/
+SPIP.widget.CalendarGroup.prototype.init = function(pageCount, id, containerId, monthyear, selected) {
+	//var self=this;
+
+	this.id = id;
+	this.selectedDates = new Array();
+	this.containerId = containerId;
+
+	this.pageCount = pageCount;
+
+	this.pages = new Array();
+
+	for (var p=0;p<pageCount;++p)
+	{
+		var cal = this.constructChild(id + "_" + p, this.containerId + "_" + p , monthyear, selected);
+
+		cal.parent = this;
+
+		cal.index = p;
+
+		cal.pageDate.setMonth(cal.pageDate.getMonth()+p);
+		cal._pageDateOrig = new Date(cal.pageDate.getFullYear(),cal.pageDate.getMonth(),cal.pageDate.getDate());
+		this.pages.push(cal);
+	}
+
+	this.doNextMonth = function(e, calGroup) {
+		calGroup.nextMonth();
+	}
+
+	this.doPreviousMonth = function(e, calGroup) {
+		calGroup.previousMonth();
+	}
+};
+
+SPIP.widget.CalendarGroup.prototype.setChildFunction = function(fnName, fn) {
+	for (var p=0;p<this.pageCount;++p) {
+		this.pages[p][fnName] = fn;
+	}
+}
+
+SPIP.widget.CalendarGroup.prototype.callChildFunction = function(fnName, args) {
+	for (var p=0;p<this.pageCount;++p) {
+		var page = this.pages[p];
+		if (page[fnName]) {
+			var fn = page[fnName];
+			fn.call(page, args);
+		}
+	}
+}
+
+/**
+* Constructs a child calendar. This method can be overridden if a subclassed version of the default
+* calendar is to be used.
+* @param {String}		id			The id of the element that will be inserted into the DOM.
+* @param {String}		containerId	The id of the container element that the calendar will be inserted into.
+* @param {String}		monthyear	The month/year string used to set the current calendar page
+* @param {String}		selected	A string of date values formatted using the date parser. The built-in
+									default date format is MM/DD/YYYY. Ranges are defined using
+									MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+									Any combination of these can be combined by delimiting the string with
+									commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+* @return							The SPIP.widget.Calendar_Core instance that is constructed
+* @type SPIP.widget.Calendar_Core
+*/
+SPIP.widget.CalendarGroup.prototype.constructChild = function(id,containerId,monthyear,selected) {
+	return new SPIP.widget.Calendar_Core(id,containerId,monthyear,selected);
+};
+
+
+/**
+* Sets the calendar group's month explicitly. This month will be set into the first
+* page of the multi-page calendar, and all other months will be iterated appropriately.
+* @param {Integer}	month		The numeric month, from 1 (January) to 12 (December)
+*/
+SPIP.widget.CalendarGroup.prototype.setMonth = function(month) {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.setMonth(month+p);
+	}
+};
+
+/**
+* Sets the calendar group's year explicitly. This year will be set into the first
+* page of the multi-page calendar, and all other months will be iterated appropriately.
+* @param {Integer}	year		The numeric 4-digit year
+*/
+SPIP.widget.CalendarGroup.prototype.setYear = function(year) {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		if ((cal.pageDate.getMonth()+1) == 1 && p>0)
+		{
+			year+=1;
+		}
+		cal.setYear(year);
+	}
+};
+
+/**
+* Calls the render function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.render = function() {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.render();
+	}
+};
+
+/**
+* Calls the select function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.select = function(date) {
+	var ret;
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		ret = cal.select(date);
+	}
+	return ret;
+};
+
+/**
+* Calls the selectCell function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.selectCell = function(cellIndex) {
+	var ret;
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		ret = cal.selectCell(cellIndex);
+	}
+	return ret;
+};
+
+/**
+* Calls the deselect function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.deselect = function(date) {
+	var ret;
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		ret = cal.deselect(date);
+	}
+	return ret;
+};
+
+/**
+* Calls the deselectAll function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.deselectAll = function() {
+	var ret;
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		ret = cal.deselectAll();
+	}
+	return ret;
+};
+
+/**
+* Calls the deselectAll function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.deselectCell = function(cellIndex) {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.deselectCell(cellIndex);
+	}
+	return this.getSelectedDates();
+};
+
+/**
+* Calls the reset function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.reset = function() {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.reset();
+	}
+};
+
+/**
+* Calls the clear function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.clear = function() {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.clear();
+	}
+};
+
+/**
+* Calls the nextMonth function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.nextMonth = function() {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.nextMonth();
+	}
+};
+
+/**
+* Calls the previousMonth function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.previousMonth = function() {
+	for (var p=this.pages.length-1;p>=0;--p)
+	{
+		var cal = this.pages[p];
+		cal.previousMonth();
+	}
+};
+
+/**
+* Calls the nextYear function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.nextYear = function() {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.nextYear();
+	}
+};
+
+/**
+* Calls the previousYear function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.previousYear = function() {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.previousYear();
+	}
+};
+
+/**
+* Synchronizes the data values for all child calendars within the group. If the sync
+* method is called passing in the caller object, the values of all children will be set
+* to the values of the caller. If the argument is ommitted, the values from all children
+* will be combined into one distinct list and set into each child.
+* @param	{SPIP.widget.Calendar_Core}	caller		The SPIP.widget.Calendar_Core that is initiating the call to sync().
+* @return								Array of selected dates, in JavaScript Date object form.
+* @type Date[]
+*/
+SPIP.widget.CalendarGroup.prototype.sync = function(caller) {
+	var calendar;
+
+	if (caller)
+	{
+		this.selectedDates = caller.selectedDates.concat();
+	} else {
+		var hash = new Object();
+		var combinedDates = new Array();
+
+		for (var p=0;p<this.pages.length;++p)
+		{
+			calendar = this.pages[p];
+
+			var values = calendar.selectedDates;
+
+			for (var v=0;v<values.length;++v)
+			{
+				var valueArray = values[v];
+				hash[valueArray.toString()] = valueArray;
+			}
+		}
+
+		for (var val in hash)
+		{
+			combinedDates[combinedDates.length]=hash[val];
+		}
+
+		this.selectedDates = combinedDates.concat();
+	}
+
+	// Set all the values into the children
+	for (p=0;p<this.pages.length;++p)
+	{
+		calendar = this.pages[p];
+		if (! calendar.Options.MULTI_SELECT) {
+			calendar.clearAllBodyCellStyles(calendar.Config.Style.CSS_CELL_SELECTED);
+		}
+		calendar.selectedDates = this.selectedDates.concat();
+
+	}
+
+	return this.getSelectedDates();
+};
+
+/**
+* Gets the list of currently selected dates from the calendar.
+* @return			An array of currently selected JavaScript Date objects.
+* @type Date[]
+*/
+SPIP.widget.CalendarGroup.prototype.getSelectedDates = function() {
+	var returnDates = new Array();
+
+	for (var d=0;d<this.selectedDates.length;++d)
+	{
+		var dateArray = this.selectedDates[d];
+
+		var date = new Date(dateArray[0],dateArray[1]-1,dateArray[2]);
+		returnDates.push(date);
+	}
+
+	returnDates.sort();
+	return returnDates;
+};
+
+/**
+* Calls the addRenderer function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.addRenderer = function(sDates, fnRender) {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.addRenderer(sDates, fnRender);
+	}
+};
+
+/**
+* Calls the addMonthRenderer function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.addMonthRenderer = function(month, fnRender) {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.addMonthRenderer(month, fnRender);
+	}
+};
+
+/**
+* Calls the addWeekdayRenderer function of all child calendars within the group.
+*/
+SPIP.widget.CalendarGroup.prototype.addWeekdayRenderer = function(weekday, fnRender) {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal.addWeekdayRenderer(weekday, fnRender);
+	}
+};
+
+/**
+* Sets an event handler universally across all child calendars within the group. For instance,
+* to set the onSelect handler for all child calendars to a function called fnSelect, the call would be:
+* <code>
+* calGroup.wireEvent("onSelect", fnSelect);
+* </code>
+* @param	{String}	eventName	The name of the event to handler to set within all child calendars.
+* @param	{Function}	fn			The function to set into the specified event handler.
+*/
+SPIP.widget.CalendarGroup.prototype.wireEvent = function(eventName, fn) {
+	for (var p=0;p<this.pages.length;++p)
+	{
+		var cal = this.pages[p];
+		cal[eventName] = fn;
+	}
+};
+
+SPIP.widget.CalGrp = SPIP.widget.CalendarGroup;
+
+SPIP.namespace("SPIP.widget");
+
+/**
+* @class
+* Calendar is the default implementation of the SPIP.widget.Calendar_Core base class.
+* This class is the UED-approved version of the calendar selector widget. For all documentation
+* on the implemented methods listed here, see the documentation for SPIP.widget.Calendar_Core.
+* @constructor
+* @param {String}	id			The id of the table element that will represent the calendar widget
+* @param {String}	containerId	The id of the container element that will contain the calendar table
+* @param {String}	monthyear	The month/year string used to set the current calendar page
+* @param {String}	selected	A string of date values formatted using the date parser. The built-in
+								default date format is MM/DD/YYYY. Ranges are defined using
+								MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+								Any combination of these can be combined by delimiting the string with
+								commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+*/
+SPIP.widget.Calendar = function(id, containerId, monthyear, selected) {
+	if (arguments.length > 0)
+	{
+		this.init(id, containerId, monthyear, selected);
+	}
+}
+
+SPIP.widget.Calendar.prototype = new SPIP.widget.Calendar_Core();
+
+SPIP.widget.Calendar.prototype.buildShell = function() {
+	this.border = document.createElement("DIV");
+	this.border.className =  this.Style.CSS_BORDER;
+
+	this.table = document.createElement("TABLE");
+	this.table.cellSpacing = 0;
+
+	SPIP.widget.Calendar_Core.setCssClasses(this.table, [this.Style.CSS_CALENDAR]);
+
+	this.border.id = this.id;
+
+	this.buildShellHeader();
+	this.buildShellBody();
+	this.buildShellFooter();
+};
+
+SPIP.widget.Calendar.prototype.renderShell = function() {
+	this.border.appendChild(this.table);
+	this.oDomContainer.appendChild(this.border);
+	this.shellRendered = true;
+};
+
+SPIP.widget.Calendar.prototype.renderHeader = function() {
+	this.headerCell.innerHTML = "";
+
+	var headerContainer = document.createElement("DIV");
+	headerContainer.className = this.Style.CSS_HEADER;
+
+	var linkLeft = document.createElement("A");
+	linkLeft.href = "javascript:" + this.id + ".previousMonth()";
+	var imgLeft = document.createElement("IMG");
+	imgLeft.src = this.Options.NAV_ARROW_LEFT;
+	imgLeft.className = this.Style.CSS_NAV_LEFT;
+	linkLeft.appendChild(imgLeft);
+
+	var linkRight = document.createElement("A");
+	linkRight.href = "javascript:" + this.id + ".nextMonth()";
+	var imgRight = document.createElement("IMG");
+	imgRight.src = this.Options.NAV_ARROW_RIGHT;
+	imgRight.className = this.Style.CSS_NAV_RIGHT;
+	linkRight.appendChild(imgRight);
+
+	headerContainer.appendChild(linkLeft);
+	var labelMonth = document.createElement("span");
+	labelMonth.innerHTML = this.buildMonthLabel();
+	headerContainer.appendChild(labelMonth);
+	headerContainer.appendChild(linkRight);
+
+	this.headerCell.appendChild(headerContainer);
+};
+
+SPIP.widget.Cal = SPIP.widget.Calendar;
+
+SPIP.namespace("SPIP.widget");
+
+/**
+* @class
+* Calendar2up_Cal is the default implementation of the Calendar_Core base class, when used
+* in a 2-up view. This class is the UED-approved version of the calendar selector widget. For all documentation
+* on the implemented methods listed here, see the documentation for Calendar_Core. This class
+* has some special attributes that only apply to calendars rendered within the calendar group implementation.
+* There should be no reason to instantiate this class directly.
+* @constructor
+* @param {String}	id			The id of the table element that will represent the calendar widget
+* @param {String}	containerId	The id of the container element that will contain the calendar table
+* @param {String}	monthyear	The month/year string used to set the current calendar page
+* @param {String}	selected	A string of date values formatted using the date parser. The built-in
+								default date format is MM/DD/YYYY. Ranges are defined using
+								MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+								Any combination of these can be combined by delimiting the string with
+								commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+*/
+SPIP.widget.Calendar2up_Cal = function(id, containerId, monthyear, selected) {
+	if (arguments.length > 0)
+	{
+		this.init(id, containerId, monthyear, selected);
+	}
+}
+
+SPIP.widget.Calendar2up_Cal.prototype = new SPIP.widget.Calendar_Core();
+
+/**
+* Renders the header for each individual calendar in the 2-up view. More
+* specifically, this method handles the placement of left and right arrows for
+* navigating between calendar pages.
+*/
+SPIP.widget.Calendar2up_Cal.prototype.renderHeader = function() {
+	this.headerCell.innerHTML = "";
+
+	var headerContainer = document.createElement("DIV");
+	headerContainer.className = this.Style.CSS_HEADER;
+
+	if (this.index == 0) {
+		var linkLeft = document.createElement("A");
+		linkLeft.href = "javascript:void(null)";
+		SPIP.util.Event.addListener(linkLeft, "click", this.parent.doPreviousMonth, this.parent);
+		var imgLeft = document.createElement("IMG");
+		imgLeft.src = this.Options.NAV_ARROW_LEFT;
+		imgLeft.className = this.Style.CSS_NAV_LEFT;
+		linkLeft.appendChild(imgLeft);
+		headerContainer.appendChild(linkLeft);
+	}
+
+	var labelMonth = document.createElement("span");
+	labelMonth.innerHTML = this.buildMonthLabel();
+	/*headerContainer.appendChild(document.createTextNode(this.buildMonthLabel()));*/
+	headerContainer.appendChild(labelMonth);
+
+	if (this.index == 1) {
+		var linkRight = document.createElement("A");
+		linkRight.href = "javascript:void(null)";
+		SPIP.util.Event.addListener(linkRight, "click", this.parent.doNextMonth, this.parent);
+		var imgRight = document.createElement("IMG");
+		imgRight.src = this.Options.NAV_ARROW_RIGHT;
+		imgRight.className = this.Style.CSS_NAV_RIGHT;
+		linkRight.appendChild(imgRight);
+		headerContainer.appendChild(linkRight);
+	}
+
+	this.headerCell.appendChild(headerContainer);
+};
+
+
+
+
+/**
+* @class
+* Calendar2up is the default implementation of the Calendar2up_Core base class, when used
+* in a 2-up view. This class is the UED-approved version of the 2-up calendar selector widget. For all documentation
+* on the implemented methods listed here, see the documentation for Calendar2up_Core.
+* @constructor
+* @param {String}	id			The id of the table element that will represent the calendar widget
+* @param {String}	containerId	The id of the container element that will contain the calendar table
+* @param {String}	monthyear	The month/year string used to set the current calendar page
+* @param {String}	selected	A string of date values formatted using the date parser. The built-in
+								default date format is MM/DD/YYYY. Ranges are defined using
+								MM/DD/YYYY-MM/DD/YYYY. Month/day combinations are defined using MM/DD.
+								Any combination of these can be combined by delimiting the string with
+								commas. Example: "12/24/2005,12/25,1/18/2006-1/21/2006"
+*/
+SPIP.widget.Calendar2up = function(id, containerId, monthyear, selected) {
+	if (arguments.length > 0)
+	{
+		this.buildWrapper(containerId);
+		this.init(2, id, containerId, monthyear, selected);
+	}
+}
+
+SPIP.widget.Calendar2up.prototype = new SPIP.widget.CalendarGroup();
+
+/**
+* Implementation of CalendarGroup.constructChild that ensures that child calendars of
+* Calendar2up will be of type Calendar2up_Cal.
+*/
+SPIP.widget.Calendar2up.prototype.constructChild = function(id,containerId,monthyear,selected) {
+	var cal = new SPIP.widget.Calendar2up_Cal(id,containerId,monthyear,selected);
+	return cal;
+};
+
+/**
+* Builds the wrapper container for the 2-up calendar.
+* @param {String} containerId	The id of the outer container element.
+*/
+SPIP.widget.Calendar2up.prototype.buildWrapper = function(containerId) {
+	var outerContainer = document.getElementById(containerId);
+
+	outerContainer.className = "calcontainer";
+	/*outerContainer.innerHTML="";
+	if (SPIP.widget.Calendar_Core._getBrowser() == "ie") {
+		outerContainer.innerHTML="<iframe src='about:blank' scrolling='no' frameborder='0' style='position:absolute;left:0px;top:0px;z-index:0;' class='califrame'></iframe>";
+	}*/
+
+	var innerContainer = document.createElement("DIV");
+	innerContainer.className = "calbordered";
+	innerContainer.id = containerId + "_inner";
+
+	var cal1Container = document.createElement("DIV");
+	cal1Container.id = containerId + "_0";
+	cal1Container.className = "cal2up";
+	cal1Container.style.marginRight = "10px";
+	cal1Container.style.zIndex="99";
+	//cal1Container.style.cssFloat="left";
+
+	var cal2Container = document.createElement("DIV");
+	cal2Container.id = containerId + "_1";
+	cal2Container.className = "cal2up2";
+	cal1Container.style.zIndex="99";
+	//cal2Container.style.cssFloat="left";
+
+	outerContainer.appendChild(innerContainer);
+	innerContainer.appendChild(cal1Container);
+	innerContainer.appendChild(cal2Container);
+
+	this.innerContainer = innerContainer;
+	this.outerContainer = outerContainer;
+}
+
+/**
+* Renders the 2-up calendar.
+*/
+SPIP.widget.Calendar2up.prototype.render = function() {
+	this.renderHeader();
+	SPIP.widget.CalendarGroup.prototype.render.call(this);
+	this.renderFooter();
+};
+
+/**
+* Renders the header located at the top of the container for the 2-up calendar.
+*/
+SPIP.widget.Calendar2up.prototype.renderHeader = function() {
+	if (! this.title) {
+		this.title = "";
+	}
+	if (! this.titleDiv)
+	{
+		this.titleDiv = document.createElement("DIV");
+		if (this.title == "")
+		{
+			this.titleDiv.style.display="none";
+		}
+	}
+
+	this.titleDiv.className = "title";
+	this.titleDiv.innerHTML = this.title;
+
+	if (this.outerContainer.style.position == "absolute")
+	{
+		var linkClose = document.createElement("A");
+		linkClose.href = "javascript:void(null)";
+		SPIP.util.Event.addListener(linkClose, "click", this.hide, this);
+
+		var imgClose = document.createElement("IMG");
+		imgClose.src = this.pages[0].Options.IMG_CLOSE;
+		imgClose.className = this.pages[0].Options.IMG_CLOSE_CLASS;
+
+		linkClose.appendChild(imgClose);
+
+		this.linkClose = linkClose;
+
+		this.titleDiv.appendChild(linkClose);
+	}
+
+	this.innerContainer.insertBefore(this.titleDiv, this.innerContainer.firstChild);
+}
+
+/**
+* Hides the 2-up calendar's outer container from view.
+*/
+SPIP.widget.Calendar2up.prototype.hide = function(e, cal) {
+	if (! cal)
+	{
+		cal = this;
+	}
+	cal.outerContainer.style.display = "none";
+}
+
+/**
+* Renders a footer for the 2-up calendar container. By default, this method is
+* unimplemented.
+*/
+SPIP.widget.Calendar2up.prototype.renderFooter = function() {}
+
+SPIP.widget.Cal2up = SPIP.widget.Calendar2up;
Index: plugins/widget_calendar_1_9/img_pack/calendar_custom.js
===================================================================
--- plugins/widget_calendar_1_9/img_pack/calendar_custom.js	(revision 6)
+++ plugins/widget_calendar_1_9/img_pack/calendar_custom.js	(revision 6)
@@ -0,0 +1,93 @@
+function findPosX(obj)
+{
+	var curleft = 0;
+	curleft += obj.offsetLeft;
+	if (obj.offsetParent)
+	{
+		while (obj.offsetParent)
+		{
+			obj = obj.offsetParent;
+			curleft += obj.offsetLeft;
+		}
+	}
+	else if (obj.x)
+		curleft += obj.x;
+	return curleft;
+}
+
+function findPosY(obj)
+{
+	var curtop = 0;
+	curtop += obj.offsetTop;
+	if (obj.offsetParent)
+	{
+		while (obj.offsetParent)
+		{
+			obj = obj.offsetParent;
+			curtop += obj.offsetTop;
+		}
+	}
+	else if (obj.y)
+		curtop += obj.y;
+	return curtop;
+}
+
+
+// Calendrier popup 2 pages International ------
+
+SPIP.widget.Calendar2up_INT_Cal = function(id, containerId, monthyear, selected) {
+	if (arguments.length > 0)
+	{
+		this.init(id, containerId, monthyear, selected);
+	}
+}
+
+SPIP.widget.Calendar2up_INT_Cal.prototype = new SPIP.widget.Calendar2up_Cal();
+
+SPIP.widget.Calendar2up_INT = function(id, containerId, monthyear, selected) {
+	if (arguments.length > 0)
+	{	
+		var outerContainer = document.getElementById(containerId);
+	
+		outerContainer.innerHTML="";
+		if (SPIP.widget.Calendar_Core._getBrowser() == "ie") {
+			outerContainer.innerHTML="<iframe src='about:blank' scrolling='no' frameborder='0' style='position:absolute;left:0px;top:0px;z-index:0;' class='califrame'></iframe>";
+		}
+		this.buildWrapper(containerId);
+		this.init(2, id, containerId, monthyear, selected);
+	}
+}
+
+SPIP.widget.Calendar2up_INT.prototype = new SPIP.widget.Calendar2up();
+
+SPIP.widget.Calendar2up_INT.prototype.constructChild = function(id,containerId,monthyear,selected) {
+	var cal = new SPIP.widget.Calendar2up_INT_Cal(id,containerId,monthyear,selected);
+	return cal;
+};
+	
+
+
+
+// Calendrier popup 2 pages International MultiSelect ------
+SPIP.widget.Calendar2up_INT_Cal_multi = function(id, containerId, monthyear, selected) {
+	if (arguments.length > 0)
+	{
+		this.init(id, containerId, monthyear, selected);
+	}
+}
+
+SPIP.widget.Calendar2up_INT_Cal_multi.prototype = new SPIP.widget.Calendar2up_Cal();
+SPIP.widget.Calendar2up_INT_multi = function(id, containerId, monthyear, selected) {
+	if (arguments.length > 0)
+	{	
+		this.buildWrapper(containerId);
+		this.init(2, id, containerId, monthyear, selected);
+	}
+}
+
+SPIP.widget.Calendar2up_INT_multi.prototype = new SPIP.widget.Calendar2up();
+
+SPIP.widget.Calendar2up_INT_multi.prototype.constructChild = function(id,containerId,monthyear,selected) {
+	var cal = new SPIP.widget.Calendar2up_INT_Cal_multi(id,containerId,monthyear,selected);
+	return cal;
+};
Index: plugins/widget_calendar_1_9/img_pack/dom.js
===================================================================
--- plugins/widget_calendar_1_9/img_pack/dom.js	(revision 6)
+++ plugins/widget_calendar_1_9/img_pack/dom.js	(revision 6)
@@ -0,0 +1,433 @@
+/*
+Copyright (c) 2006 Spip! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class Provides helper methods for DOM elements.
+ */
+SPIP.util.Dom = new function() {
+
+   /**
+    * Returns an HTMLElement reference
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @return {HTMLElement} A DOM reference to an HTML element.
+    */
+   this.get = function(el) {
+      if (typeof el == 'string') { // accept object or id
+         el = document.getElementById(el);
+      }
+
+      return el;
+   };
+
+   /**
+    * Normalizes currentStyle and ComputedStyle.
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {String} property The style property whose value is returned.
+    * @return {String} The current value of the style property.
+    */
+   this.getStyle = function(el, property) {
+      var value = null;
+      var dv = document.defaultView;
+
+      el = this.get(el);
+
+      if (property == 'opacity' && el.filters) {// IE opacity
+         value = 1;
+         try {
+            value = el.filters.item('DXImageTransform.Microsoft.Alpha').opacity / 100;
+         } catch(e) {
+            try {
+               value = el.filters.item('alpha').opacity / 100;
+            } catch(e) {}
+         }
+      }
+      else if (el.style[property]) {
+         value = el.style[property];
+      }
+      else if (el.currentStyle && el.currentStyle[property]) {
+         value = el.currentStyle[property];
+      }
+      else if ( dv && dv.getComputedStyle )
+      {  // convert camelCase to hyphen-case
+
+         var converted = '';
+         for(i = 0, len = property.length;i < len; ++i) {
+            if (property.charAt(i) == property.charAt(i).toUpperCase()) {
+               converted = converted + '-' + property.charAt(i).toLowerCase();
+            } else {
+               converted = converted + property.charAt(i);
+            }
+         }
+
+         if (dv.getComputedStyle(el, '').getPropertyValue(converted)) {
+            value = dv.getComputedStyle(el, '').getPropertyValue(converted);
+         }
+      }
+
+      return value;
+   };
+
+   /**
+    * Wrapper for setting style properties of HTMLElements.  Normalizes "opacity" across modern browsers.
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {String} property The style property to be set.
+    * @param {String} val The value to apply to the given property.
+    */
+   this.setStyle = function(el, property, val) {
+      el = this.get(el);
+      switch(property) {
+         case 'opacity' :
+            if (el.filters) {
+               el.style.filter = 'alpha(opacity=' + val * 100 + ')';
+
+               if (!el.currentStyle.hasLayout) {
+                  el.style.zoom = 1;
+               }
+            } else {
+               el.style.opacity = val;
+               el.style['-moz-opacity'] = val;
+               el.style['-khtml-opacity'] = val;
+            }
+            break;
+         default :
+            el.style[property] = val;
+      }
+   };
+
+   /**
+    * Gets the current position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    */
+   this.getXY = function(el) {
+      el = this.get(el);
+
+      // has to be part of document to have pageXY
+      if (el.parentNode === null || this.getStyle(el, 'display') == 'none') {
+         return false;
+      }
+
+      /**
+       * Position of the html element (x, y)
+       * @private
+       * @type Array
+       */
+      var parent = null;
+      var pos = [];
+      var box;
+
+      if (el.getBoundingClientRect) { // IE
+         box = el.getBoundingClientRect();
+         var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
+         var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
+
+         return [box.left + scrollLeft, box.top + scrollTop];
+      }
+      else if (document.getBoxObjectFor) { // gecko
+         box = document.getBoxObjectFor(el);
+         pos = [box.x, box.y];
+      }
+      else { // safari/opera
+         pos = [el.offsetLeft, el.offsetTop];
+         parent = el.offsetParent;
+         if (parent != el) {
+            while (parent) {
+               pos[0] += parent.offsetLeft;
+               pos[1] += parent.offsetTop;
+               parent = parent.offsetParent;
+            }
+         }
+
+         // opera & (safari absolute) incorrectly account for body offsetTop
+         var ua = navigator.userAgent.toLowerCase();
+         if (
+            ua.indexOf('opera') != -1
+            || ( ua.indexOf('safari') != -1 && this.getStyle(el, 'position') == 'absolute' )
+         ) {
+            pos[1] -= document.body.offsetTop;
+         }
+      }
+
+      if (el.parentNode) { parent = el.parentNode; }
+      else { parent = null; }
+
+      while (parent && parent.tagName != 'BODY' && parent.tagName != 'HTML') {
+         pos[0] -= parent.scrollLeft;
+         pos[1] -= parent.scrollTop;
+
+         if (parent.parentNode) { parent = parent.parentNode; }
+         else { parent = null; }
+      }
+
+      return pos;
+   };
+
+   /**
+    * Gets the current X position of an element based on page coordinates.  The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    */
+   this.getX = function(el) {
+      return this.getXY(el)[0];
+   };
+
+   /**
+    * Gets the current Y position of an element based on page coordinates.  Element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    */
+   this.getY = function(el) {
+      return this.getXY(el)[1];
+   };
+
+   /**
+    * Set the position of an html element in page coordinates, regardless of how the element is positioned.
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {array} pos Contains X & Y values for new position (coordinates are page-based)
+    */
+   this.setXY = function(el, pos, noRetry) {
+      el = this.get(el);
+      var pageXY = SPIP.util.Dom.getXY(el);
+      if (pageXY === false) { return false; } // has to be part of doc to have pageXY
+
+      if (this.getStyle(el, 'position') == 'static') { // default to relative
+         this.setStyle(el, 'position', 'relative');
+      }
+
+      var delta = [
+         parseInt( SPIP.util.Dom.getStyle(el, 'left'), 10 ),
+         parseInt( SPIP.util.Dom.getStyle(el, 'top'), 10 )
+      ];
+
+      if ( isNaN(delta[0]) ) { delta[0] = 0; } // defalts to 'auto'
+      if ( isNaN(delta[1]) ) { delta[1] = 0; }
+
+      if (pos[0] !== null) { el.style.left = pos[0] - pageXY[0] + delta[0] + 'px'; }
+      if (pos[1] !== null) { el.style.top = pos[1] - pageXY[1] + delta[1] + 'px'; }
+
+      var newXY = this.getXY(el);
+
+      // if retry is true, try one more time if we miss
+      if (!noRetry && (newXY[0] != pos[0] || newXY[1] != pos[1]) ) {
+         this.setXY(el, pos, true);
+      }
+
+      return true;
+   };
+
+   /**
+    * Set the X position of an html element in page coordinates, regardless of how the element is positioned.
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {Int} x to use as the X coordinate.
+    */
+   this.setX = function(el, x) {
+      return this.setXY(el, [x, null]);
+   };
+
+   /**
+    * Set the Y position of an html element in page coordinates, regardless of how the element is positioned.
+    * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @param {Int} Value to use as the Y coordinate.
+    */
+   this.setY = function(el, y) {
+      return this.setXY(el, [null, y]);
+   };
+
+   /**
+    * Returns the region position of the given element.
+    * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
+    * @param {String | HTMLElement} Accepts either a string to use as an ID for getting a DOM reference, or an actual DOM reference.
+    * @return {Region} A Region instance containing "top, left, bottom, right" member data.
+    */
+   this.getRegion = function(el) {
+      el = this.get(el);
+      return new SPIP.util.Region.getRegion(el);
+   };
+
+   /**
+    * Returns the width of the client (viewport).
+    * @return {Int} The width of the viewable area of the page.
+    */
+   this.getClientWidth = function() {
+      return (
+         document.documentElement.offsetWidth
+         || document.body.offsetWidth
+      );
+   };
+
+   /**
+    * Returns the height of the client (viewport).
+    * @return {Int} The height of the viewable area of the page.
+    */
+   this.getClientHeight = function() {
+      return (
+         self.innerHeight
+         || document.documentElement.clientHeight
+         || document.body.clientHeight
+      );
+   };
+};
+
+/**
+ * @class A region is a representation of an object on a grid.  It is defined
+ * by the top, right, bottom, left extents, so is rectangular by default.  If
+ * other shapes are required, this class could be extended to support it.
+ *
+ * @param {int} t the top extent
+ * @param {int} r the right extent
+ * @param {int} b the bottom extent
+ * @param {int} l the left extent
+ * @constructor
+ */
+SPIP.util.Region = function(t, r, b, l) {
+
+    /**
+     * The region's top extent
+     * @type int
+     */
+    this.top = t;
+
+    /**
+     * The region's right extent
+     * @type int
+     */
+    this.right = r;
+
+    /**
+     * The region's bottom extent
+     * @type int
+     */
+    this.bottom = b;
+
+    /**
+     * The region's left extent
+     * @type int
+     */
+    this.left = l;
+};
+
+/**
+ * Returns true if this region contains the region passed in
+ *
+ * @param  {Region}  region The region to evaluate
+ * @return {boolean}        True if the region is contained with this region,
+ *                          else false
+ */
+SPIP.util.Region.prototype.contains = function(region) {
+    return ( region.left   >= this.left   &&
+             region.right  <= this.right  &&
+             region.top    >= this.top    &&
+             region.bottom <= this.bottom    );
+};
+
+/**
+ * Returns the area of the region
+ *
+ * @return {int} the region's area
+ */
+SPIP.util.Region.prototype.getArea = function() {
+    return ( (this.bottom - this.top) * (this.right - this.left) );
+};
+
+/**
+ * Returns the region where the passed in region overlaps with this one
+ *
+ * @param  {Region} region The region that intersects
+ * @return {Region}        The overlap region, or null if there is no overlap
+ */
+SPIP.util.Region.prototype.intersect = function(region) {
+    var t = Math.max( this.top,    region.top    );
+    var r = Math.min( this.right,  region.right  );
+    var b = Math.min( this.bottom, region.bottom );
+    var l = Math.max( this.left,   region.left   );
+
+    if (b >= t && r >= l) {
+        return new SPIP.util.Region(t, r, b, l);
+    } else {
+        return null;
+    }
+};
+
+/**
+ * Returns the region representing the smallest region that can contain both
+ * the passed in region and this region.
+ *
+ * @param  {Region} region The region that to create the union with
+ * @return {Region}        The union region
+ */
+SPIP.util.Region.prototype.union = function(region) {
+    var t = Math.min( this.top,    region.top    );
+    var r = Math.max( this.right,  region.right  );
+    var b = Math.max( this.bottom, region.bottom );
+    var l = Math.min( this.left,   region.left   );
+
+    return new SPIP.util.Region(t, r, b, l);
+};
+
+/**
+ * toString
+ * @return string the region properties
+ */
+SPIP.util.Region.prototype.toString = function() {
+    return ( "Region {" +
+             "  t: "    + this.top    +
+             ", r: "    + this.right  +
+             ", b: "    + this.bottom +
+             ", l: "    + this.left   +
+             "}" );
+}
+
+/**
+ * Returns a region that is occupied by the DOM element
+ *
+ * @param  {HTMLElement} el The element
+ * @return {Region}         The region that the element occupies
+ * @static
+ */
+SPIP.util.Region.getRegion = function(el) {
+    var p = SPIP.util.Dom.getXY(el);
+
+    var t = p[1];
+    var r = p[0] + el.offsetWidth;
+    var b = p[1] + el.offsetHeight;
+    var l = p[0];
+
+    return new SPIP.util.Region(t, r, b, l);
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * @class
+ *
+ * A point is a region that is special in that it represents a single point on
+ * the grid.
+ *
+ * @param {int} x The X position of the point
+ * @param {int} y The Y position of the point
+ * @constructor
+ * @extends Region
+ */
+SPIP.util.Point = function(x, y) {
+    /**
+     * The X position of the point
+     * @type int
+     */
+    this.x      = x;
+
+    /**
+     * The Y position of the point
+     * @type int
+     */
+    this.y      = y;
+
+    this.top    = y;
+    this.right  = x;
+    this.bottom = y;
+    this.left   = x;
+};
+
+SPIP.util.Point.prototype = new SPIP.util.Region();
Index: plugins/widget_calendar_1_9/img_pack/event.js
===================================================================
--- plugins/widget_calendar_1_9/img_pack/event.js	(revision 6)
+++ plugins/widget_calendar_1_9/img_pack/event.js	(revision 6)
@@ -0,0 +1,901 @@
+/*
+Copyright (c) 2006 Spip! Inc. All rights reserved.
+version 0.9.0
+*/
+
+/**
+ * @class The CustomEvent class lets you define events for your application
+ * that can be subscribed to by one or more independent component.
+ * @param {String} type The type of event, which is passed to the callback
+ *                 when the event fires
+ * @param {Object} oScope The context the event will fire from.  "this" will
+ *                 refer to this object in the callback.  Default value:
+ *                 the window object.  The listener can override this.
+ * @constructor
+ */
+SPIP.util.CustomEvent = function(type, oScope) {
+    /**
+     * The type of event, returned to subscribers when the event fires
+     * @type string
+     */
+    this.type = type;
+
+    /**
+     * The scope the the event will fire from.  Defaults to the window obj
+     * @type object
+     */
+    this.scope = oScope || window;
+
+    /**
+     * The subscribers to this event
+     * @type array
+     */
+    this.subscribers = [];
+
+    // Register with the event utility for automatic cleanup.  Made optional
+    // so that CustomEvent can be used independently of pe.event
+    if (SPIP.util["Event"]) {
+        SPIP.util.Event.regCE(this);
+    }
+};
+
+SPIP.util.CustomEvent.prototype = {
+    /**
+     * Subscribes the caller to this event
+     * @param {Function} fn       The function to execute
+     * @param {Object}   obj      An object to be passed along when the event fires
+     * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+     *                            scope of the listener
+     */
+    subscribe: function(fn, obj, bOverride) {
+        this.subscribers.push( new SPIP.util.Subscriber(fn, obj, bOverride) );
+    },
+
+    /**
+     * Unsubscribes the caller from this event
+     * @param {Function} fn  The function to execute
+     * @param {Object}   obj An object to be passed along when the event fires
+     * @return {boolean} True if the subscriber was found and detached.
+     */
+    unsubscribe: function(fn, obj) {
+        var found = false;
+        for (var i=0; i<this.subscribers.length; ++i) {
+            var s = this.subscribers[i];
+            if (s && s.contains(fn, obj)) {
+                this._delete(i);
+                found = true;
+            }
+        }
+
+        return found;
+    },
+
+    /**
+     * Notifies the subscribers.  The callback functions will be executed
+     * from the scope specified when the event was created, and with the following
+     * parameters:
+     *   <pre>
+     *   - The type of event
+     *   - All of the arguments fire() was executed with as an array
+     *   - The custom object (if any) that was passed into the subscribe() method
+     *   </pre>
+     *
+     * @param {Array} an arbitrary set of parameters to pass to the handler
+     */
+    fire: function() {
+        for (var i=0; i<this.subscribers.length; ++i) {
+            var s = this.subscribers[i];
+            if (s) {
+                var scope = (s.override) ? s.obj : this.scope;
+                s.fn.call(scope, this.type, arguments, s.obj);
+            }
+        }
+    },
+
+    /**
+     * Removes all listeners
+     */
+    unsubscribeAll: function() {
+        for (var i=0; i<this.subscribers.length; ++i) {
+            this._delete(i);
+        }
+    },
+
+    /**
+     * @private
+     */
+    _delete: function(index) {
+        var s = this.subscribers[index];
+        if (s) {
+            delete s.fn;
+            delete s.obj;
+        }
+
+        delete this.subscribers[index];
+    }
+};
+
+/////////////////////////////////////////////////////////////////////
+
+/**
+ * @class
+ * @param {Function} fn       The function to execute
+ * @param {Object}   obj      An object to be passed along when the event fires
+ * @param {boolean}  bOverride If true, the obj passed in becomes the execution
+ *                            scope of the listener
+ * @constructor
+ */
+SPIP.util.Subscriber = function(fn, obj, bOverride) {
+    /**
+     * The callback that will be execute when the event fires
+     * @type function
+     */
+    this.fn = fn;
+
+    /**
+     * An optional custom object that will passed to the callback when
+     * the event fires
+     * @type object
+     */
+    this.obj = obj || null;
+
+    /**
+     * The default execution scope for the event listener is defined when the
+     * event is created (usually the object which contains the event).
+     * By setting override to true, the execution scope becomes the custom
+     * object passed in by the subscriber
+     * @type boolean
+     */
+    this.override = (bOverride);
+};
+
+/**
+ * Returns true if the fn and obj match this objects properties.
+ * Used by the unsubscribe method to match the right subscriber.
+ *
+ * @param {Function} fn the function to execute
+ * @param {Object} obj an object to be passed along when the event fires
+ * @return {boolean} true if the supplied arguments match this
+ *                   subscriber's signature.
+ */
+SPIP.util.Subscriber.prototype.contains = function(fn, obj) {
+    return (this.fn == fn && this.obj == obj);
+};
+
+/* Copyright (c) 2006 Spip! Inc. All rights reserved. */
+
+// Only load this library once.  If it is loaded a second time, existing
+// events cannot be detached.
+if (!SPIP.util.Event) {
+
+/**
+ * The event utility provides functions to add and remove event listeners,
+ * event cleansing.  It also tries to automatically remove listeners it
+ * registers during the unload event.
+ * @class
+ * @constructor
+ */
+    SPIP.util.Event = function() {
+
+        /**
+         * True after the onload event has fired
+         * @type boolean
+         * @private
+         */
+        var loadComplete =  false;
+
+        /**
+         * Cache of wrapped listeners
+         * @type array
+         * @private
+         */
+        var listeners = [];
+
+        /**
+         * Listeners that will be attached during the onload event
+         * @type array
+         * @private
+         */
+        var delayedListeners = [];
+
+        /**
+         * User-defined unload function that will be fired before all events
+         * are detached
+         * @type array
+         * @private
+         */
+        var unloadListeners = [];
+
+        /**
+         * Cache of the custom events that have been defined.  Used for
+         * automatic cleanup
+         * @type array
+         * @private
+         */
+        var customEvents = [];
+
+        /**
+         * Cache of DOM0 event handlers to work around issues with DOM2 events
+         * in Safari
+         * @private
+         */
+        var legacyEvents = [];
+
+        /**
+         * Listener stack for DOM0 events
+         * @private
+         */
+        var legacyHandlers = [];
+
+        return { // PREPROCESS
+
+            /**
+             * Element to bind, int constant
+             * @type int
+             */
+            EL: 0,
+
+            /**
+             * Type of event, int constant
+             * @type int
+             */
+            TYPE: 1,
+
+            /**
+             * Function to execute, int constant
+             * @type int
+             */
+            FN: 2,
+
+            /**
+             * Function wrapped for scope correction and cleanup, int constant
+             * @type int
+             */
+            WFN: 3,
+
+            /**
+             * Object passed in by the user that will be returned as a
+             * parameter to the callback, int constant
+             * @type int
+             */
+            SCOPE: 3,
+
+            /**
+             * Adjusted scope, either the element we are registering the event
+             * on or the custom object passed in by the listener, int constant
+             * @type int
+             */
+            ADJ_SCOPE: 4,
+
+            /**
+             * Safari detection is necessary to work around the preventDefault
+             * bug that makes it so you can't cancel a href click from the
+             * handler.  There is not a capabilities check we can use here.
+             * @private
+             */
+            isSafari: (navigator.userAgent.match(/safari/gi)),
+
+            /**
+             * @private
+             * IE detection needed to properly calculate pageX and pageY.
+             * capabilities checking didn't seem to work because another
+             * browser that does not provide the properties have the values
+             * calculated in a different manner than IE.
+             */
+            isIE: (!this.isSafari && navigator.userAgent.match(/msie/gi)),
+
+            /**
+             * Appends an event handler
+             *
+             * @param {Object}   el        The html element to assign the
+             *                             event to
+             * @param {String}   sType     The type of event to append
+             * @param {Function} fn        The method the event invokes
+             * @param {Object}   oScope    An arbitrary object that will be
+             *                             passed as a parameter to the handler
+             * @param {boolean}  bOverride If true, the obj passed in becomes
+             *                             the execution scope of the listener
+             * @return {boolean} True if the action was successful or defered,
+             *                        false if one or more of the elements
+             *                        could not have the event bound to it.
+             */
+            addListener: function(el, sType, fn, oScope, bOverride) {
+
+                // The el argument can be an array of elements or element ids.
+                if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0; i< el.length; ++i) {
+                        ok = ( this.on(el[i],
+                                       sType,
+                                       fn,
+                                       oScope,
+                                       bOverride) && ok );
+                    }
+                    return ok;
+
+                } else if (typeof el == "string") {
+                    // If the el argument is a string, we assume it is
+                    // actually the id of the element.  If the page is loaded
+                    // we convert el to the actual element, otherwise we
+                    // defer attaching the event until onload event fires
+
+                    // check to see if we need to delay hooking up the event
+                    // until after the page loads.
+                    if (loadComplete) {
+                        el = this.getEl(el);
+                    } else {
+                        // defer adding the event until onload fires
+                        delayedListeners[delayedListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+
+                        return true;
+                    }
+                }
+
+                // Element should be an html element or an array if we get
+                // here.
+                if (!el) {
+                    return false;
+                }
+
+                // we need to make sure we fire registered unload events
+                // prior to automatically unhooking them.  So we hang on to
+                // these instead of attaching them to the window and fire the
+                // handles explicitly during our one unload event.
+                if ("unload" == sType && oScope !== this) {
+                    unloadListeners[unloadListeners.length] =
+                            [el, sType, fn, oScope, bOverride];
+                    return true;
+                }
+
+
+                // if the user chooses to override the scope, we use the custom
+                // object passed in, otherwise the executing scope will be the
+                // HTML element that the event is registered on
+                var scope = (bOverride) ? oScope : el;
+
+                // wrap the function so we can return the oScope object when
+                // the event fires;
+                var wrappedFn = function(e) {
+                        return fn.call(scope, SPIP.util.Event.getEvent(e),
+                                oScope);
+                    };
+
+                var li = [el, sType, fn, wrappedFn, scope];
+                var index = listeners.length;
+                // cache the listener so we can try to automatically unload
+                listeners[index] = li;
+
+                if (this.useLegacyEvent(el, sType)) {
+                    var legacyIndex = this.getLegacyIndex(el, sType);
+                    if (legacyIndex == -1) {
+
+                        legacyIndex = legacyEvents.length;
+                        // cache the signature for the DOM0 event, and
+                        // include the existing handler for the event, if any
+                        legacyEvents[legacyIndex] =
+                            [el, sType, el["on" + sType]];
+                        legacyHandlers[legacyIndex] = [];
+
+                        el["on" + sType] =
+                            function(e) {
+                                SPIP.util.Event.fireLegacyEvent(
+                                    SPIP.util.Event.getEvent(e), legacyIndex);
+                            };
+                    }
+
+                    // add a reference to the wrapped listener to our custom
+                    // stack of events
+                    legacyHandlers[legacyIndex].push(index);
+
+                // DOM2 Event model
+                } else if (el.addEventListener) {
+                    el.addEventListener(sType, wrappedFn, false);
+                // Internet Explorer abstraction
+                } else if (el.attachEvent) {
+                    el.attachEvent("on" + sType, wrappedFn);
+                }
+
+                return true;
+
+            },
+
+            /**
+             * Shorthand for SPIP.util.Event.addListener
+             * @type function
+             */
+            // on: this.addListener,
+
+            /**
+             * When using legacy events, the handler is routed to this object
+             * so we can fire our custom listener stack.
+             * @private
+             */
+            fireLegacyEvent: function(e, legacyIndex) {
+                // alert("fireLegacyEvent " + legacyIndex);
+                var ok = true;
+
+                // var el = legacyEvents[SPIP.util.Event.EL];
+
+                /* this is not working because the property may get populated
+                // fire the event we replaced, if it exists
+                var origHandler = legacyEvents[2];
+                alert(origHandler);
+                if (origHandler && origHandler.call) {
+                    var ret = origHandler.call(el, e);
+                    ok = (ret);
+                }
+                */
+
+                var le = legacyHandlers[legacyIndex];
+                for (i=0; i < le.length; ++i) {
+                    var index = le[i];
+                    // alert(index);
+                    if (index) {
+                        var li = listeners[index];
+                        var scope = li[this.ADJ_SCOPE];
+                        var ret = li[this.WFN].call(scope, e);
+                        ok = (ok && ret);
+                        // alert(ok);
+                    }
+                }
+
+                return ok;
+            },
+
+            /**
+             * Returns the legacy event index that matches the supplied
+             * signature
+             * @private
+             */
+            getLegacyIndex: function(el, sType) {
+                for (var i=0; i < legacyEvents.length; ++i) {
+                    var le = legacyEvents[i];
+                    if (le && le[0] == el && le[1] == sType) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * Logic that determines when we should automatically use legacy
+             * events instead of DOM2 events.
+             * @private
+             */
+            useLegacyEvent: function(el, sType) {
+
+                return ( (!el.addEventListener && !el.attachEvent) ||
+                                (sType == "click" && this.isSafari) );
+            },
+
+            /**
+             * Removes an event handler
+             *
+             * @param {Object} el the html element or the id of the element to
+             * assign the event to.
+             * @param {String} sType the type of event to remove
+             * @param {Function} fn the method the event invokes
+             * @return {boolean} true if the unbind was successful, false
+             * otherwise
+             */
+            removeListener: function(el, sType, fn) {
+
+                // The el argument can be a string
+                if (typeof el == "string") {
+                    el = this.getEl(el);
+                // The el argument can be an array of elements or element ids.
+                } else if ( this._isValidCollection(el)) {
+                    var ok = true;
+                    for (var i=0; i< el.length; ++i) {
+                        ok = ( this.removeListener(el[i], sType, fn) && ok );
+                    }
+                    return ok;
+                }
+
+                var cacheItem = null;
+                var index = this._getCacheIndex(el, sType, fn);
+
+                if (index >= 0) {
+                    cacheItem = listeners[index];
+                }
+
+                if (!el || !cacheItem) {
+                    return false;
+                }
+
+
+                if (el.removeEventListener) {
+                    el.removeEventListener(sType, cacheItem[this.WFN], false);
+                    // alert("adsf");
+                } else if (el.detachEvent) {
+                    el.detachEvent("on" + sType, cacheItem[this.WFN]);
+                }
+
+                // removed the wrapped handler
+                delete listeners[index][this.WFN];
+                delete listeners[index][this.FN];
+                delete listeners[index];
+
+                return true;
+
+            },
+
+            /**
+             * Returns the event's target element
+             * @param {Event} ev the event
+             * @param {boolean} resolveTextNode when set to true the target's
+             *                  parent will be returned if the target is a
+             *                  text node
+             * @return {HTMLElement} the event's target
+             */
+            getTarget: function(ev, resolveTextNode) {
+                var t = ev.target || ev.srcElement;
+
+                if (resolveTextNode && t && "#text" == t.nodeName) {
+                    return t.parentNode;
+                } else {
+                    return t;
+                }
+            },
+
+            /**
+             * Returns the event's pageX
+             * @param {Event} ev the event
+             * @return {int} the event's pageX
+             */
+            getPageX: function(ev) {
+                var x = ev.pageX;
+                if (!x && 0 !== x) {
+                    x = ev.clientX || 0;
+
+                    if ( this.isIE ) {
+                        x += this._getScrollLeft();
+                    }
+                }
+
+                return x;
+            },
+
+            /**
+             * Returns the event's pageY
+             * @param {Event} ev the event
+             * @return {int} the event's pageY
+             */
+            getPageY: function(ev) {
+                var y = ev.pageY;
+                if (!y && 0 !== y) {
+                    y = ev.clientY || 0;
+
+                    if ( this.isIE ) {
+                        y += this._getScrollTop();
+                    }
+                }
+
+                return y;
+            },
+
+            /**
+             * Returns the event's related target
+             * @param {Event} ev the event
+             * @return {HTMLElement} the event's relatedTarget
+             */
+            getRelatedTarget: function(ev) {
+                var t = ev.relatedTarget;
+                if (!t) {
+                    if (ev.type == "mouseout") {
+                        t = ev.toElement;
+                    } else if (ev.type == "mouseover") {
+                        t = ev.fromElement;
+                    }
+                }
+
+                return t;
+            },
+
+            /**
+             * Returns the time of the event.  If the time is not included, the
+             * event is modified using the current time.
+             * @param {Event} ev the event
+             * @return {Date} the time of the event
+             */
+            getTime: function(ev) {
+                if (!ev.time) {
+                    var t = new Date().getTime();
+                    try {
+                        ev.time = t;
+                    } catch(e) {
+                        // can't set the time property
+                        return t;
+                    }
+                }
+
+                return ev.time;
+            },
+
+            /**
+             * Convenience method for stopPropagation + preventDefault
+             * @param {Event} ev the event
+             */
+            stopEvent: function(ev) {
+                this.stopPropagation(ev);
+                this.preventDefault(ev);
+            },
+
+            /**
+             * Stops event propagation
+             * @param {Event} ev the event
+             */
+            stopPropagation: function(ev) {
+                if (ev.stopPropagation) {
+                    ev.stopPropagation();
+                } else {
+                    ev.cancelBubble = true;
+                }
+            },
+
+            /**
+             * Prevents the default behavior of the event
+             * @param {Event} ev the event
+             */
+            preventDefault: function(ev) {
+                if (ev.preventDefault) {
+                    ev.preventDefault();
+                } else {
+                    ev.returnValue = false;
+                }
+            },
+
+            /**
+             * Returns the event, should not be necessary for user to call
+             * @param {Event} the event parameter from the handler
+             * @return {Event} the event
+             */
+            getEvent: function(e) {
+                var ev = e || window.event;
+
+                if (!ev) {
+                    var c = this.getEvent.caller;
+                    while (c) {
+                        ev = c.arguments[0];
+                        if (ev && Event == ev.constructor) {
+                            break;
+                        }
+                        c = c.caller;
+                    }
+                }
+
+                return ev;
+            },
+
+            /**
+             * Returns the charcode for an event
+             * @param {Event} ev the event
+             * @return {int} the event's charCode
+             */
+            getCharCode: function(ev) {
+                return ev.charCode || (ev.type == "keypress") ? ev.keyCode : 0;
+            },
+
+            /**
+             * @private
+             * Locating the saved event handler data by function ref
+             */
+            _getCacheIndex: function(el, sType, fn) {
+                for (var i=0; i< listeners.length; ++i) {
+                    var li = listeners[i];
+                    if ( li                 &&
+                         li[this.FN] == fn  &&
+                         li[this.EL] == el  &&
+                         li[this.TYPE] == sType ) {
+                        return i;
+                    }
+                }
+
+                return -1;
+            },
+
+            /**
+             * We want to be able to use getElementsByTagName as a collection
+             * to attach a group of events to.  Unfortunately, different
+             * browsers return different types of collections.  This function
+             * tests to determine if the object is array-like.  It will also
+             * fail if the object is an array, but is empty.
+             * @param o the object to test
+             * @return {boolean} true if the object is array-like and populated
+             */
+            _isValidCollection: function(o) {
+                // alert(o.constructor.toString())
+                // alert(typeof o)
+
+                return ( o                    && // o is something
+                         o.length             && // o is indexed
+                         typeof o != "string" && // o is not a string
+                         !o.tagName           && // o is not an HTML element
+                         !o.alert             && // o is not a window
+                         typeof o[0] != "undefined" );
+
+            },
+
+            /**
+             * @private
+             * DOM element cache
+             */
+            elCache: {},
+
+            /**
+             * We cache elements bound by id because when the unload event
+             * fires, we can no longer use document.getElementById
+             * @private
+             */
+            getEl: function(id) {
+                /*
+                // this is a problem when replaced via document.getElementById
+                if (! this.elCache[id]) {
+                    try {
+                        var el = document.getElementById(id);
+                        if (el) {
+                            this.elCache[id] = el;
+                        }
+                    } catch (er) {
+                    }
+                }
+                return this.elCache[id];
+                */
+
+                return document.getElementById(id);
+            },
+
+            /**
+             * Clears the element cache
+             */
+            clearCache: function() {
+                for (i in this.elCache) {
+                    delete this.elCache[i];
+                }
+            },
+
+            /**
+             * Called by CustomEvent instances to provide a handle to the
+             * event * that can be removed later on.  Should be package
+             * protected.
+             * @private
+             */
+            regCE: function(ce) {
+                customEvents.push(ce);
+            },
+
+            /**
+             * @private
+             * hook up any deferred listeners
+             */
+            _load: function(e) {
+                loadComplete = true;
+            },
+
+            /**
+             * Polling function that runs before the onload event fires,
+             * attempting * to attach to DOM Nodes as soon as they are
+             * available
+             * @private
+             */
+            _tryPreloadAttach: function() {
+
+                // keep trying until after the page is loaded.  We need to
+                // check the page load state prior to trying to bind the
+                // elements so that we can be certain all elements have been
+                // tested appropriately
+                var tryAgain = !loadComplete;
+
+                for (var i=0; i < delayedListeners.length; ++i) {
+                    var d = delayedListeners[i];
+                    // There may be a race condition here, so we need to
+                    // verify the array element is usable.
+                    if (d) {
+
+                        // el will be null if document.getElementById did not
+                        // work
+                        var el = this.getEl(d[this.EL]);
+
+                        if (el) {
+                            this.on(el, d[this.TYPE], d[this.FN],
+                                    d[this.SCOPE], d[this.ADJ_SCOPE]);
+                            delete delayedListeners[i];
+                        }
+                    }
+                }
+
+                if (tryAgain) {
+                    setTimeout("SPIP.util.Event._tryPreloadAttach()", 50);
+                }
+            },
+
+            /**
+             * Removes all listeners registered by pe.event.  Called
+             * automatically during the unload event.
+             */
+            _unload: function(e, me) {
+                for (var i=0; i < unloadListeners.length; ++i) {
+                    var l = unloadListeners[i];
+                    if (l) {
+                        var scope = (l[this.ADJ_SCOPE]) ? l[this.SCOPE]: window;
+                        l[this.FN].call(scope, this.getEvent(e), l[this.SCOPE] );
+                    }
+                }
+
+                if (listeners && listeners.length > 0) {
+                    for (i = 0; i < listeners.length; ++i) {
+                        l = listeners[i];
+                        if (l) {
+                            this.removeListener(l[this.EL], l[this.TYPE],
+                                    l[this.FN]);
+                        }
+                    }
+
+                    this.clearCache();
+                }
+
+                for (i = 0; i < customEvents.length; ++i) {
+                    customEvents[i].unsubscribeAll();
+                    delete customEvents[i];
+                }
+
+                for (i = 0; i < legacyEvents.length; ++i) {
+                    // dereference the element
+                    delete legacyEvents[i][0];
+                    // delete the array item
+                    delete legacyEvents[i];
+                }
+            },
+
+            /**
+             * Returns scrollLeft
+             * @private
+             */
+            _getScrollLeft: function() {
+                return this._getScroll()[1];
+            },
+
+            /**
+             * Returns scrollTop
+             * @private
+             */
+            _getScrollTop: function() {
+                return this._getScroll()[0];
+            },
+
+            /**
+             * Returns the scrollTop and scrollLeft.  Used to calculate the
+             * pageX and pageY in Internet Explorer
+             * @private
+             */
+            _getScroll: function() {
+                var dd = document.documentElement; db = document.body;
+                if (dd && dd.scrollTop) {
+                    return [dd.scrollTop, dd.scrollLeft];
+                } else if (db) {
+                    return [db.scrollTop, db.scrollLeft];
+                } else {
+                    return [0, 0];
+                }
+            }
+        };
+    } ();
+
+    SPIP.util.Event.on = SPIP.util.Event.addListener;
+
+    if (document && document.body) {
+        SPIP.util.Event._load();
+    } else {
+        SPIP.util.Event.on(window, "load", SPIP.util.Event._load,
+                SPIP.util.Event, true);
+    }
+
+    SPIP.util.Event.on(window, "unload", SPIP.util.Event._unload,
+                SPIP.util.Event, true);
+
+    SPIP.util.Event._tryPreloadAttach();
+
+}
+
Index: plugins/widget_calendar_1_9/inc/calendar.php
===================================================================
--- plugins/widget_calendar_1_9/inc/calendar.php	(revision 6)
+++ plugins/widget_calendar_1_9/inc/calendar.php	(revision 6)
@@ -0,0 +1,65 @@
+<?php
+
+$p=explode(basename(_DIR_PLUGINS)."/",str_replace('\\','/',realpath(dirname(dirname(__FILE__)))));
+define('_DIR_PLUGIN_WIDGET_CALENDAR',(_DIR_PLUGINS.end($p)));
+define('_WIDGET_CALENDAR_BACK_IN_TIME',4);
+
+global $WCalendar_independants,$WCalendar_lies,$WCalendar_statiques;
+$WCalendar_independants=array();
+$WCalendar_lies=array();
+$WCalendar_statiques=array();
+
+function WCalendar_ajoute($titre,$suffixe){
+	global $WCalendar_independants;	
+	$WCalendar_independants[] = array('titre'=>$titre,'suffixe'=>$suffixe);
+}
+function WCalendar_ajoute_lies($titre_debut,$suffixe_debut,$titre_fin,$suffixe_fin){
+	global $WCalendar_lies;	
+	$WCalendar_lies[] = array('titre1'=>$titre_debut,'suffixe1'=>$suffixe_debut,
+														'titre2'=>$titre_fin,'suffixe2'=>$suffixe_fin);
+}
+function WCalendar_ajoute_statique($titre,$suffixe){
+	global $WCalendar_statiques;	
+	$WCalendar_statiques[] = array('titre'=>$titre,'suffixe'=>$suffixe);
+}
+function WCalendar_statique_point_entree($suffixe, $dates = ""){
+	return "<div><div id='container$suffixe' style='z-index:5000;'></div>
+	<div style='display:none;'><textarea id='selected_date$suffixe' name='selected_date$suffixe'>$dates</textarea></div>
+	<a href='javascript:cal$suffixe.reset()'>Reset</a>"
+	//. "<a href='javascript:alert(cal$suffixe.getSelectedDates())'>what's selected?</a>"
+	. "</div>
+	";
+}
+
+
+function WCalendar_header($flux,$onload=""){
+	global $init_functions;
+	$init_functions = $onload;
+	include_spip('inc/calendar_init');
+	return WCalendar_header_prive($flux);
+}
+function WCalendar_body($flux){
+	include_spip('inc/calendar_init');
+	return WCalendar_body_prive($flux);
+}
+
+function WCalendar_controller($date,$suffixe){
+	if (strcmp($date,format_mysql_date())==0)
+		$date=date("Y-m-d H:i:s");
+	$s = "<a href='javascript:void(null)' onclick='showCalendar$suffixe()'>
+	<img id='dateLink$suffixe' src='"._DIR_IMG_PACK."/cal-jour.gif' border='0' style='vertical-align:middle;margin:5px'/></a>
+	";
+	$s .=
+	  afficher_jour(jour($date), "id='jour$suffixe' name='jour$suffixe' size='1' class='fondl verdana1' onchange='changeDate$suffixe()'") .
+    afficher_mois(mois($date), "id='mois$suffixe' name='mois$suffixe' size='1' class='fondl verdana1' onchange='changeDate$suffixe()'") .
+    afficher_annee(annee($date), "id='annee$suffixe' name='annee$suffixe' size='1' class='fondl verdana1' onchange='changeDate$suffixe()'", date('Y')-_WIDGET_CALENDAR_BACK_IN_TIME);
+  return $s;
+}
+
+function WCalendar_statique_controller($dates,$suffixe){
+	if (is_array($dates))
+		$dates = implode(',',$dates);
+  return WCalendar_statique_point_entree($suffixe, $dates);
+}
+
+?>
Index: plugins/widget_calendar_1_9/inc/calendar_init.php
===================================================================
--- plugins/widget_calendar_1_9/inc/calendar_init.php	(revision 6)
+++ plugins/widget_calendar_1_9/inc/calendar_init.php	(revision 6)
@@ -0,0 +1,291 @@
+<?php
+
+$p=explode(basename(_DIR_PLUGINS)."/",str_replace('\\','/',realpath(dirname(dirname(__FILE__)))));
+define('_DIR_PLUGIN_WIDGET_CALENDAR',(_DIR_PLUGINS.end($p)));
+
+function WCalendar_point_entree($suffixe){
+	return "<div id='container$suffixe' style='position:absolute;display:none;z-index:5000;'></div>
+	";
+}
+
+function WCalendar_body_prive($flux){
+	global $WCalendar_independants,$WCalendar_lies;
+	if (count($WCalendar_independants)+count($WCalendar_lies)){
+		$flux.= "<script type='text/javascript'>window.onload = init;</script>";
+		foreach($WCalendar_independants as $infos)
+			$flux .= WCalendar_point_entree($infos['suffixe']);
+		foreach($WCalendar_lies as $infos){
+			$flux .= WCalendar_point_entree($infos['suffixe1']);
+			$flux .= WCalendar_point_entree($infos['suffixe2']);
+		}
+	}
+	return $flux;
+}
+
+function WCalendar_statique_jsinit($t, $s){
+	$vars = "
+			var cal$s;";
+	$js_a = "";
+	$js_b = "
+			var selected$s = '';
+			this.content$s = document.getElementById('selected_date$s');
+			if (this.content$s){
+				selected$s=this.content$s.innerHTML;
+			}
+			cal$s = new SPIP.widget.Calendar2up_INT_multi('cal$s','container$s','',selected$s);
+			cal$s.title = '$t';
+			cal$s.sync();
+			cal$s.render();
+			";
+	$js_c = "
+		function getSelectedDate$s() {
+			var res = document.getElementById('selected_date$s');
+			res.innerHTML = cal$s.getSelectedDates();
+		}
+	";
+	return array($vars,$js_a,$js_b,$js_c);
+}
+
+function WCalendar_jsinit($t, $s){
+	$vars = "
+			var cal$s;";
+	$js_a = "
+			if (cal$s)
+				cal$s.hide();";
+	$js_b = "
+			this.link$s = document.getElementById('dateLink$s');
+			if (this.link$s){
+				this.selYear$s = document.getElementById('annee$s');
+				this.selMonth$s = document.getElementById('mois$s');
+				this.selDay$s = document.getElementById('jour$s');
+				thisYear$s = this.selYear$s.selectedIndex+parseInt(this.selYear$s.options[0].value);
+				thisMonth$s = this.selMonth$s.selectedIndex;
+				thisDay$s = this.selDay$s.selectedIndex +1;
+				cal$s = new SPIP.widget.Calendar2up_INT('cal$s','container$s',(thisMonth$s+1)+'/'+thisYear$s,(thisMonth$s+1)+'/'+thisDay$s+'/'+thisYear$s);
+				cal$s.title = '$t';
+				cal$s.setChildFunction('onSelect',setDate$s);
+				cal$s.render();
+			}
+			";
+	$js_c = "
+		function showCalendar$s() {
+			hideall();
+			cal$s.outerContainer.style.top = (link$s.height-1+findPosY(link$s)) + 'px';
+			cal$s.outerContainer.style.left = (findPosX(link$s)) + 'px';
+			cal$s.outerContainer.style.display='block';
+		}
+		";
+	return array($vars,$js_a,$js_b,$js_c);
+}
+function WCalendar_js_verifie_lies($sd,$sf){
+	return "
+		function verifie_date$sd$sf(modif){
+			var Date$sd = new Date;
+			Date$sd.setFullYear(this.selYear$sd.selectedIndex+parseInt(selYear$sd.options[0].value));
+			Date$sd.setMonth(this.selMonth$sd.selectedIndex);
+			Date$sd.setDate( this.selDay$sd.selectedIndex + 1);
+			var Date$sf = new Date;
+			Date$sf.setFullYear(this.selYear$sf.selectedIndex+parseInt(selYear$sf.options[0].value));
+			Date$sf.setMonth(this.selMonth$sf.selectedIndex);
+			Date$sf.setDate( this.selDay$sf.selectedIndex + 1);
+			if (Date$sf<Date$sd){
+				if (modif==1){
+					selYear$sf.selectedIndex=selYear$sd.selectedIndex;
+					selMonth$sf.selectedIndex=selMonth$sd.selectedIndex;
+					selDay$sf.selectedIndex=selDay$sd.selectedIndex;
+					cal$sf.select((Date$sd.getMonth()+1) + '/' + (Date$sd.getDate()) + '/' + (Date$sd.getFullYear()));
+					cal$sf.setMonth(Date$sd.getMonth());
+					cal$sf.setYear(Date$sd.getFullYear());
+					cal$sf.render();
+				}
+				else{
+					selYear$sd.selectedIndex=selYear$sf.selectedIndex;
+					selMonth$sd.selectedIndex=selMonth$sf.selectedIndex;
+					selDay$sd.selectedIndex=selDay$sf.selectedIndex;
+					cal$sd.select((Date$sf.getMonth()+1) + '/' + (Date$sf.getDate()) + '/' + (Date$sf.getFullYear()));
+					cal$sd.setMonth(Date$sf.getMonth());
+					cal$sd.setYear(Date$sf.getFullYear());
+					cal$sd.render();
+				}
+			}
+		}
+		";
+}
+function Wcalendar_js_set_change_date($s,$sdverif=NULL,$sfverif=NULL,$modif=""){
+	return "
+		function setDate$s() {
+			var date$s = cal$s.getSelectedDates()[0];
+			selYear$s.selectedIndex=date$s.getFullYear()-parseInt(selYear$s.options[0].value);
+			selMonth$s.selectedIndex=date$s.getMonth();
+			selDay$s.selectedIndex=date$s.getDate()-1;
+			cal$s.hide();
+			" .
+			($sdverif!=NULL?"verifie_date$sdverif$sfverif($modif);":"") ."
+		}
+
+		function changeDate$s() {
+			var month = this.selMonth$s.selectedIndex;
+			var day = this.selDay$s.selectedIndex + 1;
+			var year = this.selYear$s.selectedIndex+parseInt(selYear$s.options[0].value);
+			cal$s.reset();
+			cal$s.clear();
+			cal$s.select((month+1) + '/' + day + '/' + year);
+			cal$s.setMonth(month);
+			cal$s.setYear(year);
+			cal$s.render();
+			" .
+			($sdverif!=NULL?"verifie_date$sdverif$sfverif($modif);":"") ."
+		}
+		";
+}
+function WCalendar_header_prive($flux) {
+	global $WCalendar_independants,$WCalendar_lies,$WCalendar_statiques;
+	global $spip_lang_right;
+	if (count($WCalendar_independants)+count($WCalendar_lies)){
+		// Remplace les entités litérales
+		$trans_tbl = get_html_translation_table (HTML_ENTITIES);
+		$trans_tbl = array_flip ($trans_tbl);
+		
+		// les includes JS statiques
+		$flux .= "<script src = '"._DIR_PLUGIN_WIDGET_CALENDAR."/img_pack/SPIP.js' ></script>\n";
+		$flux .= "<script src = '"._DIR_PLUGIN_WIDGET_CALENDAR."/img_pack/dom.js' ></script>\n";
+		$flux .= "<script src = '"._DIR_PLUGIN_WIDGET_CALENDAR."/img_pack/event.js' ></script>\n";
+		$flux .= "<script src = '"._DIR_PLUGIN_WIDGET_CALENDAR."/img_pack/calendar.js' ></script>\n";
+		$flux .= "<script src = '"._DIR_PLUGIN_WIDGET_CALENDAR."/img_pack/calendar_custom.js' ></script>\n";
+		$flux .= '<link rel="stylesheet" href="' ._DIR_PLUGIN_WIDGET_CALENDAR . '/img_pack/calendar.css" type="text/css" />'. "\n";
+
+		// les noms de mois et de jour selon les fichiers de langue :
+		$months_long = "";
+		$months_short = "";
+		for ($j=1;$j<=12;$j++){
+			$nom = entites_html(ucfirst(strtr(_T("spip:date_mois_$j"),$trans_tbl)));
+			$months_long .= ",'".unicode2charset(charset2unicode($nom,''))."'";
+			$months_short .= ",'".unicode2charset(charset2unicode(preg_replace("/^((&#x?[0-9]{2,5};|.){0,3}).*$/i","\\1",$nom),''))."'";
+		}
+		$months_long = substr($months_long,1);
+		$months_short = substr($months_short,1);
+
+		$days_long = "";
+		$days_medium = "";
+		$days_short = "";
+		$days_1char = "";
+		for ($j=1;$j<=7;$j++){
+			$nom = entites_html(ucfirst(strtr(_T("spip:date_jour_$j"),$trans_tbl)));
+			$days_long .= ",'".$nom."'";
+			$days_medium .= ",'".preg_replace("/^((&#x?[0-9]{2,5};|.){0,3}).*$/i","\\1",$nom)."'";
+			$days_short .= ",'".preg_replace("/^((&#x?[0-9]{2,5};|.){0,2}).*$/i","\\1",$nom)."'";
+			$days_1char .= ",'".preg_replace("/^((&#x?[0-9]{2,5};|.){0,1}).*$/i","\\1",$nom)."'";
+		}
+		$days_long = substr($days_long,1);
+		$days_medium = substr($days_medium,1);
+		$days_short = substr($days_short,1);
+		$days_1char = substr($days_1char,1);
+		$start_weekday = 1;
+		$img_arrow_left = _DIR_PLUGIN_WIDGET_CALENDAR."/img_pack/callt.gif";
+		$img_arrow_right = _DIR_PLUGIN_WIDGET_CALENDAR."/img_pack/calrt.gif";
+		$img_close = _DIR_PLUGIN_WIDGET_CALENDAR."/img_pack/calx.gif";
+
+
+	// le JS dynamique d'init
+	$flux .= "<script language='javascript'>";
+
+	// partie fonction de la langue
+	$js = "";
+
+	$js .= "	
+		SPIP.widget.Calendar2up_INT_Cal.prototype.customConfig = function() {
+			this.Config.Locale.MONTHS_SHORT = [$months_short];
+			this.Config.Locale.MONTHS_LONG = [$months_long];
+			this.Config.Locale.WEEKDAYS_1CHAR = [$days_1char];
+			this.Config.Locale.WEEKDAYS_SHORT = [$days_short];
+			this.Config.Locale.WEEKDAYS_MEDIUM = [$days_medium];
+			this.Config.Locale.WEEKDAYS_LONG = [$days_long];
+		
+			this.Config.Options.START_WEEKDAY = $start_weekday;
+			this.Config.Options.NAV_ARROW_LEFT = '$img_arrow_left';
+			this.Config.Options.NAV_ARROW_RIGHT = '$img_arrow_right';
+			this.Config.Options.IMG_CLOSE = '$img_close';
+			this.Config.Options.IMG_CLOSE_CLASS = 'close-icon-$spip_lang_right';
+		}
+		";
+
+	$js .= "	
+		SPIP.widget.Calendar2up_INT_Cal_multi.prototype.customConfig = function() {
+			this.Config.Locale.MONTHS_SHORT = [$months_short];
+			this.Config.Locale.MONTHS_LONG = [$months_long];
+			this.Config.Locale.WEEKDAYS_1CHAR = [$days_1char];
+			this.Config.Locale.WEEKDAYS_SHORT = [$days_short];
+			this.Config.Locale.WEEKDAYS_MEDIUM = [$days_medium];
+			this.Config.Locale.WEEKDAYS_LONG = [$days_long];
+		
+			this.Config.Options.START_WEEKDAY = $start_weekday;
+			this.Config.Options.NAV_ARROW_LEFT = '$img_arrow_left';
+			this.Config.Options.NAV_ARROW_RIGHT = '$img_arrow_right';
+			this.Config.Options.MULTI_SELECT = true;
+		}
+		";
+	
+		// construire les variables et fonctions de mise a jour
+
+		$vars = "";
+		$js_a= "";	
+		$js_b= "";	
+		$js_c= "";	
+		$liste_suffixes = array();
+		foreach ($WCalendar_statiques as  $infos){
+			$s = $infos['suffixe'];
+			$t = $infos['titre'];
+			list($v,$a,$b,$c) = WCalendar_statique_jsinit($t, $s);
+			$vars .= $v; $js_a .= $a; $js_b .= $b;$js_c .= $c;
+		}
+		foreach ($WCalendar_independants as  $infos){
+			$s = $infos['suffixe'];
+			$t = $infos['titre'];
+			list($v,$a,$b,$c) = WCalendar_jsinit($t, $s);
+			$vars .= $v; $js_a .= $a; $js_b .= $b;$js_c .= $c;
+		}
+		foreach ($WCalendar_lies as  $infos){
+			$s = $infos['suffixe1'];
+			$t = $infos['titre1'];
+			list($v,$a,$b,$c) = WCalendar_jsinit($t, $s);
+			$vars .= $v; $js_a .= $a; $js_b .= $b;$js_c .= $c;
+
+			$s = $infos['suffixe2'];
+			$t = $infos['titre2'];
+			list($v,$a,$b,$c) = WCalendar_jsinit($t, $s);
+			$vars .= $v; $js_a .= $a; $js_b .= $b;$js_c .= $c;
+		}
+		global $init_functions;
+		$js .= "
+		$vars
+		function hideall(){
+			$js_a
+		}
+		function init() {
+			$init_functions
+			$js_b
+		}
+		
+		$js_c
+		";
+		foreach ($WCalendar_independants as  $infos){
+			$s = $infos['suffixe'];
+			$js .= Wcalendar_js_set_change_date($s);
+		}
+
+		foreach ($WCalendar_lies as  $infos){
+			$sd = $infos['suffixe1'];
+			$sf = $infos['suffixe2'];
+			$js .= WCalendar_js_verifie_lies($sd,$sf);
+			$js .= Wcalendar_js_set_change_date($sd,$sd,$sf,1);
+			$js .= Wcalendar_js_set_change_date($sf,$sd,$sf,2);
+		}
+		
+		$js .= "
+	</script>";
+		$flux .= $js;
+	}
+	return $flux;
+}
+
+?>
Index: plugins/widget_calendar_1_9/license.txt
===================================================================
--- plugins/widget_calendar_1_9/license.txt	(revision 6)
+++ plugins/widget_calendar_1_9/license.txt	(revision 6)
@@ -0,0 +1,35 @@
+Software License Agreement (BSD License)
+
+Copyright (c) 2006, Yahoo! Inc.
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms, with 
+or without modification, are permitted provided that the following 
+conditions are met:
+
+* Redistributions of source code must retain the above
+  copyright notice, this list of conditions and the
+  following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+  copyright notice, this list of conditions and the
+  following disclaimer in the documentation and/or other
+  materials provided with the distribution.
+
+* Neither the name of Yahoo! Inc. nor the names of its
+  contributors may be used to endorse or promote products
+  derived from this software without specific prior
+  written permission of Yahoo! Inc.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
+IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
+OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
Index: plugins/widget_calendar_1_9/plugin.xml
===================================================================
--- plugins/widget_calendar_1_9/plugin.xml	(revision 6)
+++ plugins/widget_calendar_1_9/plugin.xml	(revision 6)
@@ -0,0 +1,40 @@
+<plugin>
+	<nom> <!-- Nom du plugin -->
+	Widget Calendrier
+	</nom>
+	<auteur>	<!-- Auteur du plugin -->
+	Cedric MORIN - [notre-ville.net->http://www.notre-ville.net]
+_ 2006 - Distribu&eacute; sous licence GPL
+	</auteur>
+	<version>
+	0.1
+	</version>
+	<etat>
+	stable
+	</etat>
+	<description>
+	Un Widget Calendrier pret a l'emploi pour saisir vos dates
+	</description>
+	<fonctions>
+	inc/calendar.php
+	</fonctions>
+	<!-- classe d'implementation : espace de nommage qui prefixera les appels de fonction
+	sur le mode Rien::
+	ainsi les fonctions hors espace de nommage ne peuvent etre appelees
+	ce parametre est obligatoire et doit etre non vide
+	-->
+	<prefix> 
+	WCalendar
+	</prefix>
+	<!-- Definitions des fonctions qui s'inserent dans les pipelines -->
+	<pipeline>
+		<nom>header_prive</nom>
+		<inclure>inc/calendar_init.php</inclure>
+	</pipeline>
+	<pipeline>
+		<nom>body_prive</nom>
+		<inclure>inc/calendar_init.php</inclure>
+	</pipeline>
+
+	<!-- Le parametre action est facultatif : en son absence la methode de la classe portant le nom du pipeline est appelee. Le parametre inclure est facultatif.	-->
+</plugin>
Index: plugins/widget_calendar_1_9/svn.revision
===================================================================
--- plugins/widget_calendar_1_9/svn.revision	(revision 6)
+++ plugins/widget_calendar_1_9/svn.revision	(revision 6)
@@ -0,0 +1,3 @@
+Origine svn://zone.spip.org/spip-zone/_plugins_branche_stable_/_spip_1_9_0_/widget_calendar le mer sep  6 00:09:12 CEST 2006
+Revision 5125
+Dernier commit mar sep  5 20:29:42 CEST 2006
