Texture d'étalonnage

Le 28 Février 2005 à 23:39

Objectif

La macro setupMetricTextureKit

Cette macro définit un certain nombre de textures permettant de se visualiser les dimensions d'un objet. On considère qu'une unité équivaut à 1 mètre.

Si l'objet est déformé, la texture sera aussi déformée, il faudra tenir compte de cet effet.

Paramètres

baseTexture
Texture de base, par dessus laquelle on ajoute notre quadrillage.
backgroundColor
Couleur de fond, utilisée pour le calcul de la couleur du quadrillage 0.1 et 0.2
rulerColor
Couleur du quadrillage, utilisée pour le calcul de la couleur du quadrillage 1, 0.1 et 0.2
rulerWidth
Largeur du trait, en mm

Image de test

Test des textures métriques

Téléchargement

L'archive (MetricTextures.zip) contient tout le nécessaire pour générer l'image de test.

Résumé

Méthode pour créer une planète avec les patterns standards et les isosurfaces

Raisonnement

L'idée de base est la suivante : on peut utiliset les patterns standards de POVRay pour générer des terrains (heightfields par exemple), alors pourquoi ne pas faire la meme chose pour générer une planète ? On voudrait donc partir d'une sphère, et pour point de la sphère est éloigné du centre en fonction de la valeur donnée par une texture appliquée sur la sphère. Comme il n'y a pas de primitive pour ce la, on utilisera les isosurfaces

Equation de la sphère

On rappelle que l'équation d'une sphère est : x2+y2+z2=R2, avec R > 0 le rayon de la sphère. Pour simplifier, on prendra R = 1

Valeur du motif sur la sphère de rayon 1

Soit f la fonction représentant le pattern. Posons r = sqrt(x2+y2+z2) la distance d'un point M(x,y,z) à l'origine. Alors la valeur du pattern sur la sphère est f(x/r,y/r,z/r)

Equation de la planète

Soit 0 < a < 1 un coefficient utilisé pour combiner la sphère et le pattern. L'équation de la planète est alors : x2+y2+z2=a × R2 + (1 − a) × f(x/r,y/r,z/r)

Exemple

Extrait de code

#declare f_pattern = function{pattern{crackle form <1,0,0> poly_wave 2 turbulence 0.5 scale 0.5}}
#declare f_planete = function(x,y,z,r){x*x + y*y + z*z -(0.91 + 0.08 * f_pattern(x/r,y/r,z/r))}
#declare f_isosurface = function {f_planete(x,y,z,sqrt(x*x+y*y+z*z))}

isosurface {
    function { f_isosurface(x,y,z) }
    contained_by {sphere{0,1}}
    max_gradient 2.6

    //...etc...
}

Résultat

résultat obtenu avec l'extrait de code précédent

Réglage d'une caméra "réaliste"

Le 28 Février 2005 à 23:34

Objectif

On veut régler les paramètres d'une caméra pour simuler la géométrie d'un véritable appareil photo ou d'une caméra de cinéma.

Rappel sur le modèle suivi par la directive camera

Dans Povray, la directive camera définit une pyramide à base rectangulaire. Le sommet est l'origine des rayons qui sont lancés, et le pixel résultant pour le lancé d'un rayon est projeté sur la base.

Mise en oeuvre

Pour simuler un appareil photo ou une caméra, on va dimensionner la pyramide pour correspondre à la surface de la pellicule (pour la base de la pyramide). La hauteur de la pyramide correspondra à la distance focale.

A noter

Pour une largeur de 36mm, une distance focale d'environ 60mm reproduit la vision humaine. J'ai obtenu cette valeur en regardant dans le viseur d'un appareil photo Reflex et en laissant le deuxième oeil ouvert, jusqu'à ce l'image dans le viseur aie le même aspect que pour l'oeil libre.

Paramètres

focale
Distance en mm entre le centre optique et la "pellicule".
film
Largeur en mm de la "pellicule"
format
Rapport largeur/hauteur de la pellicule (p.ex. 16/9, 4/3, 3/2, etc...)

Exemple d'utilisation

#include "realcamera.inc"

//etc...

camera
{
    location  <.6 , 1.7 ,.1>
    setupRealCamera(60, 22, image_width/image_height)
    look_at   <2 , 1.0 , 2.5>
}

Code Source

//utiliser dans une camera, avant look_at
//focale : distance en mm du centre optique à la pellicule
//film : largeur en mm de la pellicule
//format : rapport largeur/hauteur de l'image (ex : 16/9, 4/3, 3/2)
#macro setupRealCamera(focale, film, format)
    #local myFocale = focale / 1000 ;
    #local myRight = film / 1000 ;
    #local myUp = myRight / format ;

    direction     myFocale        * z
    up            myUp            * y
    right         myRight         * x  
#end

Numéro de mars 2005

Le 28 Février 2005 à 18:40

Embrigadé à l'insu de mon plein gré, voici le nouveau mensuel indispensable aux instants WC : Chiot'Mag !

Télécharger Chiot'Mag

Fin de la grippe

Le 24 Février 2005 à 04:47

Crénom, cette grippe m'a bouffé une journée de vacances en m'obligeant à glander...

Mû par une inspiration soudaine, Sporniket.com change de peau...

Règles Adblock

Le 22 Février 2005 à 13:00

Mise à jour de la liste des règles

Modélisation d'un bookmark

Le 17 Février 2005 à 21:44

Objectifs

Gérer une liste de liens pour un site web. Les liens doivent être rangés par catégorie, et les catégories peuvent être imbriquées. Génération d'une portion de code HTML correspondant à la liste.

