Oenix.net Un blog comme un autre … ou pas

1déc/100

[IRC] Des tresors a pleurer

Posté par Freezy

Eh ben, qu'il date le dernier article !
Comme je n'ai pas spécialement envie de me fouler à rédiger quelque chose d'intéressant, je vais partager une quote divertissante, vécue et qui m'a causé un facepalm et un bon rire. Enjoy !

-->| activeradio (~me.radioa@learn.java) has joined #php
<activeradio> I need help
<activeradio> $tweetText = $tweets[$i]['text'];
<activeradio> I want to put text inbetween
<activeradio> The two
<Freezy> activeradio: didnt understand
<activeradio> OK so currently it does
<activeradio> Tweet
<activeradio> and then last post
<activeradio> like when the tweet was posted
<activeradio> and I want to put text inbetween
<Anubis> activeradio
<Freezy> activeradio : can you provide an example ? x)
<Anubis> copy all the code to pastebincom
<activeradio> This is a test tweet Sent 17 hours ago.
<activeradio> $tweets[$i] is the "This is the test tweet"
<activeradio> and text is when it was sent
<activeradio> I tried to use . "text" .
<activeradio> but resulted in an error
<Freezy> dnot understand. According to you first line $tweets[$i] is an array, not a string
<activeradio> Well that is what displays the tweets
<activeradio> and text determins when it was last sent
<Freezy> www.pastebin.com please, I'm not familiar with tweeter
*activeradio* http://pastebin.com/JSdT200W
<activeradio> There
<Freezy> activeradio's : http://pastebin.com/JSdT200W
<activeradio> ?
<Freezy> try to print $tweets[$i]
<activeradio> Did you change anything?
<Freezy> Just sharing your source, i'm not the only guy out there who can help
<activeradio> k
<Freezy> try to print $tweets[$i] within or out of your loop, using <pre> tags. If out of the loop, use 0 for $i or whatever number is the best.
<Freezy> Then you'll perfectly know what is in your thing
<gao> what's a tweet?
<Anubis> are you srs gao ?
<Anubis> a tweet is a short msg of max 140 chars including spaces spread over the twitter platform :/
<Freezy> « Why so serious ? »
<activeradio> http://pastebin.com/4fViQcMR
<activeradio> ?
<Freezy> What ?
<activeradio> ^
<Freezy> I'm not god, i cannot guess the issue, or even the question
<activeradio> I added in the print
<Freezy> http://php.net/manual/en/function.print-r.php
<Freezy> So out of the for loop :
<Freezy> <pre> <?=print_r($tweets[0]);?></pre>
<Freezy> (Before it).
<activeradio> I get 1
<activeradio> for output
<Freezy> mh
<Freezy> Try print_r($tweets) instead
<activeradio> error
<Freezy> that's not that much explicit. Link ?
<activeradio> **LINK DEAD**
<Freezy> syntax ...
<Freezy> you forgot a ( ou a ;
<Freezy> or a ) or whatever
<activeradio> Now try
<activeradio> that posts all of the stats
<activeradio> what would you need the stats for?
<Freezy> for you
<activeradio> I don't need them
<Freezy> This was just to better understand you
<Freezy> But i really don't understand .... You have to text and the date outputted.
<Freezy> You want to concatenate a string ?
<Freezy> pseudo-code : text."add your lolz text here". datetime
<activeradio> Here is the tweet
<activeradio> G'night everyone! See you on Wednesday the 1st in the mornin'! (if everything goes as planned)Sent 17 hours ago.
<Freezy> Okay, what else ?
<activeradio> G'night everyone! See you on Wednesday the 1st in the mornin'! (if everything goes as planned) - Sent 17 hours ago.
<Freezy> echo " - ";
<Freezy> ...
<activeradio> error
<activeradio> when I do that
<Freezy> Again, _which_ error.
<activeradio> Parse error: syntax error, unexpected line 197
<activeradio> $tweetTime = $tweets[$i] echo " - "; ['created_at'];
<gh0st> haha
<Freezy> .....
<Freezy> /facepalm
<gh0st> hahaha
<Freezy> Did you seriously write that ?
<Anubis> uhm
<Freezy> If you answer yes
<Freezy> All i can telle you is ...
<Freezy> Review the basics
<Freezy> tell*
<activeradio> Im not god. I can't tell you that.
<Freezy> Anubis : Complete source ?
<Freezy> activeradio : What cant you tell me ? This is YOUR code, YOUR source.
<activeradio> b/c I'm not god
<Freezy> If you are too worried about sharing your little scripts, i cant help you.
<activeradio> no
<activeradio> Im just not god
<Freezy> $tweetTime = $tweets[$i] echo " - "; ['created_at'];
<Freezy> Honestly
<Freezy> Did you really put that in your sourcecode ?
<Freezy> I didn't tell you to do that, hell
<Freezy> I told you to echo this string : " - "
<Freezy> Just echo the tweet
<Freezy> echo the fucking -
<Freezy> And echo the time
<Freezy> Script over
<Freezy> Plain and simple.
<Freezy> I can't even figure out how you came to the idea you had to write $tweetTime = $tweets[$i] echo " - "; ['created_at'];
|<-- activeradio (~me.radioa@learn.java) has left #php ()
7oct/100

De la publicite …

Posté par oenix

Et oui, il en faut bien, mais cette fois, c'est de la publicité pour un projet dont je fais parti : How I Met Your Cartography.

Bref, ce site codé en HTML5, CSS3 et JS requiert Safari, Firefox ou Chrome, dans leur dernière mouture pour qu'il fonctionne (c'est ça, d'être à la point de la technologie).

Voici le lien :
http://www.oenix.net/himyc

J'attends vos feedbacks !!

24sept/100

Retour sur une semaine de conferences

Posté par oenix

La semaine dernière, nous avons eu le droit à une semaine de conférences sur la recherche & l'innovation. Ainsi, nombres d'intervenants se sont succéder sur la scène, tels que des chercheurs du LRDE, des ingénieurs de Microsoft, IBM, Bouygues, Altran, Aldebaran Robotics ...

Aldebaran Robotics & NAO

De loin la conférence la plus intéressante avec celle d'Intel, Aldebaran Robotics est une PME française, créée il y a 5 ans , qui crée, développe et commercialise des robots humanoïdes.


Nao : Démonstration EPITA
envoyé par Oenix. - Vidéos des dernières découvertes technologiques.

Les notes prises

Je vous met à disposition toutes les notes que j'ai prise lors de cette semaine :

