Initiation à l’algorithmie sur fond d’arithmétique

Voici un petit exemple d’algorithmie appliqué a une situation ou l’on doit jouer avec les nombres. J’espère que cette présentation permettra à quelque-uns de mieux comprendre le fonctionnement des logiciels, voir même donner des envies à d’autres !

Définition du problème

Dans un jeux de société, nous avons 3 paquets de cartes (un bleu, un jaune et un rouge). Lorsque un joueurs tombe sur une certaine case du jeux (imaginez un monopoly) il doit recevoir une carte parmi les trois paquets. Cependant nous souhaitons qu’il pioche sa carte d’un des trois paquets selon des probabilités:

  • 10% de chances de recevoir une carte venant du paquet bleu
  • 25% de chances de recevoir une carte venant du paquet jaune
  • 65% de chances de recevoir une carte venant du paquet rouge

Pour savoir dans quel paquet le joueur devra piocher, nous devons insérer une part de hasard: imaginons donc que nous avons un dès a 100 faces. Nous établissons a l’avance ces plages de nombres afin de savoir dans quel paquet piocher quand nous aurons lancé le dé:

  • de 1 à 10: paquet bleu
  • de 11 à 35: paquet jaune
  • de 36 à 100: paquet rouge

Le défis va être d’écrire un algorithme capable de simuler ce jet de dés permettant le choix du paquet de carte.

Visualiser nos chiffres

Pour mieux visualiser ces plages de nombres, imaginez une règle de 100 graduations:

  • Les 10 premières graduations, de 1 à 10, représentes les 10%.
  • Les 25 prochaines graduations, de 11 à 35, représentes les 25%
  • Les 65 prochaines graduations, de 36 à 100, représentes les 65%

En fonction du nombre donné par le dé a 100 faces et selon la graduation, nous savons quel paquet de carte choisir tout en restant fidèle aux probabilités de 10, 25 et 65%. Nous allons désormais représenter ces plages de nombres comme ceci:

10%   |   25%   |   65%

[1 → 10] [11 → 35] [36 → 100]

Le modèle logique

Nous allons maintenant essayer de trouver un modèle logique la dedans. Un modèle qui, quelque soit le nombre de paquets de cartes et quelque soit les probabilités que nous avons, puisse toujours s’appliquer. Dans un soucis de lecture nous allons appeler les 10% « A« , les 25% « B » et les 65% « C« . On constate en premier lieux ce modèle:

[1 → 10] [10+1 → 10+25] [10+25+1 → 10+25+65]

[1 → A] [A+1 → A+B] [A+B+1 → A+B+C]

Si nous rajoutions des paquets de cartes et modifions les probabilités, ce modèle fonctionnerais toujours. Vous pouvez essayez chez vous, succès garantis.

Le modèle logique: 2ème étape

Nous allons maintenant vouloir appliquer ce modèle à un algorithme informatique. Pour pouvoir le traiter de manière informatique il faut aller un peu plus loin: Nous devons trouver le modèle logique de chaque plage de nombre ([ ]) car notre algorithme devra répéter ce modèle pour chaque paquets de cartes (pourcentages). Car en effet un algorithme est une suite d’instructions qui ne dévira pas de ce pour quoi elle a été programmé. On doit donc trouver un modèle logique, c’est a dire comment trouver les nombres a l’intérieur d’une plage de nombres ([ ]), qui fonctionne a tout les coups.

Voici le modèle logique que nous cherchons:

[ Probabilités précédentes + 1 Probabilités précédentes+Probabilité en cours ]

Pour mieux comprendre, rien de vaut une mise en pratique! Nous avons trois paquets de cartes: nous allons donc effectuer le « calcul » trois fois. La première fois pour la première plage de dates correspondant aux 10% ([1 → 10] [11 → 35] [36 → 100])

  • Modèle: [ Prob. préc. + 1 Prob. préc. + Prob. en cours ]
  • Probabilités en cours: 10
  • Probabilités précédentes: 0
  • [0+1 → 0+10] [ ] [ ]
  • soit [1 → 10] [ ] [ ]