Modélisation

On doit modéliser 2 entités : les liens et les catégories

Les catégories

Modèlisation de la table URL_CATEGORY
Colonne Type Gestion Commentaires
SID Nombre Entier SID > 0 Auto-incrémentée
GID_PATH 256 caractères maximum /((/[0-9A-Za-z]+)+)|(/)/ "Chemin de la catégorie" : '/' + liste des GID_NAME des ancêtres séparé par '/', du plus ancien jusqu'à la mère.
GID_NAME 256 caractères maximum /[0-9A-Za-z]+/ Nom de la catégorie. La taille maximum pour le nom : 256 - strlen(GID_PATH).
PID Nombre Entier PID >= 0 Si PID > 0, fait référence à un SID existant
RANK Nombre Entier RANK >= 0 Ordre d'affichage. On tri par RANK puis par LABEL pour un PID ou un GID_PATH donné.
LABEL texte libre Nom affiché de la catégorie.
DESCRIPTION texte libre Texte libre.

Les liens

Modèlisation de la table URL_ITEM
Colonne Type Gestion Commentaires
SID Nombre Entier SID > 0 Auto-incrémentée
GID 256 caractères maximum URL valide L'adresse web (URL)
PID Nombre Entier PID >= 0 Si PID > 0, fait référence à un URL_CATEGORY.SID existant
RANK Nombre Entier RANK >= 0 Ordre d'affichage. On tri par RANK puis par LABEL pour un PID ou un GID_PATH donné.
LABEL texte libre Titre du site.
DESCRIPTION texte libre Texte libre, description du site, bannière, etc...
STICKY_RANK Nombre Entier STICKY_RANK >= 0 Marque les liens à mettre en evidence. La valeur détermine l'ordre d'affichage
NEW Nombre Entier 0 ou 1 Marque les liens à afficher comme "nouveaux". Le classement est effectué en fonction de CREATION_DATE.
CREATION_DATE 12 caractères Date (AAAAMMJJHHmm) Date officielle de création du lien
UPDATE Nombre Entier 0 ou 1 Marque les liens à afficher comme "mis à jour". Le classement est effectué en fonction de MODIFICATION_DATE.
MODIFICATION_DATE 12 caractères Date (AAAAMMJJHHmm) Date officielle de dernière modification du lien.

Objectifs

On veut écrire une application multilingue pour s'adapter à l'utilisateur, ou bien on veut permettre la traduction d'une application en limitant l'effort à fournir.

Solution

En utilisant un dictionnaire de messages, on peut rassembler tous les messages dans un seul script, et créer des version traduites. Pour les gros messages, utiliser la syntaxe "here doc" pour améliorer la lisibilité.

De plus, en choisissant dès le départ l'encodage utf-8, on évite les problèmes d'encodages disparates.

Code Source