Conférence inaugurale

Ecriture Article Scientifique

Le métier de chercheur

Le traitement d'image

Scribo

Orange Labs

Bouygues Telecom

Aldebaran

Intel

Simulation numérique

Altran

Microsoft

IBM

Erst&Young

Bonne lecture

16sept/101

Mat : ca existe aussi en codage …

Posté par Freezy

Désolé pour un si beau titre, je me sentais inspiré. Surtout que ça n'a aucun rapport avec le contenu du billet.

Bref ! Aujourd'hui je vais vous parler de XPath.

XPath : Kesako

XPath est un language non XML permettant de fouiller dans un document. En gros, c'est un language vous permettant de sélectionner des éléments dans une page beaucoup plus vite qu'à coups de getElementsByTagName, getElementById, etc.

XPath compte plus de 1oo fonctions qui lui sont propres (build-in). Il y a des fonctions pour les chaînes, les entiers, les flottants, les noeuds du DOM, des booléens, et j'en passe.

Qu'est-ce qu'un noeud du DOM ? C'est une balise, tout simplement. Ainsi, getElementsByTagName("img")[0] sélectionnera la première image du DOM, qui est ... un noeud. La notion de parents et enfants se retrouve : les balises incluses dans <body> sont ses enfants. <body> est aussi l'enfant de <html> et si vous poussez le raisonnement, c'est le frère de <head>. Un petit code simple pour résumer :

<html>
	<head>
		<title>Exemple</title>
	</head>

	<body>
		<div>
			<fieldset>
				<legend>Démonstration</legend>
				Bla bla bla
			</fieldset>

			<span>Encore du blabla</span>
		</div>
	</body>
</html>

Ici , <title> est l'enfant de <head>.

<legend> est l'enfant de <fiedlset>.

<fieldset> est un enfant de <div>.

<span> est un autre enfant de <div>.

C'est compris ? On passe à la suite !

Selectionner un noeud

XPath utilise des expressions de chemins relatifs ou absolus pour accéder aux éléments DOM. Voici les plus utilisés:

noeud Sélectionne tous les noeuds de la balise noeud, sans se soucier de leur emplacement dans le document.
/ Sélectionne depuis le premier noeud.
//noeud Sélectionne tous les éléments correspondants dans le document, quelle que soit leur position.
@ Sélectionne les attributs.