La deuxième fois pour la deuxième plage de dates correspondant aux 25% ([1 → 10] [11 → 35] [36 → 100])

  • Modèle: [ Prob. préc. + 1 Prob. préc. + Prob. en cours ]
  • Probabilités en cours: 25
  • Probabilités précédentes: 10
  • [ ] [10+1 → 10+25] [ ]
  • soit [ ] [11 → 35] [ ]

La troisième fois pour la troisième plage de dates correspondant aux 65% ([1 → 10] [11 → 35] [36 → 100])

  • Modèle: [ Prob. préc. + 1 Prob. préc. + Prob. en cours ]
  • Probabilités en cours: 65
  • Probabilités précédentes: 10 + 25
  • [ ] [ ] [10+25+1 → 10+25+65]
  • soit [ ] [ ] [36 → 100]

Et voilà, nous constatons avec cette mise en pratique que le modèle logique fonctionne. Vous pouvez vérifier chez vous en ajoutant des paquets de cartes et probabilités si vous voulez.

L’algorithme de génération des plages de nombres

Tout ceci nous permet maintenant d’écrire notre premier algorithme ! Il s’agit ici de transformer le modèle logique vu précédemment en un algorithme « textuel », c’est à dire lisible par n’importe qui et respectant le modèle d’un programme informatique: Sa lecture se fait de gauche à droite et de haut en bas: comme pour la lecture !

"probabilités" contient 10%, 25% et 65%
"somme_probabilités_précédentes" vaut 0
"plages_de_nombres" est vide
pour chaque "probabilité_en_cours" dans les "probabilités":
  ajouter la plage ["somme_probabilités_précédentes"+1 → "somme_probabilités_précédentes"+"probabilité_en_cours"] aux "plages_de_nombres"
  "somme_probabilités_précédentes" vaut maintenant "somme_probabilités_précédentes" + "probabilité_en_cours"

Comprenez que pour les lignes avec un alinéa (dans le « pour ») il est effectué le processus autant de fois qu’il y a de probabilités (10%, 25%, 65%) de la même façon que nous l’avons mis en pratique dans la section « Le modèle logique: 2ème étape ». Voici la décomposition du code pour mieux comprendre ce qu’il se passe: Lors de la première passe:

pour chaque "probabilité_en_cours" dans les "probabilités":
  #note: Premier coup c'est la probabilité de 10%
  #note: et somme_probabilités_précédentes vaut 0
  ajouter la plage [0+1 → 0+10] aux "plages_de_nombres"
  "somme_probabilités_précédentes" vaut maintenant 0 + 10

Deuxième passe:

pour chaque "probabilité_en_cours" dans les "probabilités":
  #note: Deuxième coup c'est la probabilité de 25%
  #note: et somme_probabilités_précédentes vaut actuellement 10
  ajouter la plage [10+1 → 10+25] aux "plages_de_nombres"
  "somme_probabilités_précédentes" vaut maintenant 10 + 25

Troisième et dernière passe:

pour chaque "probabilité_en_cours" dans les "probabilités":
  #note: Troisième coup c'est la probabilité de 65%
  #note: et somme_probabilités_précédentes vaut actuellement 35
  ajouter la plage [35+1 → 35+65] aux "plages_de_nombres"
  "somme_probabilités_précédentes" vaut maintenant 35 + 65

Après avoir effectué les 3 passes nous avons bien nos plages de nombres:

[ 0 +1  0 + 10 ] [ 10 + 1  10 + 25 ] [ 35 + 1  35 + 65 ]

soit [1 → 10] [11 → 35] [36 → 100]

Code python

Nous pouvons maintenant rédiger notre premier script, c’est a dire notre premier « logiciel ». Nous allons rédiger ce code en python: C’est un langage de programmation propre et facilement lisible, donc bien adapté a ce petit cours. L’algorithme « textuel » vu précédemment devient:

