<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Blog personnel de Jérémy TRUFIER &#187; Jérémy TRUFIER</title>
	<atom:link href="http://www.jeremy-trufier.net/author/tronix/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.jeremy-trufier.net</link>
	<description>Un blog utilisant WordPress</description>
	<lastBuildDate>Fri, 01 Apr 2011 16:50:32 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1</generator>
		<item>
		<title>Ethical Hacking &#8211; Virus indétectables &#8211; Podcast #2</title>
		<link>http://www.jeremy-trufier.net/2011/03/24/ethical-hacking-virus-indetectables-podcast-2/</link>
		<comments>http://www.jeremy-trufier.net/2011/03/24/ethical-hacking-virus-indetectables-podcast-2/#comments</comments>
		<pubDate>Thu, 24 Mar 2011 15:00:31 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[Podcast]]></category>
		<category><![CDATA[Réseaux et Sécurité]]></category>
		<category><![CDATA[antivirus]]></category>
		<category><![CDATA[base virale]]></category>
		<category><![CDATA[démonstration]]></category>
		<category><![CDATA[ethical hacking]]></category>
		<category><![CDATA[ingésup]]></category>
		<category><![CDATA[laboratoire sécurité]]></category>
		<category><![CDATA[podcast]]></category>
		<category><![CDATA[signature]]></category>
		<category><![CDATA[virus]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=351</guid>
		<description><![CDATA[Voici mon second podcast pour Ingésup Bordeaux, il fait partie de la série de podcast que je réalise pour le laboratoire sécurité sur le thème des virus indétectables. Ce podcast traite de la modification de la signature d&#8217;un virus, c&#8217;est une technique qui fut beaucoup utilisée, il y a quelques années, lorsque les éditeurs d&#8217;antivirus [...]]]></description>
			<content:encoded><![CDATA[<p>Voici mon second podcast pour Ingésup Bordeaux, il fait partie de la série de podcast que je réalise pour le laboratoire sécurité sur le thème des virus indétectables.</p>
<p>Ce podcast traite de la modification de la signature d&#8217;un virus, c&#8217;est une technique qui fut beaucoup utilisée, il y a quelques années, lorsque les éditeurs d&#8217;antivirus ne se basaient <strong>que</strong> sur la base virale pour détecter un virus.</p>
<p>La majeure partie de ce podcast est une démonstration, où un anti-virus qui au départ, comportait des signatures virales, n&#8217;en possède plus à la fin et marche toujours aussi bien.</p>
<p>Bon visionnage !</p>
<p><strong><span style="color: #008000; font-style: italic;">Je vous invite à lire le podcast si dessous en plein écran et en résolution 720p, dans une qualité inférieure, les textes peuvent ne pas être visibles.</span></strong></p>
<p>
<object style="width:490px; height:396px;">
<param name="movie" value="http://www.youtube.com/v/AUP-ULyrqbY?version=3" />
<param name="allowScriptAccess" value="always" />
<param name="wmode" value="transparent" />
<param name="allowFullScreen" value="true" />
<embed src="http://www.youtube.com/v/AUP-ULyrqbY?version=3" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" wmode="transparent" width="490" height="396"></object>
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2011/03/24/ethical-hacking-virus-indetectables-podcast-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CocoaTouch #1 &#8211; UITextField dans UITableView, UIScrollView et animations ergonomiques</title>
		<link>http://www.jeremy-trufier.net/2011/03/21/cocoatouch-1-uitextfield-dans-uitableview-uiscrollview-et-animations-ergonomiques/</link>
		<comments>http://www.jeremy-trufier.net/2011/03/21/cocoatouch-1-uitextfield-dans-uitableview-uiscrollview-et-animations-ergonomiques/#comments</comments>
		<pubDate>Mon, 21 Mar 2011 18:48:24 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[CocoaTouch]]></category>
		<category><![CDATA[Développement]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[cocoa]]></category>
		<category><![CDATA[cocoatouch]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[ipad]]></category>
		<category><![CDATA[iphone]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[NSTableView]]></category>
		<category><![CDATA[NSTextField]]></category>
		<category><![CDATA[xcode]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=291</guid>
		<description><![CDATA[J&#8217;ai parcouru de nombreux articles explicatifs et de nombreux forums sans trouver une solution suffisamment efficace pour intégrer de façon clair des UITextView dans un UICell au sein d&#8217;un UITableView, mais surtout sans trouver de solution a une problématique qui est de conserver le UITextField visible lors de la frappe au clavier. En effet la [...]]]></description>
			<content:encoded><![CDATA[<div class="alignleft size-full wp-image-123" style="margin-right: 10px;"><object width="180" height="344"><param name="movie" value="http://www.youtube.com/v/Y9Hd_uhsBPM?hl=fr&amp;fs=1" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="180" height="344" src="http://www.youtube.com/v/Y9Hd_uhsBPM?hl=fr&amp;fs=1" allowscriptaccess="always" allowfullscreen="true"></embed></object></div>
<p>J&#8217;ai parcouru de nombreux articles explicatifs et de nombreux forums sans trouver une solution suffisamment efficace pour intégrer de façon clair des <em>UITextView</em> dans un <em>UICell</em> au sein d&#8217;un <em>UITableView</em>, mais surtout sans trouver de solution a une problématique qui est de conserver le <em>UITextField</em> visible lors de la frappe au clavier. En effet la majeure partie des solutions décalent la vue sans se soucier de la possibilité de scroll, ce qui provoque des décalages impressionnants et une impossibilité de revenir voir les champs précédents. Ce tutorial propose une solution, tout en expliquant pas à pas depuis la création de la <em>UITableView</em>, en passant par l&#8217;intégration des <em>UITextField</em>, et en finissant par les différents calculs permettant d&#8217;arriver à un résultat satisfaisant (avec utilisation de <em>Core Animation</em>).  Nous verrons également comment mettre des informations avant notre UITableView dans une même UIScrollView sans utiliser la ScrollView par défaut du TableView.</p>
<p><span id="more-291"></span></p>
<div id="attachment_339" class="wp-caption alignright" style="width: 250px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/03/Capture-2011-03-16-à-22.12.31.png" rel="lightbox[291]"><img class="size-medium wp-image-339" title="CocoaTouch #1 - arborescence virtuelle" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/03/Capture-2011-03-16-à-22.12.31-240x300.png" alt="" width="240" height="300" /></a><p class="wp-caption-text">Arborescence virtuelle</p></div>
<p>
<h2>Préliminaire</h2>
<p>Lancez XCode et créez un nouveau projet de type iOS&gt;View-Based Application pour iPhone (vous pouvez décocher Include Unit Tests dans l&#8217;assistant de création, nous ne nous servirons pas des tests unitaires).  J&#8217;ai nommé le mien &laquo;&nbsp;JT_Blog_CocoaTouch_1&#8243;, si vous retrouvez cette chaine dans le tuto, ce sera votre nom de projet qui la remplacera.</p>
<p>Par défaut XCode dispose tout les fichiers à la racine de l&#8217;espace de travail du projet, je ne trouve pas cette disposition très claire et préfère créer des groupes dans l&#8217;arborescence virtuelle tels que ci-contre</p>
<p>Vous remarquerez que mes Headers &laquo;&nbsp;.h&nbsp;&raquo; sont à un emplacement différent de son &laquo;&nbsp;.m&nbsp;&raquo;, je fais ceci tout simplement pour éviter d&#8217;alourdir visuellement l&#8217;arborescence (mon dossier Headers est toujours fermé), pour accéder aux headers, il suffit de faire glisser trois doigts vers le haut ou vers le bas du Trackpad ou d&#8217;appuyer sur<em> Command+Option+Haut </em>ou<em> Command+Option+Bas</em>.</p>
<p>
<h2>Cellule éditable</h2>
<h3>Delegates</h3>
<p>Maintenant, créez, dans le dossier Delegates, une nouvelle classe (Cocoa Touch &gt; Objective-C class) qui hérite de <em>UITableViewCell</em> nommée &laquo;&nbsp;<em>UITableViewCellEditable</em>&laquo;&nbsp;, n&#8217;oubliez pas de glisser le header dans le dossier Headers/Delegates de l&#8217;arborescence.</p>
<p>Complétez le header de la façon suivante :</p>
<pre class="brush: objc; title: ;">

#import

@class UITableViewCellEditable;

@protocol UITableViewCellEditableDelegate
- (void)editDidFinish:(NSMutableDictionary *)result; //Méthode du delegate à implémenter dans notre UITableViewController qui sera appelée lors de la fin de l'édition du UITextField

@optional
- (void)editDidBegin:(UITextField *)field; //Méthode appelée lorsque le focus passe sur le UITextField

@end

@interface UITableViewCellEditable : UITableViewCell  { //ne pas oublier d'implémenter le delegate du UITextField
    IBOutlet UITextField *textField; //le UITextField qu'on associera à notre vue dans IB
    id  delegate; //déclaration du delegate
    NSString *key; //clé associé à notre UITextField
}

@property (nonatomic, retain) IBOutlet UITextField *textField;
@property (nonatomic, assign) id  delegate;
@property (nonatomic, retain) NSString *key;

@end
</pre>
<p>Rien de bien compliqué pour le moment.</p>
<p>Passons maintenant à l&#8217;implémentation des différentes méthodes de notre classe dans le &laquo;&nbsp;<em>UITableViewCellEditable.m</em>&nbsp;&raquo;</p>
<p>Vous n&#8217;avez pas besoin des méthodes d&#8217;initialisation, ni des méthodes déjà implémentées dans UITableViewCell, nous allons nous contenter de rediriger le textFieldDidBeginEditing (méthode déléguée de UITextField) vers notre fonction editDidBegin. Bien entendu ne pas oublier le dealloc pour préserver la mémoire et éviter des fuites :</p>
<pre class="brush: objc; title: ;">#import &quot;UITableViewCellEditable.h&quot;

@implementation UITableViewCellEditable

@synthesize textField, delegate, key;

- (void)textFieldDidBeginEditing:(UITextField *)txtField {
    [[self delegate] editDidBegin:txtField];
}

- (void)dealloc
{
    [textField release];
    [key release];
    [super dealloc];
}

@end</pre>
<p>Désormais nous avons un nouveau type de cellule pouvant être insérée dans le UITableView, qui délègue les différentes méthodes nécessaires à l&#8217;utilisation d&#8217;un UITextField en son sein.</p>
<h3>Et dans IB ?</h3>
<p>Passons un peu du côté d&#8217;interface builder, afin de créer notre model de cellule. Pour ce faire, dans le dossier/groupe Views, créez un nouveau xib vierge (New File &gt; iOS &gt; User Interface &gt; Empty) pour iPhone et nommez le UITVCellEditable (TV=TableView).</p>
<p>Ajoutez dans cette vue un nouvel Objet &laquo;&nbsp;Table View Cell&nbsp;&raquo; (UITableViewCell) et renseignez notre classe dans l&#8217;onglet Identity Inspector : Class= UITableViewCellEditable.</p>
<p>Enfin ajoutez un &laquo;&nbsp;Text Field&nbsp;&raquo; (UITextField) dans notre &laquo;&nbsp;Table View Cell Editable&nbsp;&raquo;. Puis configurez de la façon suivante :</p>
<p>* Agrandissez le de façon à ce qu&#8217;il touche presque les deux bords de notre Table View Cell (laissez une marge, ce n&#8217;est pas vraiment visuel sans marge, surtout si la table view cell est utilisée en mode Grouped, avec des bords arrondis).</p>
<p>* Dans l&#8217;onglet Size Inspector du &laquo;&nbsp;UITextField&nbsp;&raquo;, cochez l&#8217;autosizing de façon à ce que le TextField puisse s&#8217;agrandir horizontalement (toutes les flèches horizontales), puis faites de même avec l&#8217;autosizing de la &laquo;&nbsp;Table View Cell Editable&nbsp;&raquo;.</p>
<p>* Dans l&#8217;onglet Attribute Inspector du &laquo;&nbsp;UITextField&nbsp;&raquo;, il est possible de personnaliser le UITextField de sorte à l&#8217;intégrer parfaitement à notre Cellule, pour ce faire, mettez un Border Style invisible, niveau accessibilité, mettez le Clear Button (petite croix pour vider le champs) à &laquo;&nbsp;Appears while editing&nbsp;&raquo;</p>
<p>* Dans l&#8217;onglet Attributes Inspector de &laquo;&nbsp;Table View Cell Editable&nbsp;&raquo;, passez &laquo;&nbsp;Selection&nbsp;&raquo; à &laquo;&nbsp;None&nbsp;&raquo;, pour désactiver le clic de sélection sur la cellule.</p>
<p>N&#8217;oubliez pas de lier le TextField à notre TableViewCell, en faisant un clic droit (ou ctrl+clic) et un glissement de la tableview au textfield, et sélectionnez textfield (vous pouvez lier en faisant un clic droit et en glissant textField sur l&#8217;objet correspondant).</p>
<p></p>
<h2>Interface de notre application</h2>
<h3>Dans IB</h3>
<p>Maintenant, nous allons nous occuper d&#8217;ajouter une UITableView à notre application, pour ce faire, ouvrez votre xViewController.xib (x est à remplacer par le nom de votre application, c&#8217;est la vue depuis laquelle MainWindow.xib charge sa vue au lancement de l&#8217;application).</p>
<p>Nous allons faire une interface de saisie d&#8217;information pour un utilisateur.</p>
<p>Par défaut, seule une vue est présente. Dans cette vue, ajoutez une &laquo;&nbsp;Scroll View&nbsp;&raquo; (UIScrollView). Puis à l&#8217;intérieur de cette ScrollView, ajoutez deux &laquo;&nbsp;Label&nbsp;&raquo; (UILabel) (l&#8217;un représentera le prénom l&#8217;autre le nom, deux champs qui seront juste affichés sans être éditables). Enfin, au même niveau, ajoutez une &laquo;&nbsp;Table View&nbsp;&raquo; (UITableView).</p>
<p>Maintenant passons à la configuration de tout ce beau monde.</p>
<p>Comme une image vaut mieux que 1000 explications, voici le rendu final dans Interface Builder :</p>
<div id="attachment_341" class="wp-caption alignleft" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/03/Capture-2011-03-17-à-09.43.21.png" rel="lightbox[291]"><img class="size-medium wp-image-341 " title="CocoaTouch #1 - IB interface" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/03/Capture-2011-03-17-à-09.43.21-300x281.png" alt="" width="300" height="281" /></a><p class="wp-caption-text">Vue sous IB</p></div>
<p>Pour arriver à ce résultat, il ne faut pas hésitez à utilisation la fonction &laquo;&nbsp;Arrange&nbsp;&raquo; de l&#8217;onglet Size Inspector, pour étendre le Scroll View et la Table View aux bonnes dimensions.</p>
<p>Pour les deux labels, je pense qu&#8217;il n&#8217;y a pas besoin d&#8217;explication.</p>
<p>Quant à la Table View, changez le style en &laquo;&nbsp;Grouped&nbsp;&raquo;, changez &laquo;&nbsp;Separator&nbsp;&raquo; à &laquo;&nbsp;None&nbsp;&raquo; (c&#8217;est plus joli), puis désactivez &laquo;&nbsp;Show selection on Touch) et désactivez le &laquo;&nbsp;Scrolling&nbsp;&raquo;, pour l&#8217;empêcher de prendre la main en cas de scroll, nous laisserons cela à la Scroll View. Dans cette dernière (la Scroll View), sélectionnez pour Background : &laquo;&nbsp;Group Table View Background Color&nbsp;&raquo;, en effet la Table View avec son background particulier ne couvre pas toute la Scroll.</p>
<p>Au niveau de l&#8217;autosizing, qui permet d&#8217;étendre les vues automatiquement en fonction des modifications de taille de l&#8217;élément parent, allez dans l&#8217;onglet &laquo;&nbsp;Size Inspector&nbsp;&raquo; de la &laquo;&nbsp;Table View&nbsp;&raquo;, et coller à droite, en haut, à gauche, étendre horizontalement doivent être cochés (décochez donc coller en bas et étendre verticalement). Faites de même pour la &laquo;&nbsp;Scroll View&nbsp;&raquo;.</p>
<p>Maintenant faites un bouton de droite sur la &laquo;&nbsp;Table View&nbsp;&raquo; et liez le &laquo;&nbsp;datasource&nbsp;&raquo; et le &laquo;&nbsp;delegate&nbsp;&raquo; au &laquo;&nbsp;File&#8217;s Owner&nbsp;&raquo; (la classe correspondante au &laquo;&nbsp;File&#8217;s Owner&nbsp;&raquo; est contenu dans le fichier &laquo;&nbsp;.m&nbsp;&raquo; de même nom).</p>
<h3>Déclaration des IBOutlets et des liaisons IB</h3>
<p>Puis ouvrez le header du ViewController correspondant à la vue que vous venez d&#8217;éditer dans Interface Builder, remplissez le comme suit :</p>
<pre class="brush: objc; title: ;">

#import

#import &quot;UITableViewCellEditable.h&quot; //ne pas oubliez d'importer le Headers du UITableViewCellEditable

@interface JT_Blog_CocoaTouch_1ViewController : UIViewController  {
    IBOutlet UITableView* tblView;
    IBOutlet UIScrollView* scrlView;
    IBOutlet UILabel* lblFirstName;
    IBOutlet UILabel* lblLastName;
    UITextField* curTextField; //le UITextField actuellement en cours d'édition (nous verrons tout à l'heure l'utilité)

    NSArray* tableViewDataSource; //le DataSource (contenu) de notre tableView
    BOOL dataLoaded; //YES lorsque toutes les données de la tableview sont chargées, nous verrons l'utilité plus tard
    NSMutableDictionary* userDataSource; //le DataSource contenant les informations de l'utilisateur (vous remarquerez le &quot;Mutable&quot; qui signifie que le dictionnaire peut-être modifié)

    CGRect viewNormalFrame; //la taille originale de la vue (avant nos redimensionnements, histoire d'éviter des calculs pour la repositionner)
    CGRect keyboardFrame; //dimension du clavier
    BOOL keyboardOut; //est-ce que le clavier est affiché ?
    float keyboardAnimationDuration; //durée de l'apparition du clavier
    int keyboardAnimationCurve; //comportement dans le temps de l'animation (exemple: lent au début, plus rapide au milieu, lent à la fin)
}

- (void)keyboardWillShow:(NSNotification *)notification; //méthode appelé par une notification que l'on capturera

@end
</pre>
<div id="attachment_342" class="wp-caption alignright" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/03/Capture-2011-03-19-à-00.25.44.png" rel="lightbox[291]"><img class="size-medium wp-image-342" title="CocoaTouch #1 - IB links" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/03/Capture-2011-03-19-à-00.25.44-300x154.png" alt="" width="300" height="154" /></a><p class="wp-caption-text">Liaisons</p></div>
<p>Retournez ensuite dans votre vue sur InterfaceBuilder et faites les liaisons suivantes :</p>
<ul>
<li>File&#8217;s Owner : scrlView =&gt; Scroll View</li>
<li>File&#8217;s Owner : tblView =&gt; Table View</li>
<li>File&#8217;s Owner : lblFirstName =&gt; Label &#8211; Prénom</li>
<li>File&#8217;s Owner : lblLastName =&gt; Label &#8211; Nom</li>
</ul>
<p>N&#8217;oubliez pas d&#8217;enregistrer le fichier.</p>
<p></p>
<h2>Un peu de code maintenant <img src='http://www.jeremy-trufier.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> </h2>
<h3>Méthodes utilisées</h3>
<p>Dirigez vous ensuite vers le &laquo;&nbsp;.m&nbsp;&raquo; correspondant :</p>
<pre class="brush: objc; title: ;">
#import &quot;JT_Blog_CocoaTouch_1ViewController.h&quot;

@implementation JT_Blog_CocoaTouch_1ViewController

- (void)dealloc
{
    /* ne pas oublier les release pour préserver la mémoire vive */
    [super dealloc];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

#pragma mark - Keyboard Handling
- (void)keyboardWillShow:(NSNotification *)notification {
    /* lorsque le clavier apparait pour la première fois, nous allons initialiser nos variables concernant le clavier */
}

#pragma mark - Text Field delegate
-(void)textFieldDidBeginEditing:(UITextField *)textField{
    /* animation de la vue afin de la réduire et de la mettre au bon niveau, en positionnant le scroll au bon endroit */
}

-(BOOL)textFieldShouldReturn:(UITextField *)textField{
	/* appellée lors de la fin d'édition, juste avant la disparition du clavier, la vue originale doit être restaurée */
}

#pragma mark - View lifecycle
- (void)viewDidLoad
{
    /* Préparation de notre DataSource */
    [super viewDidLoad];
}

- (void)viewDidAppear:(BOOL)animated{
    /*
     * Préparation des tailles et positions des différentes parties
     * Ajout d'un Observer sur l'apparition du clavier
     */
    [super viewDidAppear:animated];
}

-(void)viewWillDisappear:(BOOL)animated{
    /* On enlève l'Observer sur l'apparition du clavier, pour éviter d'utiliser des ressources en envoyant des notifications qui n'aboutiront nul part */
    [super viewWillDisappear:animated];
}

#pragma mark - TableView
- (void)editDidFinish:(NSMutableDictionary *)result {
    /* Fin de l'édition d'un champs, enregistrement de la valeur dans un tableau (généralement on utilise Core Data, mais ce n'est pas l'objectif de ce tutorial) */
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    /* UITableViewCell à afficher pour la cellule à l'index indexPath */
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    /* nombre total de section (groupes) dans la tableView en mode &quot;grouped&quot; */
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    /* nombre total de ligne dans la tableView dans la section/groupe section */
}

@end
</pre>
<p>Passons directement à la programmation de toutes ces méthodes.</p>
<h3>viewDidLoad</h3>
<p>Pour créer les différentes informations qui seront demandées, nous allons créer une arborescence de notre invention, je vous propose la suivante : un &laquo;&nbsp;NSArray&nbsp;&raquo; contient les sections, chaque section est un &laquo;&nbsp;NSArray&nbsp;&raquo; qui contient des &laquo;&nbsp;NSDictionnary&nbsp;&raquo; représentants chacun la clé et le label d&#8217;un champs. Pour le &laquo;&nbsp;userDataSource&nbsp;&raquo;, rien de bien compliqué, cela peut-être un objet d&#8217;un model de CoreData, mais nous allons pour l&#8217;exemple, nous contenter d&#8217;un simple &laquo;&nbsp;NSMutableDictionary&nbsp;&raquo;, nous allons renseigner deux valeurs qui devront, au final, apparaitre dans les champs textes correspondants.</p>
<pre class="brush: objc; title: ;">
- (void)viewDidLoad
{
    /* Préparation de notre DataSource */
    NSArray* sectionAddress = [[NSArray alloc] initWithObjects:
                               [[NSDictionary alloc] initWithObjectsAndKeys:
                                @&quot;address&quot;, @&quot;key&quot;,
                                @&quot;Addresse&quot;, @&quot;label&quot;,
                                nil],
                               [[NSDictionary alloc] initWithObjectsAndKeys:
                                @&quot;city&quot;, @&quot;key&quot;,
                                @&quot;Ville&quot;, @&quot;label&quot;,
                                nil],
                               [[NSDictionary alloc] initWithObjectsAndKeys:
                                @&quot;zipCode&quot;, @&quot;key&quot;,
                                @&quot;Code postal&quot;, @&quot;label&quot;,
                                nil],
                               nil];

    NSArray* sectionContact = [[NSArray alloc] initWithObjects:
                               [[NSDictionary alloc] initWithObjectsAndKeys:
                                @&quot;phone&quot;, @&quot;key&quot;,
                                @&quot;Téléphone&quot;, @&quot;label&quot;,
                                nil],
                               [[NSDictionary alloc] initWithObjectsAndKeys:
                                @&quot;mail&quot;, @&quot;key&quot;,
                                @&quot;e-mail&quot;, @&quot;label&quot;,
                                nil],
                               nil];

    NSArray* sectionProfil = [[NSArray alloc] initWithObjects:
                              [[NSDictionary alloc] initWithObjectsAndKeys:
                               @&quot;hobbies&quot;, @&quot;key&quot;,
                               @&quot;Loisirs&quot;, @&quot;label&quot;,
                               nil],
                              [[NSDictionary alloc] initWithObjectsAndKeys:
                               @&quot;like&quot;, @&quot;key&quot;,
                               @&quot;Intérêts&quot;, @&quot;label&quot;,
                               nil],
                              [[NSDictionary alloc] initWithObjectsAndKeys:
                               @&quot;hate&quot;, @&quot;key&quot;,
                               @&quot;Déteste&quot;, @&quot;label&quot;,
                               nil],
                              [[NSDictionary alloc] initWithObjectsAndKeys:
                               @&quot;sports&quot;, @&quot;key&quot;,
                               @&quot;Sports&quot;, @&quot;label&quot;,
                               nil],
                              [[NSDictionary alloc] initWithObjectsAndKeys:
                               @&quot;movies&quot;, @&quot;key&quot;,
                               @&quot;Films&quot;, @&quot;label&quot;,
                               nil],
                              [[NSDictionary alloc] initWithObjectsAndKeys:
                               @&quot;musics&quot;, @&quot;key&quot;,
                               @&quot;Musiques&quot;, @&quot;label&quot;,
                               nil],
                              [[NSDictionary alloc] initWithObjectsAndKeys:
                               @&quot;books&quot;, @&quot;key&quot;,
                               @&quot;Livres&quot;, @&quot;label&quot;,
                               nil],
                              [[NSDictionary alloc] initWithObjectsAndKeys:
                               @&quot;videogames&quot;, @&quot;key&quot;,
                               @&quot;Jeux vidéos&quot;, @&quot;label&quot;,
                               nil],
                              nil];

    tableViewDataSource = [[NSArray alloc] initWithObjects:sectionAddress,sectionContact,sectionProfil,nil];

    [sectionAddress release];
    [sectionContact release];
    [sectionProfil release];

    userDataSource = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
                      @&quot;Bordeaux&quot;,@&quot;city&quot;,
                      @&quot;33000&quot;,@&quot;zipCode&quot;,
                      @&quot;basket, footing, ...&quot;,@&quot;sports&quot;,
                      nil];

    dataLoaded=NO; /* les données ne sont pas encore dans la table view, nous verrons plus tard pourquoi nous faisons cela */

    [super viewDidLoad];
}
</pre>
<h3>numberOfSectionsInTableView:</h3>
<p>Doit retourner le nombre de sections contenues dans la Table View, ça correspond pour nous au nombre d&#8217;éléments dans &laquo;&nbsp;arrTblViewDataSource&nbsp;&raquo;.</p>
<pre class="brush: objc; title: ;">
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    /* nombre total de section (groupes) dans la tableView en mode &quot;grouped&quot; */
    return [tableViewDataSource count];
}
</pre>
<h3>tableView: numberOfRowsInSection:</h3>
<p>Ici non plus, rien de bien compliqué, il faut récupérer le nombre d&#8217;élément dans la section.</p>
<pre class="brush: objc; title: ;">
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    /* nombre total de ligne dans la tableView dans la section/groupe section */
    return [[tableViewDataSource objectAtIndex:section] count];
}
</pre>
<h3>tableView: cellForRowAtIndexPath:</h3>
<p>En entrée de cette méthode, on a le tableView qui est en train de s&#8217;afficher, et l&#8217;indexPath qui correspond à la cellule actuellement à afficher.</p>
<p>A partir de ces informations, nous allons construire une cellule et lui retourner.</p>
<p>Quelques explications pour le code qui va suivre :</p>
<ul>
<li>Notez l&#8217;utilisation de &laquo;&nbsp;dequeueReusableCellWithIdentifier&nbsp;&raquo; qui permet de charger la cellule en copiant une cellule déjà existante, dans le cas où aucune cellule n&#8217;est écrite avant, alors nous en créons une nouvelle.</li>
<li>Il ne faut pas non plus oublier de paramétrer les &laquo;&nbsp;delegate&nbsp;&raquo; des deux éléments de notre cellule</li>
<li>Enfin, il ne reste plus qu&#8217;a mettre les bonnes valeurs aux bons endroits !</li>
</ul>
<pre class="brush: objc; title: ;">
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    /* UITableViewCell à afficher pour la cellule à l'index indexPath */
    static NSString *CellIdentifier = @&quot;Cell&quot;;
    UITableViewCellEditable *cell = (UITableViewCellEditable *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil){
        NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:@&quot;UITVCellEditable&quot; owner:nil options:nil];
        for(id currentObject in topLevelObjects) {
            if([currentObject isKindOfClass:[UITableViewCellEditable class]]) {
                cell = (UITableViewCellEditable *) currentObject;
                break;
            }
        }
    }

    [cell setDelegate:self];
    [cell.textField setDelegate:self];

    NSDictionary* cellInfos=[[tableViewDataSource objectAtIndex:indexPath.section] objectAtIndex:indexPath.row];
    cell.key = [cellInfos objectForKey:@&quot;key&quot;];
    cell.textField.text = [userDataSource objectForKey:[cellInfos objectForKey:@&quot;key&quot;]];
    cell.textField.placeholder = [cellInfos objectForKey:@&quot;label&quot;];

    return cell;

}
</pre>
<h3>editDidFinish:</h3>
<p>Rien de bien compliqué, result correspond à un NSMutableDictionary, contenant toute les infos du textField dont l&#8217;édition vient de finir, il n&#8217;y a plus qu&#8217;à enregistrer ces infos (dans l&#8217;idéal en core data, mais pour l&#8217;exemple : ) dans notre &laquo;&nbsp;userDataSource&nbsp;&raquo;.</p>
<pre class="brush: objc; title: ;">- (void)editDidFinish:(NSMutableDictionary *)result {
    /* Fin de l'édition d'un champs, enregistrement de la valeur dans un tableau (généralement on utilise Core Data, mais ce n'est pas l'objectif de ce tutorial) */
    [userDataSource setValue:[result objectForKey:@&quot;text&quot;]
                      forKey:[result objectForKey:@&quot;key&quot;]
     ];
}
</pre>
<h3>dealloc</h3>
<p>Finalement on termine par notre dealloc :</p>
<pre class="brush: objc; title: ;">

- (void)dealloc
{
    /* ne pas oublier les release pour préserver la mémoire vive */
    [userDataSource release];
    [tableViewDataSource release];
    [super dealloc];
}
</pre>
<p><img class="alignleft size-full wp-image-123" title="Good" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Good.png" alt="" width="50" height="50" /> Si vous avez été attentif jusque là, si vous avez suivit à la lettre ce tutorial, alors, vous pouvez lancer la compilation et démarrer le simulateur (bouton Play). L&#8217;application devrait être quasiment fonctionnelle.</p>
<p><img class="alignleft size-full wp-image-123" title="Bad" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/bad.png" alt="" width="50" height="50" /> Mais il y a quelques petits soucis, notamment l&#8217;impossibilité de scroller, mais aussi quelques soucis lors de l&#8217;édition, les champs ne se positionnant pas correctement. Nous allons voir comment résoudre tout ces petits soucis.</p>
<p>
<h2>Finitions</h2>
<h3>Correction du Scroll</h3>
<p>Le composant UITableView est fait de tel manière que seulement ce qui est affiché est chargé, c&#8217;est à dire, que si seulement 10 lignes sont visibles sur 20, l&#8217;appel à &laquo;&nbsp;- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath&nbsp;&raquo; ne se fera que 10 fois, ceci afin d&#8217;économiser les ressources, lors d&#8217;appel à des dataSources très couteux ou de plusieurs centaines de lignes.</p>
<p>Le petit hic, c&#8217;est que nous avons besoin de redimensionner la taille du tableView, afin que toute la tableView soit affichée (même en dehors de l&#8217;écran), dans la scrollView, ceci dans le but de pouvoir tout scroller, grâce à une seule et unique scrollView. Mais pour arriver à faire cela, il nous faut récupérer la hauteur du contenu de la tableView, cela se fait généralement grâce à la propriété &laquo;&nbsp;contentSize&nbsp;&raquo;, mais cette propriété n&#8217;est valable que pour les cellules déjà chargées ! C&#8217;est à dire qu&#8217;avec notre exemple précédent, nous n&#8217;aurions la taille que de seulement 10 lignes sur 20&#8230;</p>
<p>Pour résoudre ce problème, nous allons, à l&#8217;apparition de la Vue globale, rafraîchir le UITableView avec la méthode &laquo;&nbsp;reloadData&nbsp;&raquo;. Aussi bizarre que cela puisse être, cette méthode fonctionne différemment du premier chargement et charge toutes les données et cellules. Une fois chargées, nous avons accès à la propriété contentSize qui contient désormais la bonne valeur à exploiter !</p>
<p>Afin de préparer nos opérations sur le clavier plus tard, nous allons observer les notifications sur l&#8217;apparition du clavier. Nous sauvegardons également la frame de la vue globale, afin d&#8217;éviter de la recalculer lorsque nous la redimensionnerons.</p>
<pre class="brush: objc; title: ;">

- (void)viewDidAppear:(BOOL)animated{
    /*
     * Préparation des tailles et positions des différentes parties
     * Ajout d'un Observer sur l'apparition du clavier
     */
    dataToLoad=YES;
    [tblView reloadData];

    [tblView setFrame:CGRectMake(tblView.frame.origin.x, tblView.frame.origin.y, tblView.frame.size.width, tblView.contentSize.height)];
    scrlView.contentSize=CGSizeMake(scrlView.frame.size.width, tblView.frame.origin.y+tblView.frame.size.height);
    viewNormalFrame=self.view.frame;

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];

    [super viewDidAppear:animated];
}

-(void)viewWillDisappear:(BOOL)animated{
    /* On enlève l'Observer sur l'apparition du clavier, pour éviter d'utiliser des ressources en envoyant des notifications qui n'aboutiront nul part */
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
	[super viewWillDisappear:animated];
}
</pre>
<p>Vous souvenez vous de dataToLoad ? Je vous avez dit que nous en aurions besoin plus tard, je vais donc vous expliquez à quoi il va servir. Comme au chargement de la vue, nous rafraichissons manuellement la tableView, alors nous n&#8217;avons pas besoin de charger des lignes lorsqu&#8217;elle s&#8217;affiche la premiere fois, nous pouvons faire une économie de mémoire et de processeur à ce niveau là. Comme précédemment, nous avons passé à YES, dataToLoad, nous savons désormais quand le reloadData est appelé, nous pouvons donc modifier le delegate qui retourne le nombre de section, pour lui demander de retourner 0 lorsque dataToLoad est à NO, si il n&#8217;y a pas de section, aucune cellule ne sera chargée.</p>
<p>Modifiez la fonction &laquo;&nbsp;numberOfSectionsInTableView&nbsp;&raquo; tel que :</p>
<pre class="brush: objc; title: ;">
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    /* nombre total de section (groupes) dans la tableView en mode &quot;grouped&quot; */
    return dataToLoad ? [tableViewDataSource count]:0;
}
</pre>
<p>
<img class="alignleft size-full wp-image-123" title="Good" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Good.png" alt="" width="50" height="50" /> Testez, le scroll marche, tout les champs s&#8217;affichent désormais !</p>
<p>
<img class="alignleft size-full wp-image-123" title="Bad" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/bad.png" alt="" width="50" height="50" /> Désormais il nous reste seulement que quelques petits problèmes à régler :</p>
<p><object width="184" height="358"><param name="movie" value="http://www.youtube.com/v/on9_2SLkjzM?hl=fr&amp;fs=1&amp;ap=%2526fmt%223D&amp;ap=%2526fmt%3D22" /><param name="allowFullScreen" value="true" /><param name="allowscriptaccess" value="always" /><embed type="application/x-shockwave-flash" width="184" height="358" src="http://www.youtube.com/v/on9_2SLkjzM?hl=fr&amp;fs=1&amp;ap=%2526fmt%223D&amp;ap=%2526fmt%3D22" allowfullscreen="true" allowscriptaccess="always"></embed></object></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h3>Animer et montrer les cellules lorsque le clavier s&#8217;active</h3>
<p>Avant toute chose, nous allons initialiser quelques variables dont nous allons avoir besoin, pour cela, ajoutez au début de la méthode &laquo;&nbsp;- (void)viewDidLoad&nbsp;&raquo; les initialisations suivantes :</p>
<pre class="brush: objc; title: ;">
        keyboardOut=NO;
        keyboardAnimationCurve=0;
        keyboardFrame=CGRectMake(0, 0, 0, 0);
        keyboardAnimationDuration=-1;
        curTextField=nil;
</pre>
<p>Nous allons utiliser la notification d&#8217;apparition du clavier pour récupérer les différents réglages d&#8217;animation du clavier afin de les reproduire. Une fois fait, nous pouvons supprimer &laquo;&nbsp;l&#8217;observer&nbsp;&raquo; d&#8217;apparition du clavier, nous n&#8217;en nécessiterons plus ensuite.</p>
<p>Enfin, nous verrons tout de suite après pourquoi, nous appelons la méthode &laquo;&nbsp;textFieldDidBeginEditing:curTextField&nbsp;&raquo;. En effet, dans cette méthode si nous n&#8217;avons pas encore récupéré les réglages, nous devons le faire avant (enregistrer le textField cliqué dans &laquo;&nbsp;curTextField&nbsp;&raquo;), et donc rappeler la méthode une fois fait.</p>
<pre class="brush: objc; title: ;">
- (void)keyboardWillShow:(NSNotification *)notification {
    /* lorsque le clavier apparait pour la première fois, nous allons initialiser nos variables concernant le clavier */
    if(keyboardAnimationDuration==-1 &amp;&amp; curTextField!=nil){
        keyboardAnimationCurve=[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue];
        keyboardAnimationDuration=[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
        keyboardFrame=[[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
        [self textFieldDidBeginEditing:curTextField];
    }

}
</pre>
<h3>Les petits calculs ^^</h3>
<p>C&#8217;est maintenant qu&#8217;il va falloir être attentif&#8230; Nous allons faire quelques petits calculs.</p>
<p>Dans tout les cas, on ajuste la vue en hauteur juste au dessus du clavier.</p>
<p>Lors du clic sur un textField, s&#8217;il n&#8217;est pas visible, on va positionner le scroll de façon à ce qu&#8217;il le devienne.</p>
<p>On utilise bien entendu Core Animation avec les même réglages que possède le clavier afin d&#8217;obtenir une animation semblable.</p>
<p>Suivez les commentaires du code ci-dessous. En réfléchissant 5 minutes tout est normalement compréhensible.</p>
<pre class="brush: objc; title: ;">

-(void)textFieldDidBeginEditing:(UITextField *)textField{
    /* animation de la vue afin de la réduire et de la mettre au bon niveau, en positionnant le scroll au bon endroit */
    curTextField=textField;
    if(keyboardAnimationDuration!=-1) { //sinon on attend que keyboardwillappear soit executé
        CGRect viewFrame = self.view.frame;
        CGPoint contentOffset=scrlView.contentOffset; //position actuelle du scroll
        CGRect cellFrame = textField.superview.superview.frame; //correspond à la cellule en cours (deux vues au dessus de notre textfield
        int top=tblView.frame.origin.y+cellFrame.origin.y; //origine verticale de la cellule depuis le haut de la scrollView
        int newFrameHeight=viewNormalFrame.size.height-keyboardFrame.size.height; //on réajuste la vue en hauteur, de façon à ce que le bas de la vue globale soit coincide avec le haut de la frame du clavier

        if((top+cellFrame.size.height)-contentOffset.y&gt;newFrameHeight) //si le bas du textinput plus bas que l'affichage
            contentOffset.y=top+cellFrame.size.height-newFrameHeight;
        else if(top-contentOffset.y&lt;0) //si le haut du textinput plus haut que l'affichage
            contentOffset.y=top;

        [UIView beginAnimations:nil context:NULL]; //à partir de là on utilise Core Animation
        [UIView setAnimationDuration:keyboardAnimationDuration];
        [UIView setAnimationCurve:keyboardAnimationCurve];
        [scrlView setContentOffset:contentOffset animated:YES]; //on positionne le scroll au bon endroit, calculé précédemment, attention, setContentOffset ne fonctionne pas avec UIView beginAnimation, il faut specifier animated:YES
        if(!keyboardOut){ //si le clavier est déjà sorti, pas besoin de redimensionner la vue
            viewFrame.size.height=newFrameHeight;
            [self.view setFrame:viewFrame];
        }
        [UIView commitAnimations]; //et enfin on lance les animations

        keyboardOut=YES; //désormais, on peut dire que le clavier est sorti
    }
}
</pre>
<h3>Fin d&#8217;édition</h3>
<p>Finalement, il ne nous reste plus qu&#8217;a définir les actions lorsque nous avons finit d&#8217;éditer un textField. Si le clavier était sorti, il va se fermer, nous allons donc repositionner notre vue globale à son état d&#8217;origine.</p>
<pre class="brush: objc; title: ;">

-(BOOL)textFieldShouldReturn:(UITextField *)textField{
	/* appellée lors de la fin d'édition, juste avant la disparition du clavier, la vue originale doit être restaurée */
    [textField resignFirstResponder];

    [UIView beginAnimations:nil context:NULL];
    [UIView setAnimationDuration:keyboardAnimationDuration];
    [UIView setAnimationCurve:keyboardAnimationCurve];

    if(keyboardOut)
        [self.view setFrame:viewNormalFrame];

    [UIView commitAnimations];

    keyboardOut=NO;
    return YES;

}
</pre>
<p></p>
<h2>
<p>A bientôt</h2>
<p>Et oui ! C&#8217;est désormais fini ! Normalement tout fonctionne parfaitement bien ! Merci de m&#8217;avoir suivit pendant ce cours tuto <img src='http://www.jeremy-trufier.net/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  ! Ne ratez pas la suite <img src='http://www.jeremy-trufier.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2011/03/21/cocoatouch-1-uitextfield-dans-uitableview-uiscrollview-et-animations-ergonomiques/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Ethical Hacking &#8211; Virus indétectables &#8211; Podcast #1</title>
		<link>http://www.jeremy-trufier.net/2011/03/16/ethical-hacking-virus-indetectables-podcast-1/</link>
		<comments>http://www.jeremy-trufier.net/2011/03/16/ethical-hacking-virus-indetectables-podcast-1/#comments</comments>
		<pubDate>Wed, 16 Mar 2011 19:26:12 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[Podcast]]></category>
		<category><![CDATA[Réseaux et Sécurité]]></category>
		<category><![CDATA[analyse comportementale]]></category>
		<category><![CDATA[antivirus]]></category>
		<category><![CDATA[ethical hacking]]></category>
		<category><![CDATA[heuristique]]></category>
		<category><![CDATA[ingésup]]></category>
		<category><![CDATA[laboratoire sécurité]]></category>
		<category><![CDATA[podcast]]></category>
		<category><![CDATA[sandbox]]></category>
		<category><![CDATA[securité]]></category>
		<category><![CDATA[virus]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=249</guid>
		<description><![CDATA[Depuis cette année, je me suis immergé dans le monde de la sécurité informatique, avec comme objectif premier, le passage de la certification CEH proposée par Ec-Council. Le programme de cette certification se concentre essentiellement sur l&#8217;attaque et très peu sur la défense. Il est en effet pratique de savoir comment attaquer afin d&#8217;être efficace [...]]]></description>
			<content:encoded><![CDATA[<p>Depuis cette année, je me suis immergé dans le monde de la sécurité informatique, avec comme objectif premier, le passage de la certification CEH proposée par Ec-Council.</p>
<p>Le programme de cette certification se concentre essentiellement sur l&#8217;attaque et très peu sur la défense. Il est en effet pratique de savoir comment attaquer afin d&#8217;être efficace lorsqu&#8217;il s&#8217;agit de défendre.  Un des projets sur lesquels je travaille est le mécanisme de défense des anti-virus et comment le contourner.</p>
<p>La finalité de ce projet est la création d&#8217;un virus totalement indétectable par les anti-virus.  Ce podcast, que j&#8217;ai réalisé pour mon école Ingésup, est en quelque sorte une préface à toute une série d&#8217;articles sur ce projet.</p>
<p>
<object style="width:490px; height:396px;">
<param name="movie" value="http://www.youtube.com/v/AaK7loO2xsM?version=3" />
<param name="allowScriptAccess" value="always" />
<param name="wmode" value="transparent" />
<param name="allowFullScreen" value="true" />
<embed src="http://www.youtube.com/v/AaK7loO2xsM?version=3" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" wmode="transparent" width="490" height="396"></object>
</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2011/03/16/ethical-hacking-virus-indetectables-podcast-1/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Google Storage</title>
		<link>http://www.jeremy-trufier.net/2011/01/21/google-storage/</link>
		<comments>http://www.jeremy-trufier.net/2011/01/21/google-storage/#comments</comments>
		<pubDate>Fri, 21 Jan 2011 11:36:02 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[Application]]></category>
		<category><![CDATA[Informatique]]></category>
		<category><![CDATA[Réseaux et Sécurité]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[acl]]></category>
		<category><![CDATA[amazon S3]]></category>
		<category><![CDATA[bucket]]></category>
		<category><![CDATA[cloud]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[google storage for developpers]]></category>
		<category><![CDATA[gsutil]]></category>
		<category><![CDATA[hébergement]]></category>
		<category><![CDATA[host]]></category>
		<category><![CDATA[storage]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=262</guid>
		<description><![CDATA[Il y a quelques semaine, j&#8217;ai fait une demande d&#8217;un accès google Storage, j&#8217;ai reçu ce matin le lien d&#8217;invitation de ce service. Je vais vous en faire une petite présentation aujourd&#8217;hui. Google Storage for Developpers fournit un espace de stockage illimité et hautement disponible, ainsi qu&#8217;une interface RESTFull, ce n&#8217;est pas la peine de [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Google-Code-Labs.gif" rel="lightbox[262]"><img class="alignleft size-full wp-image-278" title="Google Code Labs" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Google-Code-Labs.gif" alt="" width="167" height="40" /></a>Il y a quelques semaine, j&#8217;ai fait une demande d&#8217;un accès google Storage, j&#8217;ai reçu ce matin le lien d&#8217;invitation de ce service. Je vais vous en faire une petite présentation aujourd&#8217;hui.</p>
<p>Google Storage for Developpers fournit un espace de stockage illimité et hautement disponible, ainsi qu&#8217;une interface RESTFull, ce n&#8217;est pas la peine de le comparer avec Dropbox, mais avec le service d&#8217;amazon : Amazon S3 (que dropbox utilise).</p>
<p><span id="more-262"></span></p>
<h2>Organisation</h2>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/42b.jpeg" rel="lightbox[262]"><img class="alignleft size-medium wp-image-286" title="chess" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/42b-300x255.jpg" alt="" width="240" height="204" /></a></p>
<p>Chaque fichier envoyé sera stocké sur le Cloud Google, c&#8217;est à dire sur une multitude de serveurs répartis à travers le monde. Chaque fichier pourra donc être accessible de n&#8217;importe, le serveur sera choisit de manière transparente en fonction de son temps de réponse. Les données étant répliquées sur plusieurs serveur, plus besoin de sauvegarde, si un des serveurs tombe, le fichier sera toujours disponible grâce aux autres serveurs.</p>
<p>Comme sur Amazon, des répertoires racines doivent être créés. Appelés Bucket, ces répertoires doivent avoir un nom en minuscule selon le principe d&#8217;un alias de nom de domaine. Ce bucket pourra en effet être atteint depuis un alias de l&#8217;url de google storage : nom_du_bucket.commondatastorage.googleapis.com .</p>
<p>Chaque bucket peut ensuite contenir :</p>
<ul>
<li>des fichiers</li>
<li>des dossiers</li>
<li>des buckets</li>
</ul>
<p>Une gestion des ACL (Access Control List ou encore gestion des droits) fait également partie intégrante du système de fichiers, il existe 3 droits pouvant être appliqués à des domaines mails ou encore des comptes google spécifiés explicitement.</p>
<ul>
<li>READ : droit de lecture uniquement</li>
<li>WRITE : droit de lecture et d&#8217;écriture</li>
<li>FULLCONTROL : ce droit permet d&#8217;attribuer tout les droits à un fichier, y compris les droits de modification des ACL</li>
</ul>
<p>Une fonctionnalité interessante est la possibilité de reprendre un envoi ou un téléchargement, imaginons qu&#8217;un envoi d&#8217;un très gros fichier de plusieurs centaines de Mo ai été interrompu par une coupure de connection, il est possible de reprendre l&#8217;upload exactement où la coupure c&#8217;est produite.</p>
<p>Par contre, c&#8217;est dommage (mais en même temps très dur à gérer), mais un fichier sur le serveur ne peut être modifié. Ainsi, lors de la modification d&#8217;un fichier, ce fichier est supprimé, puis renvoyé. Il est considéré comme un fichier totalement différent du premier, et sa date de &laquo;&nbsp;modification&nbsp;&raquo; devient donc sa date de création, le libéllé dans l&#8217;explorateur est &laquo;&nbsp;Last upload&nbsp;&raquo;.</p>
<p>La compression du flux est également gérée, en envoyant un fichier, il est possible d&#8217;utiliser la compression gZip, le temps de transfert sera réduit, la bande passante (BP facturée ^^)  sera également réduite.</p>
<p>Lors de l&#8217;envoi d&#8217;un fichier, ce fichier est considéré comme inexistant, et n&#8217;apparait donc pas dans notre bucket. Dès que le serveur a entièrement reçu le fichier, il apparait instantanément, et est immédiatement disponible. De la même façon, une fois supprimé, il n&#8217;apparait plus et renvoi une 404 immédiatement.</p>
<p>Google storage utilise le protocole HTTPS pour l&#8217;échange de fichier, nos données sont donc sécurisées (relativement bien) pendant toute la durée du transit.</p>
<h2>Interface Web</h2>
<p>Mieux vaut une petite démonstration avec quelques screenshot que des explications imbuvables :</p>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.49.47.png" rel="lightbox[262]"><img class="size-medium wp-image-266 alignnone" title="Google Storage - Interface" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.49.47-300x197.png" alt="" width="300" height="197" /></a><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.50.09.png" rel="lightbox[262]"><img class="size-medium wp-image-267 alignnone" title="Google Storage - Nom de bucket déjà utilisé" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.50.09-300x194.png" alt="" width="300" height="194" /></a></p>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.50.35.png" rel="lightbox[262]"><img class="size-medium wp-image-268 alignnone" title="Google Storage - Bucket créé" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.50.35-300x196.png" alt="" width="300" height="196" /></a><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.51.00.png" rel="lightbox[262]"><img class="size-medium wp-image-269 alignnone" title="Google Storage - Dans le bucket" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.51.00-300x195.png" alt="" width="300" height="195" /></a></p>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.51.00.png" rel="lightbox[262]"></a><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.52.48.png" rel="lightbox[262]"><img class="size-medium wp-image-270 alignnone" title="Google Storage - Folder et fichier envoyé" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.52.48-300x173.png" alt="" width="300" height="173" /></a><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.53.51.png" rel="lightbox[262]"><img class="size-medium wp-image-271 " title="Google Storage - Affichage d'un fichier public" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/Capture-2011-01-21-à-11.53.51-300x97.png" alt="" width="300" height="97" /></a></p>
<h2>Ligne de commande</h2>
<p><img class="alignleft size-medium wp-image-284" title="5" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/5-300x225.jpg" alt="" width="240" height="180" /></p>
<p>Là une partie un tout petit peu plus technique&#8230; Google fournit un utilitaire développé en Python qui est un client RESTFull pour Google Storage.</p>
<p>L&#8217;avantage par rapport à l&#8217;interface Web est que nous avons accès à la quasi-totalité des fonctions REST, notamment la gestion des ACL que nous n&#8217;avons pas encore sur l&#8217;interface Web.</p>
<p>Cet utilitaire s&#8217;appelle GSUtil et son utilisation est plutôt simple :</p>
<p>Pour reprendre le même exemple que ci-dessus :</p>
<p>Création d&#8217;un bucket : gsutil mb gs://jeremy</p>
<p>Création d&#8217;un dossier : gsutil mb gs://jeremy/test</p>
<p>Envoi d&#8217;un fichier : gsutil cp Lorem\ Ipsum.txt gs://jeremy/</p>
<p>Liste du dossier : gsutil ls -l gs://jeremy</p>
<p>Affichage du fichier : gsutil cat gs://jeremy/Lorem\ Ipsum.txt</p>
<p>Suppression de fichier : gsutil rm gs://jeremy/Lorem\ Ipsum.txt</p>
<p>Gestion des acls :</p>
<ul>
<li>Tout d&#8217;abord récupérer la configuration acl existante : gsutil getacl gs://jeremy/Lorem\ Ipsum.txt &gt; acl.txt</li>
<li>Ensuite éditer ce fichier en fonction des nouvelles ACL</li>
<li>Puis renvoyer le fichier : gsutil setacl acl.txt gs://jeremy/Lorem\ Ipsum.txt</li>
</ul>
<h2>Prix</h2>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/54a.jpeg" rel="lightbox[262]"><img class="alignright size-medium wp-image-282" title="54a" src="http://www.jeremy-trufier.net/wp-content/uploads/2011/01/54a-300x225.jpg" alt="" width="240" height="180" /></a>Je vous ai dit en début d&#8217;article que l&#8217;espace de stockage était illimité ? oui, mais pas sans coût.</p>
<p>Voici le tableau de prix donné par google, la facturation se fait en fonction de la taille des données transitants entre l&#8217;utilisateur et les serveurs, et de l&#8217;espace de stockage utilisé.</p>
<ul>
<li>Utilisation d&#8217;espace de stockage : $0.17/Go/mois</li>
<li>Réseau
<ul>
<li>Envoi des données
<ul>
<li>$0.10/Go</li>
</ul>
</li>
<li>Téléchargement des données
<ul>
<li>$0.15/Go pour l&#8217;Amerique, l&#8217;Europe, le Moyen-Orient et l&#8217;Afrique</li>
<li>$0.30/Go pour l&#8217;Asie-Pacifique</li>
</ul>
</li>
</ul>
</li>
<li>Requêtes
<ul>
<li>PUT, POST, LIST—$0.01 pour 1,000 requêtes</li>
<li>GET, HEAD—$0.01 pour 10,000 requêtes</li>
</ul>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2011/01/21/google-storage/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript et les trois manières de faire un IF</title>
		<link>http://www.jeremy-trufier.net/2010/09/29/javascript-et-les-trois-manieres-de-faire-un-if/</link>
		<comments>http://www.jeremy-trufier.net/2010/09/29/javascript-et-les-trois-manieres-de-faire-un-if/#comments</comments>
		<pubDate>Wed, 29 Sep 2010 14:30:11 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[Comparatifs]]></category>
		<category><![CDATA[Développement]]></category>
		<category><![CDATA[Informatique]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[comparaison]]></category>
		<category><![CDATA[firefox]]></category>
		<category><![CDATA[internet explorer]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[les différents if]]></category>
		<category><![CDATA[navigateurs]]></category>
		<category><![CDATA[opera]]></category>
		<category><![CDATA[optimisation]]></category>
		<category><![CDATA[réduction taille]]></category>
		<category><![CDATA[safari]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=202</guid>
		<description><![CDATA[La syntaxe du javascript n&#8217;est régie par aucune norme prédéfinie, ainsi n&#8217;importe qui peut programmer de la manière qu&#8217;il veut. Pour ma part ces derniers temps je  me suis penché sur l&#8217;optimisation de mon code javascript en me basant sur trois points : gagner du temps en programmant =&#62; code simple à écrire, facilement lisible pour [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-240" title="if ou else" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/if-else1.png" alt="" width="149" height="141" /></p>
<p>La syntaxe du javascript n&#8217;est régie par aucune norme prédéfinie, ainsi n&#8217;importe qui peut programmer de la manière qu&#8217;il veut.</p>
<p>Pour ma part ces derniers temps je  me suis penché sur l&#8217;optimisation de mon code javascript en me basant sur trois points :</p>
<ul>
<li>gagner du temps en programmant =&gt; code simple à écrire, facilement lisible pour y revenir plus tard</li>
<li>optimisation de la vitesse d’exécution du code</li>
<li>diminution de la taille de notre javascript =&gt; les compresseurs automatiques existent, mais leurs algorithmes ne permettent pas de tout réduire, un code faisant 150ko pourra être réduit à 40ko, mais ce même code programmé d&#8217;une autre façon pourra très bien être réduit à 30ko. Bien entendu, nous ne sommes plus aussi attentif qu&#8217;avant sur la taille de nos fichiers grâce à l&#8217;ADSL, mais n&#8217;oublions pas nos clients mobile, et surtout la charge en moins que la bande passante de notre serveur évitera.</li>
</ul>
<p><span id="more-202"></span></p>
<h2>Les Trois &laquo;&nbsp;if&nbsp;&raquo;</h2>
<p>Afin de connaitre facilement duquel on parle dans la suite de l&#8217;article, j&#8217;ai décidé de les nommer de cette façon : if explicite, if implicite et if ternaire. Je rajouterai bientôt le Switch dans ces graphiques.</p>
<p>Attention tout de même, ils ne permettent pas tous la même chose !</p>
<h3>If Explicite</h3>
<p>Bon celui-là tout le monde le connait, et si vous ne le connaissez pas, je pense que vous vous êtes trompé de site <img src='http://www.jeremy-trufier.net/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  !</p>
<pre class="brush: jscript; title: ;">if ( variable1 === 'valeur 1' ) {
//alors
} else {
//sinon
}</pre>
<p>&laquo;&nbsp;Ah ah, le noob&#8230; il a même pas mit les elseif !!!&nbsp;&raquo;<br />
En fait les &laquo;&nbsp;else if&nbsp;&raquo; sont simplement des &laquo;&nbsp;else&nbsp;&raquo; ou dans le bloc nous avons un &laquo;&nbsp;if&nbsp;&raquo;, mais comme vous le savez, nous pouvons omettre les accolades lorsque le bloc suivant ne contient qu&#8217;une instruction.</p>
<p>Ainsi le code suivant :</p>
<pre class="brush: jscript; title: ;">if ( variable1 === 'valeur 1' ) {
//alors
} else if ( variable1 === 'valeur 2' ) {
//sinon si
}
else{
//sinon
}</pre>
<p>est l&#8217;équivalent de celui-ci :</p>
<pre class="brush: jscript; title: ;">
if ( variable1 === 'valeur 1' ) {
//alors
} else {
if ( variable1 === 'valeur 2' ) {
//sinon si
}
else{
//sinon
}
}
</pre>
<p>Voici un petit graphe qui compare la vitesse d&#8217;exécution de cette structure afin de faire une simple affectation.<br />
Cette structure contient 1 if, 4 elseif et 1 else, chaque niveau correspond à un if/else différent (level 0=if, level 5=else).</p>
<p style="text-align: center;"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-26-à-12.19.20.png" rel="lightbox[202]"><img class="size-medium wp-image-218 aligncenter" title="Graphique de comparaison d'un If explicite sur des navigateurs PC" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-26-à-12.19.20-300x170.png" alt="" width="300" height="170" /></a></p>
<p style="text-align: left;">Et là grande surprise, remarquez comme la dernière version de firefox, l&#8217;air de rien, arrive en tête de se classement ! Firefox n&#8217;étant pourtant pas réputé pour son moteur de javascript très performant, il arrive a se démarquer des autres sur les tests conditionnels/affectation de façon impressionnante. Safari 5 en version PC est quant à lui, un peu à la traîne, je rajouterai bientôt le même comparatif en utilisant les navigateurs sous OS X. Opera qui a également amélioré son moteur javascript, se trouve dans la même unité de grandeur que les autres avec un peu d&#8217;avance par rapport à Chrome. J&#8217;ai été déçu par les résultats de ce dernier sur ce test. Finalement Internet Explorer 9, pourtant prometteur <a title="IE9 béta a dopé son moteur Javascript" href="http://www.jeremy-trufier.net/2010/09/21/ie9-beta-a-dope-son-moteur-javascript/">(voir mon autre test)</a> ne se met pas non plus en avant sur ce test.</p>
<p style="text-align: left;">
<h3>If Ternaire</h3>
<p>Beaucoup de gens l&#8217;utilisent également, il est très pratique et surtout lisible quand il s&#8217;agit de faire un choix entre deux valeurs en inline. Il marchera même en plein milieu d&#8217;une chaîne de caractère ou d&#8217;une instruction.</p>
<pre class="brush: jscript; title: ;">
var nb=5,
	s='Il y a '+nb+' utilisateur'+((nb&gt;1)?'s':'')+' sur ce site'; //ici 5 est supérieur à 2, nous aurons donc un S à la fin de utilisateurs
</pre>
<p>Bon pas trop mal n&#8217;est-ce pas, mais ça devient très vite imbuvable et illisible si on veut faire un peu plus compliqué :</p>
<pre class="brush: jscript; title: ;">
var nb=5,
	s='il y a '+((nb&gt;1)?nb+' utilisateurs':((nb&gt;0)?1:'aucun')+' utilisateur')+' sur ce site';
</pre>
<p>Au niveau du petit combat entre navigateur :</p>
<div id="attachment_224" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-ternaire.png" rel="lightbox[202]"><img class="size-medium wp-image-224" title="Graphique de comparaison d'un If ternaire sur les navigateurs PC" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-ternaire-300x192.png" alt="" width="300" height="192" /></a><p class="wp-caption-text">Graphique de comparaison d&#39;un If ternaire sur les navigateurs PC</p></div>
<p>Toujours firefox de loin en tête, pas de majeurs changement par rapport au test précédent.</p>
<h3>If Implicite</h3>
<p>Alors là, nous allons un peu jouer avec les spécificités du langage Javascript. Cette structure conditionnelle est très peu utilisée, un peu moins lisible que le if explicite ou ternaire dans certains cas, mais beaucoup plus rapide à écrire et à lire dans d&#8217;autres.</p>
<p>Imaginons que nous avons un objet appelé &laquo;&nbsp;O&nbsp;&raquo;, et que nous voudrions appeler la fonction &laquo;&nbsp;f&nbsp;&raquo; de cet objet seulement dans le cas où cette fonction existe, ainsi avec un if explicite nous ferions :</p>
<pre class="brush: jscript; title: ;">
if(O.f)
	O.f();
</pre>
<p>Maintenant en if implicite :</p>
<pre class="brush: jscript; title: ;">
O.f &amp;&amp; O.f();
</pre>
<p>Bon on ne gagne pas grand chose ici n&#8217;est-ce pas ?</p>
<p>Imaginons une petite fonction getter/setter pour des inputs :</p>
<pre class="brush: jscript; title: ;">
function iV(idt,v){
	var el=document.getElementById(idt) || {};
	el= (el.value &amp;&amp; el) || {value:''};
	return el.value =  (arguments&gt;1 &amp;&amp; v) || el.value;
}
</pre>
<p>Ce code est un exemple extrême peu optimisé, mais qui donne un bon aperçu de la syntaxe.<br />
Que fait le code ?<br />
ligne 2 : on récupère notre input et s&#8217;il n&#8217;existe pas, on retourne simplement un objet vierge pour ne pas générer une erreur javascript ensuite.<br />
ligne 3 : si notre objet contient un champs value, c&#8217;est bon, donc on retourne notre objet, sinon, on retourne un objet vierge contenant un champs value pour ne pas non plus générer une erreur javascript ensuite.<br />
ligne 4 : si nous avons plus d&#8217;un argument, alors nous affectons notre deuxième argument (v) au champs value de notre input, sinon, on ne change rien, on le réaffecte lui-même. Finalement on retourne tout ça !</p>
<p>Pourquoi ne pas directement à la ligne 3 passer la &laquo;&nbsp;value&nbsp;&raquo; dans une variable ?<br />
Tout simplement car la &laquo;&nbsp;value&nbsp;&raquo; n&#8217;est pas un objet, et ici ce ne sera pas le pointeur qui sera copié, mais la valeur. Il ne faut pas oublier qu&#8217;en javascript les objets sont passé par référence et String/int/Bool/&#8230; sont passé par valeur.</p>
<p>Nous enregistrons également notre élément dans une variable el, car document.getElementById prend du temps à s’exécuter, étant donné qu&#8217;elle parcourt le Dom de notre page. Ainsi on ne l&#8217;appelle ici qu&#8217;une seule fois.</p>
<p>Un code équivalent avec une structure if/else :</p>
<pre class="brush: jscript; title: ;">
function iV(idt,v){
	var el;

	if(el=document.getElementById(idt)){
		if(arguments.length&gt;1){
			if(el.value){
				return el.value=v;
			}
			else
				return v;
		}
		else if(el.value)
			return el.value;
	}
	else if(arguments.length&gt;1)
		return v;
	return false;
}
</pre>
<p>Si on traduit ligne à ligne en structure conditionnelle implicite :</p>
<pre class="brush: jscript; title: ;">
function iV(idt,v){
    var el;
    return (
        (el=document.getElementById(idt)) &amp;&amp; (
            (
                arguments.length&gt;1 &amp;&amp; (
                    (el.value &amp;&amp; (el.value=v))
                    || v
                )
            )
            || el.value
        )
    )
    || (arguments.length&gt;1 &amp;&amp; v)
    || false;
}
</pre>
<p>En réduisant :</p>
<pre class="brush: jscript; title: ;">
function iV(idt,v){
    var el;
    return ((el=document.getElementById(idt)) &amp;&amp; ((arguments.length&gt;1 &amp;&amp; ( (el.value &amp;&amp; (el.value=v)) || v)) || el.value)) || (arguments.length&gt;1 &amp;&amp; v) || false;
}
</pre>
<p>Maintenant les deux codes compressés :</p>
<pre class="brush: jscript; title: ;">
function iV(a,v){var b;if(b=document.getElementById(a)){if(arguments.length &gt;1){if(b.value){return b.value=v}else return v}else if(b.value)return b.value} else if(arguments.length&gt;1)return v;return false}
</pre>
<p>et</p>
<pre class="brush: jscript; title: ;">
function iV(a,v){var b;return((b=document.getElementById(a))&amp;&amp;((arguments .length&gt;1&amp;&amp;((b.value&amp;&amp;(b.value=v))||v))||b.value))|| (arguments.length&gt;1&amp;&amp;v)||false}
</pre>
<p>Et on se retrouve avec un code à 156 caractères en if implicite et un à 202 caractères en if explicite, soit 25% de moins ce qui est énorme.</p>
<p>Je pense notamment à ce concours : <a href="http://10k.aneventapart.com/">10K Apart</a> dont le but était de faire une application web impressionnante, dont la taille serait la plus petite possible, avec une limite de 10kb. Avec cette méthode, j&#8217;ai réussi à rapporter le code du gagnant de 6,9kb à 4,1kb. Plutôt sympas non ? pour perdre son temps <img src='http://www.jeremy-trufier.net/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  !</p>
<p>Vous l&#8217;aurez donc compris, ce code est très utile pour des structures très simple, tel que pour vérifier l&#8217;existence d&#8217;attributs d&#8217;objets, mais très dur à lire dès qu&#8217;on arrive dans des structures complexes (et sans habitude <img src='http://www.jeremy-trufier.net/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  ). Toutefois, nous nous rapprochons d&#8217;un langage plus brut, et il est donc plus petit au final. Je pense notamment au</p>
<p>Voici pour le petit graphique :</p>
<div id="attachment_225" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-implicit.png" rel="lightbox[202]"><img class="size-medium wp-image-225" title="Graphique de comparaison d'un If Implicite sur les navigateurs PC" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-implicit-300x193.png" alt="" width="300" height="193" /></a><p class="wp-caption-text">Graphique de comparaison d&#39;un If Implicite sur les navigateurs PC</p></div>
<p>Ici encore nous tombons sur des résultats sensiblement pareils. Ce qui va être intéressant maintenant, c&#8217;est au sein d&#8217;un navigateur, quel if est le plus rapide ? C&#8217;est l&#8217;objet de la partie suivante.</p>
<h2>Comparaison des &laquo;&nbsp;If&nbsp;&raquo;</h2>
<p>Voici les comparaisons des trois If par navigateur, les graphiques suffisent à eux-même.</p>
<div id="attachment_229" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-firefox.png" rel="lightbox[202]"><img class="size-medium wp-image-229" title="Benchmark if sous Firefox 3.6 PC" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-firefox-300x208.png" alt="" width="300" height="208" /></a><p class="wp-caption-text">Benchmark if sous Firefox 3.6 PC</p></div>
<div id="attachment_230" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-ie.png" rel="lightbox[202]"><img class="size-medium wp-image-230" title="Benchmark if sous Internet Explorer 9" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-ie-300x208.png" alt="" width="300" height="208" /></a><p class="wp-caption-text">Benchmark if sous Internet Explorer 9</p></div>
<div id="attachment_231" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-opera.png" rel="lightbox[202]"><img class="size-medium wp-image-231" title="Benchmark if sous Opera 10.62" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-opera-300x200.png" alt="" width="300" height="200" /></a><p class="wp-caption-text">Benchmark if sous Opera 10.62</p></div>
<div id="attachment_232" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-safari.png" rel="lightbox[202]"><img class="size-medium wp-image-232" title="Benchmark if sous Safari 5 PC" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-safari-300x208.png" alt="" width="300" height="208" /></a><p class="wp-caption-text">Benchmark if sous Safari 5 PC</p></div>
<div id="attachment_233" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-chrome.png" rel="lightbox[202]"><img class="size-medium wp-image-233" title="Benchmark if sous Chrome 6 PC" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/3if-chrome-300x208.png" alt="" width="300" height="208" /></a><p class="wp-caption-text">Benchmark if sous Chrome 6 PC</p></div>
<p>Ainsi nous pouvons voir, qu&#8217;il faudra privilégier les If Implicites aux If Ternaires qui sont fortement moins performants sur la plupart des navigateurs.<br />
Il est ici impossible de tenir compte de Firefox étant donné l&#8217;ordre de grandeur 10 fois moindre, les différences entre les trois if ne sont donc, sur ce navigateur, pas représentatives.</p>
<h2>Ce qu&#8217;il faut retenir</h2>
<ul>
<li>En règle générale, utiliser des <strong>if explicites</strong> <em>(lisibilité, performance, au détriment du poids)</em></li>
<li>Utiliser des <strong>If implicites</strong> en lieu et place des <strong>If ternaires</strong> moins performants <em>(performance)</em></li>
<li>Utiliser des <strong>If implicites</strong> pour une simple vérification de valeur et une action ou une autre <em>(lisibilité, performance, nombre de caractère plus petit)</em></li>
<li>Pour les grandes structures conditionnelles : utiliser des <strong>If Explicites</strong> à moins de vouloir à tout pris gagner des kilo-octets sur le poids du fichier script<em> (lisibilité)</em></li>
</ul>
<p>A bientôt !</p>
<p>(PS: je n&#8217;ai pas corrompu les résultats de Firefox, mon navigateur favori étant Safari)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2010/09/29/javascript-et-les-trois-manieres-de-faire-un-if/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PHP, vérification de mail complète, avec DNS</title>
		<link>http://www.jeremy-trufier.net/2010/09/24/php-verification-de-mails-complete-avec-dns/</link>
		<comments>http://www.jeremy-trufier.net/2010/09/24/php-verification-de-mails-complete-avec-dns/#comments</comments>
		<pubDate>Fri, 24 Sep 2010 14:00:26 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[Développement]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[astuce]]></category>
		<category><![CDATA[développement]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[regexp]]></category>
		<category><![CDATA[vérification]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=156</guid>
		<description><![CDATA[gMail permet de rajouter un &#171;&#160;+cequonveut&#160;&#187; juste avant le @, ainsi toto+nimportequoi@gmail.com est la même chose que toto@gmail.com, cela peut-être très utile pour savoir de qui viennent les spams, ou encore savoir qui vend illégalement des listes d&#8217;adresses. J&#8217;ai ainsi prit l&#8217;habitude à chaque inscription sur un site ou une newsletter de rajouter le nom [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-medium wp-image-168" title="appleMail" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/appleMail-300x300.png" alt="" width="150" height="150" /></p>
<p>gMail permet de rajouter un &laquo;&nbsp;+cequonveut&nbsp;&raquo; juste avant le @, ainsi toto+nimportequoi@gmail.com est la même chose que toto@gmail.com, cela peut-être très utile pour savoir de qui viennent les spams, ou encore savoir qui vend illégalement des listes d&#8217;adresses. J&#8217;ai ainsi prit l&#8217;habitude à chaque inscription sur un site ou une newsletter de rajouter le nom du site après le +, exemple : monprenom.monnom+gizmodo.fr@gmail.com . Si un jour je reçois du spam sur cette adresse je saurais donc à qui m&#8217;en prendre ! Bien entendu les applications sont multiples et variées, notamment avec l&#8217;application des filtres ! Ainsi quand j&#8217;envois un mail à monprenom.monnom+note@gmail.com je le reçois directement (grâce à un filtre) dans mon dossier Notes&#8230; De la même façon il est possible de rajouter des points n&#8217;importe où dans l&#8217;adresse, gmail ne fera pas la différence ! ex: mon.prenom.mon.n.o.m@gmail.com est l&#8217;équivalent de monprenom.monnom@gmail.com lui même équivalent à monprenommonnom@gmail.com !</p>
<p>Mais il y a un petit hic dans tout ça ! Beaucoup de sites n&#8217;acceptent pas des emails avec des + ou d&#8217;autres caractères spéciaux !</p>
<p>Valide ou pas valide alors ???</p>
<h2><span id="more-156"></span></h2>
<h2>Normes</h2>
<p><img class="alignleft size-thumbnail wp-image-170" title="elephant-elephant-php-logo" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/elephant-elephant-php-logo-150x150.png" alt="" width="100" height="100" />Voici donc un petit tuto bien sympathique en php, une vérification de mail&#8230;<br />
&laquo;&nbsp;Mais il en traine plein sur internet ???&nbsp;&raquo;</p>
<p>et même PHP fournit une fonction déjà toute prête pour vérifier les mails :</p>
<pre>filter_var($email, FILTER_VALIDATE_EMAIL)</pre>
<p>Et oui, mais les adresses emails sont régis par des normes RFC5321 et RFC5322, des documents imbuvables que personne ne lit jamais&#8230; Du coup, il est rare qu&#8217;un regexp soit en accord avec ces normes, à vrai dire, il semblerait bien qu&#8217;il n&#8217;y en ai qu&#8217;un seul qui respecte ces normes (celui de <a href="http://squiloople.com/" target="_blank">Michael Rushton</a>). La fonction <span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; font-size: 12px; white-space: pre;">filter_var</span> avec <span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; font-size: 12px; white-space: pre;">FILTER_VALIDATE_EMAIL</span> ne prenait pas du tout en compte ces normes là et majorité d&#8217;emails sortant de l&#8217;ordinaire étaient invalides pour elle. Depuis le 2 avril 2010 (<a href="http://svn.php.net/viewvc/php/php-src/trunk/ext/filter/logical_filters.c?revision=297350&amp;view=markup#l499" target="_blank">révision 297350 de php</a>), ce regexp est inclut directement avec cependant quelques petites suppressions dans FILTER_VALIDATE_EMAIL. Toutefois, la version de PHP contenant cette mise à jour n&#8217;et pas encore sortie.</p>
<p>Ce que nous allons faire aujourd&#8217;hui est utiliser ce regexp pour vérifier nos adresses emails, mais également vérifier si le nom de domaine utilisé dans l&#8217;adresse email existe et est enregistré sur les serveurs DNS.</p>
<h2>Application</h2>
<h3>Le Regexp</h3>
<p>Voici le fameux regexp en php (accrochez-vous bien) :</p>
<blockquote>
<pre>$regexp = '/^(?!(?:\x22?(?:\x5C[\x00-\x'
.'7E]|[^\x22\x5C])\x22?){255,})(?!(?:\x'
.'22?(?:\x5C[\x00-\x7E]|[^\x22\x5C])\x2'
.'2?){65,}@)(?:[\x21\x23-\x27\x2A\x2B\x'
.'2D\x2F-\x39\x3D\x3F\x5E-\x7E]+|(?:\x2'
.'2(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x'
.'23-\x5B\x5D-\x7F]|\x5C[\x00-\x7F])*\x'
.'22))(?:\.(?:[\x21\x23-\x27\x2A\x2B\x2'
.'D\x2F-\x39\x3D\x3F\x5E-\x7E]+|(?:\x22'
.'(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x2'
.'3-\x5B\x5D-\x7F]|\x5C[\x00-\x7F])*\x2'
.'2)))*@(?:(?:(?!.*[^.]{64,})(?:(?:xn--'
.')?[a-z0-9]+(?:-[a-z0-9]+)*\.){0,126}('
.'?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*)|(?:'
.'\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::['
.'a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9]'
.'[:\]]){8,})(?:[a-f0-9]{1,4}(?::[a-f0-'
.'9]{1,4}){0,6})?::(?:[a-f0-9]{1,4}(?::'
.'[a-f0-9]{1,4}){0,6})?)))|(?:(?:IPv6:('
.'?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){'
.'5}:)|(?:(?!(?:.*[a-f0-9]:){6,})(?:[a-'
.'f0-9]{1,4}(?::[a-f0-9]{1,4}){0,4})?::'
.'(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,'
.'4}:)?)))?(?:25[0-5]|2[0-4][0-9]|1[0-9'
.']{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-'
.'4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\'
.']))$/iD';'</pre>
</blockquote>
<p style="text-align: center;"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/regexp0.png" rel="lightbox[156]"><img class="size-medium wp-image-171 aligncenter" title="regexp0" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/regexp0-300x80.png" alt="" width="300" height="80" /></a></p>
<p>Alors ça rigole moins là hein ! Bon je ne vais pas détailler l&#8217;expression, sachez juste qu&#8217;elle permet de vérifier notre mail selon les dernières normes RFC (sauf cas particulier non connus).</p>
<p>Et maintenant on va faire appel à une fonction bien pratique en php : checkdnsrr qui va vérifier l&#8217;enregistrement DNS en champs MX (domaines pour les mails) de ce qu&#8217;on lui passe en paramètre. &laquo;&nbsp;afzxgdegedsgesd.com&nbsp;&raquo; renverra FALSE tandis que &laquo;&nbsp;gmail.com&nbsp;&raquo; renverra TRUE :</p>
<pre>
<blockquote>

$domain=substr(strchr($email,'@'),1); //on récupère la partie après le dernier @
if(checkdnsrr($domain,'MX')) //on vérifie l'enregistrement
return true; //tout est bon on retourne TRUE</blockquote>
</pre>
<p>Notre fonction complète sera donc :</p>
<pre>
<blockquote>

function checkMail($mail){
	$regexp = '/^(?!(?:\x22?(?:\x5C[\x00-\x'
	.'7E]|[^\x22\x5C])\x22?){255,})(?!(?:\x'
	.'22?(?:\x5C[\x00-\x7E]|[^\x22\x5C])\x2'
	.'2?){65,}@)(?:[\x21\x23-\x27\x2A\x2B\x'
	.'2D\x2F-\x39\x3D\x3F\x5E-\x7E]+|(?:\x2'
	.'2(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x'
	.'23-\x5B\x5D-\x7F]|\x5C[\x00-\x7F])*\x'
	.'22))(?:\.(?:[\x21\x23-\x27\x2A\x2B\x2'
	.'D\x2F-\x39\x3D\x3F\x5E-\x7E]+|(?:\x22'
	.'(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x2'
	.'3-\x5B\x5D-\x7F]|\x5C[\x00-\x7F])*\x2'
	.'2)))*@(?:(?:(?!.*[^.]{64,})(?:(?:xn--'
	.')?[a-z0-9]+(?:-[a-z0-9]+)*\.){0,126}('
	.'?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*)|(?:'
	.'\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::['
	.'a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9]'
	.'[:\]]){8,})(?:[a-f0-9]{1,4}(?::[a-f0-'
	.'9]{1,4}){0,6})?::(?:[a-f0-9]{1,4}(?::'
	.'[a-f0-9]{1,4}){0,6})?)))|(?:(?:IPv6:('
	.'?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){'
	.'5}:)|(?:(?!(?:.*[a-f0-9]:){6,})(?:[a-'
	.'f0-9]{1,4}(?::[a-f0-9]{1,4}){0,4})?::'
	.'(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,'
	.'4}:)?)))?(?:25[0-5]|2[0-4][0-9]|1[0-9'
	.']{2}|[1-9]?[0-9])(?:\.(?:25[0-5]|2[0-'
	.'4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\'
	.']))$/iD';

	if(!preg_match($regexp, $mail))
		return false;

	$domain=substr(strchr($email,'@'),1);
	return checkdnsrr($parts[1], "MX");
}</blockquote>
</pre>
<p>Elle est jolie, non ?</p>
<p>Le mail suivant est donc valide : $%^%JerE_my*&amp;&amp;1@gmail.com</p>
<p>Mais celui là non : !def!xyz%abc@@gmail.com</p>
<h2>Conclusion</h2>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/16a.jpg" rel="lightbox[156]"><img class="alignleft size-full wp-image-172" title="16a" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/16a.jpg" alt="" width="150" height="150" /></a>Vous savez désormais créer une fonction de validation mail digne de ce nom, quelques améliorations peuvent y être apportée, principalement vérifier si la partie après le dernier @ est une IP (ipv4, ipv6, &#8230;) ou un domaine composé, dans ce cas il ne faut pas faire la vérification de champs MX car elle n&#8217;aboutira à rien.</p>
<p>Mais au moins n&#8217;importe qui pourra entrer ces adresses spéciales sans que ce ne soit considéré comme invalide. Du moins en attendant que le dernier FILTER_VALIDATE_EMAIL intégré à PHP ne sorte.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2010/09/24/php-verification-de-mails-complete-avec-dns/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Google Doc Spreadsheets &#8211; Requêter une table</title>
		<link>http://www.jeremy-trufier.net/2010/09/23/google-doc-spreadsheets-requeter-une-table/</link>
		<comments>http://www.jeremy-trufier.net/2010/09/23/google-doc-spreadsheets-requeter-une-table/#comments</comments>
		<pubDate>Thu, 23 Sep 2010 14:00:00 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[Application]]></category>
		<category><![CDATA[Informatique]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[base de données]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[google spreadsheets]]></category>
		<category><![CDATA[query]]></category>
		<category><![CDATA[requêtes]]></category>
		<category><![CDATA[tableur]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=109</guid>
		<description><![CDATA[Aujourd&#8217;hui nous allons parler un petit peu de Google Doc Spreadsheets et des possibilités qu&#8217;il donne. Il est possible de faire une base de donnée en google doc spreadsheet&#8230; &#171;&#160;Hein que quoi ?! on m&#8217;aurait caché des choses ?&#160;&#187; Yep yep, et c&#8217;est super simple. Bien entendu nous parlons d&#8217;une base de donnée locale utilisable [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/google_docs_logo.png" rel="lightbox[109]"><img class="alignright size-full wp-image-110" title="google_docs_logo" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/google_docs_logo.png" alt="" width="231" height="218" /></a>Aujourd&#8217;hui nous allons parler un petit peu de Google Doc Spreadsheets et des possibilités qu&#8217;il donne.</p>
<p>Il est possible de faire une base de donnée en google doc spreadsheet&#8230; &laquo;&nbsp;Hein que quoi ?! on m&#8217;aurait caché des choses ?&nbsp;&raquo;</p>
<p>Yep yep, et c&#8217;est super simple. Bien entendu nous parlons d&#8217;une base de donnée locale utilisable uniquement dans notre document, nous ne pourrons pas la requêter facilement de l&#8217;extérieur.</p>
<p>Cette fonction est super utile pour gérer des plannings et connaitre approximativement le coût final sachant que chaque tâche peut être un type de travail différent.</p>
<p><span id="more-109"></span></p>
<h2>Pratique</h2>
<p>Tout d&#8217;abord nous allons nous créer une feuille de tableur toute simple récapitulant nos différents prix (faux les prix <img src='http://www.jeremy-trufier.net/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  ) :</p>
<div id="attachment_112" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/tarifs.jpg" rel="lightbox[109]"><img class="size-medium wp-image-112" title="Feuille Tarifs" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/tarifs-300x130.jpg" alt="Feuille Tarifs" width="300" height="130" /></a><p class="wp-caption-text">Feuille Tarifs</p></div>
<p>Puis maintenant notre planning de base, trois colonne Nom de la tache, Type de la tache correspondant à la référence dans la page Tarif, et la durée horaire de chaque tâche :</p>
<div id="attachment_113" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/planning1.jpg" rel="lightbox[109]"><img class="size-medium wp-image-113" title="Planning étape 1" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/planning1-300x183.jpg" alt="Planning étape 1" width="300" height="183" /></a><p class="wp-caption-text">Planning étape 1</p></div>
<p>A présent comme vous l&#8217;aurez deviné le but du jeu est de faire remplir la 4e colonne avec les bons montants en utilisant la feuille Tarifs.</p>
<p>Pour cela nous allons utiliser la fonction QUERY(). Le premier paramètre est la plage de donnée que nous voulons requêter, c&#8217;est donc ici la plage A:C (les collonnes A à C) de la page Tarifs, donc la plage : Tarifs!A2:C10 par exemple, mais il faut rajouter nos $ pour ne pas modifier ces valeurs lorsque nous allons répliquer la formule : <strong>Tarifs!$A$2:$C$10</strong></p>
<p>Le deuxième paramètre est notre requête, ici nous voulons récupérer le tarif horaire correspondant à la référence dans la colonne B de notre feuille Planning. Notre requête pour la tâche 1 va donc être :</p>
<blockquote>
<pre>SELECT B WHERE A=B2</pre>
</blockquote>
<p>Et oui mais petit problème, on mixe deux pages là, on veut bien récupérer le contenu de la colonne Tarifs!B lorsque Tarifs!A=Planning!B2, mais comment google spreadsheets saura que B2 fait partie de la feuille planning ???</p>
<p>Il nous suffit de concaténer :</p>
<blockquote>
<pre>CONCATENATE("SELECT B WHERE A='",B2,"'")</pre>
</blockquote>
<p>Notre requête finale sera donc :</p>
<blockquote>
<pre>=QUERY(Tarifs!$A$2:$C$10,CONCATENATE("SELECT B WHERE A='",B2,"'"))*C2</pre>
</blockquote>
<p>Vous remarquez le petit *C2 pour prendre en compte le nombre d&#8217;heures.</p>
<p>Maintenant appliquons la requête dans une cellule et dupliquons là dans les autres et cela nous donne :</p>
<div id="attachment_114" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/planning2.jpg" rel="lightbox[109]"><img class="size-medium wp-image-114" title="Feuille planning - Etape 2" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/planning2-300x212.jpg" alt="Feuille planning - Etape 2" width="300" height="212" /></a><p class="wp-caption-text">Feuille planning - Etape 2</p></div>
<h2>Conclusion</h2>
<p>Vous avez maintenant appris à requêter en google spreadsheets, les possibilités sont impressionnantes et seulement une d&#8217;entre elle est survolée par cet article. J&#8217;avais cependant envie de vous la faire découvrir étant donné le gain de temps apporté.</p>
<p>Si vous voulez plus d&#8217;infos, je vous invite à consulter la page de google concernant ce langage de requêtage :<a href="http://code.google.com/intl/fr/apis/visualization/documentation/querylanguage.html" target="_blank"> http://code.google.com/intl/fr/apis/visualization/documentation/querylanguage.html</a></p>
<p>A bientôt !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2010/09/23/google-doc-spreadsheets-requeter-une-table/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How I met your mother, saison 6</title>
		<link>http://www.jeremy-trufier.net/2010/09/22/how-i-met-your-mother-saison-6/</link>
		<comments>http://www.jeremy-trufier.net/2010/09/22/how-i-met-your-mother-saison-6/#comments</comments>
		<pubDate>Wed, 22 Sep 2010 14:00:36 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[Multimédia]]></category>
		<category><![CDATA[Séries TV]]></category>
		<category><![CDATA[himym]]></category>
		<category><![CDATA[How I Met Your Mother]]></category>
		<category><![CDATA[saison]]></category>
		<category><![CDATA[série TV]]></category>
		<category><![CDATA[spoil]]></category>
		<category><![CDATA[tv show]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=134</guid>
		<description><![CDATA[Et oui !!! hier fut le grand retour d&#8217;une de mes séries favorites pour une 6ème saison : How I met your mother. Vous en avez surement entendu parler, une série où nous sommes en 2030 et où le protagoniste Ted Mosby, raconte à ces enfants agés de 15 et 16ans comment il a rencontré [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_138" class="wp-caption aligncenter" style="width: 443px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.10.33.png" rel="lightbox[134]"><img class="size-full wp-image-138" title="HIMYM-Generique" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.10.33.png" alt="" width="433" height="250" /></a><p class="wp-caption-text">Générique HIMYM</p></div>
<p>Et oui !!! hier fut le grand retour d&#8217;une de mes séries favorites pour une 6ème saison : How I met your mother.</p>
<p>Vous en avez surement entendu parler, une série où nous sommes en 2030 et où le protagoniste Ted Mosby, raconte à ces enfants agés de 15 et 16ans comment il a rencontré leur mère ! L&#8217;entière série est donc un retour en arrière qui suit notre époque. Bien entendu, nous n&#8217;avons jamais vu la mère tout au long des 6 saisons, ni sut qui elle est.</p>
<div id="attachment_142" class="wp-caption alignright" style="width: 160px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.08.20.png" rel="lightbox[134]"><img class="size-thumbnail wp-image-142" title="HIMYM - 601 - Enfants" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.08.20-150x150.png" alt="" width="150" height="150" /></a><p class="wp-caption-text">HIMYM - 601 - Enfants de Ted</p></div>
<p>Nous avons cependant quelques informations :</p>
<ul>
<li>Elle suit des cours dans l&#8217;université où enseigne Ted, un jour qu&#8217;il s&#8217;est trompé de cours, elle était dans la salle&#8230;</li>
<li>Nous connaissons sa colocataire, Cyndi, une ex petite amie à Ted</li>
<li>Nous avons aperçu chez Cyndi un bout de son pied et sa cheville</li>
<li>Ted possède un parapluie jaune qu&#8217;il a trouvé dans une soirée, et qui lui a appartenu</li>
<li>Ted habite enfin dans la maison qu&#8217;il partagera avec elle et ces enfants dans le futur</li>
<li>surement deux ou trois autres que j&#8217;oublie</li>
</ul>
<p>Cet épisode nous en apprend un autre plutôt sympathique.</p>
<p><span id="more-134"></span></p>
<h2>Attention SPOIL</h2>
<p>Dans cet épisode, par déduction, nous commençons par ce qu&#8217;il semble être la fin de la saison 6, un fameux mariage auquel Ted et Marshall sont présent, et au cour duquel sa dulcinée sera présente. Nous apprenons à la fin de l&#8217;épisode, qu&#8217;il est le témoin de ce mariage, ce n&#8217;est donc pas le sien, mais celui d&#8217;une connaissance commune à Ted et Marshall&#8230; Barney ? Robin ? nous n&#8217;en savons pas plus, mais il semblerait bizarre que ce soit l&#8217;un de ces deux là au vu de leur réticence au mariage.</p>
<div id="attachment_141" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.09.50.png" rel="lightbox[134]"><img class="size-medium wp-image-141" title="HIMYM - 601 - Wedding" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.09.50-300x199.png" alt="" width="300" height="199" /></a><p class="wp-caption-text">HIMYM - 601 - Mariage, Ted témoin</p></div>
<p>Après la première minute, un gros retour en arrière, pour nous montrer une occasion quelque mois auparavant où Ted est stressé et gratte l&#8217;étiquette de sa bierre. Tout l&#8217;épisode se passe à ce moment là.</p>
<p>Parallèlement, Marshall et Lily essayent d&#8217;avoir des enfants, mais le fait que Marshall partage ça avec tout le monde, ces collègues, sa famille, ses voisins, ne semble pas particulièrement enthousiasmer Lily&#8230; Ajoutons à cela le caractère plus qu&#8217;envahissant du père de Marshall, et ce dernier devra se retenir plus longtemps encore <img src='http://www.jeremy-trufier.net/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  !</p>
<div id="attachment_140" class="wp-caption alignright" style="width: 160px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.11.16.png" rel="lightbox[134]"><img class="size-thumbnail wp-image-140" title="HIMYM - 601 - Cindy kiss a girl" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.11.16-150x150.png" alt="" width="150" height="150" /></a><p class="wp-caption-text">HIMYM - 601 - Cindy changing her side</p></div>
<p>Nous retrouvons également Cindy (sensée détester Ted), et une fille blonde que Ted voudrait approcher, qui pensons nous pourrait n&#8217;être autre que sa colocataire, et pourquoi pas la mère tant recherchée, mais bon la deuxième idée est que c&#8217;est impossible en début de saison ^.</p>
<p>A un moment de l&#8217;épisode, Cindy voit Ted et surprise ! Elle lui pardonne et le remercie de lui avoir ouvrir les yeux qu&#8217;elle a compris pourquoi ils n&#8217;étaient pas fait l&#8217;un pour l&#8217;autre. Soulagement de Ted qui se dit qu&#8217;il pourrait ainsi plus facilement approcher sa blonde de copine&#8230;</p>
<p>Cependant il n&#8217;est pas au bout de ses peines, et quand enfin il prend le courage d&#8217;aller voir la blonde, arf, pile le moment qu&#8217;elles choisissent avec Cindy pour s&#8217;embrasser !!!</p>
<p>Nous retrouvons bien évidemment les deux derniers protagonistes principaux dans la personne de Robin, déprimée et addict aux gâteaux, vêtements amples et appliquant la consigne : &laquo;&nbsp;la crasse protège des microbres&nbsp;&raquo;, ainsi que Barney, toujours le même, toujours aussi manipulateur, abusant de son coté des &laquo;&nbsp;Preums&nbsp;&raquo;&#8230;</p>
<div id="attachment_139" class="wp-caption aligncenter" style="width: 160px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.12.23.png" rel="lightbox[134]"><img class="size-thumbnail wp-image-139 " title="HIMYM - 601 - Robin déprimée" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Capture-2010-09-21-à-23.12.23-150x150.png" alt="" width="150" height="150" /></a><p class="wp-caption-text">HIMYM - 601 - Robin déprimée</p></div>
<p>Du côté de Robin, c&#8217;est bizarre mais elle est plus déprimée encore depuis ça rupture avec Don que lorsqu&#8217;elle a rompu avec Ted ou avec Barney.</p>
<p>Bien entendu toujours des petits retours en arrières anecdotique bien sympathique.</p>
<p>Si toute la saison se calque sur le même plan, nous aurons à chaque épisode des informations sur le mariage (dernier épisode de la saison selon l&#8217;hypothèse), puis un retour en arrière dans lequel se déroulera l&#8217;action.</p>
<p>Si je calcule bien : le présent est en 2030 &lt;- le moment raconté est en 2011 (mariage) &lt;- l&#8217;action se passe en 2010 (épisode) &lt;- et nous avons des anecdotes du passé</p>
<p>Tout ceci peut sembler bien embrouillant, mais que nenni, il n&#8217;en est rien, ça accentue le suspens et va en continuité avec l&#8217;esprit original de la série.</p>
<p>Bref cela promet une suite de saison plutôt sympathique, même si on aimerait bien enfin rencontrer la mère&#8230; Mais bon, tant qu&#8217;il y aura de l&#8217;audience, il y aura un scénario, et tant qu&#8217;il y a un scénario, nous ne rencontrerons pas la mère car nous aurions affaire à une aberration avec le titre et l&#8217;essence même de la série.</p>
<p>Demain, un petit tuto bien sympathique sur google Spreadsheets&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2010/09/22/how-i-met-your-mother-saison-6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IE9 béta a dopé son moteur Javascript</title>
		<link>http://www.jeremy-trufier.net/2010/09/21/ie9-beta-a-dope-son-moteur-javascript/</link>
		<comments>http://www.jeremy-trufier.net/2010/09/21/ie9-beta-a-dope-son-moteur-javascript/#comments</comments>
		<pubDate>Tue, 21 Sep 2010 10:52:28 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[Comparatifs]]></category>
		<category><![CDATA[Informatique]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[acid3]]></category>
		<category><![CDATA[benchmarks]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[IE9 béta]]></category>
		<category><![CDATA[internet explorer]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[navigateur]]></category>
		<category><![CDATA[web]]></category>
		<category><![CDATA[websockets]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=81</guid>
		<description><![CDATA[Bonjour à tout les passants, rares soient-il qui liront cet article ! Il y a quelques jour, le navigateur haït par tout développeur Web quel qu&#8217;il soit est sortie dans une nouvelle mouture dont le slogan est : &#171;&#160;Bienvenue dans un monde plus beau&#160;&#187;. En passant leur banière est absolument horrible : MEEEEEESSSS YEUUUXXXXXX !!! [...]]]></description>
			<content:encoded><![CDATA[<p>Bonjour à tout les passants, rares soient-il qui liront cet article !</p>
<p>Il y a quelques jour, le navigateur haït par tout développeur Web quel qu&#8217;il soit est sortie dans une nouvelle mouture dont le slogan est : &laquo;&nbsp;Bienvenue dans un monde plus beau&nbsp;&raquo;.</p>
<p>En passant leur banière est absolument horrible :</p>
<div id="attachment_82" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/ban_ie9.jpg" rel="lightbox[81]"><img class="size-medium wp-image-82" title="Bannière IE9" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/ban_ie9-300x117.jpg" alt="Bannière IE9 &quot;Bienvenue dans un monde plus beau&quot;" width="300" height="117" /></a><p class="wp-caption-text">Bannière IE9 &quot;Bienvenue dans un monde plus beau&quot;</p></div>
<p>MEEEEEESSSS YEUUUXXXXXX !!! C&#8217;est quoi ce noir qui sort de nul part contrastant bien entendu avec le blanc, mais pas du tout avec l&#8217;arrière plan ! Cela ferait hérisser les cheveux de n&#8217;importe quel ergonome Web, en passant  en Noir et Blanc, le noir ne se différencie que très peu du bleu&#8230;</p>
<p><span id="more-81"></span></p>
<p>Bon une fois Internet Explorer 9 béta lancé, une erreur comme quoi la page ne peut se charger, amélioration ici, le message d&#8217;erreur est discret et non bloquant. Un petit click sur OK et &#8230; ah ! un autre message d&#8217;erreur&#8230; bon ben on reclic sur OK&#8230; ah ! nous revoilà sur le premier message d&#8217;erreur&#8230; Bon je suis mauvaise langue, c&#8217;est une béta, c&#8217;est normal.</p>
<p>Un message nous indiquant que le chargement de la page est surement ralentie par l&#8217;utilisation de plugin et nous invite à les désactiver en un clic. Petite interface bien pratique.</p>
<p>Nous apprenons ici que IE9 gère chaque page indépendamment, le premier onglet était buggé, mais pas le navigateur.</p>
<p>Au niveau du navigateur en lui-même quelques changements :</p>
<div id="attachment_83" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/ie9-screenshot.jpg" rel="lightbox[81]"><img class="size-medium wp-image-83" title="Interface IE9 béta" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/ie9-screenshot-300x182.jpg" alt="Interface IE9 béta" width="300" height="182" /></a><p class="wp-caption-text">Interface IE9 béta</p></div>
<p>Et surprise, à l&#8217;instar de google chrome nous retrouvons une certaine simplicité d&#8217;utilisation : notamment avec la barre unique servant à la fois à la recherche et à entrer des urls. A l&#8217;ouverture d&#8217;un onglet nous avons également l&#8217;affichage des sites récents introduits il y a quelques temps par Safari. Je ne m&#8217;en sers que rarement mais nombre de gens y trouveront leur bonheur.</p>
<p>Maintenant du côté technique, IE9 est-il aussi respectueux des standards qu&#8217;il le prétend ?</p>
<h2>Technique</h2>
<h3>Acid3</h3>
<p>Pour savoir cela direction Acid3 :</p>
<div id="attachment_84" class="wp-caption aligncenter" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/ie9-screenshot2.jpg" rel="lightbox[81]"><img class="size-medium wp-image-84" title="IE9 et acid3" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/ie9-screenshot2-300x228.jpg" alt="IE9 et acid3" width="300" height="228" /></a><p class="wp-caption-text">IE9 et acid3</p></div>
<p>Pour rappel, voici les scores des autres navigateurs :</p>
<ul>
<li>Firefox 3.6 : 94%</li>
<li>Safari 5 : 100%</li>
<li>Chrome : 100%</li>
<li>IE6 : 12%</li>
<li>IE7 : 14%</li>
<li>IE8 : 20%</li>
</ul>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/IE+6+troll+internet+explorer+browser+trollface.png" rel="lightbox[81]"><img class="alignleft size-thumbnail wp-image-91" title="IE ugly" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/IE+6+troll+internet+explorer+browser+trollface-150x150.png" alt="" width="128" height="128" /></a></p>
<p>Quand on voit le retard des précédentes version de Internet Explorer, la réussite presque parfaite de ce test montre une grande évolution, mais surtout permet d&#8217;envisager une perte de temps négligeable pour les développeurs.</p>
<p>Précédemment, il fallait gérer tout les cas particuliers, majoritairement présents sur IE6, IE7 et IE8, désormais il faudra toujours gérer IE7 et IE8, mais IE9 s&#8217;en sortira de lui même. (comment ça IE6 a disparut de ma liste&#8230; <img src='http://www.jeremy-trufier.net/wp-includes/images/smilies/icon_razz.gif' alt=':P' class='wp-smiley' />  )</p>
<h3>Javascript</h3>
<p>Maintenant continuons nos investigations par un petit test de performance Javascript.</p>
<p>Pour réaliser ce test j&#8217;ai utilisé SunSpider, en fermant toutes les applications éventuellement nuisibles aux résultats sur le PC. Tout les navigateurs sont testés dans les même conditions.</p>
<p>Le score indiqué en nombre de point et la somme du classement des navigateurs pour chaque tâche. (Ainsi sur crypto-md5, IE9 arrive 3e il a donc 1 point, Firefox arrive dernier 0 points, Safari 1er donc 3 points et enfin Chrome 2eme par conséquent 2points)</p>
<p><strong><br />
</strong></p>
<div id="attachment_89" class="wp-caption alignleft" style="width: 310px"><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/score-js.jpg" rel="lightbox[81]"><img class="size-medium wp-image-89  " title="Total Benchmarks Javascript" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/score-js-300x43.jpg" alt="Total Benchmarks Javascript" width="300" height="43" /></a><p class="wp-caption-text">Total Benchmarks Javascript</p></div>
<p>Voici le test complet en PDF téléchargeable ici :<a href="http://bit.ly/da6JY8"><br />
Benchmarks Javascript &#8211; comparatifs IE9, Safari, Firefox et Chrome</a><br />
Ou une lecture en ligne est disponible ici :<a title="Benchmarks Javascript - lecture en ligne" href="http://bit.ly/bvyJAu" target="_blank"><br />
Benchmarks Javascript &#8211; lecture en ligne</a></p>
<p>Quelle ne fut pas ma surprise de voir le score de IE9 monter à 38 points, suivant de près Safari à 44 points et aussi de près chrome à 59 points. Firefox est tellement lent qu&#8217;il est presque hors concours : 11 points, avec des temps très longs, et même trop longs pour des fonctions simples.</p>
<p>IE9 arrive même à être le premier sur plusieurs temps de test, ce qui était in-envisageable précédemment.</p>
<h3>WebSockets</h3>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Nuvola_filesystems_socket.png" rel="lightbox[81]"><img class="alignleft size-full wp-image-90" title="Nuvola_filesystems_socket" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/Nuvola_filesystems_socket.png" alt="" width="128" height="128" /></a>Petite déception également, IE9 ne gère pas les WebSockets qui est quand même une évolution majeure en Web. Connaissant la rétiscence de Microsoft à intégrer de nouvelles technologies dans son navigateur, nous en avons pour quelques années encore avant que cela ne soit géré.</p>
<p>Pour ceux qui se demandent ce qu&#8217;est un WebSocket je vais le détailler rapidement. Je ferais surement un article plus complet avec node.js et les websockets dans le futur.</p>
<p>Lorsque un navigateur demande une page à un serveur, il ouvre une session, puis une connexion. Dès que le serveur retourne un message, la connexion se ferme. La session quant à elle reste ouverte plus longtemps, jusqu&#8217;à ce que le client devienne inactif et ne demande plus de pages pendant une certaine durée. Le problème est que nous avons deux transactions unidirectionnelles, d&#8217;un côté on fait une demande, de l&#8217;autre on retourne une réponse, mais dès que la réponse est arrivée la connexion se coupe et le serveur ne peut par conséquent plus envoyer de données jusqu&#8217;à ce que le client lui en redemande.</p>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/ajax.jpg" rel="lightbox[81]"><img class="alignright size-thumbnail wp-image-97" title="ajax" src="http://www.jeremy-trufier.net/wp-content/uploads/2010/09/ajax-150x150.jpg" alt="" width="150" height="150" /></a></p>
<p>C&#8217;est très handicapant pour un chat par exemple, des méthodes existent pour outrepasser cette limitation, notamment utiliser du Pull grâce à ajax (rester en attente de donnée, et dès que des données arrivent depuis le serveur, on se remet en attente juste après la clôture de la connexion), ou tout simplement demander, toujours en ajax, toutes les X millisecondes si de nouveaux messages ne sont pas arrivés sur le serveur. Du coup les performances sont fortement réduites, le serveur tout le temps sollicité en connexion, etc&#8230;</p>
<p>Les websockets permettent justement de laisser une connexion ouverte en permanence depuis le serveur, ce dernier peut donc envoyer des infos quand il le veut, tout comme le client, nous avons donc une communication bidirectionnelle, voir omnidirectionnel en cas de communication à plusieurs, nous pourrons même nous affranchir du passage par le serveur.</p>
<h2>The end&#8230;</h2>
<p>Je pense que IE9 béta est il est vrai une  grande évolution de Internet Explorer, plus respectueux des standards,  plus performant au niveau Javascript, intégrant une gestion indépendante  des onglets, en bref possédant ce qu&#8217;il doit avoir, pour un vrai  navigateur moderne.</p>
<p>Bon, bien sur le mot de la fin est que je ne  quitterai pas ni mon safari sous mac où mon chrome sous windows pour  IE9, je trouve que l&#8217;interface a trop de fioritures, tels que les  dégradés un peu partout, où encore le texte des onglets qui ne se  différencie pas correctement de leur arrière plan. L&#8217;œil est  inconsciemment attiré par ces détails, et le cerveau se concentre moins  sur l&#8217;essentiel.</p>
<p>See you soon !!!</p>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 1342px; width: 1px; height: 1px; overflow: hidden;"><a href="http://bit.ly/da6JY8">Benchmarks Javascript &#8211; comparatifs IE9, Safari, Firefox et Chrome</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2010/09/21/ie9-beta-a-dope-son-moteur-javascript/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Véritable VPN au travers d&#8217;un tunnel SSH</title>
		<link>http://www.jeremy-trufier.net/2009/12/21/veritable-vpn-au-travers-dun-tunnel-ssh/</link>
		<comments>http://www.jeremy-trufier.net/2009/12/21/veritable-vpn-au-travers-dun-tunnel-ssh/#comments</comments>
		<pubDate>Mon, 21 Dec 2009 01:42:04 +0000</pubDate>
		<dc:creator>Jérémy TRUFIER</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Réseaux et Sécurité]]></category>
		<category><![CDATA[Osx]]></category>
		<category><![CDATA[Réseau]]></category>
		<category><![CDATA[Tunnel SSH]]></category>
		<category><![CDATA[Virtual Private Network]]></category>
		<category><![CDATA[VPN]]></category>

		<guid isPermaLink="false">http://www.jeremy-trufier.net/?p=34</guid>
		<description><![CDATA[Bonjour ami informaticien ! Posons le décor : tu viens d&#8217;arriver dans un hôtel, tu t&#8217;installes confortablement afin de profiter de la connexion internet offerte gratuitement et de pouvoir téléphoner à ta tante Gertrude gratuitement grâce à ton compte SIP, et là ! Misère de misère, les ports SIP sont  bloqués, logique, l&#8217;hôtelier préfère faire [...]]]></description>
			<content:encoded><![CDATA[<p>Bonjour ami informaticien !</p>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/image_hotel_exterior_night_1.jpg" rel="lightbox[34]"><img class="alignleft size-medium wp-image-99" title="image_hotel_exterior_night_1" src="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/image_hotel_exterior_night_1-225x300.jpg" alt="" width="197" height="262" /></a> Posons le décor : tu viens d&#8217;arriver dans un hôtel, tu t&#8217;installes confortablement afin de profiter de la connexion internet offerte gratuitement et de pouvoir téléphoner à ta tante Gertrude gratuitement grâce à ton compte SIP, et là ! Misère de misère, les ports SIP sont  bloqués, logique, l&#8217;hôtelier préfère faire payer les communications avec une légère surtaxe ! <em>[IRONIE ON] Oui oui, cet exemple est sorti de mon imagination, non non, ça ne m&#8217;est jamais arrivé&#8230; [IRONIE OFF]</em></p>
<p>Le problème est le même si tu désires jouer à un jeu dont les ports sont bloqués.</p>
<p>Ce qu&#8217;on va donc réaliser, c&#8217;est un VPN entre son ordinateur, appelons le A, et son serveur personnel S situé chez soi ou encore chez un hébergeur, S doit bien entendu être affranchi de toute limitation au niveau des ports. S doit également posséder un serveur SSH accessible depuis un port débloqué à l&#8217;hôtel. Généralement le port 22 par défaut est débloqué, cela ne devrait donc pas poser de problème.</p>
<p>Pour rappel un VPN (Virtual Private Network) permet de se connecter à un réseau distant et d&#8217;envoyer tout le trafic réseau par cette nouvelle connexion.</p>
<p><span id="more-34"></span></p>
<p><strong>Mais quels sont les avantages de cette méthode par rapport à un VPN PPTP, L2TP ou OpenVPN ???</strong></p>
<p>Pratiquement aucun, ce tunnel va juste être très rapide à configurer, seulement quelques lignes de commandes seront nécessaires, sécurisé grâce au tunnel SSH, et souvent les ports requis par PPTP ou L2TP sont bloqués.</p>
<p><strong>Bon, un petit schémas pour résumer peut-être ?</strong></p>
<p><strong> </strong></p>
<div id="attachment_48" class="wp-caption alignnone" style="width: 460px"><strong><strong><a href="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/vpnSSH_2-m1.png" rel="lightbox[34]"><img class="size-full wp-image-48 " title="vpnSSH_2-m" src="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/vpnSSH_2-m1.png" alt="VPN et tunnel SSH, schémas" width="450" height="167" /></a></strong></strong><p class="wp-caption-text">VPN et tunnel SSH, schémas</p></div>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><strong> </strong></p>
<p><strong><span style="font-weight: normal;">C&#8217;est plus clair ? En fin de compte, tout le trafic transitera au travers d&#8217;un tunnel SSH, notre ordinateur sera donc connecté au réseau distant (192.168.0.0) comme s&#8217;il en faisait parti.</span></strong></p>
<p><strong><span style="font-weight: normal;">Bien maintenant, on sait où on va, mais on sait pas trop comment ! Pas de panique je ne te largue pas comme ça juste avec le principe ^^, la théorie est faite, place à la pratique.</span></strong></p>
<h3>Configuration du server SSH</h3>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/ssh.png" rel="lightbox[34]"><img class="size-medium wp-image-100 alignright" title="ssh" src="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/ssh-190x300.png" alt="" width="190" height="300" /></a>Quelques petits prérequis afin que notre tunnel s&#8217;établisse correctement, nous allons devoir modifier un petit peu la configuration de notre serveur SSH :</p>
<p>Ce fichier est généralement situé ici : /etc/ssh/sshd_config<br />
Vous devez vérifier que les réglages suivant soit paramétrés comme ceci :</p>
<blockquote style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; font-size: 12px; white-space: pre;"><p>X11Forwarding yes</p>
<p>PermitTunnel yes</p>
<p>PermitRootLogin yes</p></blockquote>
<p>Ensuite il nous faut activer la redirection des paquets, désactivé par défaut sur la majorité des Linux.</p>
<blockquote style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; font-size: 12px; white-space: pre;"><p>sudo echo 1 &gt; /proc/sys/net/ipv4/ip_forward</p></blockquote>
<p>Puis finalement redemarrer le serveur SSH :</p>
<blockquote style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; font-size: 12px; white-space: pre;"><p>sudo /etc/init.d/sshd restart</p></blockquote>
<h3>Création du Tunnel SSH</h3>
<p>Sur la machine cliente (Ordinateur A sur notre schémas), la commande permettant de creer le tunnel est celle-ci :</p>
<blockquote style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; font-size: 12px; white-space: pre;"><p>sudo ssh -NTfv -w 11:10 root@ip_du_serveur_S</p></blockquote>
<p>Passons en revu les différentes options :<a href="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/railway.jpg" rel="lightbox[34]"><img class="alignleft size-thumbnail wp-image-104" title="railway" src="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/railway-150x150.jpg" alt="" width="150" height="150" /></a></p>
<ul>
<li>N : empêche l&#8217;execution d&#8217;une commande</li>
<li>T : n&#8217;alloue pas un terminal TTY à cette instance de connection SSH</li>
<li>f : executé en arrière plan</li>
<li>v : mode verbose, afin d&#8217;afficher les différents messages</li>
<li>w : lie deux interfaces, nous allons avoir l&#8217;interface tun11 sur Ordinateur A et tun10 sur Serveur S. Les deux auraient pu être tun10 ou encore tun0, mais je voulais bien les différencier pour ne pas les confondre. De plus dans mon cas tun0 est déjà utilisé sur mon serveur pour un VPN.</li>
<li>C : je ne l&#8217;ai pas mise, à essayer avec, cette option permet de compresser les données, du coup gain énorme de bande passante, mais perte de réactivité, pour des jeux à bannir, pour des page web à utiliser.</li>
</ul>
<p>Désormais, si tout c&#8217;est bien passé, nous avons notre tunnel SSH entre notre serveur et notre pc, il ne nous reste plus qu&#8217;a configurer les interfaces TUN et rediriger tout le traffic vers ce tunnel pour faire un pseudo-vpn.</p>
<h3>Configuration des interfaces TUN</h3>
<p>Sur notre machine cliente Ordinateur A :</p>
<blockquote>
<pre>sudo ifconfig tun11 192.168.0.61 pointopoint 192.168.0.60</pre>
</blockquote>
<p>si Ordinateur A tourne sous osx :</p>
<blockquote>
<pre>sudo ifconfig tun11 192.168.0.61 192.168.0.60</pre>
</blockquote>
<p>et sur notre serveur distant S :</p>
<blockquote>
<pre>sudo ifconfig tun10 192.168.0.60 pointopoint 192.168.0.61</pre>
</blockquote>
<p>ou sous osx :</p>
<blockquote>
<pre>sudo ifconfig tun10 192.168.0.60 192.168.0.61</pre>
</blockquote>
<p>Ces deux commandes a exécuter permette de définir une adresse ip aux interfaces TUN et de les lier en mode point-à-point pour simplifier les choses à l&#8217;interface distante.</p>
<p>Pour tester la configuration, faites un ping vers 192.168.0.60 depuis l&#8217;ordinateur A :</p>
<blockquote>
<pre>ping 192.168.0.60</pre>
</blockquote>
<p>Si 192.168.0.60 répond, c&#8217;est que vous êtes correctement relié au réseau distant.</p>
<p>Faites de même avec 192.168.0.61 depuis le serveur S pour tester dans l&#8217;autre sens.</p>
<h3>Redirection du trafic et création des routes</h3>
<p><a href="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/DP3_La_ferrage_Cuers_APPIA_la_route.jpg" rel="lightbox[34]"><img class="alignright size-thumbnail wp-image-102" title="DP3_La_ferrage_Cuers_APPIA_la_route" src="http://www.jeremy-trufier.net/wp-content/uploads/2009/12/DP3_La_ferrage_Cuers_APPIA_la_route-150x150.jpg" alt="" width="150" height="150" /></a>Depuis le serveur S, nous allons redirigé tout le traffic envoyé par l&#8217;ordinateur A au travers de l&#8217;interface eth0 relié au réseau local.</p>
<blockquote>
<pre>sudo arp -sD 192.168.0.61 eth0 pub</pre>
</blockquote>
<p>Désormais, tout est bouclé du côté serveur, vous pouvez fermer votre terminal distant.</p>
<p>Maintenant sur ordinateur A, nous allons configurer les routes.</p>
<p>Pour voir les routes déjà configurée :</p>
<blockquote>
<pre>netstat -nr</pre>
</blockquote>
<p>sur linux :</p>
<blockquote>
<pre>sudo route add -net 192.168.0.0 netmask 255.255.255.0 gw 192.168.0.61 tun11
sudo route add ip_du_serveur_S gw 172.16.0.254 eth0
sudo route del default gw 172.16.0.254 eth0
sudo route add default gw 192.168.0.61 tun11</pre>
</blockquote>
<p>sur mac :</p>
<blockquote>
<pre>sudo route add -net 192.168.0/24 192.168.0.61
sudo route add ip_du_serveur_S 172.16.0.254
sudo route delete default 172.16.0.254
sudo route add default 192.168.0.61</pre>
</blockquote>
<p>And it&#8217;s done !!!</p>
<p>Un petit test dans un navigateur depuis Ordinateur A sur le site http://monip.org devra montrer l&#8217;IP internet du réseau du serveur S. Si ce n&#8217;est pas le cas, il faut retester les ping, puis si tout est bon, vérifier les routes, il y a surement une erreur de ce coté là.</p>
<p>Edit: Il se peut que vous n&#8217;arriviez pas à joindre des adresses Web, si c&#8217;est votre cas,un petit ping des dns google :</p>
<pre style="padding-left: 30px;">ping 8.8.8.8</pre>
<p>Si le ping passe, alors c&#8217;est que vos DNS ne sont pas correct, allez dans vos préférences réseau et changez les par :</p>
<pre style="padding-left: 30px;">8.8.8.8
4.4.4.4</pre>
<p>(Ce sont les serveurs DNS de google).</p>
<p>Et normalement tout devrais fonctionner.</p>
<p>Si le ping 8.8.8.8 ne passe pas, vous devez surement avoir un problème dans votre configuration des routes, vérifiez là.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.jeremy-trufier.net/2009/12/21/veritable-vpn-au-travers-dun-tunnel-ssh/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
<!-- WP Super Cache is installed but broken. The path to wp-cache-phase1.php in wp-content/advanced-cache.php must be fixed! -->