Voici quelques exemples : (Oui, certains ne sont pas dans le tableau. De toute façon avec des exemples c'est clair)

//fieldset sélectionne tous les fieldset du document, où qu'ils soient.

//fieldset[@class='demo'] sélectionne tous les fieldset ayant pour classe 'demo'.

//fieldset[position()<3] sélectionne les deux premiers fieldset du document.

//fieldset[position()=2] sélectionne le deuxième fieldset du document.

//fieldset[last()] sélectionne le dernier fieldset.

//fieldset[@class="demo" and position()=2]/legend sélectionne l'enfant legend du fieldset du DOM qui est le 2ème à avoir l'attribut class='demo'.

XPath et les operateurs

XPath accepte les opérateurs suivants :

+ (2+3=5), - (3-2=1) , * (2*3=6), div (6 div 2 = 3), mod (5 mod 2 = 1 (reste de la division entière))

XPath et GreaseMonkey

Comme les 3/4 de mes codes utilisant du JS sont pour GreaseMonkey, j'appelle XPath grâce à ceci :

new XPathEvaluator().evaluate(xpath, dom, null, result_type, null)

xpath : la chaîne de XPath.

dom : l'élément du DOM où chercher. le plus souvent, ce sera document.

result_type : prend plusieurs formes spécifiques, je reviendrai dessus.

Les arguments null doivent être indiqués.

RESULT_TYPE

L'objet XPathResult permet de renvoyer les ensembles de nœuds sous la forme de trois types principaux :

* Itérateurs

* Snapshots

* Premiers nœuds

Itérateurs

Lorsque le type de résultat spécifié dans le paramètre resultType est soit :

Lorsque le type de résultat spécifié dans resultType est soit :

  • NUMBER_TYPE — un nombre
  • STRING_TYPE — une chaîne
  • BOOLEAN_TYPE — une valeur booléenne

On obtiendra la valeur de retour de l'expression en accédant respectivement aux propriétés suivantes de l'objet XPathResult :

  • numberValue
  • stringValue
  • booleanValue
Exemple

Cet exemple utilise l'expression XPath count(//p) pour obtenir le nombre d'éléments <p> présents dans le document HTML :

var paragraphCount = new XPathEvaluator().evaluate( 'count(//p)', document, null, XPathResult.ANY_TYPE, null );

alert( 'Ce document contient ' + paragraphCount.numberValue + ' éléments de paragraphe' );

Types d'ensembles de nœuds

L'objet XPathResult permet de renvoyer les ensembles de nœuds sous la forme de trois types principaux :

  • Itérateurs
  • Snapshots
  • Premiers nœuds
Itérateurs

Lorsque le type de résultat spécifié dans le paramètre resultType est soit :

  • UNORDERED_NODE_ITERATOR_TYPE
  • ORDERED_NODE_ITERATOR_TYPE

L'objet XPathResult renvoyé sera un ensemble de nœuds correspondant à l'expression se comportant comme un itérateur. On pourra accéder individuellement aux nœuds qu'il contient en utilisant la méthode iterateNext() de l'objet XPathResult.

Lorsque tous les nœuds ont été parcourus, iterateNext() renverra null.

Notez cependant que si le document le document est modifié (l'arbre du document est modifié) entre les itérations, l'itérateur sera invalidé et la propriété invalidIteratorState de XPathResult deviendra true. Une exception NS_ERROR_DOM_INVALID_STATE_ERR sera également déclenchée.

Exemple d'itérateur
var iterator = document.evaluate('//phoneNumber', documentNode, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null );

try {
  var thisNode = iterator.iterateNext();

  while (thisNode) {
    alert( thisNode.textContent );
    thisNode = iterator.iterateNext();
  }
}
catch (e) {
  dump( 'Erreur : L'arbre du document a été modifié pendant l'itération ' + e );
}

Vous remarquerez document.evaluate(). Cette fonction est fonctionnelle chez tous les naviguateurs mais new XPathEvaluator().evaluate() fait partie du core de Mozilla Firefox, on la préfèrera donc.

Snapshots

Lorsque le type de résultat spécifié dans le paramètre resultType est l'une des valeurs suivantes :

  • UNORDERED_NODE_SNAPSHOT_TYPE
  • ORDERED_NODE_SNAPSHOT_TYPE

L'objet XPathResult renvoyé sera un ensemble statique de nœuds correspondant à l'expression. L'accès à chaque nœud se fera au travers de la méthode snapshotItem(itemNumber) de l'objet XPathResult, où itemNumber est l'indice du nœud à récupérer. On peut accéder au nombre total de nœuds contenus dans l'ensemble par la propriété snapshotLength.

Les snapshots ne changent pas avec les mutations du document. Aussi, contrairement aux itérateurs, le snapshot ne deviendra pas invalide mais peut ne plus correspondre au document actuel. Par exemple, des nœuds peuvent avoir été déplacés, il peut contenir des nœuds qui n'existent plus ou de nouveaux nœuds peuvent avoir été ajoutés.

Exemple de snapshot
var nodesSnapshot = document.evaluate('//phoneNumber', documentNode, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null );

for ( var i=0 ; i < nodesSnapshot.snapshotLength; i++ )
{
  dump( nodesSnapshot.snapshotItem(i).textContent );
}
Premier nœud

Lorsque le type de résultat spécifié dans le paramètre resultType est l'une des valeurs suivantes :

  • ANY_UNORDERED_NODE_TYPE
  • FIRST_ORDERED_NODE_TYPE

L'objet XPathResult renvoyé n'est que le premier nœud trouvé correspondant à l'expression XPath. On peut y accéder à l'aide de la propriété singleNodeValue de l'objet XPathResult. Celle-ci vaudra null si l'ensemble de nœuds est vide.

Notez que pour le sous-type non ordonné (le premier), le nœud unique renvoyé ne sera peut-être pas le premier nœud dans l'ordre du document. Dans le cas du sous-type ordonné (le second), vous pouvez être sûr d'obtenir le premier nœud correspond dans l'ordre du document. C'est conpliqué , hein ? ^_^

Exemple de premier nœud
var firstPhoneNumber = document.evaluate('//phoneNumber', documentNode, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null );

dump( 'Le premier numéro de téléphone trouvé est ' + firstPhoneNumber.singleNodeValue.textContent );

La constante ANY_TYPE

Lorsque le type de résultat spécifié dans le paramètre resultType est la valeur ANY_TYPE, l'objet XPathResult renvoyé pourra être de n'importe quel type, c'est-à-dire du type résultant le plus naturellement de l'évaluation de l'expression.

Il peut s'agir de n'importe lequel des types simples (NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE), mais si le type du résultat retourné est un ensemble de nœuds alors il ne pourra être que du type UNORDERED_NODE_ITERATOR_TYPE.

Pour déterminer le type utilisé après l'évaluation, on utilisera la propriété resultType de l'objet XPathResult. Voyez le tableau ci-après :

Constantes définies de XPathResult

Constante du type de résultat Valeur Description
ANY_TYPE 0 Un ensemble contenant n'importe quel type qui résulte naturellement de l'évaluation de l'expression. Notez que si c'est un ensemble de noeuds qui doit être retourné, alors le type résultant sera toujours UNORDERED_NODE_ITERATOR_TYPE.
NUMBER_TYPE 1 Un résultat contenant un seul nombre. C'est utile, par exemple, dans une expression XPath utilisant la fonction count().
STRING_TYPE 2 Un résultat contenant une seule chaîne de caractère.
BOOLEAN_TYPE 3 Un résultat contenant une seule valeur booléenne. C'est utile, par exemple, dans une expression XPath utilisant la fonction not().
UNORDERED_NODE_ITERATOR_TYPE 4 Un ensemble de nœuds contenant tous les nœuds vérifiant l'expression. Les nœuds ne sont pas nécessairement dans le même ordre que celui dans lequel ils apparaissent dans le document.
ORDERED_NODE_ITERATOR_TYPE 5 Un ensemble de nœuds contenant tous les nœuds vérifiant l'expression. Les nœuds du résultat sont dans le même ordre que celui dans lequel ils apparaissent dans le document.
UNORDERED_NODE_SNAPSHOT_TYPE 6 Un ensemble de nœuds contenant les snapshots de tous les nœuds vérifiant l'expression. Les nœuds ne sont pas nécessairement dans le même ordre que celui dans lequel ils apparaissent dans le document.
ORDERED_NODE_SNAPSHOT_TYPE 7 Un ensemble de nœuds contenant les snapshots de tous les nœuds vérifiant l'expression. Les nœuds du résultat sont dans le même ordre que celui dans lequel ils apparaissent dans le document.
ANY_UNORDERED_NODE_TYPE 8 Un ensemble de nœuds contenant un seul nœud vérifiant l'expression. Le nœud n'est pas nécessairement le premier dans l'ordre du document qui correspond à l'expression.
FIRST_ORDERED_NODE_TYPE 9 Un ensemble de nœuds contenant le premier nœud du document vérifiant l'expression.

Voilà, ce billet touche à sa fin. Bien à vous !

Freezy

11sept/100

Les Canvas : vous allez aimer !

Posté par Freezy

Attention, ceci est une note aux éditeurs : Ce billet doit être édité sous le mode HTML et non Visuel de WordPress.
Raison : Le parseur de WordPress supprime les canvas.
Merci.

Tintintin !
Voici donc ce billet tant attendu !

Rentrons dans le vif du sujet

Pas trop profondément quand même, il ne faut pas lui faire mal, inconscient !

Vous voulez un bel exemple de canvas ? Vous n'avez qu'à regarder le logo du blog, et les titres de billets ! Sur WordPress, les canvas sont partout ...

Documentation

Je ne vais pas vous parler de toute les fonctions des canvas. Pour ce soir, je vais plutôt parler de ce que j'ai dû expérimenter =). Voici l'histoire

Je me promenais sur le web quand je suis tombé sur un script GreaseMonkey décodant les captchas de MegaUpload. Fantastique ! J'ai donc plongé dans le code source ... Et je n'en ai rien compris ! J'en suis sorti avec une immense migraine ... Quelques heures plus tard, j'ai décidé de creuser le sujet. Et j'ai été ébloui.

À la fin de ce billet, vous saurez décoder des captchas (Pas très élaborés, je l'admet. D'ailleurs, plus ils sont élaborés, plus c'est difficile ... Ce qui est logique : le tricheur « décode » le mécanisme, l'administrateur le complexifie, le tricheur le re-« décode », etc.)

Rien que ça !

On va commencer avec une image basique :

Premièrement : on déclare le canvas et on lui assigne les dimensions de l'image. Rien de sorcier :

//On crée le canvas
var canvas = document.createElement("canvas");
//On lit son contexte pour pouvoir travailler dessus.
var context = canvas.getContext("2d");

//On crée l'image pour la mettre dans le canvas
var image = ...; // image contient l'élément DOM de l'image, eg document.getElementsByTagName("img")[0]
var imgWidth = image.width;
var imgHeight = image.height;

//Pour éviter les bogues, on donne au canvas les dimensions de l'image
canvas.width = imgWidth;
canvas.height = imgHeight;

Bon, et comment on met l'image dans le canvas ?

context.drawImage(image , 0, 0);

C'est d'une simplicité, vraiment ... On demande tout simplement de dessiner l'image ligne par ligne à partir du coin supérieur gauche du canvas.

Et ça donne ceci :

Votre naviguateur n'affiche pas les canvas.

C'est bien beau tout ça me direz-vous, mais il faut aussi lire le texte, et on en est pas encore là ...

Si vous n'êtes pas convaincu, cliquez droit sur l' «image». Le menu est différent, non ? =)

Pixellisation

On va faire une petite étape utile mais pas indispensable, elle permet de se simplifier le travail. On va rechercher tous les pixels gris, du moment qu'ils sont opaques (le fond est transparent) et les passer en noir. En gros, on fait pixelliser. Dans la foulée, on vire la transparence du fond.

var imageData = context.getImageData(0, 0, imgWidth, imgHeight); //On lit les données du canvas
var pixels = imageData.data; //On obtient le tableau des pixels
for ( var i = 0, n = pixels.length ; i < n ; i += 4 )
{
	//On lit les trois composantes R,V,B du pixel et sa transparence alpha.
	var red = pixels[i];
	var green = pixels[i+1];
	var blue = pixels[i+2];
	var alpha = pixels[i+3];

	//if(red != 255 && green != 255 && blue != 255)
	//Condition alternative : les pixels de fond sont transparents, pas le texte, ce qui diminue la condition et augmente donc la vitesse du code.
	if(alpha != 0)
	{
		//On est tombé sur un pixel non blanc / transparent, on le met en noir et opaque.
		pixels[i] = 0;
		pixels[i+1] = 0;
		pixels[i+2] = 0;
	}
	else
	{
		//C'est un pixel blanc, on le passe en opaque.
		pixels[i] = 255;
		pixels[i+1] = 255;
		pixels[i+2] = 255;
		pixels[i+3] = 255;
	}
}

Oui, je vous dois pas mal d'explications.

La première chose à savoir, c'est que les pixels ont 4 informations dans un canvas : les trois composantes des couleurs primaires, et leur transparence alpha. Pour lire tous les pixels, il ne faut donc pas lire le tableau des pixels un à un, mais 4 à 4, et lire chaque valeure. Le pixel 1 est en position 0, et le 2 en position 4, le 3ème en 8, etc...

Ensuite, je lis les composantes du pixel et sa transparence. Une bête condition me permet de distinguer les pixels transparents des gris (la condition alternative est superbe). Si je tombe sur un pixel grisé ou noir, je met ses 3 composantes RVB à 0, et dans le cas échéant, je met le pixel en blanc opaque.

Vous voulez un rendu, petits chanceux ?


Votre naviguateur Web ne supporte pas les canvas.

Pas mal, hein ?

Je ne vous ai pas parlé de la fonction permettant d'envoyer les données du canvas. La voici :

context.putImageData(imageData, 0, 0);

Encore une fois, très simple, on envoie les données des pixels dans le canvas en écrasant les anciennes données.

On a fait la moitié, les enfants ... x) Maintenant, on va faire un peu de théorie.