probabilites = [10, 25, 65]
somme_probabilites_precedentes = 0
plages_de_nombres = []
for probabilite_en_cours in probabilites:
  plages_de_nombres.append([somme_probabilites_precedentes+1, somme_probabilites_precedentes+probabilite_en_cours]) 
  somme_probabilites_precedentes = somme_probabilites_precedentes + probabilite_en_cours

Et voilà! Ce code peut être compris par un ordinateur comprenant le langage python: pour une démonstration cliquez ici. Lorsque l’algorithme arrive a sa fin « plages_de_nombres » contient bien nos plages de nombres!

[ [1, 10], [11, 35], [36, 100] ]

Code python: simuler l’ensemble

Il nous faut maintenant ajouter du code pour simuler le jet du dés et le choix du paquet de carte dans lequel le joueur devra piocher. Cette ligne permet d’obtenir un nombre au hasard entre 1 et 100:

jet = random.randint(1, 100)

Pour savoir a quel paquet de carte correspond le jet de dés, nous allons, pour chaque plages de dates, voir si le nombre obtenu au dés s’y trouve. Si il s’y trouve, c’est le paquet de cartes, correspondant a cette plage de dates qui sera notre résultat. Commençons avec l’algorithme « textuel » (rappelons nous que « plages_de_nombres » contient « [[1,10] [11,35] [36,100]] »):

pour chaque plage_de_nombre dans les plages_de_nombres:
  Si le jet est supérieur ou égal au premier nombre de cette plage_de_nombres 
  ET si le jet est inférieur ou égal aux deuxième nombre de cette plage_de_nombres:
    c'est cette plage_de_nombre a laquelle correspond le jet

Illustrons cet algorithme « textuel » dans un cas pratique comme nous l’avons déjà fait la fois précédente. Imaginons que notre jet de dés à fait 49. Nous faisons trois fois ce qui est écrit dans le « pour » (puisque nous avons 3 « plages_de_nombres »):

pour chaque plage_de_nombre dans les plages_de_nombres:
  #note: Premier coup c'est la plage [1, 10]
  Si 49 est supérieur ou égal à 1 
  ET si 49 est inférieur ou égal à 10:
    c'est cette plage_de_nombre a laquelle correspond 49

Les conditions de la phrase « Si » ne sont pas remplis, on passe à la suivante:

pour chaque plage_de_nombre dans les plages_de_nombres:
  #note: Deuxième coup c'est la plage [11, 35]
  Si 49 est supérieur ou égal à 11 
  ET si 49 est inférieur ou égal à 35:
    c'est cette plage_de_nombre a laquelle correspond 49

Les conditions de la phrase « Si » ne sont toujours pas remplis, on passe à la suivante:

pour chaque plage_de_nombre dans les plages_de_nombres:
  #note: Troisème coup c'est la plage [36, 100]
  Si 49 est supérieur ou égal à 36 
  ET si 49 est inférieur ou égal à 100:
    c'est cette plage_de_nombre a laquelle correspond 49

A la troisième passe les conditions du « Si » sont remplis, c’est donc bien la plage de nombres du paquet de cartes rouges qui correspond à 49 ! Le code adapté au langage python est le suivant :

jet = random.randint(1, 100)
plage_de_nombre_correspondant = None
for plage_de_nombre in plages_de_nombres:
  if jet >= plage_de_nombre[0] and jet <= plage_de_nombre[1]:
    plage_de_nombre_correspondant = plage_de_nombre

Une fois les deux portions de code associés, cela nous donne:

import random

probabilites = [10, 25, 65]
somme_probabilites_precedentes = 0
plages_de_nombres = []
for probabilite_en_cours in probabilites:
  plages_de_nombres.append([somme_probabilites_precedentes+1, somme_probabilites_precedentes+probabilite_en_cours]) 
  somme_probabilites_precedentes = somme_probabilites_precedentes + probabilite_en_cours

jet = random.randint(1, 100)
plage_de_nombre_correspondant = None
for plage_de_nombre in plages_de_nombres:
  if jet >= plage_de_nombre[0] and jet <= plage_de_nombre[1]:
    plage_de_nombre_correspondant = plage_de_nombre