<?
/*
(c)2004 David Sporn

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License version 2.1 as published by the Free Software Foundation.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

$messages = array();
//Error messages
$messages["ERROR_MYSQL_CONNECT"] = "Impossible de se connecter.";
$messages["ERROR_MYSQL_SELECT_DB"] = "Impossible de choisir la base.";
$messages["ERROR_QUERY_DO_NOT_EXIST"] = "L'objet demand&eacute; n'existe pas.";
$messages["ERROR_NO_DATA"] = "Pas de donn&eacute;es." ;

//App title
$messages["TITLE"] = "VirtualPage Manager v0.2.0";

//Action Label
$messages["LABEL_GOTO_EDIT"] = "Modifier";
$messages["LABEL_GOTO_NEW"] = "Ajouter une page";
$messages["LABEL_GOTO_VIEW"] = "Retour &agrave; la liste";
$messages["LABEL_GOTO_DELETE"] = "Supprimer";
$messages["LABEL_GOTO_PREVIEW"] = "Pr&eacute;visualiser";
$messages["LABEL_GOTO_RESUME"] = "Reprendre";

//Directions
$messages["DIRECTION_CONFIRM_DELETE"] = "Confirmer la suppression en cliquant sur \"Supprimer\".";
$messages["DIRECTION_COPYRIGHT"] = "&copy;2004 David Sporn";
$messages["DIRECTION_LICENSE"] = <<< EOF
<p>Ce logiciel est libre; vous pouvez le redistribuer et/ou le
modifier selon les termes du contrat GNU General Public License
version 2.1 tel qu'il est publi&eacute; par la Free Software Foundation.
</p>
<p>Ce logiciel est distribu&eacute; dans l'espoir qu'il se 
r&eacute;v&egrave;lera utile, mais SANS AUCUNE GARANTIE; pas m&ecirc;me
une garantie implicite de COMMERCIABILIT&Eacute; ou d'AD&Eacute;QUATION 
&Agrave; UN BUT PARTICULIER. Pour plus de d&eacute;tails, consultez le
contrat GNU General Public License.
</p>
<p>Vous devez avoir re&ccedil;u un exemplaire du contrat GNU General Public License
avec ce logiciel; sinon, &eacute;crivez &agrave; la Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
</p>
EOF;
$messages["DIRECTION_BROWSER"] = <<< EOF
Visuellement optimal avec un navigateur respectant 
<strong>compl&egrave;tement</strong> les standards 
<a href="http://validator.w3.org/check/referer">XHTML 1.0</a>, 
<a href="http://jigsaw.w3.org/css-validator/check/referer">CSS 2.1</a> 
et <a href="http://www.w3.org/Graphics/PNG/">PNG</a>.
EOF;

//Form fields
$messages["FORM_TITLE"] = "Fiche VirtualPage";
$messages["FORM_ENTRY"] = "Url";
$messages["FORM_LABEL"] = "Libell&eacute;";
$messages["FORM_DATA"] = "Data";
$messages["FORM_MENU"] = "Menu";
$messages["FORM_FIRST"] = "Premi&egrave;re page";
$messages["FORM_PREVIOUS"] = "Page pr&eacute;c&eacute;dente";
$messages["FORM_NEXT"] = "Page suivante";
$messages["FORM_LAST"] = "Derni&egrave;re page";
$messages["FORM_TYPE"] = "Type";
$messages["FORM_TYPE_VALUE_0"] = "Code XHTML";
$messages["FORM_TYPE_VALUE_1"] = "Code PHP";
$messages["FORM_TYPE_VALUE_2"] = "Url externe";
$messages["FORM_SUBMIT"] = "Envoyer";
$messages["FORM_PREVIEW"] = "Pr&eacute;visualisation";

?>

(Modèle) LinkerXxx

Le 17 Février 2005 à 11:19

Objectifs

Cette classe isole la construction des liens dans l'application. L'avantage de cette approche apparaît lorsque la nomenclature des liens changes : il suffit de réimplémenter la classe, sans toucher à l'application. On peut aussi décider d'utiliser des URLs classique (avec des paramètres d'URL) ou des URLs réécrites (module mod_rewrite d'Apache).

En revanche, il y a un couplage fort entre cette classe et l'examen des paramètres de l'URL : si le changement introduit une nouvelle nomenclature de paramètres, des changements de formats pour les paramètres existants, il faut revoir cette portion également. D'ou l'intérêt d'isoler également l'examen de ces paramètres.

Enfin, tout changement de l'API existente dans la classe a bien évidemment des répercussion dans toute l'application.

Choix de l'implémentation

Tous les liens de l'applications doivent être construits par la classe. Habituellement, on pourra distinguer 3 parties dans un lien :

La base
C'est le préfixe présent dans tous les liens de l'application. Par exemple http://www.mondomaine.com/monappli/
Le script
A partir de la base, le chemin du script à executer, par exemple module/monscript.php
Les paramètres
La liste des paramètres transmis à la page, par exemple ?userId=toto&action=login.

La base est renseignée dans le constructeur de la classe. Ensuite, pour chaque script, il faut rajouter une fonction de construction des liens, par exemple getMonScript(...). Les paramètres dépendent des fonctionnalités.

On se retrouve ensuite à choisir entre 2 stratégies :

  1. Implémenter la construction de tous les liens dans une seule classe.
  2. Implémenter une classe par script, ou même par action.

Dans le premier cas, le nombre de fonctions se multiplie avec l'augmentation du nombre de liens différents à créer (scripts, fonctions, etc...)

Dans le deuxième cas, c'est le nombre de classes qui se multiplient.

La stratégie la plus probable sera donc une combinaison des deux stratégies, a savoir des constructions de liens regroupés, par exemple, par fonctionnalité, ou par script.

Code source

<?php
/*
(c)2004 David Sporn

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License version 2.1 as published by the Free Software Foundation.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

class LinkerXxx
{
	var myTopPage ;
	
	function LinkerXxx($baseUrl)
	{
		$this->myTopPage = $baseUrl.'index.html' ;
	}
	
	function getTopPage()
	{
		return $this->myTopPage ;
	}
}
?>

Objectifs

Afin de renvoyer au client le contenu le plus adapté, on va examiner ses capacités. Deux objectifs pour cette première version :

  1. Examen des langues acceptées, afin de servir si possible dans la langue du client.
  2. Examen des contenus acceptés, ce qui peut permettre, par exemple, de renvoyer un contenu en XHTML ou en WML.

Code source

<?php
/*
(c)2004 David Sporn

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License version 2.1 as published by the Free Software Foundation.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

class UserAgentCapabilities
{
	var myLanguages ;
	var myAccepts ;
	
	function UserAgentCapabilities()
	{
		//Init languages capabilities
		$this->myLanguages = array() ;
		if (@$_SERVER["HTTP_ACCEPT_LANGUAGE"])
		{
			$langs_list = explode(',',@$_SERVER["HTTP_ACCEPT_LANGUAGE"]) ;// each language is separated by a ","
			foreach($langs_list as $lang_item)
			{
				$lang_parts = explode(';',$lang_item) ; //the pattern is "lang[;q=quality]"
				if (!preg_match('/^[a-z]{1,8}(?:[-][a-z]{1,8}){0,8}$/i', $lang_parts[0])) //skip invalid language names or too long names
				{
					continue ;
				}
				$quality_value = (float)1.0 ; //Default value
				if (1 < $lang_parts.length)
				{
					if (preg_match('/q=(0(?:.d{1,3})?)|(1(?:.[0]{1,3})?)/', $lang_parts[1],$values_array))
					{
						$quality_value = (float)$values_array[1] ;
					}
				}
				if ($this->myLanguages[$quality_value])
				{
					$this->myLanguages[$quality_value] += ','.$lang_parts[0] ;
				}
				else
				{
					$this->myLanguages[$quality_value] = $lang_parts[0] ;
				}
			}
			krsort($this->myLanguages) ;
		}
		
		//Init accept-content capabilities
		/*
		source : http://www.ietf.org/rfc/rfc1700.txt
		
		Recognized Content Types and Subtypes (exhaustive)
		--------------------------------------------------
		
		Type            Subtype         Description                 Reference
		----            -------         -----------                 ---------
		text            plain                                   [RFC1521,NSB]
		                xml                                               [?]
		                html                                              [?]
		
		application     octet-stream                            [RFC1521,NSB]
		                xml                                               [?]
		                xhtml+xml                                         [?]
		
		image           jpeg                                    [RFC1521,NSB]
		                gif                                     [RFC1521,NSB]
		                png                                               [?]
		

		Generic types (text/*, application/* and image/* are also recognized)
		
		Not recognised Content Types and Subtypes (non exhaustive)
		--------------------------------------------------
		
		Type            Subtype         Description                 Reference
		----            -------         -----------                 ---------
		text            richtext                                [RFC1521,NSB]
		                tab-separated-values                   [Paul Lindner]

		multipart       mixed                                   [RFC1521,NSB]
		                alternative                             [RFC1521,NSB]
		                digest                                  [RFC1521,NSB]
		                parallel                                [RFC1521,NSB]
		                appledouble                [MacMime,Patrik Faltstrom]
		                header-set                             [Dave Crocker]
		
		message         rfc822                                  [RFC1521,NSB]
		                partial                                 [RFC1521,NSB]
		                external-body                           [RFC1521,NSB]
		                news                        [RFC 1036, Henry Spencer]
		
		image           ief             Image Exchange Format       [RFC1314]
		                tiff            Tag Image File Format           [MTR]
		
		application     postscript                              [RFC1521,NSB]
		                oda                                     [RFC1521,NSB]
		                atomicmail                           [atomicmail,NSB]
		                andrew-inset                       [andrew-inset,NSB]
		                slate                           [slate,terry crowley]
		                wita              [Wang Info Transfer,Larry Campbell]
		                dec-dx            [Digital Doc Trans, Larry Campbell]
		                dca-rft        [IBM Doc Content Arch, Larry Campbell]
		                activemessage                          [Ehud Shapiro]
		                rtf                                    [Paul Lindner]
		                applefile                  [MacMime,Patrik Faltstrom]
		                mac-binhex40               [MacMime,Patrik Faltstrom]
		                news-message-id              [RFC1036, Henry Spencer]
		                news-transmission            [RFC1036, Henry Spencer]
		                wordperfect5.1                         [Paul Lindner]
		                pdf                                    [Paul Lindner]
		                zip                                    [Paul Lindner]
		                macwriteii                             [Paul Lindner]
		                msword                                 [Paul Lindner]
		                remote-printing                         [RFC1486,MTR]

		audio           basic                                   [RFC1521,NSB]
		
		video           mpeg                                    [RFC1521,NSB]
		                quicktime                              [Paul Lindner]

		*/
		$this->myAccepts = array() ;
		if (@$_SERVER["HTTP_ACCEPT"])
		{
			$pattern_any_type = '(\*/\*)' ;
			$pattern_text_type = '(text/(\*)|(html)|(xml)|(plain))' ;
			$pattern_image_type = '(image)/(\*)|(jpg)|(gif)|(jpeg)|(png)' ;
			$pattern_application_type = '(application)/(\*)|(octet-stream)|(xml)|(xhtml+xml)' ;

			$accepts_list = explode(',',@$_SERVER["HTTP_ACCEPT"]) ;// each content-type is separated by a ","
			foreach($accepts_list as $accept_item)
			{
				$accept_parts = explode(';',$accept_item) ; //the pattern is "lang[;q=quality]"
				if (!preg_match('/^'.$pattern_any_type.'|'.$pattern_text_type.'|'
					.$pattern_image_type.'|'.$pattern_application_type.'$/i'
					,$accept_parts[0])) //keep recognized type names only
				{
					continue ;
				}
				$quality_value = (float)1.0 ; //Default value
				if (1 < $accept_parts.length)
				{
					if (preg_match('/q=(0(?:.d{1,3})?)|(1(?:.[0]{1,3})?)/', $accept_parts[1],$values_array))
					{
						$quality_value = (float)$values_array[1] ;
					}
				}
				if ($this->myAccepts[$quality_value])
				{
					$this->myAccepts[$quality_value] += ','.$accept_parts[0] ;
				}
				else
				{
					$this->myAccepts[$quality_value] = $accept_parts[0] ;
				}
			}
			krsort($this->myAccepts) ;
		}
	}
	
	/**Get a comma separated list of languages.
	 * The returned list contains all the preferred languages of the user agent
	 * (with a quality value of 1).
	 */
	function getPreferredLanguages()
	{
		if ($this->myLanguages.length)
		{
			reset($this->myLanguages) ;
			return current($this->myLanguages)
		}
		else
		{
			return '' ;
		}
	}

	/**Get the best match among a list of specified language.
	 * The best match means that it has the best quality value here.
	 * If there are more that one answer, the first language in the
	 * provided list is returned.
	 * @param languages a list of language, the most preferred first.
	 * @return the language code that has the best match. Empty if the language does not exists.
	 */
	function getBestLanguage($languages)
	{
		$retour_language = '' ;
		$score_language = -1 ;
		if ($languages.length && $this->myLanguages.length)
		{
			//Looks for an exact match first
			foreach($languages as $candidate_language)
			{
				$language_index = 0 ;
				foreach($this->myLanguages.length as $languages_list)
				{
					if (0 <= $score_language && $language_index >= $score_language)
					{
						break ; //Not a better match
					}
					$languages_match = explode(',',$languages_list) ;
					foreach($languages_match as $languages_item)
					{
						if ($candidate_language == $languages_item)
						{
							$score_language = $language_index ;
							$retour_language = $candidate_language ;
							break 2; //WARNING//==> foreach($this->myLanguages.length as $languages_list)
						}
					}
					$language_index++ ;
				}
			}
			if (0 <= $score_language)
			{
				return $retour_language ; //Exact match
			}

			//Looks for an close match
			//for instance, 'fr-FR' is a close match for 'fr'
			foreach($languages as $candidate_language)
			{
				$language_index = 0 ;
				foreach($this->myLanguages.length as $languages_list)
				{
					if (0 <= $score_language && $language_index >= $score_language)
					{
						break ; //Not a better match
					}
					$languages_match = explode(',',$languages_list) ;
					foreach($languages_match as $languages_item)
					{
						if (stripos($candidate_language == $languages_item) == 0) //starts with $candidate_language
						{
							$score_language = $language_index ;
							$retour_language = $candidate_language ;
							break 2; //WARNING//==> foreach($this->myLanguages.length as $languages_list)
						}
					}
					$language_index++ ;
				}
			}
			if (0 <= $score_language)
			{
				return $retour_language ; //Exact match
			}
		}
		return '' ;
	}
	
	/**Get a comma separated list of languages.
	 * The returned list contains all the preferred languages of the user agent
	 * (with a quality value of 1).
	 */
	function getPreferredContentType()
	{
		if ($this->myAccepts.length)
		{
			reset($this->myAccepts) ;
			return current($this->myAccepts)
		}
		else
		{
			return '' ;
		}
	}
	
	/**Get the best match among a list of specified content type.
	 * The best match means that it has the best quality value here.
	 * If there are more that one answer, the first content type in the
	 * provided list is returned.
	 * @param contentTypes a list of content types, the most preferred first.
	 * @return the content type code that has the best match. Empty if the content type does not exists.
	 */
	function getBestContentType($contentTypes)
	{
		$retour_content_type = '' ;
		$score_content_type = -1 ;
		if ($contentTypes.length && $this->myAccepts.length)
		{
			//Looks for an exact match first
			foreach($contentTypes as $candidate_content_type)
			{
				$content_type_index = 0 ;
				foreach($this->myAccepts.length as $content_types_list)
				{
					if (0 <= $score_content_type && $content_type_index >= $score_content_type)
					{
						break ; //Not a better match
					}
					$content_types_match = explode(',',$content_types_list) ;
					foreach($content_types_match as $content_types_item)
					{
						if ($candidate_content_type == $content_types_item)
						{
							$score_content_type = $content_type_index ;
							$retour_content_type = $candidate_content_type ;
							break 2; //WARNING//==> foreach($this->myAccepts.length as $content_types_list)
						}
					}
					$content_type_index++ ;
				}
			}
			if (0 <= $score_content_type)
			{
				return $retour_content_type ; //Exact match
			}
		}
		return '' ;
	}
}
?>