Lecture des chiffres

Comment l'œil humain lit-il un caractère ? Il le voit dans sa globalité. Mais un script, lui, doit le lire colonne par colonne. On va donc créer un array contenant toutes les colonnes de pixels de l'image. Cette solution est suffisante ici car l'image n'est pas dans des dimensions gigantesques. Dès qu'on touche à des canvas plus complexes, il faudrait spécifier au script à quel pixel précisement commencer et finir, pour éviter de collecter des données inutiles.

Voici mon code source. L'explication le suit

    var columns = new Array(); //On déclare le tableau des colonnes
    var imageDataWidth = imageData.width;
    var imageDataHeight = imageData.height;
    //On lit les pixels
    for ( var x = 0 ; x < imageDataWidth ; x += 1 )
    {
        var column_buffer = new Array(); // Cette variable contiendra chaque colonne.
        for ( var y = 0 ; y < imageDataHeight ; y += 1 )
        {
            var imageDataPixels = imageData.data; //On lit les informations sur l'image
            var i = y * imageDataWidth * 4 + x * 4; //L'index du pixel considéré

            //On teste les composantes R, V ,B
            if (imageDataPixels[i] == 0 && imageDataPixels[i+1] == 0 && imageDataPixels[i+2] == 0)
            {
                //Pixel noir = 1
                column_buffer.push(1);
            }
            else
            {
                //Pixel blanc = 0
                column_buffer.push(0);
            }
        }

        columns.push(column_buffer); //On envoie la colonne de pixels dans l'array les contenant tous.
    }

D'abord, on récupère les dimensions des données sur l'image. imageData est un objet contenant un mappage des pixels du canvas.

Ici, les variables x et y sont trompeuses.x parcourt toutes les colonnes de pixels, et y les pixels des lignes. C'est un peu compliqué et je ne vois pas trop comment expliquer ça. Le mieux est que vous testiez le code source.

Ah, et i, c'est quoi ? La documentation Mozilla (anglaise) l'explique très bien :

For example, to read the blue component's value from the pixel at column 200, row 50 in the image, you would do the following:

blueComponent = imageData.data[((50*(imageData.width*4)) + (200*4)) + 2];

Ce qui se traduit par : « Pour lire la composante bleue du pixel aux coordonnées X = 200 et Y = 50 dans une image, vous écririez ceci : ... »

J'ai repris la formule, en supprimant le + 2, puisque je veux lire toutes les composantes.

On va donc se retrouver avec un tableau de tous les pixels : s'ils sont blancs, ils sont représentés par un 0, sinon par un 1. Simple, non ? ^_^

Je ne colle pas ici l'état de l'array, c'est inutile puisque le code source fonctionne parfaitement comme vous allez le voir à la suite de cette partie.

La cerise sur le gateau : le dechiffrage !