Ne prêtez pas attention la ligne « import random », elle est juste nécessaire pour pouvoir utiliser random.randint. A la fin de l’exécution de ces lignes « plage_de_nombre_correspondant » contiendra la page de nombre correspondant au jet du dé. Pour voir le code s’exécuter, cliquez ici.

Code python final

Pour que le logiciel est un intérêt supplémentaire, nous devrions l’améliorer de sorte à ce que nous puissions rapidement et facilement lancer la procédure à plusieurs reprises. Comme ceci ne concerne plus de l’initiation a l’algorithmie mais plutôt de la simple programmation logicielle je ne m’attarderais pas sur comment à été construit le code suivant. Cependant il intéressera les plus curieux ;)

import random

def generer_les_plages_de_nombres(probabilites):
  somme_probabilites_precedentes = 0
  plages_de_nombres = []
  for probabilite_en_cours in probabilites:
    plages_de_nombres.append([somme_probabilites_precedentes+1, somme_probabilites_precedentes+probabilite_en_cours]) 
    somme_probabilites_precedentes = somme_probabilites_precedentes + probabilite_en_cours
  return plages_de_nombres

def trouver_plage_de_nombres_correspondantte_au_jet(jet, plages_de_nombres):
  plage_de_nombre_correspondant = None
  for plage_de_nombre in plages_de_nombres:
    if jet >= plage_de_nombre[0] and jet <= plage_de_nombre[1]:
      return plage_de_nombre

def trouver_cle(plage_de_nombres_trouve, plages_de_nombres):
  if plage_de_nombres_trouve in plages_de_nombres:
    return plages_de_nombres.index(plage_de_nombres_trouve)

def lancer_simulation(probabilites, paquets_de_cartes):
  jet = random.randint(1, 100)
  plages_de_nombres = generer_les_plages_de_nombres(probabilites)
  plage_de_nombre_correspondant_au_jet = trouver_plage_de_nombres_correspondantte_au_jet(jet, plages_de_nombres)
  cle = trouver_cle(plage_de_nombre_correspondant_au_jet, plages_de_nombres)
  print "pour le jet "+str(jet)+" c'est dans le paquet "+paquets_de_cartes[cle]+" que le joueur doit piocher"

paquets_de_cartes = ['Bleu', 'Jaune', 'Rouge']
probabilites = [10, 25, 65]
lancer_simulation(probabilites, paquets_de_cartes)

Pour une démonstration, cliquez ici.

Conclusion

La programmation logicielle consiste a cela: Répondre a un problème et synthétiser sa solution en adaptant de contextes réels des modèles logiques de manière a ce qu’ils soient compréhensible par une machine. Vos ordinateurs, les appareils électroniques et même des système uniquement mécaniques (voir par exemple le métier à tisser Jacquard) sont constitués de quelques ou de millions voir milliards de morceaux de logiques comme celui que nous venons de voir. Complexe, mais pas sorcier !

Could not open command file ‘/usr/local/nagios/var/rw/nagios.cmd’ for update!

Si vous utilisez nagios et que vous êtes confrontés a cette erreur lorsque vous souhaitez effectuer une opération a partir de l’interface web de nagios, cela est du aux droits du fichier. Si on regarde d’un peu plus près:

/usr/local/nagios/var/rw# ls -l
total 0
prw-rw---- 1 nagios nagios 0 11 sept. 14:32 nagios.cmd

On constate que le fichier ne peut être manipulé que pas l’utilisateur nagios. Or lorsque l’on utilise l’interface web, c’est l’utilisateur www-data qui est utilisé. Il faut donc mettre a jours les droits sur le fichier. Le problème c’est que ce fichier est recréé a chaque démarrage de nagios. On modifie donc le fichier /etc/init.d/nagios de façon a changer les droits sur le fichier lors de sa création:

[...]