source : No Software Patent

Nouvelle avanie dans l'histoire de la directive sur la brevetabilité des logiciels : Microsoft menace 800 emplois au Danemark si le gouvernement Danois s'oppose à l'adoption de la directive en point A (vote sans débat).

Mais Microsoft n'est pas le premier à le faire. Il ne fait qu'imiter Siemens, Nokia, Philips, Ericsson and Alcatel qui auraient suggérés, dans une lettre adressée au gouvernement Polonais, que leurs investissement dans ce pays ne se feraient qu'à condition que la Pologne cesse de s'opposer à la directive.

Autres sources

http://swpat.ffii.org/
Brevets logiciels en Europe.
http://www.ffii.fr/
Brevets logiciels en France.
http://kwiki.ffii.org/
Wiki sur les brevets logiciels.

Objectif

Isoler les traitements de bas niveau sur une table d'un base de données : sélection d'une ou plusieurs lignes avec retour partiel du résultat, insertion/mise à jour d'une ligne, suppression d'une ou plusieurs lignes.

Pour une table, on définit 3 classes

Filtre
La classe pour stocker les critères. Les critères permettent de construire la clause WHERE dans une requete de sélection ou de suppression.
Row
La classe pour stocker un enregistrement. On pourra notamment implémenter des contraintes, comme des listes de valeurs autorisées par exemple.
Table
La classe pour écrire et lire dans la table.