Allez, maintenant, on va faire encore un peu de théorie.

On a un tableau des colonnes de pixels. Comment détecter la fin d'un caractère ? S'il est suivi d'une colonne entièrement vide, autrement dit constituée de 0 dans l'array ! Mais il peut y avoir une ou deux colonnes vides ... Alors comment fait-on ? Eh bien, on s'en fout !

Ici, la lecture des caractères est extrêmement simple. Pour des lettres plus difficiles, il faut utiliser un réseau neuronal. Je ne m'y connais pas du tout. Tout ce que je sais, c'est qu'il s'agit d'un script qui, sur la base de valeurs précalculées, est capable de déterminer si tel caractère est un a, un z, un t, etc ... Peut-être qu'Oenix vous éclairera.

On va faire une bête comparaison. Je me suis embêté à obtenir les structures des chiffres de 0 à 9 et du point dans le canvas pixellisé. Les voici en prime time pour vous.

	var empty_column_reference = new Array(0,0,0,0,0,0,0,0); // Référence pour la colonne vide.
	var one = new Array(0,1,0,0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0); // Référence pour le 1. Suite des colonnes.
	var two = new Array(1,1,0,0,0,1,1,0,1,1,0,0,1,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,0,1,0,1,1,1,1,0,0,1,0); // Référence pour le 2. ------------------.
	var thr = new Array(1,1,0,0,0,1,1,0,1,1,0,0,0,1,1,0,1,0,0,1,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0); // Référence pour le 3. ------------------.
	var fou = new Array(0,0,0,1,1,0,0,0,0,1,1,1,1,0,0,0,1,1,1,0,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,1,0,0,0); // Référence pour le 4. ------------------.
	var fiv = new Array(1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,1,1,0,1,1,0,1,0,1,1,1,1,1,0); // Référence pour le 5. ------------------.
	var six = new Array(0,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,1,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0); // Référence pour le 6. ------------------.
	var sev = new Array(1,0,0,0,0,0,0,0,1,0,0,0,0,1,1,0,1,0,0,1,1,1,1,0,1,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0); // Référence pour le 7. ------------------.
	var hei = new Array(1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0,1,0,1,1,0,0,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,0); // Référence pour le 8. ------------------.
	var nin = new Array(1,1,1,1,0,0,0,0,1,1,1,1,0,0,1,0,1,0,0,1,0,1,1,0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0); // Référence pour le 9. ------------------.
	var zer = new Array(1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1,1,1,1,1,1,1,0); // Référence pour le 0. ------------------.
	var poi = new Array(0,0,0,0,0,1,1,0); // Référence pour le .

Et voici la routine qui lit les caractères.

var matrixBuffer = new Array();
var numerb_sequence = new Array();

//Columsn est la matrice des pixels obtenue à l'étape précédente.
	for ( var x = 0 , arrayLength = columns.length; x < arrayLength ; x += 1 )
	{
		//On vérifie si on a affaire à une colonne vide.
		if( columns[x].join(",") ==  empty_column_reference.join(","))
		{
			//Il s'agit d'une colonne vide
			//Ce qui signifie qu'il y a un chiffre derrière
			//Si la matrice n'est pas vide on la teste
			if(matrixBuffer.length != 0)
			{
				//On teste
				if (matrixBuffer.join(",") == one.join(","))
				{
					number_sequence.push(1);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == two.join(","))
				{
					number_sequence.push(2);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == thr.join(","))
				{
					number_sequence.push(3);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == fou.join(","))
				{
					number_sequence.push(4);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == fiv.join(","))
				{
					number_sequence.push(5);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == six.join(","))
				{
					number_sequence.push(6);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == sev.join(","))
				{
					number_sequence.push(7);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == hei.join(","))
				{
					number_sequence.push(8);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == nin.join(","))
				{
					number_sequence.push(9);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == zer.join(","))
				{
					number_sequence.push(0);
					matrixBuffer = new Array();
				}
				if (matrixBuffer.join(",") == poi.join(","))
				{
					number_sequence.push(" ");
					matrixBuffer = new Array();
				}
			}
		}
		else
		{
			//On ajoute l'array à la matrice sans tenir compte des colonnes : on les met les unes après les autres.
			for ( var y = 0 ; y < columns[x].length; y += 1 )
			{
				matrixBuffer.push(columns[x][y]);
			}
		}
	}

Je ne sais pas si vous avez compris. En gros, chaque lettre est référencée par l'ensemble des colonnes de pixels la composant qui possèdent au moins 1 pixel noir. Cet ensemble de colonnes est mis bout à bout.

Ensuite, je créée une variable qui est un tableau, matrixBuffer. Dans cette variable, je stocke les pixels en lecture, tant que je ne tombe pas sur une colonne vide ou une lettre. Dans le cas d'une lettre, je l'envoie dans le tableau contenant la liste des chiffres, et je vide matrixBuffer pour ne pas avoir les données de précédentes lettres.

Si matrixBuffer est vide, on la remplit. Il est vrai que je peux le faire hors du code source mais c'est plus classe comme ça, je trouve.

La vérification de la présence d'un caractère se fait si on tombe sur une colonne vide : on compare matrixBuffer aux références pour déterminer le caractère. Dans tous les cas, on vide matrixBuffer.

Et voici donc pour vous, en exclusivité, le décodage de cette image. Le code n'est pas optimisé du tout et n'a pas été concu dans cette approche.

Somme lue :

Rappel de l'image :

Pas mal, hein ? À bientôt !

Freezy

Attention, ceci est une note aux éditeurs : Ce billet doit être édité sous le mode HTML et non Visuel de WordPress.
Raison : Le parseur de WordPress supprime les canvas.
Merci.

Oh, et tant que j'y suis ...

[Site "Chess.com"]
[Date "2010.09.10"]
[White "Freezy"]
[Black "U.N. Owen"]
[Result "1-0"]

1.d4 d5 2.Nc3 e6 3.Nf3 c5 4.e3 Nf6 5.Ne5 Nc6 6.Nxc6 bxc6 7.f4 cxd4 8.exd4 c5 9.Bb5+ Bd7 10.Be2 Bd6
 11.O-O O-O 12.f5 e5 13.dxe5 Bxe5 14.Nxd5 Bxf5 15.Rxf5 Bd4+ 16.Kh1 Nxd5 17.Bg5 Qd7 18.Bg4 Ne3 19.Bxe3 { Cette prise est un piège. Si le fou prend, la dame noire disparaît. Et effectivement ... } Bxe3 20.Qxd7 Rad8
 21.Qxa7 Rd2 22.Rxf7 { 2 variantes ici. Si Rxf7, alors la suite de la partie vous intéressera. Si la tour n'est pas capturée, alors Rxg7+, Kh8, Rxh7+, Kg8, Qh7# } Rxf7 23.Be6 { Clouant la tour. } Rdf2 { Prévenant du mat par Qxf7+, mais pas de celui qui s'en suit. } 24.Qb8# 1-0