case "$1" in

        start)
                echo -n "Starting nagios:"
                $NagiosBin -v $NagiosCfgFile > /dev/null 2>&1;
                if [ $? -eq 0 ]; then
                        su - $NagiosUser -c "touch $NagiosVarDir/nagios.log $NagiosRetentionFile"
                        rm -f $NagiosCommandFile
                        touch $NagiosRunFile
                        chown $NagiosUser:$NagiosGroup $NagiosRunFile
                        $NagiosBin -d $NagiosCfgFile
                        if [ -d $NagiosLockDir ]; then touch $NagiosLockDir/$NagiosLockFile; fi

                        # added by bux
                        chmod 770 $NagiosCommandFile
                        chown nagios:www-data $NagiosCommandFile
                        # end added by bux

                        echo " done."
                        exit 0
                else
                        echo "CONFIG ERROR!  Start aborted.  Check your Nagios configuration."
                        exit 1
                fi
                ;;


[...]

Et voilà !

Configurer thunderbird pour google app (email)

Je teste actuellement le service de google app permettant d’utiliser les serveurs mail de google  comme serveur mx et il y a une petite configuration a connaître lorsque l’on souhaite utiliser thunderbird pour cette boite mail. Lors de l’ajout d’un compte de courrier vous devez saisir votre login sans le @domaine.tdl dans cette partie, sinon thunderbird ne pourra pas se connecter:

Info qui peut toujours servir !

Isoler les tests fonctionnels et unitaires dans symfony2

Edit: Voir le commentaire de Bidule pour une solution plus simple

Il est très pratique d’isoler ses tests du reste de l’application. Il est donc nécessaire de faire en sorte que la base de donnée utilisé lors des tests soit indépendante de la base utilisé lors du développement.  Cela évite de fausser ses tests si des données ont été modifier pendant le développement ainsi que d’utiliser une base fidèle aux fixtures entre chaque tests.

Cet article est issue de la combinaison des deux articles suivants:

Dans mon cas, l’article de haulynjason.net seul ne me permettait pas d’exécuter mes tests fonctionnels sur la même base que les tests unitaires. J’ai du utiliser l’astuce de l’article d’alexamdre-salome.fr.

Premièrement nous configurons de quoi éxécuter les tests dans une base sqlite, de façon a ce qu’elle soit isolé de la base de développement.

config_test.yml:

doctrine:
dbal
:
driver
: pdo_sqlite
path
: ":memory:"
memory
: true
orm
:
auto_generate_proxy_classes
: true
auto_mapping
: true

Nous créons la classe ModelTestCase a partir de laquelle seront étendus nos classes de tests (git):

<!--?php /*  * Adapt to your AppKernel.php path  */ require_once(__DIR__ . "../../../../../../app/AppKernel.php"); /**  * @see http://haulynjason.net/weblog/2012/01/fully-isolated-tests-in-symfony2/  */ class ModelTestCase extends \PHPUnit_Framework_TestCase {      protected $_kernel;   protected $_application;   protected $_container;   public function __construct()   {     $this--->_kernel = new \AppKernel("test", true);
$this-&gt;_kernel-&gt;boot();
$this-&gt;_container = $this-&gt;_kernel-&gt;getContainer();
parent::__construct();
}

protected function get($service)
{
return $this-&gt;_container-&gt;get($service);
}

public function setUp()
{
$this-&gt;_application = new \Symfony\Bundle\FrameworkBundle\Console\Application($this-&gt;_kernel);
$this-&gt;_application-&gt;setAutoExit(false);

$this-&gt;runConsole("doctrine:schema:drop", array("--force" =&gt; true));
$this-&gt;runConsole("doctrine:schema:create");
$this-&gt;runConsole("cache:warmup");
$this-&gt;runConsole("doctrine:fixtures:load");
}

protected function runConsole($command, Array $options = array())
{
$options["-e"] = "test";
$options["-q"] = null;
$options = array_merge($options, array('command' =&gt; $command));
return $this-&gt;_application-&gt;run(new \Symfony\Component\Console\Input\ArrayInput($options));
}
}