Les modèles et traitement de haut niveau ("couche métier") utiliseront ensuite ce modèle de bas niveau. On bénéficie en plus de la possibilité d'adapter la couche bas niveau à une nouvelle base de données au fonctionnalitée équivalentes sans toucher à la couche métier.

Enfin, on peut aussi utiliser des "espaces de noms" pour les tables, et les colonnes, afin d'éviter les collisions de noms. Cela permet de faire cohabiter plusieurs instance de l'application indépendantes.

Améliorations possibles

Ecrire des fonctions qui se chargent de la construction d'un objet Critère ad hoc pour des cas simple (recherche sur un identifiant, etc...)

Code Source

<?php
/*
(c)2004 David Sporn

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License version 2.1 as published by the Free Software Foundation.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

/**Class that will be used for constructing a "WHERE" clause.
 */
class DbXx_Filter
{
	//Filter value
	var $myYyy ;
	//etc...
	
	function DbXx_Filter()
	{
		$this->myYyy = '' ; //whatever default value here
	}
	
	/**Write access to property Yyy.
	 * @param default default value.
	 */
	function setYyy($default = '')
	{
		$this->myYyy = $default ;
	}

	/**Read access to property Yyy.
	 * @return a string
	 */
	function getYyy()
	{
		return $this->myYyy ;
	}
}