10sept/100

Objective Caml (Partie 1)

Posté par oenix

Oh, un langage de programmation obscur que je vais utiliser toute l'année scolaire.

Presentation du langage

Objective Caml est un langage fonctionnel et impératif, qui peut être interprété et compilé.  Il a été créé en 1984 par INRIA (Je vous invite, pour plus de précision, à aller sur leur site : http://caml.inria.fr ).

Avant de commencer quoi que ce soit, nous allons tout d'abord télécharger le logiciel Objective Caml, pour interpréter notre code. Rendez vous ici : http://caml.inria.fr/ocaml/release.fr.html et lancez l'installation.

Un langage fortement type

Objective Caml est un langage tellement typé, qu'il est impossible d'additionner entre eux des réels et des entiers, et les opérateurs sont spécifiques à chaque type.

+ : opérateur d'addition sur des entiers
+. : opérateur d'addition sur des réels
- : annonce le résultat d'un calcul
:int : calcul de type entier
:float : calcul de type réel

# 1 + 2;;
-:int = 3

#(1. +. 1. /. 7.) *. 7.;;
-:float = 8

Vous l'aurez compris, les entiers avec un point derrière sont considérés comme des réels

Il vaut mieux apprendre par l'exemple

#let pi = 4.0 *. atan 1.0;;
val pi : float = 3.14159265358979312

#let square x = x *. x;;
val square : float -> float = <fun>

#square(sin pi) +. square(cos pi);;
- : float = 1.

Ici, on définit la valeur de pi grâce à la propriété let, puis nous définissons une fonction carré grâce encore à la propriété let, et nous nous en servons avec des valeurs. La classe ! (Bon, si vous n'avez jamais programmé quoi que ce soit, ça doit être obscur)

# let x = 1 and y = 2 and u="un";;
val x :int = 1
val y :int = 2
val u :string = "un"

C'est magnifique, nous pouvons déclarer trois variables en une seule ligne, et trois variables de types différents !

# let x = 10 in let y = 2 * x in x + y;
-:int = 30

Ici, nous déclarons des variables utilisable uniquement dans l'expression qui suit. Ainsi, on définit x = 10, on l'utilise pour y de telle sorte que y = 2*x = 20, et nous utilisons les deux dans x + y = 10 + 20 = 30. C'est pas sorcier, n'est-ce pas !

# let quad x = let carre y = y*y in carre (carre x);;
val quad : int -> int = <fun>
# quad 4;;
-:int = 256

Ca marche aussi avec les fonctions !

Allez, je vous dis à la prochaine fois, avec les filtrages !

10sept/102

Echec et mats

Posté par Freezy

Non, je ne vais pas vous parler des canvas. Pas encore. En fait, j'ai la flemme de le rédiger, ce billet.

Le saviez vous ? Oenix est une tanche aux échecs. Pour ne pas le ridiculiser, je ne posterai pas les mats que je lui pose, mais juste quelques belles parties par mes soins.

[Site "Internet"]
[Date "2010.09.09"]
[White "Freezy"]
[Black "N"]
[Result "1-0"]

1.d4 c6 2.Nf3 e6 3.e4 c5 4.d5 exd5 5.exd5 c4 6.Bxc4 Bc5 7.d6 h6 8.Qd5 Qf6 9.Qxc5 Nc6 10.O-O Qg6 11.Re1+ Kd8 12.Na3 Nf6 13.Bf4 Ne4 14.Rxe4 { Évite les complications techniques. } 14...Qxe4 15.g3 { Protège le fou mais oublie le cavalier. } 15...Qxf3 16.Re1 { Prend le contrôle de la colonne e. } 16...Re8 17.Re3 Qd1+ 18.Bf1 { Plutôt que de défendre avec la tour, je protège à l'aide de mon fou. } 18...b6 19.Bg5+! { Une tentative osée.
1) Si hxg5, alors Qxg5+. Trois variantes :
a) f7. Elle a eu lieu dans la partie.
b) Ne7. Faible car Qc7#.
c) Re7. Suivi par Rxe7, et les blancs ont l'avantage.
2) Si Ne7, Qc7#.
3) Si Re7, Alors Bxe7+ etc. } 19...hxg5 20.Qxg5+ f6 21.Qxg7 { Un coup intéressant.
Rxe4 serait de loin la meilleure défense, laissant le roi exposé mais évitant le mat.
Supposons :
Rxe4, fxe3, et les blancs menacent du mat par Qxf7, forçant soit la défense par le cavalier, soit la fuite du roi sur e.
Mais les noirs ont une autre vision des choses. } 21...Re6? 22.Qf8+ Re8 23.Rxe8# 1-0


Voilà, vous avez découvert ma deuxième grande passion : les échecs <3

Oh et puis, au diable les scrupules ...

[Site "Internet"]
[Event "Live Chess"]
[Date "2010.09.09"]
[White "freezy"]
[Black "karzix"]
[Result "1-0"]

1.d4 c5 2.dxc5 Qa5+ 3.c3 Qxc5 4.Nh3 d5 5.b4 Qc4 6.e3 Qc7 7.Bd3 h5 8.Qf3 Qc6 9.a4 Bg4 10.Qg3 g5
 11.Bb5 h4 { M'offrant le mat sur un plateau } 12.Qxg4 ?? Qxb5 13.Qc8# 1-0


J'espère que mon nouveau collège, dont le billet ne devrait sans doute pas tarder, est plus doué :D

7sept/100

Les series critiquees par oenix.net

Posté par oenix

La rentrée des séries approche à grands pas , et il est désormais l'heure pour nous de vous proposer l'agenda de sortie des séries qui seront critiquées par notre site.

Lundi 20 septembre

How I met Your Mother - CBS
Two and a Half Men - CBS
House - Fox

Mardi 21 septembre

Glee - Fox

Jeudi 23 septembre

Big Bang Theory - CBS
30 Rock - NBC

D'autres séries viendront peut être s'ajouter au fur et à mesure de l'année.
Voilà, vous savez désormais où suivre l'actualité de vos séries préférées.

7sept/100

Le cryptage a masques jetables : implementation en PHP

Posté par Freezy

Coucou les enfants !

Ne vous inquiétez pas, les articles sur les canvas (dont vous devez baver d'impatience, j'imagine :) ) ne sont pas annulés, mais simplement reportés. Promis !