A partir d’ici vos classes de tests unitaires étendus de cette classes utiliserons la base sqlite pour exécuter ses tests. Passons maintenant aux tests fonctionnels: définissons le paramètre test.client.class afin d’écrire notre propre classe Client:

config.yml:

parameters:
test.client.class
: MyApp\CoreBundle\lib\Test\Client
<!--?php namespace MyApp\CoreBundle\lib\Test; use Symfony\Bundle\FrameworkBundle\Client as BaseClient; class Client extends BaseClient {   static protected $connection;   protected $requested;   protected function doRequest($request)   {       if ($this--->requested) {
$this-&gt;kernel-&gt;shutdown();
$this-&gt;kernel-&gt;boot();
}

$this-&gt;injectConnection();
$this-&gt;requested = true;

return $this-&gt;kernel-&gt;handle($request);
}

protected function injectConnection()
{
if (null === self::$connection) {
self::$connection = $this-&gt;getContainer()-&gt;get('doctrine.dbal.default_connection');
} else {
if (! $this-&gt;requested) {
self::$connection-&gt;rollback();
}
$this-&gt;getContainer()-&gt;set('doctrine.dbal.default_connection', self::$connection);
}

if (! $this-&gt;requested) {
self::$connection-&gt;beginTransaction();
}
}
}

Nous écrivons la classe WebTestCase a partir de laquelle nous étendrons nos classe de test fonctionnels:

<!--?php namespace MyApp\CoreBundle\lib\Test; use MyApp\CoreBundle\lib\Test\ModelTestCase; class WebTestCase extends ModelTestCase {      /**    *    * @param array $server    * @return Symfony\Bundle\FrameworkBundle\Client     */   protected function createClient(array $server = array())   {       $client = $this--->get('test.client');
$client-&gt;setServerParameters($server);

return $client;
}

}

Et voilà, nos tests fonctionnels seront étendu de WebTestCase, nos tests unitaires seront eux étendus de ModelTestCase et ils seront totalement isolé de la base de dév puisque ils travailleront avec une base indépendante. Les performances de vos tests seront affectés puisque avec cette méthode chaque test (fichier, pas fonction) effectue une rechargement de la base.

SQL: Exclusion de résultats avec enregistrement en jointures

Selon le cas de figure suivant: Nous avons des éléments lié a des couleurs.

Table element

id # name #
1     Sea
2     tree

Table colour

id # name #
1     green
2     blue
3     brown

Table relation

element_id # colour_id
1                 2
2                 1
2                 3

Pour répondre a la demande:

Obtenir les éléments ayant une ou plus des couleurs suivantes

Il nous suffit d’effectuer cette requête (pour les couleurs green et brown):

SELECT element.name, colour.name FROM element
LEFT JOIN relation
ON (element.id = relation.element_id)
LEFT JOIN colour
ON (colour.id = relation.colour_id)
WHERE (relation.colour_id = 1 OR relation.colour_id = 3)

Mais si nous souhaitons répondre a la demande:

Obtenir les éléments ayant toutes les couleurs suivantes

Nous allons devoir utiliser une méthode différente. Ici nous allons utiliser une première requête en utilisant un having count pour isoler les element.id qui ont le nombre de relations (vers les couleurs) suffisantes. Donc pour les couleurs green et brown:

SELECT relation.element_id FROM relation
WHERE relation.colour_id IN (1, 3)
GROUP BY relation.element_id
HAVING COUNT (DISTINCT relation.colour_id) = 2

Nous obtiendrons les element_id qui ont bien deux relations vers couleur, sachant que nous avons filtrer ces relation pour n’être que celle vers le green et le brown. Il n’y a ensuite plus qu’a récupérer nos éléments:

SELECT element.name, colour.name FROM element
WHERE element.id IN (#Ids récupérés#)

Doctrine 2: Effectuer une requete SQL pure

Il est parfois nécessaire lorsque l’on utilise Doctrine 2 d’effectuer une requête SQL et non une requête DQL. Pour cela nous pouvons utiliser la méthode createNativeQuery dans laquelle nous pouvons utiliser le langage SQL.

// La requête SQL
$sql = "SELECT u.address FROM user u WHERE u.sex = 'M' ";
// Construction de l'objet ResultSetMapping
$rsm = new \Doctrine\ORM\Query\ResultSetMapping;
// On définie quel champs doit être retourné dans la réponse
$rsm->addScalarResult('address', 'address');
// On récupère les résultats
$addresss = $this->getEntityManager()
->createNativeQuery($sql, $rsm)
->getScalarResult()
;

Plus d’information sur la doc officielle: http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/native-sql.html

Debian: Passage d’un système 32bits en 64bits

Je me suis récemment posé la question suivante puisque j’allais changé le processeur de mon ordinateur portable: Y a t-il des opérations a effectuer sur son système lors d’un changement d’architecture processeur. La rétrocompatibilité des processeur 64bits vers le jeux d’instructions 32bits est totale. Pas d’inquiétude a avoir de coté la donc.

Cependant pour une question d’optimisation il peut être intéressant de mettre a jour les paquets présent sur le système de façon a remplacer les paquet disponible en 64bits actuellement présent sur le système en version 32bits. Pour cela, grâce a l’incroyable puissance du gestionnaire de paquet vous pouvez effectuer cette opération en trois ligne de commande:

dpkg --get-selections > packets.txt
dpkg --set-selections < packets.txt
apt-get dselect-upgrade

Ces actions aurons pour effet de lister les paquets installés sur le système, puis de demander leur installation. Seul les paquets disponible dans une nouvelle version (comme en 64b après un changement d’architecture processeur) seront réinstallés. Pour les windowsiens qui lirais cet article: Pas de soucis de configuration liés a la réinstallation de ces paquets car seul les binaires sont affecté. Pas les fichiers de configuration.

jConfirmAction: Quelques modifications

J’utilise pour un de mes projets le plugin jQuery jConfirmAction sous licence GPL version 2. J’y est effectué quelques modifications et les redistribuent donc sous cette même licence.

Le script, téléchargeable ici: jconfirmaction.jquery. Les différences avec le script de Hidayat Sagita sont les suivantes:

Exécution de fonctions

A l’origine le click sur « Oui » n’avait pour effet que de faire suivre le lien d’origine. L’ajout des trois paramètres « onYes », « onOpen » et « onClose » auxquels on transmet des fonctions nous permet de faire un peu plus de choses.

  • onYes est appelé lorsque le bouton « Oui » est cliqué.
  • onOpen est appelé lorsque la boite de confirmation apparaît.
  • onClose est appelé lorsque l’utilisateur

Ces fonctions reçoivent toujours comme argument le lien d’origine (sur lequel a été appliqué jConfirmAction).

$('a.remove').jConfirmAction({
  question : "Supprimer ?",
  yesAnswer : "Oui",
  cancelAnswer : "non",
  onYes: function(link){
    // [...]
    return false;
  },
  onOpen: function(link){
    // [...]
    return false;
  },
  onClose: function(link){
    // [...]
    return false;
  }
});

justOneAtTime

Le paramètre justOneAtTime (par défaut sur vrai) permet de détruire les autre boites de confirmations lorsqu’une s’ouvre. Cela permet donc simplement de d’en n’avoir qu’une a la fois.

Utilisation de ‘live’

J’ai préféré remplacer l’utilisation de bind par live. Décision prise par rapport a ce dont je parlais dans cet article.

Les modification apportés sont essentiellement pour rendre l’utilisation de ce plugin plus souple en particulier dans un contexte ou vous utilisez l’ajax.

Enjoy ;)

Sécurité informatique: Vous jouez peut-être un rôle

Je suis tombé tout a fait par hasard sur ce très bon article de Chris Heilmann traduit par Frédéric de Villamil a propos du rôle que nous, acteurs du web, avons a propos de la sécurité informatique. Je vous conseil vivement de le lire si il vous arrive d’administrer des système, d’écrire des logiciels web ou même d’administrer votre propre blog.

http://t37.net/la-securite-du-web-passera-t-elle-par-vous.html