/**Class that models a row of the table Xx.
 */
class DbXx_Row
{
	//Filter value
	var $myAaa ;
	//etc...
	
	function DbXx_Row($nameSpace = '')
	{
		$this->myAaa = '' ; //whatever default value here
	}
	
	/**Write access to property Aaa.
	 * @param default default value.
	 */
	function setAaa($default = '')
	{
		$this->myAaa = $default ;
	}

	/**Read access to property Aaa.
	 * @return a string
	 */
	function getAaa()
	{
		return $this->myAaa ;
	}
}

/**Class that accesses the database.
 */
class DbXx_Table
{
	var $myTable ;
	var $myModel ;
	
	function DbXx_Table($tableNameSpace = '', $modelNameSpace = '')
	{
		$this->myTable = $tableNameSpace.'page' ; //the name of the table
		$this->myModel = array(
			'sid'=>$modelNameSpace.'SID' ,
			'entry'=>$modelNameSpace.'GID' ,
			'label'=>$modelNameSpace.'LABEL' ,
			'data'=>$modelNameSpace.'DATA' ,
			'type'=>$modelNameSpace.'TYPE' ,
			'menu'=>$modelNameSpace.'MENU' ,
			'first_page'=>$modelNameSpace.'FIRST' ,
			'last_page'=>$modelNameSpace.'LAST' ,
			'previous_page'=>$modelNameSpace.'PREV' ,
			'next_page'=>$modelNameSpace.'NEXT' 
		) ;
	}

	/**Select rows from the table according to a filter.
	 * @param filter the filter (might be null)
	 * @param rangeStart (>=0 : skip the $rangeStart first records)
	 * @param rangeLength ($rangeStart >= 0 && $rangeLength > 0 : return only $rangeLength records)
	 * @return an array of DbXx_Row
	 */
	function getList($filter = null, $rangeStart = -1, $rangeLength = 0)
	{
		//Sanity check
		if ($rangeStart >= 0 && $rangeLength <= 0)
		{
			return array() ;
		}
		$list_retour = array() ;
		
		//TODO : Build the sql request using the optionnal filter
		$sql = '' ;
		if (null == $filter)
		{
			//build the sql request with no filter
			//$sql = 'select * from '.$this->myTable.' order by '.$this->myModel['entry'] ;
			//sample query build
			//	'select '
			//	.$this->myModel['entry'].', '
			//	.$this->myModel['label'].', '
			//	.$this->myModel['data'].', '
			//	.$this->myModel['type'].', '
			//	.$this->myModel['menu'].', '
			//	.$this->myModel['first_page'].', '
			//	.$this->myModel['last_page'].', '
			//	.$this->myModel['previous_page'].', '
			//	.$this->myModel['next_page'].' '
			//	.'from '.$this->myTable
		}
		else
		{
			//build the sql request with a filter
		}
		
		$db_result = mysql_query($sql) ;
		$row_counter = 0 ;
		
		while ($next_record = mysql_fetch_array($db_result))
		{
			if ($rangeStart >= 0 && $row_counter < $rangeStart)
			{
				continue ; //range not reached yet
			}
			else if ($rangeStart >= 0 && ($rangeStart + $rangeLength) <= $row_counter)
			{
				break ; //range ends
			}
			$new_row = new DbXx_Row ;
			
			//TODO : copy data from $next_record to $new_row
			
			array_push($list_retour, $new_row) ;
			$row_counter++ ;
		}

		return $list_retour ;
	}
	
	/**Insert a row from a DbXx_Row.
	 * @param row the DbXx_Row
	 * @return -1 if the query failed
	 */
	function insert($row)
	{
		//TODO : build the sql query
		$sql = '' ;

		//sample query build
		//	'insert into '.$this->name.'('
		//	.$this->model['entry'].', '
		//	.$this->model['label'].', '
		//	.$this->model['data'].', '
		//	.$this->model['type'].', '
		//	.$this->model['menu'].', '
		//	.$this->model['first_page'].', '
		//	.$this->model['last_page'].', '
		//	.$this->model['previous_page'].', '
		//	.$this->model['next_page'].') '
		//	." values('".addslashes($entry)."', "
		//	."'".addslashes($label)."', "
		//	."'".addslashes($data)."', "
		//	."".(integer)$type.", "
		//	."'".addslashes($menu)."', "
		//	."'".addslashes($first)."', "
		//	."'".addslashes($last)."', "
		//	."'".addslashes($prev)."', "
		//	."'".addslashes($next)."') ";
		
		mysql_query($sql);
		return mysql_affected_rows() ;
	}
	
	/**Update a row from a DbXx_Row.
	 * @param row the DbXx_Row
	 * @return -1 if the query failed
	 */
	function update($row)
	{
		//TODO : build the sql query
		$sql = '' ;

		//sample query build
		//	"insert into ".$this->name."("
		//	.$this->model['entry'].", "
		//	.$this->model['label'].", "
		//	.$this->model['data'].", "
		//	.$this->model['type'].", "
		//	.$this->model['menu'].", "
		//	.$this->model['first_page'].", "
		//	.$this->model['last_page'].", "
		//	.$this->model['previous_page'].", "
		//	.$this->model['next_page'].") "
		//	." values('".addslashes($entry)."', "
		//	."'".addslashes($label)."', "
		//	."'".addslashes($data)."', "
		//	."".(integer)$type.", "
		//	."'".addslashes($menu)."', "
		//	."'".addslashes($first)."', "
		//	."'".addslashes($last)."', "
		//	."'".addslashes($prev)."', "
		//	."'".addslashes($next)."') ";
		
		mysql_query($sql);
		return mysql_affected_rows() ;
	}
	