Je vais donc vous parler du cryptage à masque jetable.

Quel interet ?

Admettons que sur votre site, vous ayez un espace membres. Un de vos fidèles lecteurs (comme vous !) oublie son mot de passe. Penaud, il envoie un mail de génération d'un nouveau mot de passe. Le problème est réglé.

Oui, mais il y a plus simple. Vous n'avez jamais vu de sites vous rendre votre mot de passe ? Oh non, je ne vais pas vous dire qu'il faut stocker les mots de passe en clair (imprudent !). Mais vous parlez d'un système de cryptage (Comment ça, je radote ?).

Theo rit

(pardon). On va ajouter un nouvel élément sur votre site : une clef de cryptage. En gros, il s'agit d'une phrase, d'un mot, ou de que sais-je encore, que l'on utilise pour crypter votre mot de passe de façon réversible.

L'idée est la suivante : à chaque lettre correspond un nombre. Lors du cryptage, on concatène la clef à elle même. Puis on la met à la longueur du mot de passe. Ensuite, on lit la première lettre du mot de passe. On récupère le nombre correspondant. On fait pareil pour la clef. On fait la somme des deux nombres et on répète ça pour chaque caractère, et le mot de passe est crypté !

Et si le nombre obtenu dépasse le « maximum » (26 si vous numérotez ainsi : a : 1, b : 2, etc) ? Eh bien, on lui soustrait 26, et c'est réglé : tout se passe comme si on concaténait l'alphabet (j'aime ce mot) à lui même !

Ce n'est pas clair ? Avec le code PHP dont vous êtes friants, ça va l'être !

Pra tique

(Ce jeu de mots merdique ne fonctionne pas toujours. Hum...)

On va faire simple : à la lettre a correspond le chiffre 1, et à z 26. On se fout de la casse (pas envie de me fatiguer avec 52 valeures).

Ca nous donne un joli array tout ce qu'il y a de plus basique :

$alphabet = array(1 => "a",
				  2 => "b",
				  3 => "c",
				  4 => "d",
				  5 => "e",
				  6 => "f",
				  7 => "g",
				  8 => "h",
				  9 => "i",
				  10 => "j",
				  11 => "k",
				  12 => "l",
				  13 => "m",
				  14 => "n",
				  15 => "o",
				  16 => "p",
				  17 => "q",
				  18 => "r",
				  19 => "s",
				  20 => "t",
				  21 => "u",
				  22 => "v",
				  23 => "w",
				  24 => "x",
				  25 => "y",
				  26 => "z");

Bon, et maintenant ? On va s'amuser !

Cryptage

On va déclarer une jolie fonction PHP =)

function crypt($pass, $key)
{
	//Il faut vraiment que je me calme avec les parenthèses.
}

Première chose à faire : lire la longueur du mot de passe, pour modifier celle de la clef, et faire la boucle pour crypter.

function crypt($pass, $key)
{
	$passLength = strlen($key);
}

Rien de fabuleux pour l'instant. Et dites-moi, comment fait on pour lire le x-ième caractère d'un mot ?

[...]

string substr ( string $string , int $start [, int $length ] )

[...]

On fait avec cette fonction. Nouvelle question : quelle est la position de "l" dans la chaîne "cuticule" ?

Si vous avez répondu 6, bravo ! En effet, le premier caractère est à la position 0 :

C U T I C U L E
0 1 2 3 4 5 6 7

Passons maintenant à la modification de la clef : il faut qu'elle soit aussi longue que le mot de passe.

Ce petit code simple fera l'affaire :

	while ( strlen($key) =< $passLength )
	{
		$key .= $key;
	}
	$key = substr($key, 0, $passLength);

Rien de sorcier : tant que la clef n'est pas aussi longue ou plus longue que le mot de passe, on la concatène à elle-même. Ensuite, on coupe pour avoir une clef de longueur égale à celle du mot de passe.

Et maintenant ? Maintenant, on va tout passer en lowercase pour pouvoir utiliser notre bel alphabet ! On a donc finalement cette fonction :

function crypt($pass, $key)
{
	$alphabet = array(1 => "a",
					2 => "b",
					3 => "c",
					4 => "d",
					5 => "e",
					6 => "f",
					7 => "g",
					8 => "h",
					9 => "i",
					10 => "j",
					11 => "k",
					12 => "l",
					13 => "m",
					14 => "n",
					15 => "o",
					16 => "p",
					17 => "q",
					18 => "r",
					19 => "s",
					20 => "t",
					21 => "u",
					22 => "v",
					23 => "w",
					24 => "x",
					25 => "y",
					26 => "z");
	$passLength = strlen($key);
	while ( strlen($key) =< $passLength )
	{
		$key .= $key;
	}
	$key = substr($key, 0, $passLength);
	$key = strtolower($key);
	$pass = strtolower($pass);
}

Et allons-y pour notre chère boucle. Vous pouvez faire un while() ou un for(). Je préfère while()

	$i = 0;
	while( $i < $passLength )
	{

	}

Si vous ne comprenez pas pourquoi la comparaison est stricte, c'est écrit plus haut.

Que met-on dans notre boucle ? D'abord, on lit le caractère à la $i-ième position dans le mot de passe et dans la clef. Ensuite, on récupère le caractère correspondant à la somme, et on le concatène à la chaîne résultante.

Ça nous donne ceci :

function crypt($pass, $key)
{
	$alphabet = array(1 => "a",
					2 => "b",
					3 => "c",
					4 => "d",
					5 => "e",
					6 => "f",
					7 => "g",
					8 => "h",
					9 => "i",
					10 => "j",
					11 => "k",
					12 => "l",
					13 => "m",
					14 => "n",
					15 => "o",
					16 => "p",
					17 => "q",
					18 => "r",
					19 => "s",
					20 => "t",
					21 => "u",
					22 => "v",
					23 => "w",
					24 => "x",
					25 => "y",
					26 => "z");
	$passLength = strlen($key);
	while ( strlen($key) =< $passLength )
	{
		$key .= $key;
	}
	$key = substr($key, 0, $passLength);
	$key = strtolower($key);
	$pass =	strtolower($pass);

	//Je triche parceque les valeurs de l'alphabet devraient être les clefs. Oui, je suis maso ! (en codage seulement)
	$alphabet = array_flip($alphabet); //Et un problème en moins !

	$outputHash = "";
	$i = 0;

	while( $i < $passLength )
	{
		$charPass = substr($pass, $i, 1);
		$charKey = substr($key, $i, 1);

		$indexPass = $alphabet[$charPass];
		$indexKey = $alphabet[$charKey];

		$indexOutput = $indexKey + $indexPass;
		$outputChar = array_search($indexOutput, $alphabet);
		$outputHash .= $outputChar;
	}

	return $outputHash;
}

Je n'ai rien oublié, je crois.

Pardon !

function crypt($pass, $key)
{
	$alphabet = array(1 => "a",
					2 => "b",
					3 => "c",
					4 => "d",
					5 => "e",
					6 => "f",
					7 => "g",
					8 => "h",
					9 => "i",
					10 => "j",
					11 => "k",
					12 => "l",
					13 => "m",
					14 => "n",
					15 => "o",
					16 => "p",
					17 => "q",
					18 => "r",
					19 => "s",
					20 => "t",
					21 => "u",
					22 => "v",
					23 => "w",
					24 => "x",
					25 => "y",
					26 => "z");
	$passLength = strlen($key);
	while ( strlen($key) =< $passLength )
	{
		$key .= $key;
	}
	$key = substr($key, 0, $passLength);
	$key = strtolower($key);
	$pass =	strtolower($pass);

	//Je triche parceque les valeurs de l'alphabet devraient être les clefs. Oui, je suis maso ! (en codage seulement)
	$alphabet = array_flip($alphabet); //Et un problème en moins !

	$outputHash = "";
	$i = 0;

	while( $i < $passLength )
	{
		$charPass = substr($pass, $i, 1);
		$charKey = substr($key, $i, 1);

		$indexPass = $alphabet[$charPass];
		$indexKey = $alphabet[$charKey];

		$indexOutput = $indexKey + $indexPass;
		$outputChar = array_search($indexOutput, $alphabet);
		$outputHash .= $outputChar;
		$i++;
	}

	return $outputHash;
}

Ah zut, il manque encore la condition pour le dépassement des 26 nombres ...

function crypt($pass, $key)
{
	$alphabet = array(1 => "a",
					2 => "b",
					3 => "c",
					4 => "d",
					5 => "e",
					6 => "f",
					7 => "g",
					8 => "h",
					9 => "i",
					10 => "j",
					11 => "k",
					12 => "l",
					13 => "m",
					14 => "n",
					15 => "o",
					16 => "p",
					17 => "q",
					18 => "r",
					19 => "s",
					20 => "t",
					21 => "u",
					22 => "v",
					23 => "w",
					24 => "x",
					25 => "y",
					26 => "z");
	$passLength = strlen($key);
	while ( strlen($key) =< $passLength )
	{
		$key .= $key;
	}
	$key = substr($key, 0, $passLength);
	$key = strtolower($key);
	$pass =	strtolower($pass);

	//Je triche parceque les valeurs de l'alphabet devraient être les clefs. Oui, je suis maso ! (en codage seulement)
	$alphabet = array_flip($alphabet); //Et un problème en moins !

	$outputHash = "";
	$i = 0;

	while( $i < $passLength )
	{
		$charPass = substr($pass, $i, 1);
		$charKey = substr($key, $i, 1);

		$indexPass = $alphabet[$charPass];
		$indexKey = $alphabet[$charKey];

		$indexOutput = $indexKey + $indexPass;
		if($indexOutput > 26)
		{
			$indexOutput -= 26;
		}

		$outputChar = array_search($indexOutput, $alphabet);
		$outputHash .= $outputChar;
		$i++;
	}

	return $outputHash;
}

Je vous laisse la tester, je la code à la volée. Explications sur la boucle ...

1) On lit le $i-ième caractère de la clef et du mot de passe.

2) On récupère le chiffre correspondant à chacun, dont on fait la somme.

3)  On récupère le caractère correspondant, qu'on concatène ( <3 ) à la chaîne renvoyée, à savoir la chaîne cryptée.

Décryptage

Rien de sorcier, vous renommez la fonction ci-dessus, en changeant le signe de la somme ligne 52. Je pense que la condition lignes 53 / 54 / 55 / 56 est inutile, je vous laisse le soin de le déterminer. Il commence à faire tard, je n'ai pas voulu enregistrer ce billet en brouillon, et j'ai codé tout ça à la volée.

À bientôt !

6sept/100

HTML5 & Canvas : Oh joie !

Posté par Freezy

Pardonnez Oenix pour son précédent billet, c'est un faggot des séries pas françaises. D'une certaine manière, il n'a pas tout à fait tort ... Qui peut me citer une série télévisée française diffusée aux États-Unis ?

Je vais donc vous parler de quelque chose qui n'a aucun rapport avec Rock 3o : les canvas.

Qu'est-ce qu'un canvas ?

Un canvas est un élément d'HTML5 qui autorise le rendu dynamique d'images bitmap en 2D.

C'est très simple. Un canvas vous permet d'afficher des images bitmap en 2D.

okay

Désolé. La précision est importante car il est prévu que les canvas affichent des images en 3D. Mais faut pas rêver, ça ne sera pas du niveau de vos jeux adorés.

Quelles sont les utilisations d'un canvas ?

Il y en a un paquet. Citons quelques exemples :

- Google, pour les 3o ans de PacMan, a créé une version Googlisée du jeu disponible d'ailleurs ici. Avis aux amateurs.

- Il est possible de copier une image pour en obtenir la base64. De même, on peut travailler sur ses pixels. Je vous en parlerai dans d'autres billets. Plus d'informations sur la base64 ? Wikipédia rendra tout limpide ici.

- Enfin, on peut dessiner dans un canvas.

Manipulation des canvas

Si un canvas se déclare en HTML, grâce à la balise <canvas>, toutes les manipulations sur ce dernier se font via JavaScript. Pour une liste presque exhaustive (rien n'est parfait) des fonctionnalités des canvas, clicouillez ici.

Comment faire un canvas ? Rien n'est plus simple :

<canvas width="" height="">
     Texte alternatif dans le cas où la balise n'est pas supportée par le navigateur.
</canvas>

Je sens que vous brûlez d'envie de commencer à les manipuler. Bande de petits impatients, vous devrez attendre mon prochain billet ! En fait, mes deux prochains billets, tant les notions sont vastes.

À bientôt :)