	/**Delete using DbXx_Row (delete a row) or a DbXx_Filter (delete several rows).
	 * @param filter the DbXx_Row
	 * @return -1 if the query failed
	 */
	function delete($filter)
	{
		//TODO : Build the sql request using either a filter, either a row
		$sql = '' ;
		
		if (is_a($filter, 'DbXx_Filter'))
		{
			//build the sql request with a filter
			//
		}
		else if (is_a($filter, 'DbXx_Row'))
		{
			//build the sql request with a row
		}
		else
		{
			return -1 ;
		}
		
		mysql_query($sql) ;
		return mysql_affected_rows() ;
	}
}
?>

Objectifs

Extension de la classe RequestParserBase, ce modèle de classe à personnaliser remplit 2 objectifs :

  1. La récupération des paramètres d'une requête est isolée dans une boîte noire (du point de vue de l'application). L'application n'a pas, par exemple, à connaitre le nom des paramètres à récupérer. Par contre, il faudra prévoir le couplage de RequestParserXxx avec le module chargé de créer les liens entre les pages.
  2. Dans le cas d'une application basé sur le principe d'une collection de "portlet" (par exemple), il faut que chaque portlet puisse recevoir spécifiquement des paramètre. Le constructeur prévoit un "espace de nom" optionnel pour éviter les collisions de noms.

Améliorations possibles

Rajouter des fonctions qui appliquent des contraintes sur le contenu d'un paramètre de la requête. Par exemple une expression regulière précise. Une telle fonction serait rajoutée dans la classe étendue et non dans RequestParserBase car la contrainte est spécifique à l'application. Par exemple une énumération de valeurs.

Code Source

<?php
/*
(c)2004 David Sporn

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License version 2.1 as published by the Free Software Foundation.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
require_once("includes/RequestParserBase.php") ;

class RequestParserXxx extends RequestParserBase
{
	//Name of request variables
	var $myYyy ;
	//etc...
	
	function Xxx($nameSpace = '')
	{
		$this->myYyy = $nameSpace.'Yyy' ;
	}
	
	/**Get Yyy value, used for ... .
	 * @param default default value.
	 * @return a string
	 */
	function getYyy($default = '')
	{
		return $this->getSingleLineValue($this->myYyy, $default );
	}
}
?>

RequestParserBase

Le 09 Février 2005 à 14:20

Objectifs

Lors de la récupération de certains paramètres, cette classe permet de garantir certaines propriétés à la récupération d'un paramètre de la requête. Le but est d'augmenter la sécurité.

Améliorations possibles

Rajouter des fonctions qui appliquent des contraintes sur le contenu d'un paramètre de la requête. Par exemple une expression regulière précise.

Code source

<?php
/*
(c)2004,2005 David Sporn

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License version 2.1 as published by the Free Software Foundation.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

class RequestParserBase
{
	/**Return a single line from an arbitrary request parameter.
	 * Additionnaly, whitespaces are trimed and slashes are striped.
	 * @param name the request parameter name.
	 * @param default a default value that is returned when the request parameter does not exist.
	 * @return a string
	 */
	function getSingleLineValue($name, $default = '')
	{
		if (@isset($_REQUEST[$name]))
		{
			//we only care about the first line, so limit 
			//to 2 elements : the first line and the remaining
			$temp = explode("\n",$_REQUEST[$name],2) ; 
			return stripslashes(trim($temp[0])) ;
		}
		return $default ;
	}

	/**Return a string from an arbitrary request parameter.
	 * Additionnaly, slashes are striped.
	 * @param name the request parameter name.
	 * @param default a default value that is returned when the request parameter does not exist.
	 * @return a string
	 */
	function getStringValue($name, $default = '')
	{
		if (@isset($_REQUEST[$name]))
		{
			return stripslashes($_REQUEST[$name]) ;
		}
		return $default ;
	}

	/**Return an integer from an arbitrary request parameter.
	 * @param name the request parameter name.
	 * @param default a default value that is returned when the request parameter does not exist.
	 * @return a string
	 */
	function getIntegerValue($name, $default = 0)
	{
		if (@isset($_REQUEST[$name]))
		{
			return (integer)stripslashes(trim($_REQUEST[$name])) ;
		}
		return (integer)$default ;
	}
}
?>

Un test qui permet de déterminer les partis politiques français les plus proches de l'opinion du testé

Le résultat

Vous vous situez à gauche.

Aucun parti ne correspond exactement à vos opinions (Note du Sporniket : c'est normal, je suis anarchiste libertaire, à en croire le test du political compass). Cependant, les partis dont vous êtes le plus proche (dans l'ordre) :

1. Lutte ouvrière (LO)

mais, en règle générale, vous accordez plus d'importance à la responsabilité personnelle des gens (ou moins d'importance au contexte dans lequel les gens évoluent).

Lutte Ouvrière est totalement CONTRE la Constitution européenne.

Et, dans une moindre mesure

2. le Parti Communiste

mais, en règle générale, vous accordez plus d'importance à la responsabilité personnelle des gens (ou moins d'importance au contexte dans lequel les gens évoluent).

Le Parti Communiste est CONTRE la Constitution européenne.

3. la Ligue Communiste Révolutionnaire (LCR)

mais vous ne partagez pas toujours les mêmes opinions sur l'importance de la responsabilité personnelle des gens, ni sur l'évolution des moeurs.

La LCR est totalement CONTRE la Constitution européenne.

4. les Verts

La tendance des Verts dont vous êtes le plus proche est CONTRE la Constitution européenne.

Le(s) parti(s) qui vien(nen)t ensuite

5. le Mouvement Républicain et Citoyen (MRC) de Jean-Pierre Chevènement

mais vous accordez plus d'importance au rôle de l'Etat dans le domaine économique et social.

Le MRC est CONTRE la Constitution européenne.

6. le Parti Socialiste

mais vous accordez plus d'importance au rôle de l'Etat dans le domaine économique et social.

Lors d'un référendum interne, les militants du Parti Socialiste se sont prononcés à 59% POUR la Constitution européenne. (L'aile droite du parti était en général POUR, l'aile gauche du parti, ainsi que Laurent Fabius et ses partisans, étaient CONTRE, le reste du parti était divisé).

Européen convaincu, le projet d'une constitution européenne est pour moi une étape logique dans un processus qui doit mener à terme les Européens de l'Union à se sentir Européens avant de se sentir Français, Allemand, etc...

C'est donc d'un bon oeil que je voyais ce projet de constitution arriver à terme. Malheureusement, force est de constater que certains points me semblent innacceptables, et par conséquent, je n'approuverai pas ce texte lors du référendum.

Avant d'expliquer mon choix, je vous présente d'abord mon idéal de l'europe. Sur le plan de la vie quotidienne, une bonne protection sociale, tant au niveau de l'emploi que de la santé, des services publics de qualités -tant au niveau de l'efficacité que de la relation avec les usagers- et sanctuaires de la laïcité. Sur le plan politique, la limitation des souverainetés nationales, qui donnent surtout une image de querelles de clochers, un parlement européen fort et démocratiquement élu, et une commission affaiblie, car moins représentative d'un point de vue démocratique.

Le texte de la constitution répond à certains de ces idéaux, mais en élude d'autres ou les contrevient.

Article I-3-2 + Article I-4-2 = "Directive Bolkestein" ?

Article I-3-2
L'Union offre à ses citoyens un espace de liberté, de sécurité et de justice sans frontières intérieures, et un marché intérieur où la concurrence est libre et non faussée.
Article I-4-2
Dans le champ d'application de la Constitution, et sans préjudice de ses dispositions particulières, toute discrimination exercée en raison de la nationalité est interdite.

Ces deux articles, pris séparéments, sont prometteurs. Malheureusement (ou heureusement) la directive "Bolkestein" sur les services, et en particulier le "principe du pays d'origine" a montré un tout autre but : le dumping social, fiscal et règlementaire. En fait, il manque ici une définition précise de ce qu'est une concurrence "non faussée", définition qui tienne compte des réalité économiques et sociales de chaque membres de l'Union.

Article II-70-1

Article II-70-1
Toute personne a droit à la liberté de pensée, de conscience et de religion. Ce droit implique la liberté de changer de religion ou de conviction, ainsi que la liberté de manifester sa religion ou sa conviction individuellement ou collectivement, en public ou en privé, par le culte, l'enseignement, les pratiques et l'accomplissement des rites.

Le problème que me pose cet article, c'est qu'un agent du service public serait libre de manifester sa religion, et donc représente à la fois sa religion et l'état/l'Union Européenne, ce qui contrevient à ma conception de la séparation des églises et de l'état/l'Union Européenne. Là aussi il manque une "sanctuarisation" de la laïcité qui est, à mon sens, le garant de la liberté de religion et de culte.

Une précision importante, en mettant en parallèle la loi française contre les signes religieux à l'école. Je ne m'interesse ici qu'aux agents de la fonction public (dont les professeurs et le personnel d'encadrement), pas aux usagers (les élèves et les parents d'élèves), qui eux ont et doivent avoir cette liberté.

Article II-96

Article II-96 : Accès aux services d'intérêt économique général
L'Union reconnaît et respecte l'accès aux services d'intérêt économique général tel qu'il est prévu par les législations et pratiques nationales, conformément à la Constitution, afin de promouvoir la cohésion sociale et territoriale de l'Union.

Il s'agit ici de la négation du service public pur et simple. Sinon, pourquoi ne pas avoir utilisé le terme "service public" ? En le mettant en parallèle avec la directive "Bolkestein", on pourrait se demander si ce n'est pas la plannification du dépeçage du service public. En effet, le service public fournit des services "d'intérêt économique général", mais ces services peuvent aussi être assurés par des prestataires privés. Sans oublier la possibilité de privatiser les services publics (France Télécom dans le passé, bientôt EDF et GDF).

Autrement dit, la présence d'un service public implique la présence de "services d'intérêt économique général", mais la présence de "services d'intérêt économique général" n'implique pas nécessairement la présence d'un service public.

Conclusion

Les quelques articles qui ont attirés mon attention m'incitent à penser que malgré les idéaux affichés, le texte de la constitution européenne qui nous est proposée porte les germes de l'échec social de l'Europe, ce que je n'accepte pas. Je préfère donc risquer l'échec politique : je voterai "NON" à la constitution européenne qu'on nous propose.

C'est dommage, car par ailleurs ce projet comportait de réelles avancées. Mais la note est éliminatoire.

Feuille CSS de base

Le 03 Février 2005 à 15:36

Je ne sais plus où j'ai trouvé cette feuille de style, mais celle-ci redéfinie toutes les valeurs de base, afin de ne plus dépendre du navigateur hôte. Ca m'a bien aidé pour des menu en CSS.